Merge branch 'master' into topic-fix-453

This commit is contained in:
David Dalcino
2021-11-24 22:01:27 -08:00
committed by GitHub
10 changed files with 142 additions and 22 deletions

View File

@@ -7,6 +7,22 @@ All notable changes to this project will be documented in this file.
`Unreleased`_ `Unreleased`_
============= =============
`v2.0.2`_ (1, Nov. 2021)
=========================
Added
-----
* Support Qt 6.2.1 (#441)
Fixed
-----
* Degraded install-tool (#442,#443)
Changed
-------
* Add suggestion to use ``--external`` for MemoryError (#439)
`v2.0.1`_ (29, Oct. 2021) `v2.0.1`_ (29, Oct. 2021)
========================= =========================
@@ -248,7 +264,7 @@ Fixed
========================= =========================
Added Added
----- -----.. _v2.0.1: https://github.com/miurahr/aqtinstall/compare/v2.0.0...v2.0.1
* Patching android installation for Qt6 * Patching android installation for Qt6
- patch target_qt.conf - patch target_qt.conf
@@ -294,7 +310,8 @@ Fixed
.. _Unreleased: https://github.com/miurahr/aqtinstall/compare/v2.0.1...HEAD .. _Unreleased: https://github.com/miurahr/aqtinstall/compare/v2.0.2...HEAD
.. _v2.0.2: https://github.com/miurahr/aqtinstall/compare/v2.0.1...v2.0.2
.. _v2.0.1: https://github.com/miurahr/aqtinstall/compare/v2.0.0...v2.0.1 .. _v2.0.1: https://github.com/miurahr/aqtinstall/compare/v2.0.0...v2.0.1
.. _v2.0.0: https://github.com/miurahr/aqtinstall/compare/v1.2.5...v2.0.0 .. _v2.0.0: https://github.com/miurahr/aqtinstall/compare/v1.2.5...v2.0.0
.. _v1.2.5: https://github.com/miurahr/aqtinstall/compare/v1.2.4...v1.2.5 .. _v1.2.5: https://github.com/miurahr/aqtinstall/compare/v1.2.4...v1.2.5

View File

@@ -79,7 +79,7 @@ def getUrl(url: str, timeout) -> str:
return result return result
def downloadBinaryFile(url: str, out: str, hash_algo: str, exp: bytes, timeout): def downloadBinaryFile(url: str, out: Path, hash_algo: str, exp: bytes, timeout):
logger = getLogger("aqt.helper") logger = getLogger("aqt.helper")
filename = Path(url).name filename = Path(url).name
with requests.Session() as session: with requests.Session() as session:
@@ -114,7 +114,7 @@ def downloadBinaryFile(url: str, out: str, hash_algo: str, exp: bytes, timeout):
raise ArchiveChecksumError( raise ArchiveChecksumError(
f"Downloaded file {filename} is corrupted! Detect checksum error.\n" f"Downloaded file {filename} is corrupted! Detect checksum error.\n"
f"Expect {exp.hex()}: {url}\n" f"Expect {exp.hex()}: {url}\n"
f"Actual {hash.digest().hex()}: {out}" f"Actual {hash.digest().hex()}: {out.name}"
) )
@@ -305,6 +305,14 @@ class SettingsClass:
result = record["modules"] result = record["modules"]
return result return result
@property
def archive_download_location(self):
return self.config.get("aqt", "archive_download_location", fallback=".")
@property
def always_keep_archives(self):
return self.config.getboolean("aqt", "always_keep_archives", fallback=False)
@property @property
def concurrency(self): def concurrency(self):
"""concurrency configuration. """concurrency configuration.

View File

@@ -33,6 +33,8 @@ import sys
import time import time
from logging import getLogger from logging import getLogger
from logging.handlers import QueueHandler from logging.handlers import QueueHandler
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Any, Callable, List, Optional from typing import Any, Callable, List, Optional
import aqt import aqt
@@ -219,6 +221,24 @@ class Cli:
getLogger("aqt.installer").info(f"Resolved spec '{qt_version_or_spec}' to {version}") getLogger("aqt.installer").info(f"Resolved spec '{qt_version_or_spec}' to {version}")
return version return version
@staticmethod
def choose_archive_dest(archive_dest: Optional[str], keep: bool, temp_dir: str) -> Path:
"""
Choose archive download destination, based on context.
There are three potential behaviors here:
1. By default, return a temp directory that will be removed on program exit.
2. If the user has asked to keep archives, but has not specified a destination,
we return Settings.archive_download_location ("." by default).
3. If the user has asked to keep archives and specified a destination,
we create the destination dir if it doesn't exist, and return that directory.
"""
if not archive_dest:
return Path(Settings.archive_download_location if keep else temp_dir)
dest = Path(archive_dest)
dest.mkdir(parents=True, exist_ok=True)
return dest
def run_install_qt(self, args): def run_install_qt(self, args):
"""Run install subcommand""" """Run install subcommand"""
start_time = time.perf_counter() start_time = time.perf_counter()
@@ -235,7 +255,8 @@ class Cli:
else: else:
qt_version: str = args.qt_version qt_version: str = args.qt_version
Cli._validate_version_str(qt_version) Cli._validate_version_str(qt_version)
keep = args.keep keep: bool = args.keep or Settings.always_keep_archives
archive_dest: Optional[str] = args.archive_dest
output_dir = args.outputdir output_dir = args.outputdir
if output_dir is None: if output_dir is None:
base_dir = os.getcwd() base_dir = os.getcwd()
@@ -295,7 +316,9 @@ class Cli:
base, base,
) )
target_config = qt_archives.get_target_config() target_config = qt_archives.get_target_config()
run_installer(qt_archives.get_packages(), base_dir, sevenzip, keep) with TemporaryDirectory() as temp_dir:
_archive_dest = Cli.choose_archive_dest(archive_dest, keep, temp_dir)
run_installer(qt_archives.get_packages(), base_dir, sevenzip, keep, _archive_dest)
if not nopatch: if not nopatch:
Updater.update(target_config, base_dir) Updater.update(target_config, base_dir)
self.logger.info("Finished installation") self.logger.info("Finished installation")
@@ -322,7 +345,8 @@ class Cli:
base_dir = os.getcwd() base_dir = os.getcwd()
else: else:
base_dir = output_dir base_dir = output_dir
keep = args.keep keep: bool = args.keep or Settings.always_keep_archives
archive_dest: Optional[str] = args.archive_dest
if args.base is not None: if args.base is not None:
base = args.base base = args.base
else: else:
@@ -355,7 +379,9 @@ class Cli:
), ),
base, base,
) )
run_installer(srcdocexamples_archives.get_packages(), base_dir, sevenzip, keep) with TemporaryDirectory() as temp_dir:
_archive_dest = Cli.choose_archive_dest(archive_dest, keep, temp_dir)
run_installer(srcdocexamples_archives.get_packages(), base_dir, sevenzip, keep, _archive_dest)
self.logger.info("Finished installation") self.logger.info("Finished installation")
def run_install_src(self, args): def run_install_src(self, args):
@@ -407,7 +433,8 @@ class Cli:
version = getattr(args, "version", None) version = getattr(args, "version", None)
if version is not None: if version is not None:
Cli._validate_version_str(version, allow_minus=True) Cli._validate_version_str(version, allow_minus=True)
keep = args.keep keep: bool = args.keep or Settings.always_keep_archives
archive_dest: Optional[str] = args.archive_dest
if args.base is not None: if args.base is not None:
base = args.base base = args.base
else: else:
@@ -444,7 +471,9 @@ class Cli:
), ),
base, base,
) )
run_installer(tool_archives.get_packages(), base_dir, sevenzip, keep) with TemporaryDirectory() as temp_dir:
_archive_dest = Cli.choose_archive_dest(archive_dest, keep, temp_dir)
run_installer(tool_archives.get_packages(), base_dir, sevenzip, keep, _archive_dest)
self.logger.info("Finished installation") self.logger.info("Finished installation")
self.logger.info("Time elapsed: {time:.8f} second".format(time=time.perf_counter() - start_time)) self.logger.info("Time elapsed: {time:.8f} second".format(time=time.perf_counter() - start_time))
@@ -805,6 +834,13 @@ class Cli:
action="store_true", action="store_true",
help="Keep downloaded archive when specified, otherwise remove after install", help="Keep downloaded archive when specified, otherwise remove after install",
) )
subparser.add_argument(
"-d",
"--archive-dest",
type=str,
default=None,
help="Set the destination path for downloaded archives (temp directory by default).",
)
def _set_module_options(self, subparser): def _set_module_options(self, subparser):
subparser.add_argument("-m", "--modules", nargs="*", help="Specify extra modules to install") subparser.add_argument("-m", "--modules", nargs="*", help="Specify extra modules to install")
@@ -888,14 +924,14 @@ class Cli:
return function(fallback_url) return function(fallback_url)
def run_installer(archives: List[QtPackage], base_dir: str, sevenzip: Optional[str], keep: bool): def run_installer(archives: List[QtPackage], base_dir: str, sevenzip: Optional[str], keep: bool, archive_dest: Path):
queue = multiprocessing.Manager().Queue(-1) queue = multiprocessing.Manager().Queue(-1)
listener = MyQueueListener(queue) listener = MyQueueListener(queue)
listener.start() listener.start()
# #
tasks = [] tasks = []
for arc in archives: for arc in archives:
tasks.append((arc, base_dir, sevenzip, queue, keep)) tasks.append((arc, base_dir, sevenzip, queue, archive_dest, keep))
ctx = multiprocessing.get_context("spawn") ctx = multiprocessing.get_context("spawn")
pool = ctx.Pool(Settings.concurrency, init_worker_sh) pool = ctx.Pool(Settings.concurrency, init_worker_sh)
@@ -946,6 +982,7 @@ def installer(
base_dir: str, base_dir: str,
command: Optional[str], command: Optional[str],
queue: multiprocessing.Queue, queue: multiprocessing.Queue,
archive_dest: Path,
keep: bool = False, keep: bool = False,
response_timeout: Optional[int] = None, response_timeout: Optional[int] = None,
): ):
@@ -956,7 +993,7 @@ def installer(
name = qt_archive.name name = qt_archive.name
url = qt_archive.archive_url url = qt_archive.archive_url
hashurl = qt_archive.hashurl hashurl = qt_archive.hashurl
archive = qt_archive.archive archive: Path = archive_dest / qt_archive.archive
start_time = time.perf_counter() start_time = time.perf_counter()
# set defaults # set defaults
Settings.load_settings() Settings.load_settings()
@@ -993,10 +1030,10 @@ def installer(
"-bd", "-bd",
"-y", "-y",
"-o{}".format(base_dir), "-o{}".format(base_dir),
archive, str(archive),
] ]
else: else:
command_args = [command, "x", "-aoa", "-bd", "-y", archive] command_args = [command, "x", "-aoa", "-bd", "-y", str(archive)]
try: try:
proc = subprocess.run(command_args, stdout=subprocess.PIPE, check=True) proc = subprocess.run(command_args, stdout=subprocess.PIPE, check=True)
logger.debug(proc.stdout) logger.debug(proc.stdout)
@@ -1005,7 +1042,7 @@ def installer(
raise ArchiveExtractionError(msg) from cpe raise ArchiveExtractionError(msg) from cpe
if not keep: if not keep:
os.unlink(archive) os.unlink(archive)
logger.info("Finished installation of {} in {:.8f}".format(archive, time.perf_counter() - start_time)) logger.info("Finished installation of {} in {:.8f}".format(archive.name, time.perf_counter() - start_time))
qh.flush() qh.flush()
qh.close() qh.close()
logger.removeHandler(qh) logger.removeHandler(qh)

View File

@@ -5,6 +5,8 @@ concurrency: 4
baseurl: https://download.qt.io baseurl: https://download.qt.io
7zcmd: 7z 7zcmd: 7z
print_stacktrace_on_error: False print_stacktrace_on_error: False
always_keep_archives: False
archive_download_location: .
[requests] [requests]
connection_timeout: 3.5 connection_timeout: 3.5

View File

@@ -32,7 +32,7 @@ jobs:
- job: Mac - job: Mac
dependsOn: MatricesGenerator dependsOn: MatricesGenerator
pool: pool:
vmImage: 'macOS-10.14' vmImage: 'macOS-10.15'
strategy: strategy:
matrix: $[ dependencies.MatricesGenerator.outputs['mtrx.mac'] ] matrix: $[ dependencies.MatricesGenerator.outputs['mtrx.mac'] ]
steps: steps:

View File

@@ -361,7 +361,20 @@ are described here:
.. option:: --keep, -k .. option:: --keep, -k
Keep downloaded archive when specified, otherwise remove after install Keep downloaded archive when specified, otherwise remove after install.
Use ``--archive-dest <path>`` to choose where aqt will place these files.
If you do not specify a download destination, aqt will place these files in
the current working directory.
.. option:: --archive-dest <path>
Set the destination path for downloaded archives (temp directory by default).
All downloaded archives will be automatically deleted unless you have
specified the ``--keep`` option above, or ``aqt`` crashes.
Note that this option refers to the intermediate ``.7z`` archives that ``aqt``
downloads and then extracts to ``--outputdir``.
Most users will not need to keep these files.
.. option:: --modules, -m (<list of modules> | all) .. option:: --modules, -m (<list of modules> | all)
@@ -440,6 +453,7 @@ install-qt command
[-E | --external <7zip command>] [-E | --external <7zip command>]
[--internal] [--internal]
[-k | --keep] [-k | --keep]
[-d | --archive-dest] <path>
[-m | --modules (all | <module> [<module>...])] [-m | --modules (all | <module> [<module>...])]
[--archives <archive> [<archive>...]] [--archives <archive> [<archive>...]]
[--noarchives] [--noarchives]
@@ -515,6 +529,7 @@ install-src command
[-E | --external <7zip command>] [-E | --external <7zip command>]
[--internal] [--internal]
[-k | --keep] [-k | --keep]
[-d | --archive-dest] <path>
[--archives <archive> [<archive>...]] [--archives <archive> [<archive>...]]
[--kde] [--kde]
<host> [<target>] (<Qt version> | <spec>) <host> [<target>] (<Qt version> | <spec>)
@@ -574,6 +589,7 @@ install-doc command
[-E | --external <7zip command>] [-E | --external <7zip command>]
[--internal] [--internal]
[-k | --keep] [-k | --keep]
[-d | --archive-dest] <path>
[-m | --modules (all | <module> [<module>...])] [-m | --modules (all | <module> [<module>...])]
[--archives <archive> [<archive>...]] [--archives <archive> [<archive>...]]
<host> [<target>] (<Qt version> | <spec>) <host> [<target>] (<Qt version> | <spec>)
@@ -625,6 +641,7 @@ install-example command
[-E | --external <7zip command>] [-E | --external <7zip command>]
[--internal] [--internal]
[-k | --keep] [-k | --keep]
[-d | --archive-dest] <path>
[-m | --modules (all | <module> [<module>...])] [-m | --modules (all | <module> [<module>...])]
[--archives <archive> [<archive>...]] [--archives <archive> [<archive>...]]
<host> [<target>] (<Qt version> | <spec>) <host> [<target>] (<Qt version> | <spec>)
@@ -678,6 +695,7 @@ install-tool command
[-E | --external <7zip command>] [-E | --external <7zip command>]
[--internal] [--internal]
[-k | --keep] [-k | --keep]
[-d | --archive-dest] <path>
<host> <target> <tool name> [<tool variant name>] <host> <target> <tool name> [<tool variant name>]
Install tools like QtIFW, mingw, Cmake, Conan, and vcredist. Install tools like QtIFW, mingw, Cmake, Conan, and vcredist.

View File

@@ -20,6 +20,8 @@ A file is like as follows:
baseurl: https://download.qt.io baseurl: https://download.qt.io
7zcmd: 7z 7zcmd: 7z
print_stacktrace_on_error: False print_stacktrace_on_error: False
always_keep_archives: False
archive_download_location: .
[requests] [requests]
connection_timeout: 3.5 connection_timeout: 3.5
@@ -71,6 +73,18 @@ print_stacktrace_on_error:
The ``False`` setting will hide the stack trace, unless an unhandled The ``False`` setting will hide the stack trace, unless an unhandled
exception occurs. exception occurs.
always_keep_archives:
This is either ``True`` or ``False``.
The ``True`` setting turns on the ``--keep`` option every time you run aqt,
and cannot be overridden by command line options.
The ``False`` setting will require you to set ``--keep`` manually every time
you run aqt, unless you don't want to keep ``.7z`` archives.
archive_download_location:
This is the relative or absolute path to the location in which ``.7z`` archives
will be downloaded, when ``--keep`` is turned on.
You can override this location with the ``--archives-dest`` option.
The ``[requests]`` section controls the way that ``aqt`` makes network requests. The ``[requests]`` section controls the way that ``aqt`` makes network requests.

View File

@@ -351,3 +351,26 @@ def test_cli_set_7zip(monkeypatch):
cli._set_sevenzip("some_nonexistent_binary") cli._set_sevenzip("some_nonexistent_binary")
assert err.type == CliInputError assert err.type == CliInputError
assert format(err.value) == "Specified 7zip command executable does not exist: 'some_nonexistent_binary'" assert format(err.value) == "Specified 7zip command executable does not exist: 'some_nonexistent_binary'"
@pytest.mark.parametrize(
"archive_dest, keep, temp_dir, expect, should_make_dir",
(
(None, False, "temp", "temp", False),
(None, True, "temp", ".", False),
("my_archives", False, "temp", "my_archives", True),
("my_archives", True, "temp", "my_archives", True),
),
)
def test_cli_choose_archive_dest(
monkeypatch, archive_dest: Optional[str], keep: bool, temp_dir: str, expect: str, should_make_dir: bool
):
enclosed = {"made_dir": False}
def mock_mkdir(*args, **kwargs):
enclosed["made_dir"] = True
monkeypatch.setattr("aqt.installer.Path.mkdir", mock_mkdir)
assert Cli.choose_archive_dest(archive_dest, keep, temp_dir) == Path(expect)
assert enclosed["made_dir"] == should_make_dir

View File

@@ -127,10 +127,10 @@ def test_helper_downloadBinary_wrong_checksum(tmp_path, monkeypatch):
expected_err = ( expected_err = (
f"Downloaded file test.xml is corrupted! Detect checksum error." f"Downloaded file test.xml is corrupted! Detect checksum error."
f"\nExpect {wrong_hash.hex()}: {url}" f"\nExpect {wrong_hash.hex()}: {url}"
f"\nActual {actual_hash.hex()}: {out}" f"\nActual {actual_hash.hex()}: {out.name}"
) )
with pytest.raises(ArchiveChecksumError) as e: with pytest.raises(ArchiveChecksumError) as e:
helper.downloadBinaryFile(url, str(out), "md5", wrong_hash, 60) helper.downloadBinaryFile(url, out, "md5", wrong_hash, 60)
assert e.type == ArchiveChecksumError assert e.type == ArchiveChecksumError
assert format(e.value) == expected_err assert format(e.value) == expected_err

View File

@@ -146,11 +146,11 @@ def make_mock_geturl_download_archive(
def locate_archive() -> MockArchive: def locate_archive() -> MockArchive:
for arc in archives: for arc in archives:
if out == arc.filename_7z: if Path(out).name == arc.filename_7z:
return arc return arc
assert False, "Requested an archive that was not mocked" assert False, "Requested an archive that was not mocked"
locate_archive().write_compressed_archive(Path("./")) locate_archive().write_compressed_archive(Path(out).parent)
return mock_getUrl, mock_download_archive return mock_getUrl, mock_download_archive
@@ -810,6 +810,7 @@ def test_install_installer_archive_extraction_err(monkeypatch):
base_dir=temp_dir, base_dir=temp_dir,
command="some_nonexistent_7z_extractor", command="some_nonexistent_7z_extractor",
queue=MockMultiprocessingManager.Queue(), queue=MockMultiprocessingManager.Queue(),
archive_dest=Path(temp_dir),
) )
assert err.type == ArchiveExtractionError assert err.type == ArchiveExtractionError
err_msg = format(err.value).rstrip() err_msg = format(err.value).rstrip()