Commercial fixes, CI tests, more tests, coverage (#883)

* Add authentication flags for list-qt-commercial, add tests for coverage

* Add dry run

* Make tests really use auth since secrets have been added, fix some indents

* Fix auth issue, rename user 'email, and password 'pw'

* Fix modules param type

* Update commands names
This commit is contained in:
Alexandre Poumaroux
2025-02-22 01:56:56 +01:00
committed by GitHub
parent a30f5a3d05
commit 5d699b9ebf
13 changed files with 1172 additions and 830 deletions

View File

@@ -3,18 +3,21 @@ name: Check tox tests
on:
push:
branches:
- master
- releases/*
- master
- releases/*
pull_request:
types:
- opened
- synchronize
- reopened
- opened
- synchronize
- reopened
jobs:
check_document:
name: Check packaging 📦
runs-on: ubuntu-22.04
env:
AQT_TEST_EMAIL: ${{ secrets.AQT_TEST_EMAIL }}
AQT_TEST_PASSWORD: ${{ secrets.AQT_TEST_PASSWORD }}
steps:
- uses: actions/checkout@v4
with:

1
.gitignore vendored
View File

@@ -20,3 +20,4 @@ qtaccount.ini
.pytest_cache
.run/
.python-version
.env

View File

@@ -9,7 +9,15 @@ import requests
from defusedxml import ElementTree
from aqt.exceptions import DiskAccessNotPermitted
from aqt.helper import Settings, get_os_name, get_qt_account_path, get_qt_installer_name, safely_run, safely_run_save_output
from aqt.helper import (
Settings,
extract_auth,
get_os_name,
get_qt_account_path,
get_qt_installer_name,
safely_run,
safely_run_save_output,
)
from aqt.metadata import Version
@@ -103,19 +111,14 @@ class QtPackageManager:
version_str = self._get_version_string()
base_package = f"qt.qt{self.version.major}.{version_str}"
cmd = [
installer_path,
"--accept-licenses",
"--accept-obligations",
"--confirm-command",
"--default-answer",
"search",
base_package,
]
cmd = [installer_path, "--accept-licenses", "--accept-obligations", "--confirm-command", "--default-answer"]
if self.username and self.password:
cmd.extend(["--email", self.username, "--pw", self.password])
cmd.append("search")
cmd.append(base_package)
try:
output = safely_run_save_output(cmd, Settings.qt_installer_timeout)
@@ -190,7 +193,7 @@ class CommercialInstaller:
output_dir: Optional[str] = None,
logger: Optional[Logger] = None,
base_url: str = "https://download.qt.io",
override: Optional[list[str]] = None,
override: Optional[List[str]] = None,
modules: Optional[List[str]] = None,
no_unattended: bool = False,
):
@@ -198,14 +201,21 @@ class CommercialInstaller:
self.target = target
self.arch = arch or ""
self.version = Version(version) if version else Version("0.0.0")
self.username = username
self.password = password
self.output_dir = output_dir
self.logger = logger or getLogger(__name__)
self.base_url = base_url
self.modules = modules
self.no_unattended = no_unattended
# Extract credentials from override if present
if override:
extracted_username, extracted_password, self.override = extract_auth(override)
self.username = extracted_username or username
self.password = extracted_password or password
else:
self.username = username
self.password = password
# Set OS-specific properties
self.os_name = get_os_name()
self._installer_filename = get_qt_installer_name()
@@ -247,15 +257,15 @@ class CommercialInstaller:
if not no_unattended:
cmd.extend(["--accept-licenses", "--accept-obligations", "--confirm-command"])
# Add authentication if provided
if username and password:
cmd.extend(["--email", username, "--pw", password])
if override:
# When using override, still include unattended flags unless disabled
cmd.extend(override)
return cmd
# Add authentication if provided
if username and password:
cmd.extend(["--email", username, "--pw", password])
# Add output directory if specified
if output_dir:
cmd.extend(["--root", str(Path(output_dir).resolve())])
@@ -271,36 +281,34 @@ class CommercialInstaller:
"""Run the Qt installation process."""
if (
not self.qt_account.exists()
and not (self.username and self.password)
and (not self.username or not self.password)
and not os.environ.get("QT_INSTALLER_JWT_TOKEN")
):
raise RuntimeError(
"No Qt account credentials found. Provide username and password or ensure qtaccount.ini exists."
)
# Check output directory if specified
if self.output_dir:
output_path = Path(self.output_dir) / str(self.version)
if output_path.exists():
if Settings.qt_installer_overwritetargetdirectory.lower() == "yes":
self.logger.warning(f"Target directory {output_path} exists - removing as overwrite is enabled")
try:
import shutil
shutil.rmtree(output_path)
except (OSError, PermissionError) as e:
raise DiskAccessNotPermitted(f"Failed to remove existing target directory {output_path}: {str(e)}")
else:
msg = (
f"Target directory {output_path} already exists. "
"Set overwrite_target_directory='Yes' in settings.ini to overwrite, or select another directory."
)
raise DiskAccessNotPermitted(msg)
# Setup cache directory
cache_path = Path(Settings.qt_installer_cache_path)
cache_path.mkdir(parents=True, exist_ok=True)
# Setup output directory and validate access
output_dir = Path(self.output_dir) if self.output_dir else Path(os.getcwd()) / "Qt"
version_dir = output_dir / str(self.version)
qt_base_dir = output_dir
if qt_base_dir.exists():
if Settings.qt_installer_overwritetargetdirectory.lower() == "yes":
self.logger.warning(f"Target directory {qt_base_dir} exists - removing as overwrite is enabled")
try:
import shutil
if version_dir.exists():
shutil.rmtree(version_dir)
except (OSError, PermissionError) as e:
raise DiskAccessNotPermitted(f"Failed to remove existing version directory {version_dir}: {str(e)}")
# Setup temp directory
import shutil
temp_dir = Settings.qt_installer_temp_path
@@ -316,7 +324,16 @@ class CommercialInstaller:
try:
cmd = []
if self.override:
cmd = self.build_command(str(installer_path), override=self.override, no_unattended=self.no_unattended)
if not self.username or not self.password:
self.username, self.password, self.override = extract_auth(self.override)
cmd = self.build_command(
str(installer_path),
override=self.override,
no_unattended=self.no_unattended,
username=self.username,
password=self.password,
)
else:
# Initialize package manager and gather packages
self.package_manager.gather_packages(str(installer_path))
@@ -325,20 +342,18 @@ class CommercialInstaller:
str(installer_path.absolute()),
username=self.username,
password=self.password,
output_dir=self.output_dir,
output_dir=str(qt_base_dir.absolute()),
no_unattended=self.no_unattended,
)
cmd = [
*base_cmd,
*self.package_manager.get_install_command(self.modules, temp_dir),
]
install_cmd = self.package_manager.get_install_command(self.modules, temp_dir)
cmd = [*base_cmd, *install_cmd]
self.logger.info(f"Running: {cmd}")
safely_run(cmd, Settings.qt_installer_timeout)
except Exception as e:
self.logger.error(f"Installation failed with exit code {e.__str__()}")
self.logger.error(f"Installation failed: {str(e)}")
raise
finally:
self.logger.info("Qt installation completed successfully")

View File

@@ -459,18 +459,18 @@ class SettingsClass:
"""Path for Qt installer cache."""
config = self._get_config()
# If no cache_path or blank, return default without modifying config
if not config.has_option("qtcommercial", "cache_path") or config.get("qtcommercial", "cache_path").strip() == "":
if not config.has_option("qtofficial", "cache_path") or config.get("qtofficial", "cache_path").strip() == "":
return str(get_default_local_cache_path())
return config.get("qtcommercial", "cache_path")
return config.get("qtofficial", "cache_path")
@property
def qt_installer_temp_path(self) -> str:
"""Path for Qt installer cache."""
config = self._get_config()
# If no cache_path or blank, return default without modifying config
if not config.has_option("qtcommercial", "temp_path") or config.get("qtcommercial", "temp_path").strip() == "":
if not config.has_option("qtofficial", "temp_path") or config.get("qtofficial", "temp_path").strip() == "":
return str(get_default_local_temp_path())
return config.get("qtcommercial", "temp_path")
return config.get("qtofficial", "temp_path")
@property
def archive_download_location(self):
@@ -572,47 +572,47 @@ class SettingsClass:
@property
def qt_installer_timeout(self) -> int:
"""Timeout for Qt commercial installer operations in seconds."""
return self._get_config().getint("qtcommercial", "installer_timeout", fallback=3600)
return self._get_config().getint("qtofficial", "installer_timeout", fallback=3600)
@property
def qt_installer_operationdoesnotexisterror(self) -> str:
"""Handle OperationDoesNotExistError in Qt installer."""
return self._get_config().get("qtcommercial", "operation_does_not_exist_error", fallback="Ignore")
return self._get_config().get("qtofficial", "operation_does_not_exist_error", fallback="Ignore")
@property
def qt_installer_overwritetargetdirectory(self) -> str:
"""Handle overwriting target directory in Qt installer."""
return self._get_config().get("qtcommercial", "overwrite_target_directory", fallback="No")
return self._get_config().get("qtofficial", "overwrite_target_directory", fallback="No")
@property
def qt_installer_stopprocessesforupdates(self) -> str:
"""Handle stopping processes for updates in Qt installer."""
return self._get_config().get("qtcommercial", "stop_processes_for_updates", fallback="Cancel")
return self._get_config().get("qtofficial", "stop_processes_for_updates", fallback="Cancel")
@property
def qt_installer_installationerrorwithcancel(self) -> str:
"""Handle installation errors with cancel option in Qt installer."""
return self._get_config().get("qtcommercial", "installation_error_with_cancel", fallback="Cancel")
return self._get_config().get("qtofficial", "installation_error_with_cancel", fallback="Cancel")
@property
def qt_installer_installationerrorwithignore(self) -> str:
"""Handle installation errors with ignore option in Qt installer."""
return self._get_config().get("qtcommercial", "installation_error_with_ignore", fallback="Ignore")
return self._get_config().get("qtofficial", "installation_error_with_ignore", fallback="Ignore")
@property
def qt_installer_associatecommonfiletypes(self) -> str:
"""Handle file type associations in Qt installer."""
return self._get_config().get("qtcommercial", "associate_common_filetypes", fallback="Yes")
return self._get_config().get("qtofficial", "associate_common_filetypes", fallback="Yes")
@property
def qt_installer_telemetry(self) -> str:
"""Handle telemetry settings in Qt installer."""
return self._get_config().get("qtcommercial", "telemetry", fallback="No")
return self._get_config().get("qtofficial", "telemetry", fallback="No")
@property
def qt_installer_unattended(self) -> bool:
"""Control whether to use unattended installation flags."""
return self._get_config().getboolean("qtcommercial", "unattended", fallback=True)
return self._get_config().getboolean("qtofficial", "unattended", fallback=True)
def qt_installer_cleanup(self) -> None:
"""Control whether to use unattended installation flags."""
@@ -644,3 +644,26 @@ def safely_run_save_output(cmd: List[str], timeout: int) -> Any:
return result
except Exception:
raise
def extract_auth(args: List[str]) -> Tuple[str | None, str | None, List[str] | None]:
username = None
password = None
i = 0
while i < len(args):
if args[i] == "--email":
if i + 1 < len(args):
username = args[i + 1]
del args[i : i + 2]
else:
del args[i]
continue
elif args[i] == "--pw":
if i + 1 < len(args):
password = args[i + 1]
del args[i : i + 2]
else:
del args[i]
continue
i += 1
return username, password, args

View File

@@ -28,6 +28,7 @@ import multiprocessing
import os
import platform
import posixpath
import re
import signal
import subprocess
import sys
@@ -59,6 +60,7 @@ from aqt.helper import (
MyQueueListener,
Settings,
downloadBinaryFile,
extract_auth,
get_hash,
get_os_name,
get_qt_installer_name,
@@ -123,6 +125,7 @@ class CommonInstallArgParser(BaseArgumentParser):
internal: bool
keep: bool
archive_dest: Optional[str]
dry_run: bool
class InstallArgParser(CommonInstallArgParser):
@@ -133,8 +136,8 @@ class InstallArgParser(CommonInstallArgParser):
qt_version: str
qt_version_spec: str
version: Optional[str]
user: Optional[str]
password: Optional[str]
email: Optional[str]
pw: Optional[str]
operation_does_not_exist_error: str
overwrite_target_dir: str
stop_processes_for_updates: str
@@ -337,6 +340,7 @@ class Cli:
arch: str = self._set_arch(args.arch, os_name, target, qt_version_or_spec)
keep: bool = args.keep or Settings.always_keep_archives
archive_dest: Optional[str] = args.archive_dest
dry_run: bool = args.dry_run
output_dir = args.outputdir
if output_dir is None:
base_dir = os.getcwd()
@@ -405,47 +409,50 @@ class Cli:
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)
run_installer(qt_archives.get_packages(), base_dir, sevenzip, keep, _archive_dest, dry_run=dry_run)
if not nopatch:
Updater.update(target_config, base_path, expect_desktop_archdir)
if dry_run:
return
if not nopatch:
Updater.update(target_config, base_path, expect_desktop_archdir)
# If autodesktop is enabled and we need a desktop installation, do it first
if should_autoinstall and autodesk_arch is not None:
is_wasm = arch.startswith("wasm")
is_msvc = "msvc" in arch
is_win_desktop_msvc_arm64 = (
effective_os_name == "windows"
and target == "desktop"
and is_msvc
and arch.endswith(("arm64", "arm64_cross_compiled"))
)
if is_win_desktop_msvc_arm64:
qt_type = "MSVC Arm64"
elif is_wasm:
qt_type = "Qt6-WASM"
else:
qt_type = target
# Create new args for desktop installation
self.logger.info("")
self.logger.info(
f"Autodesktop will now install {effective_os_name} desktop "
f"{qt_version} {autodesk_arch} as required by {qt_type}"
)
desktop_args = args
args.autodesktop = False
args.host = effective_os_name
args.target = "desktop"
args.arch = autodesk_arch
# Run desktop installation first
self.run_install_qt(desktop_args)
# If autodesktop is enabled and we need a desktop installation, do it first
if should_autoinstall and autodesk_arch is not None:
is_wasm = arch.startswith("wasm")
is_msvc = "msvc" in arch
is_win_desktop_msvc_arm64 = (
effective_os_name == "windows"
and target == "desktop"
and is_msvc
and arch.endswith(("arm64", "arm64_cross_compiled"))
)
if is_win_desktop_msvc_arm64:
qt_type = "MSVC Arm64"
elif is_wasm:
qt_type = "Qt6-WASM"
else:
qt_type = target
# Create new args for desktop installation
self.logger.info("")
self.logger.info(
f"Autodesktop will now install {effective_os_name} desktop "
f"{qt_version} {autodesk_arch} as required by {qt_type}"
)
desktop_args = args
args.autodesktop = False
args.host = effective_os_name
args.target = "desktop"
args.arch = autodesk_arch
# Run desktop installation first
self.run_install_qt(desktop_args)
else:
self.logger.info("Finished installation")
self.logger.info("Time elapsed: {time:.8f} second".format(time=time.perf_counter() - start_time))
self.logger.info("Finished installation")
self.logger.info("Time elapsed: {time:.8f} second".format(time=time.perf_counter() - start_time))
def _run_src_doc_examples(self, flavor, args, cmd_name: Optional[str] = None):
self.show_aqt_version()
@@ -498,7 +505,9 @@ class Cli:
)
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)
run_installer(
srcdocexamples_archives.get_packages(), base_dir, sevenzip, keep, _archive_dest, dry_run=args.dry_run
)
self.logger.info("Finished installation")
def run_install_src(self, args):
@@ -585,7 +594,7 @@ class Cli:
)
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)
run_installer(tool_archives.get_packages(), base_dir, sevenzip, keep, _archive_dest, dry_run=args.dry_run)
self.logger.info("Finished installation")
self.logger.info("Time elapsed: {time:.8f} second".format(time=time.perf_counter() - start_time))
@@ -676,42 +685,43 @@ class Cli:
"""Execute commercial Qt installation"""
self.show_aqt_version()
if args.override:
commercial_installer = CommercialInstaller(
target="", # Empty string as placeholder
arch="",
version=None,
logger=self.logger,
base_url=args.base if args.base is not None else Settings.baseurl,
override=args.override,
no_unattended=not Settings.qt_installer_unattended,
)
else:
if not all([args.target, args.arch, args.version]):
raise CliInputError("target, arch, and version are required")
commercial_installer = CommercialInstaller(
target=args.target,
arch=args.arch,
version=args.version,
username=args.user,
password=args.password,
output_dir=args.outputdir,
logger=self.logger,
base_url=args.base if args.base is not None else Settings.baseurl,
no_unattended=not Settings.qt_installer_unattended,
modules=args.modules,
)
try:
if args.override:
username, password, override_args = extract_auth(args.override)
commercial_installer = CommercialInstaller(
target="", # Empty string as placeholder
arch="",
version=None,
logger=self.logger,
base_url=args.base if args.base is not None else Settings.baseurl,
override=override_args,
no_unattended=not Settings.qt_installer_unattended,
username=username or args.email,
password=password or args.pw,
)
else:
if not all([args.target, args.arch, args.version]):
raise CliInputError("target, arch, and version are required")
commercial_installer = CommercialInstaller(
target=args.target,
arch=args.arch,
version=args.version,
username=args.email,
password=args.pw,
output_dir=args.outputdir,
logger=self.logger,
base_url=args.base if args.base is not None else Settings.baseurl,
no_unattended=not Settings.qt_installer_unattended,
modules=args.modules,
)
commercial_installer.install()
Settings.qt_installer_cleanup()
except DiskAccessNotPermitted:
# Let DiskAccessNotPermitted propagate up without additional logging
raise
except Exception as e:
self.logger.error(f"Commercial installation failed: {str(e)}")
raise
self.logger.error(f"Error installing official installer {str(e)}")
finally:
self.logger.info("Done")
def show_help(self, args=None):
"""Display help message"""
@@ -837,44 +847,46 @@ class Cli:
install_qt_commercial_parser.add_argument("version", nargs="?", help="Qt version", action=ConditionalRequiredAction)
install_qt_commercial_parser.add_argument(
"--user",
help="Qt account username",
"--email",
help="Qt account email",
)
install_qt_commercial_parser.add_argument(
"--password",
"--pw",
help="Qt account password",
)
install_qt_commercial_parser.add_argument(
"-m",
"--modules",
nargs="*",
help="Add modules",
)
self._set_common_options(install_qt_commercial_parser)
def _make_list_qt_commercial_parser(self, subparsers: argparse._SubParsersAction) -> None:
"""Creates a subparser for listing Qt commercial packages"""
list_parser = subparsers.add_parser(
"list-qt-commercial",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="Examples:\n"
"$ aqt list-qt-commercial # list all available packages\n"
"$ aqt list-qt-commercial gcc_64 # search for specific archs\n"
"$ aqt list-qt-commercial 6.8.1 # search for specific versions\n"
"$ aqt list-qt-commercial qtquick3d # search for specific packages\n"
"$ aqt list-qt-commercial gcc_64 6.8.1 # search for multiple terms at once\n",
def _set_list_qt_commercial_parser(self, list_qt_commercial_parser: argparse.ArgumentParser) -> None:
"""Configure parser for list-qt-official command with flexible argument handling."""
list_qt_commercial_parser.set_defaults(func=self.run_list_qt_commercial)
list_qt_commercial_parser.add_argument(
"--email",
help="Qt account email",
)
list_parser.add_argument(
list_qt_commercial_parser.add_argument(
"--pw",
help="Qt account password",
)
# Capture all remaining arguments as search terms
list_qt_commercial_parser.add_argument(
"search_terms",
nargs="*",
help="Optional search terms to pass to the installer search command. If not provided, lists all packages",
nargs="*", # Zero or more arguments
help="Search terms (all non-option arguments are treated as search terms)",
)
list_parser.set_defaults(func=self.run_list_qt_commercial)
def run_list_qt_commercial(self, args) -> None:
"""Execute Qt commercial package listing"""
"""Execute Qt commercial package listing."""
self.show_aqt_version()
# Create temporary directory to download installer
# Create temporary directory for installer
import shutil
from pathlib import Path
@@ -893,6 +905,7 @@ class Cli:
self.logger.info(f"Downloading Qt installer to {installer_path}")
base_url = Settings.baseurl
url = f"{base_url}/official_releases/online_installers/{installer_filename}"
import requests
response = requests.get(url, stream=True, timeout=Settings.qt_installer_timeout)
@@ -905,33 +918,30 @@ class Cli:
if get_os_name() != "windows":
os.chmod(installer_path, 0o500)
# Build search command
cmd = [
str(installer_path),
"--accept-licenses",
"--accept-obligations",
"--confirm-command",
"search",
"" if not args.search_terms else " ".join(args.search_terms),
]
# Build command
cmd = [str(installer_path), "--accept-licenses", "--accept-obligations", "--confirm-command"]
# Run search and display output
if args.email and args.pw:
cmd.extend(["--email", args.email, "--pw", args.pw])
cmd.append("search")
# Add all search terms if present
if args.search_terms:
cmd.extend(args.search_terms)
# Run search
output = safely_run_save_output(cmd, Settings.qt_installer_timeout)
# Process and print the output properly
if output.stdout:
# Print the actual output with proper newlines
print(output.stdout)
# If there are any errors, print them as warnings
self.logger.info(output.stdout)
if output.stderr:
for line in output.stderr.splitlines():
self.logger.warning(line)
except Exception as e:
self.logger.error(f"Failed to list Qt commercial packages: {e}")
self.logger.error(f"Failed to list Qt official packages: {e}")
finally:
# Clean up
Settings.qt_installer_cleanup()
def _warn_on_deprecated_command(self, old_name: str, new_name: str) -> None:
@@ -987,18 +997,23 @@ class Cli:
make_parser_it("install-qt", "Install Qt.", self._set_install_qt_parser, argparse.RawTextHelpFormatter)
make_parser_it("install-tool", "Install tools.", self._set_install_tool_parser, None)
make_parser_it(
"install-qt-commercial",
"Install Qt commercial.",
"install-qt-official",
"Install Qt with official installer.",
self._set_install_qt_commercial_parser,
argparse.RawTextHelpFormatter,
)
make_parser_it(
"list-qt-official",
"Search packages using Qt official installer.",
self._set_list_qt_commercial_parser,
argparse.RawTextHelpFormatter,
)
make_parser_sde("install-doc", "Install documentation.", self.run_install_doc, False)
make_parser_sde("install-example", "Install examples.", self.run_install_example, False)
make_parser_sde("install-src", "Install source.", self.run_install_src, True, is_add_modules=False)
# Create list command parsers
self._make_list_qt_parser(subparsers)
self._make_list_qt_commercial_parser(subparsers)
self._make_list_tool_parser(subparsers)
make_parser_list_sde("list-doc", "List documentation archives available (use with install-doc)", "doc")
make_parser_list_sde("list-example", "List example archives available (use with install-example)", "examples")
@@ -1018,11 +1033,16 @@ class Cli:
'$ aqt list-qt mac desktop --spec "5.9" --latest-version # print latest Qt 5.9\n'
"$ aqt list-qt mac desktop --modules 5.12.0 clang_64 # print modules for 5.12.0\n"
"$ aqt list-qt mac desktop --spec 5.9 --modules latest clang_64 # print modules for latest 5.9\n"
"$ aqt list-qt mac desktop --arch 5.9.9 # print architectures for 5.9.9/mac/desktop\n"
"$ aqt list-qt mac desktop --arch latest # print architectures for the latest Qt 5\n"
"$ aqt list-qt mac desktop --archives 5.9.0 clang_64 # list archives in base Qt installation\n"
"$ aqt list-qt mac desktop --archives 5.14.0 clang_64 debug_info # list archives in debug_info module\n"
"$ aqt list-qt all_os wasm --arch 6.8.1 # print architectures for Qt WASM 6.8.1\n",
"$ aqt list-qt mac desktop --arch 5.9.9 # print architectures for "
"5.9.9/mac/desktop\n"
"$ aqt list-qt mac desktop --arch latest # print architectures for the "
"latest Qt 5\n"
"$ aqt list-qt mac desktop --archives 5.9.0 clang_64 # list archives in base Qt "
"installation\n"
"$ aqt list-qt mac desktop --archives 5.14.0 clang_64 debug_info # list archives in debug_info "
"module\n"
"$ aqt list-qt all_os wasm --arch 6.8.1 # print architectures for Qt WASM "
"6.8.1\n",
)
list_parser.add_argument(
"host",
@@ -1182,6 +1202,11 @@ class Cli:
default=None,
help="Set the destination path for downloaded archives (temp directory by default).",
)
subparser.add_argument(
"--dry-run",
action="store_true",
help="Print what would be downloaded and installed without actually doing it",
)
def _set_module_options(self, subparser):
subparser.add_argument("-m", "--modules", nargs="*", help="Specify extra modules to install")
@@ -1354,7 +1379,28 @@ def run_installer(
sevenzip: Optional[str],
keep: bool,
archive_dest: Path,
dry_run: bool = False,
):
if dry_run:
logger = getLogger("aqt.installer")
logger.info("DRY RUN: Would download and install the following:")
for arc in archives:
line_parts = [f" - {arc.name}: {arc.archive_path}"]
if hasattr(arc, "package_desc") and arc.package_desc:
size_match = re.search(r"Size: ([^,]+)", arc.package_desc)
if size_match:
line_parts.append(f" ({size_match.group(1)})")
if arc.archive_install_path and arc.archive_install_path.strip():
line_parts.append(f" -> {arc.archive_install_path}")
logger.info("".join(line_parts))
logger.info(f"Total packages: {len(archives)}")
return
queue = multiprocessing.Manager().Queue(-1)
listener = MyQueueListener(queue)
listener.start()

View File

@@ -19,11 +19,11 @@ max_retries_to_retrieve_hash : 5
hash_algorithm : sha256
INSECURE_NOT_FOR_PRODUCTION_ignore_hash : False
[qtcommercial]
[qtofficial]
unattended : True
installer_timeout : 1800
operation_does_not_exist_error : Ignore
overwrite_target_directory : Yes
overwrite_target_directory : No
stop_processes_for_updates : Ignore
installation_error_with_cancel : Ignore
installation_error_with_ignore : Ignore

View File

@@ -7,13 +7,13 @@ jobs:
pool:
vmImage: 'ubuntu-22.04'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.12'
addToPath: true
- bash: python ci/generate_azure_pipelines_matrices.py
name: mtrx
displayName: Generate test matrices and set variables in Azure Pipelines
- task: UsePythonVersion@0
inputs:
versionSpec: '3.12'
addToPath: true
- bash: python ci/generate_azure_pipelines_matrices.py
name: mtrx
displayName: Generate test matrices and set variables in Azure Pipelines
- job: Mac
dependsOn: MatricesGenerator
@@ -22,9 +22,9 @@ jobs:
strategy:
matrix: $[ dependencies.MatricesGenerator.outputs['mtrx.mac'] ]
steps:
- script: brew install p7zip
displayName: Install 7zip
- template: ci/steps.yml
- script: brew install p7zip
displayName: Install 7zip
- template: ci/steps.yml
- job: Windows
dependsOn: MatricesGenerator
@@ -37,7 +37,7 @@ jobs:
startYear: $[format('{0:yyyy}', pipeline.startTime)]
startMonth: $[format('{0:MM}', pipeline.startTime)]
steps:
- template: ci/steps.yml
- template: ci/steps.yml
- job: Linux
dependsOn: MatricesGenerator
@@ -46,7 +46,7 @@ jobs:
strategy:
matrix: $[ dependencies.MatricesGenerator.outputs['mtrx.linux'] ]
steps:
- template: ci/steps.yml
- template: ci/steps.yml
#- job: Linux_ARM64
# dependsOn: MatricesGenerator

View File

@@ -3,7 +3,6 @@ This sets variables for a matrix of QT versions to test downloading against with
"""
import collections
import json
import secrets as random
import re
from itertools import product
from typing import Dict, Optional
@@ -46,7 +45,8 @@ class BuildJob:
is_autodesktop: bool = False,
tool_options: Optional[Dict[str, str]] = None,
check_output_cmd: Optional[str] = None,
emsdk_version: str = "sdk-fastcomp-1.38.27-64bit@3.1.29", # did not change for safety, created func self.emsdk_version()
emsdk_version: str = "sdk-fastcomp-1.38.27-64bit@3.1.29",
# did not change for safety, created func self.emsdk_version()
autodesk_arch_folder: Optional[str] = None,
):
self.command = command
@@ -167,13 +167,13 @@ for qt_version in qt_versions:
BuildJob("install-qt", qt_version, "mac", "desktop", "clang_64", "macos")
)
mac_build_jobs.append(BuildJob(
"install-qt",
"6.2.0",
"mac",
"desktop",
"clang_64",
"macos",
module="qtcharts qtnetworkauth", ))
"install-qt",
"6.2.0",
"mac",
"desktop",
"clang_64",
"macos",
module="qtcharts qtnetworkauth", ))
# Windows Desktop
for qt_version in qt_versions:
@@ -211,7 +211,7 @@ windows_build_jobs.extend(
# Extra modules test
linux_build_jobs.extend(
[
BuildJob(
BuildJob(
# Archives stored as .7z
"install-src", "6.1.0", "linux", "desktop", "gcc_64", "gcc_64", subarchives="qtlottie",
# Fail the job if this path does not exist:
@@ -235,10 +235,12 @@ linux_build_jobs.extend(
"install-example", "6.1.3", "linux", "desktop", "gcc_64", "gcc_64",
subarchives="qtdoc", module="qtcharts",
# Fail the job if these paths do not exist:
check_output_cmd="ls -lh ./Examples/Qt-6.1.3/charts/ ./Examples/Qt-6.1.3/demos/ ./Examples/Qt-6.1.3/tutorials/",
check_output_cmd="ls -lh ./Examples/Qt-6.1.3/charts/ ./Examples/Qt-6.1.3/demos/ "
"./Examples/Qt-6.1.3/tutorials/",
),
# test for list commands
BuildJob('list-qt', '6.1.0', 'linux', 'desktop', 'gcc_64', '', spec=">6.0,<6.1.1", list_options={'HAS_WASM': "False"}),
BuildJob('list-qt', '6.1.0', 'linux', 'desktop', 'gcc_64', '', spec=">6.0,<6.1.1",
list_options={'HAS_WASM': "False"}),
BuildJob('list-qt', '6.1.0', 'linux', 'android', 'android_armv7', '', spec=">6.0,<6.1.1", list_options={}),
]
)
@@ -271,7 +273,8 @@ windows_build_jobs.append(
# WASM post 6.7.x
linux_build_jobs.append(
BuildJob("install-qt", "6.7.3", "all_os", "wasm", "wasm_multithread", "wasm_multithread",
is_autodesktop=True, emsdk_version=f"sdk-{BuildJob.emsdk_version_for_qt("6.7.3")}-64bit", autodesk_arch_folder="gcc_64")
is_autodesktop=True, emsdk_version=f"sdk-{BuildJob.emsdk_version_for_qt("6.7.3")}-64bit",
autodesk_arch_folder="gcc_64")
)
for job_queue, host, desk_arch, target, qt_version in (
(linux_build_jobs, "all_os", "linux_gcc_64", "wasm", qt_versions[0]),
@@ -281,7 +284,8 @@ for job_queue, host, desk_arch, target, qt_version in (
for wasm_arch in ("wasm_singlethread", "wasm_multithread"):
job_queue.append(
BuildJob("install-qt", qt_version, host, target, wasm_arch, wasm_arch,
is_autodesktop=True, emsdk_version=f"sdk-{BuildJob.emsdk_version_for_qt(qt_version)}-64bit", autodesk_arch_folder=desk_arch)
is_autodesktop=True, emsdk_version=f"sdk-{BuildJob.emsdk_version_for_qt(qt_version)}-64bit",
autodesk_arch_folder=desk_arch)
)
# mobile SDK
@@ -335,6 +339,20 @@ mac_build_jobs.append(
BuildJob("install-tool", "", "mac", "desktop", "", "", tool_options=tool_options_mac)
)
# Commercial
windows_build_jobs.append(
BuildJob("install-qt-official", qt_version="6.8.1", target="desktop", arch="win64_msvc2022_64",
archdir="win64_msvc2022_64", module="qtquick3d")
)
linux_build_jobs.append(
BuildJob("install-qt-official", qt_version="6.8.1", target="desktop", arch="linux_gcc_64",
archdir="linux_gcc_64", module="qtquick3d")
)
mac_build_jobs.append(
BuildJob("install-qt-official", qt_version="6.8.1", target="desktop", arch="clang_64",
archdir="clang_64", module="qtquick3d")
)
matrices = {}
for platform_build_job in all_platform_build_jobs:
@@ -375,8 +393,8 @@ for platform_build_job in all_platform_build_jobs:
("OUTPUT_DIR", build_job.output_dir if build_job.output_dir else ""),
("QT_BINDIR", build_job.qt_bindir()),
("WIN_QT_BINDIR", build_job.win_qt_bindir()),
("EMSDK_VERSION", (build_job.emsdk_version+"@main").split('@')[0]),
("EMSDK_TAG", (build_job.emsdk_version+"@main").split('@')[1]),
("EMSDK_VERSION", (build_job.emsdk_version + "@main").split('@')[0]),
("EMSDK_TAG", (build_job.emsdk_version + "@main").split('@')[1]),
("WIN_AUTODESK_QT_BINDIR", build_job.win_autodesk_qt_bindir()),
("TOOL1_ARGS", build_job.tool_options.get("TOOL1_ARGS", "")),
("LIST_TOOL1_CMD", build_job.tool_options.get("LIST_TOOL1_CMD", "")),

View File

@@ -1,385 +1,282 @@
env:
AQT_TEST_EMAIL: ${{ secrets.AQT_TEST_EMAIL }}
AQT_TEST_PASSWORD: ${{ secrets.AQT_TEST_PASSWORD }}
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: $(PYTHON_VERSION)
architecture: 'x64'
- powershell: |
pip install -e .
displayName: install package
- task: UsePythonVersion@0
inputs:
versionSpec: $(PYTHON_VERSION)
architecture: 'x64'
- powershell: |
pip install -e .
displayName: install package
# Install linux dependencies
- bash: |
sudo apt-get update
sudo apt-get install -y libgl1-mesa-dev libxkbcommon-x11-0
if [[ "$(SUBCOMMAND)" == "install-tool" ]]; then
sudo apt-get install -y libxcb-{icccm4,image0,keysyms1,randr0,render-util0,shape0,sync1,xfixes0,xinerama0,xkb1}
# Install linux dependencies
- bash: |
sudo apt-get update
sudo apt-get install -y libgl1-mesa-dev libxkbcommon-x11-0
if [[ "$(SUBCOMMAND)" == "install-tool" || "$(SUBCOMMAND)" == "install-qt-official" ]]; then
sudo apt-get install -y libxcb-{icccm4,image0,keysyms1,randr0,render-util0,shape0,sync1,xfixes0,xinerama0,xkb1}
fi
condition: and(eq(variables['TARGET'], 'desktop'), eq(variables['Agent.OS'], 'Linux'))
displayName: install test dependency for Linux
# Run Aqt
##----------------------------------------------------
## we insert sleep in random 1sec < duration < 60sec to reduce
## download server load.
- bash: |
set -ex
number=$RANDOM
let "number %= 60" || true
let "number += 1"
sleep $number
mkdir Qt
cd Qt
if [[ "$(SUBCOMMAND)" == "install-qt-official" ]]; then
opt+=" --email $(AQT_TEST_EMAIL) --pw $(AQT_TEST_PASSWORD)"
python -m aqt install-qt-official $opt $(TARGET) $(ARCH) $(QT_VERSION) --m $(MODULE)
fi
if [[ "$(SUBCOMMAND)" == "install-qt" ]]; then
opt=""
if [[ "$(QT_BASE_MIRROR)" != "" ]]; then
opt+=" -b $(QT_BASE_MIRROR)"
fi
condition: and(eq(variables['TARGET'], 'desktop'), eq(variables['Agent.OS'], 'Linux'))
displayName: install test dependency for Linux
# Run Aqt
##----------------------------------------------------
## we insert sleep in random 1sec < duration < 60sec to reduce
## download server load.
- bash: |
set -ex
number=$RANDOM
let "number %= 60" || true
let "number += 1"
sleep $number
mkdir Qt
cd Qt
if [[ "$(SUBCOMMAND)" == "install-qt" ]]; then
opt=""
if [[ "$(QT_BASE_MIRROR)" != "" ]]; then
opt+=" -b $(QT_BASE_MIRROR)"
fi
if [[ "$(MODULE)" != "" ]]; then
opt+=" -m $(MODULE)"
fi
if [[ "$(OUTPUT_DIR)" != "" ]]; then
opt+=" --outputdir $(OUTPUT_DIR)"
sudo mkdir -p "$(OUTPUT_DIR)"
sudo chown $(whoami) "$(OUTPUT_DIR)"
fi
if [[ "$(SUBARCHIVES)" != "" ]]; then
opt+=" --archives $(SUBARCHIVES)"
fi
if [[ "$(IS_AUTODESKTOP)" == "True" ]]; then
opt+=" --autodesktop"
elif [[ "$(TARGET)" == "android" || "$(TARGET)" == "ios" ]]; then
if [[ "$(HOST)" == "windows" ]]; then
python -m aqt install-qt $(HOST) desktop $(QT_VERSION) mingw81_64 --archives qtbase
else
# qtdeclarative contains `qmlimportscanner`: necessary for ios builds, Qt6+
python -m aqt install-qt $(HOST) desktop $(QT_VERSION) --archives qtbase qtdeclarative
fi
fi
if [[ "$(SPEC)" == "" ]]; then
python -m aqt install-qt $(HOST) $(TARGET) $(QT_VERSION) $(ARCH) $opt
if [[ "$(MODULE)" != "" ]]; then
opt+=" -m $(MODULE)"
fi
if [[ "$(OUTPUT_DIR)" != "" ]]; then
opt+=" --outputdir $(OUTPUT_DIR)"
sudo mkdir -p "$(OUTPUT_DIR)"
sudo chown $(whoami) "$(OUTPUT_DIR)"
fi
if [[ "$(SUBARCHIVES)" != "" ]]; then
opt+=" --archives $(SUBARCHIVES)"
fi
if [[ "$(IS_AUTODESKTOP)" == "True" ]]; then
opt+=" --autodesktop"
elif [[ "$(TARGET)" == "android" || "$(TARGET)" == "ios" ]]; then
if [[ "$(HOST)" == "windows" ]]; then
python -m aqt install-qt $(HOST) desktop $(QT_VERSION) mingw81_64 --archives qtbase
else
python -m aqt install-qt $(HOST) $(TARGET) "$(SPEC)" $(ARCH) $opt
fi
if [[ "$(OUTPUT_DIR)" != "" ]]; then
# Use 'strings' to read binary
echo "Verify patched value of qt_prfxpath"
[[ "$(strings $(QT_BINDIR)/qmake | grep qt_prfxpath | cut -d '=' -f 2)" == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
echo "Verify patched value of qt_epfxpath"
[[ "$(strings $(QT_BINDIR)/qmake | grep qt_epfxpath | cut -d '=' -f 2)" == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
echo "Verify patched value of qt_hpfxpath"
[[ "$(strings $(QT_BINDIR)/qmake | grep qt_hpfxpath | cut -d '=' -f 2)" == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
# Use 'qmake -query' to check paths
echo "Hide qt.conf so it doesn't interfere with test"
mv $(QT_BINDIR)/qt.conf $(QT_BINDIR)/_qt.conf
#export PATH=$(QT_BINDIR):$PATH
echo "Require that qt_epfxpath was set to '$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)'"
[[ $($(QT_BINDIR)/qmake -query QT_INSTALL_PREFIX) == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
echo "Require that qt_prfxpath was set to '$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)'"
[[ $($(QT_BINDIR)/qmake -query QT_INSTALL_PREFIX/dev) == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
echo "Require that qt_hpfxpath was set to '$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)'"
[[ $($(QT_BINDIR)/qmake -query QT_HOST_PREFIX) == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
# qtdeclarative contains `qmlimportscanner`: necessary for ios builds, Qt6+
python -m aqt install-qt $(HOST) desktop $(QT_VERSION) --archives qtbase qtdeclarative
fi
fi
if [[ "$(SUBCOMMAND)" == "list" ]]; then
aqt list-qt $(HOST) # print all targets for host
aqt list-tool $(HOST) $(TARGET) # print all tools for host/target
aqt list-tool $(HOST) $(TARGET) qt3dstudio_runtime_240 # print all tool variant names for qt3dstudio
aqt list-tool $(HOST) $(TARGET) qt3dstudio_runtime_240 --long # print tool variant names, versions, release dates
if [[ "$(TARGET)" == "desktop" ]]; then
aqt list-tool $(HOST) $(TARGET) tools_qtcreator # print all tool variant names for qtcreator
aqt list-tool $(HOST) $(TARGET) tools_qtcreator -l # print tool variant names, versions, release dates
if [[ "$(SPEC)" == "" ]]; then
python -m aqt install-qt $(HOST) $(TARGET) $(QT_VERSION) $(ARCH) $opt
else
python -m aqt install-qt $(HOST) $(TARGET) "$(SPEC)" $(ARCH) $opt
fi
if [[ "$(OUTPUT_DIR)" != "" ]]; then
# Use 'strings' to read binary
echo "Verify patched value of qt_prfxpath"
[[ "$(strings $(QT_BINDIR)/qmake | grep qt_prfxpath | cut -d '=' -f 2)" == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
echo "Verify patched value of qt_epfxpath"
[[ "$(strings $(QT_BINDIR)/qmake | grep qt_epfxpath | cut -d '=' -f 2)" == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
echo "Verify patched value of qt_hpfxpath"
[[ "$(strings $(QT_BINDIR)/qmake | grep qt_hpfxpath | cut -d '=' -f 2)" == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
# Use 'qmake -query' to check paths
echo "Hide qt.conf so it doesn't interfere with test"
mv $(QT_BINDIR)/qt.conf $(QT_BINDIR)/_qt.conf
#export PATH=$(QT_BINDIR):$PATH
echo "Require that qt_epfxpath was set to '$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)'"
[[ $($(QT_BINDIR)/qmake -query QT_INSTALL_PREFIX) == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
echo "Require that qt_prfxpath was set to '$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)'"
[[ $($(QT_BINDIR)/qmake -query QT_INSTALL_PREFIX/dev) == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
echo "Require that qt_hpfxpath was set to '$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)'"
[[ $($(QT_BINDIR)/qmake -query QT_HOST_PREFIX) == "$(OUTPUT_DIR)/$(QT_VERSION)/$(ARCHDIR)" ]]
fi
fi
if [[ "$(SUBCOMMAND)" == "list" ]]; then
aqt list-qt $(HOST) # print all targets for host
aqt list-tool $(HOST) $(TARGET) # print all tools for host/target
aqt list-tool $(HOST) $(TARGET) qt3dstudio_runtime_240 # print all tool variant names for qt3dstudio
aqt list-tool $(HOST) $(TARGET) qt3dstudio_runtime_240 --long # print tool variant names, versions, release dates
if [[ "$(TARGET)" == "desktop" ]]; then
aqt list-tool $(HOST) $(TARGET) tools_qtcreator # print all tool variant names for qtcreator
aqt list-tool $(HOST) $(TARGET) tools_qtcreator -l # print tool variant names, versions, release dates
fi
aqt list-qt $(HOST) $(TARGET) # print all versions of Qt
aqt list-qt $(HOST) $(TARGET) --spec "$(SPEC)" # print all versions of Qt in SimpleSpec
ver=$(aqt list-qt $(HOST) $(TARGET) --spec "$(SPEC)" --latest-version) # latest Qt in SimpleSpec
[ $ver == $(QT_VERSION) ] # latest version in SPEC must be QT_VERSION
aqt list-qt $(HOST) $(TARGET) --spec "$(SPEC)" --modules latest $(ARCH) # print modules for latest in SimpleSpec
aqt list-qt $(HOST) $(TARGET) --modules $(QT_VERSION) $(ARCH) # print modules for version/host/target/arch
aqt list-qt $(HOST) $(TARGET) --arch $(QT_VERSION) # print architectures for version/host/target
if [[ "$(TARGET)" == "desktop" ]]; then
if [[ "$(HAS_WASM)" == "True" ]]; then # fail if 'wasm_32' is not in the list
aqt list-qt $(HOST) $(TARGET) --arch $(QT_VERSION) | grep -w -q "wasm_32"
else # fail if 'wasm_32' is in the list
! aqt list-qt $(HOST) $(TARGET) --arch $(QT_VERSION) | grep -w -q "wasm_32"
fi
aqt list-qt $(HOST) $(TARGET) # print all versions of Qt
aqt list-qt $(HOST) $(TARGET) --spec "$(SPEC)" # print all versions of Qt in SimpleSpec
ver=$(aqt list-qt $(HOST) $(TARGET) --spec "$(SPEC)" --latest-version) # latest Qt in SimpleSpec
[ $ver == $(QT_VERSION) ] # latest version in SPEC must be QT_VERSION
aqt list-qt $(HOST) $(TARGET) --spec "$(SPEC)" --modules latest $(ARCH) # print modules for latest in SimpleSpec
aqt list-qt $(HOST) $(TARGET) --modules $(QT_VERSION) $(ARCH) # print modules for version/host/target/arch
aqt list-qt $(HOST) $(TARGET) --arch $(QT_VERSION) # print architectures for version/host/target
if [[ "$(TARGET)" == "desktop" ]]; then
if [[ "$(HAS_WASM)" == "True" ]]; then # fail if 'wasm_32' is not in the list
aqt list-qt $(HOST) $(TARGET) --arch $(QT_VERSION) | grep -w -q "wasm_32"
else # fail if 'wasm_32' is in the list
! aqt list-qt $(HOST) $(TARGET) --arch $(QT_VERSION) | grep -w -q "wasm_32"
fi
# Extra check for Qt 6.5.0 WASM:
for host in mac linux windows; do
export WASM_ARCHES=$(aqt list-qt $host desktop --arch 6.5.0)
echo $WASM_ARCHES | grep -w -q "wasm_singlethread" # fail if 'wasm_singlethread' is not in the list
echo $WASM_ARCHES | grep -w -q "wasm_multithread" # fail if 'wasm_multithread' is not in the list
done
fi
aqt list-qt $(HOST) $(TARGET) --spec "$(SPEC)" --arch latest
# list-src/doc/example
aqt list-src $(HOST) $(QT_VERSION) # print source archives available for host/desktop/version
aqt list-doc $(HOST) $(QT_VERSION) # print docs archives available for host/desktop/version
aqt list-doc $(HOST) $(QT_VERSION) --modules # print docs modules available for host/desktop/version
aqt list-example $(HOST) $(QT_VERSION) # print example archives available for host/desktop/version
aqt list-example $(HOST) $(QT_VERSION) --modules # print example modules available for host/desktop/version
# Extra check for Qt 6.5.0 WASM:
for host in mac linux windows; do
export WASM_ARCHES=$(aqt list-qt $host desktop --arch 6.5.0)
echo $WASM_ARCHES | grep -w -q "wasm_singlethread" # fail if 'wasm_singlethread' is not in the list
echo $WASM_ARCHES | grep -w -q "wasm_multithread" # fail if 'wasm_multithread' is not in the list
done
fi
if [[ "$(SUBCOMMAND)" == "install-src" ]]; then
python -m aqt $(SUBCOMMAND) $(HOST) $(QT_VERSION) --archives $(SUBARCHIVES)
$(CHECK_OUTPUT_CMD)
aqt list-qt $(HOST) $(TARGET) --spec "$(SPEC)" --arch latest
# list-src/doc/example
aqt list-src $(HOST) $(QT_VERSION) # print source archives available for host/desktop/version
aqt list-doc $(HOST) $(QT_VERSION) # print docs archives available for host/desktop/version
aqt list-doc $(HOST) $(QT_VERSION) --modules # print docs modules available for host/desktop/version
aqt list-example $(HOST) $(QT_VERSION) # print example archives available for host/desktop/version
aqt list-example $(HOST) $(QT_VERSION) --modules # print example modules available for host/desktop/version
fi
if [[ "$(SUBCOMMAND)" == "install-src" ]]; then
python -m aqt $(SUBCOMMAND) $(HOST) $(QT_VERSION) --archives $(SUBARCHIVES)
$(CHECK_OUTPUT_CMD)
fi
if [[ "$(SUBCOMMAND)" =~ ^install-(doc|example)$ ]]; then
opt=""
if [[ "$(MODULE)" != "" ]]; then
opt+=" -m $(MODULE)"
fi
if [[ "$(SUBCOMMAND)" =~ ^install-(doc|example)$ ]]; then
opt=""
if [[ "$(MODULE)" != "" ]]; then
opt+=" -m $(MODULE)"
fi
python -m aqt $(SUBCOMMAND) $(HOST) $(QT_VERSION) --archives $(SUBARCHIVES) $opt
$(CHECK_OUTPUT_CMD)
python -m aqt $(SUBCOMMAND) $(HOST) $(QT_VERSION) --archives $(SUBARCHIVES) $opt
$(CHECK_OUTPUT_CMD)
fi
if [[ "$(SUBCOMMAND)" == "install-tool" ]]; then
opt=""
if [[ "$(OUTPUT_DIR)" != "" ]]; then
opt+=" --outputdir $(OUTPUT_DIR)"
sudo mkdir -p "$(OUTPUT_DIR)"
sudo chown $(whoami) "$(OUTPUT_DIR)"
fi
if [[ "$(SUBCOMMAND)" == "install-tool" ]]; then
opt=""
if [[ "$(OUTPUT_DIR)" != "" ]]; then
opt+=" --outputdir $(OUTPUT_DIR)"
sudo mkdir -p "$(OUTPUT_DIR)"
sudo chown $(whoami) "$(OUTPUT_DIR)"
fi
python -m aqt $(SUBCOMMAND) $(HOST) $(TARGET) $(TOOL1_ARGS) $opt
$(LIST_TOOL1_CMD)
echo "Testing $(TOOL1_ARGS) with '$(TEST_TOOL1_CMD)'"
$(TEST_TOOL1_CMD)
python -m aqt $(SUBCOMMAND) $(HOST) $(TARGET) $(TOOL2_ARGS) $opt
$(LIST_TOOL2_CMD)
echo "Testing $(TOOL2_ARGS) with '$(TEST_TOOL2_CMD)'"
$(TEST_TOOL2_CMD)
fi
workingDirectory: $(Build.BinariesDirectory)
env:
AQT_CONFIG: $(Build.SourcesDirectory)/ci/settings.ini
LOG_CFG: $(Build.SourcesDirectory)/ci/logging.ini
displayName: Run Aqt
python -m aqt $(SUBCOMMAND) $(HOST) $(TARGET) $(TOOL1_ARGS) $opt
$(LIST_TOOL1_CMD)
echo "Testing $(TOOL1_ARGS) with '$(TEST_TOOL1_CMD)'"
$(TEST_TOOL1_CMD)
python -m aqt $(SUBCOMMAND) $(HOST) $(TARGET) $(TOOL2_ARGS) $opt
$(LIST_TOOL2_CMD)
echo "Testing $(TOOL2_ARGS) with '$(TEST_TOOL2_CMD)'"
$(TEST_TOOL2_CMD)
fi
workingDirectory: $(Build.BinariesDirectory)
env:
AQT_CONFIG: $(Build.SourcesDirectory)/ci/settings.ini
LOG_CFG: $(Build.SourcesDirectory)/ci/logging.ini
displayName: Run Aqt
##----------------------------------------------------
# for Android target
- bash: |
set -ex
if [[ "$(Agent.OS)" == "Linux" ]]; then
wget https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip
unzip android-ndk-r21e-linux-x86_64.zip
fi
if [[ "$(Agent.OS)" == "Darwin" ]]; then
wget https://dl.google.com/android/repository/android-ndk-r21e-darwin-x86_64.zip
unzip android-ndk-r21e-darwin-x86_64.zip
fi
export ANDROID_NDK_ROOT=$(Build.SourcesDirectory)/android-ndk-r21e
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/accelbubble.7z)
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/accelbubble
make
condition: |
and(
eq(variables['TARGET'], 'android'),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
),
ne(variables['SUBCOMMAND'], 'list-qt'),
ne(variables['SUBCOMMAND'], 'install-tool')
)
displayName: Build accelbubble example application to test for android
##----------------------------------------------------
# for Android target
- bash: |
set -ex
if [[ "$(Agent.OS)" == "Linux" ]]; then
wget https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip
unzip android-ndk-r21e-linux-x86_64.zip
fi
if [[ "$(Agent.OS)" == "Darwin" ]]; then
wget https://dl.google.com/android/repository/android-ndk-r21e-darwin-x86_64.zip
unzip android-ndk-r21e-darwin-x86_64.zip
fi
export ANDROID_NDK_ROOT=$(Build.SourcesDirectory)/android-ndk-r21e
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/accelbubble.7z)
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/accelbubble
make
condition: |
and(
eq(variables['TARGET'], 'android'),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
),
ne(variables['SUBCOMMAND'], 'list-qt'),
ne(variables['SUBCOMMAND'], 'install-tool')
)
displayName: Build accelbubble example application to test for android
##----------------------------------------------------
# for iOS target
- bash: |
set -ex
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/accelbubble.7z)
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/accelbubble
make
condition: |
and(eq(variables['TARGET'], 'ios'),
ne(variables['SUBCOMMAND'], 'list'),
ne(variables['SUBCOMMAND'], 'install-tool'))
displayName: Build accelbubble example application to test for ios
##----------------------------------------------------
# for iOS target
- bash: |
set -ex
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/accelbubble.7z)
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/accelbubble
make
condition: |
and(eq(variables['TARGET'], 'ios'),
ne(variables['SUBCOMMAND'], 'list'),
ne(variables['SUBCOMMAND'], 'install-tool'))
displayName: Build accelbubble example application to test for ios
##----------------------------------------------------
# Cache Powershell Modules in $MODULES_FOLDER
- task: Cache@2
inputs:
key: '"pwsh modules" | "$(startYear)" | "$(startMonth)"'
path: $(MODULES_FOLDER)
cacheHitVar: PSModules_IsCached
condition: |
and(eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['SUBCOMMAND'], 'install-qt'))
displayName: Cache Powershell Modules
# On cache miss: Download Powershell Modules to $MODULES_FOLDER
- powershell: |
Install-PackageProvider NuGet -Force
Import-PackageProvider NuGet -Force
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
md -p $(MODULES_FOLDER) # mkdir
Save-Module -Name Pscx -AllowPrerelease -Path $(MODULES_FOLDER)
condition: |
and(eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['SUBCOMMAND'], 'install-qt'),
ne(variables.PSModules_IsCached, 'true'))
displayName: Download Powershell Modules for Windows on cache miss
##----------------------------------------------------
# Cache Powershell Modules in $MODULES_FOLDER
- task: Cache@2
inputs:
key: '"pwsh modules" | "$(startYear)" | "$(startMonth)"'
path: $(MODULES_FOLDER)
cacheHitVar: PSModules_IsCached
condition: |
and(eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['SUBCOMMAND'], 'install-qt'))
displayName: Cache Powershell Modules
# On cache miss: Download Powershell Modules to $MODULES_FOLDER
- powershell: |
Install-PackageProvider NuGet -Force
Import-PackageProvider NuGet -Force
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
md -p $(MODULES_FOLDER) # mkdir
Save-Module -Name Pscx -AllowPrerelease -Path $(MODULES_FOLDER)
condition: |
and(eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['SUBCOMMAND'], 'install-qt'),
ne(variables.PSModules_IsCached, 'true'))
displayName: Download Powershell Modules for Windows on cache miss
##----------------------------------------------------
# determine Windows build system
- powershell: |
if ('$(ARCH)' -like '*msvc*') {
Write-Host '##vso[task.setvariable variable=TOOLCHAIN]MSVC'
}
if ('$(ARCH)' -like '*mingw*') {
Write-Host '##vso[task.setvariable variable=TOOLCHAIN]MINGW'
}
if ('$(ARCH)' -like 'win64_msvc*') {
Write-Host '##vso[task.setvariable variable=ARCHITECTURE]amd64'
} else {
Write-Host '##vso[task.setvariable variable=ARCHITECTURE]x86'
}
if ('$(ARCH)' -like '*msvc*') {
Write-Host '##vso[task.setvariable variable=VSVER]2022'
}
cd $(WIN_QT_BINDIR)
unzip $(Build.SourcesDirectory)\ci\jom_1_1_3.zip
condition: |
and(eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['SUBCOMMAND'], 'install-qt'))
displayName: Detect toolchain for Windows and update PATH
##----------------------------------------------------
# determine Windows build system
- powershell: |
if ('$(ARCH)' -like '*msvc*') {
Write-Host '##vso[task.setvariable variable=TOOLCHAIN]MSVC'
}
if ('$(ARCH)' -like '*mingw*') {
Write-Host '##vso[task.setvariable variable=TOOLCHAIN]MINGW'
}
if ('$(ARCH)' -like 'win64_msvc*') {
Write-Host '##vso[task.setvariable variable=ARCHITECTURE]amd64'
} else {
Write-Host '##vso[task.setvariable variable=ARCHITECTURE]x86'
}
if ('$(ARCH)' -like '*msvc*') {
Write-Host '##vso[task.setvariable variable=VSVER]2022'
}
cd $(WIN_QT_BINDIR)
unzip $(Build.SourcesDirectory)\ci\jom_1_1_3.zip
condition: |
and(eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['SUBCOMMAND'], 'install-qt'))
displayName: Detect toolchain for Windows and update PATH
# When no modules
- script: |
set -ex
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/helloworld.7z)
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/helloworld
make
condition: |
and(
eq( variables['TARGET'], 'desktop' ),
not( startsWith( variables['ARCH'], 'wasm_' ) ),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
),
eq(variables['MODULE'], ''),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: Build test with qmake for Linux and macOS w/o extra module
# Update the MSVC build step to use the new compiler flags
- powershell: |
if ( $env:TOOLCHAIN -eq 'MSVC' ) {
# Load modules from cache
$Env:PSModulePath = '$(MODULES_FOLDER)', $Env:PSModulePath -join [System.IO.Path]::PathSeparator
Write-Host $Env:PSModulePath
Import-Module "Pscx"
Import-Module "VSSetup"
Import-VisualStudioVars -VisualStudioVersion $(VSVER) -Architecture $(ARCHITECTURE)
$env:Path += ";$(WIN_QT_BINDIR)"
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
7z x $(Build.SourcesDirectory)\ci\helloworld.7z
cd ..
qmake $(Build.BinariesDirectory)\tests\helloworld
jom
} elseif ( $env:TOOLCHAIN -eq 'MINGW' ) {
python -m aqt install-tool $(if (($QT_BASE_MIRROR + "") -ne "") { "-b $QT_BASE_MIRROR" } else {""}) `
--outputdir $(Build.BinariesDirectory)/Qt $(HOST) desktop $(MINGW_TOOL_NAME) qt.tools.$(MINGW_VARIANT)
if ($?) {
Write-Host 'Successfully installed tools_mingw'
} else {
throw 'Failed to install tools_mingw'
}
Set-Item -Path Env:Path -Value ("$(Build.BinariesDirectory)\Qt\Tools\$(MINGW_FOLDER)\bin;$(WIN_QT_BINDIR);" + $Env:Path)
Write-Host "Path == " + $env:Path
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
7z x $(Build.SourcesDirectory)\ci\helloworld.7z
cd ..
qmake $(Build.BinariesDirectory)\tests\helloworld
mingw32-make
}
condition: |
and(
eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['MODULE'], ''),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: build test with qmake w/o extra module
env:
AQT_CONFIG: $(Build.SourcesDirectory)/ci/settings.ini
LOG_CFG: $(Build.SourcesDirectory)/ci/logging.ini
# When --archives non-empty
- script: |
set -ex
rm -rf $(Build.BinariesDirectory)/tests
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests && 7zr x $(Build.SourcesDirectory)/ci/helloworld_qttools.7z)
export PATH=$(QT_BINDIR):$PATH
qmake -d $(Build.BinariesDirectory)/tests/helloworld_qttools
make
condition: |
and(
eq( variables['TARGET'], 'desktop' ),
not( startsWith( variables['ARCH'], 'wasm_' ) ),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
),
contains(variables['SUBARCHIVES'], 'qttools'),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: build test with qmake for Linux and macOS with specific Qt modules (QT += uitools)
- powershell: |
if ( $env:TOOLCHAIN -eq 'MSVC' ) {
# Load modules from cache
$Env:PSModulePath = '$(MODULES_FOLDER)', $Env:PSModulePath -join [System.IO.Path]::PathSeparator
Write-Host $Env:PSModulePath
Import-Module "Pscx"
Import-Module "VSSetup"
Import-VisualStudioVars -VisualStudioVersion $(VSVER) -Architecture $(ARCHITECTURE)
$env:Path += ";$(WIN_QT_BINDIR)"
try { rm -r -fo $(Build.BinariesDirectory)\tests } catch { $Error.Clear() }
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
7z x $(Build.SourcesDirectory)\ci\helloworld_qttools.7z
qmake -d $(Build.BinariesDirectory)\tests\helloworld_qttools
nmake
} elseif ( $env:TOOLCHAIN -eq 'MINGW' ) {
Set-Item -Path Env:Path -Value ("$(Build.BinariesDirectory)\Qt\Tools\$(MINGW_FOLDER)\bin;$(WIN_QT_BINDIR);" + $Env:Path)
Write-Host "Path == " + $env:Path
if (![bool] (Get-Command -ErrorAction Ignore -Type Application mingw32-make)) {
python -m aqt install-tool $(if (($QT_BASE_MIRROR + "") -ne "") { "-b $QT_BASE_MIRROR" } else {""}) `
--outputdir $(Build.BinariesDirectory)/Qt $(HOST) desktop $(MINGW_TOOL_NAME) qt.tools.$(MINGW_VARIANT)
if ($?) {
Write-Host 'Successfully installed tools_mingw'
} else {
throw 'Failed to install tools_mingw'
}
}
try { rm -r -fo $(Build.BinariesDirectory)\tests } catch { $Error.Clear() }
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
7z x $(Build.SourcesDirectory)\ci\helloworld_qttools.7z
qmake -d $(Build.BinariesDirectory)\tests\helloworld_qttools
mingw32-make
}
condition: |
and(
eq( variables['Agent.OS'], 'Windows_NT'),
contains(variables['SUBARCHIVES'], 'qttools'),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: build test with qmake with specific Qt modules (QT += uitools)
env:
AQT_CONFIG: $(Build.SourcesDirectory)/ci/settings.ini
LOG_CFG: $(Build.SourcesDirectory)/ci/logging.ini
- powershell: |
# When no modules
- script: |
set -ex
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/helloworld.7z)
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/helloworld
make
condition: |
and(
eq( variables['TARGET'], 'desktop' ),
not( startsWith( variables['ARCH'], 'wasm_' ) ),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
),
eq(variables['MODULE'], ''),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: Build test with qmake for Linux and macOS w/o extra module
# Update the MSVC build step to use the new compiler flags
- powershell: |
if ( $env:TOOLCHAIN -eq 'MSVC' ) {
# Load modules from cache
$Env:PSModulePath = '$(MODULES_FOLDER)', $Env:PSModulePath -join [System.IO.Path]::PathSeparator
Write-Host $Env:PSModulePath
@@ -388,109 +285,219 @@ steps:
Import-VisualStudioVars -VisualStudioVersion $(VSVER) -Architecture $(ARCHITECTURE)
$env:Path += ";$(WIN_QT_BINDIR)"
echo Add Qt to PATH: $env:PATH
mkdir $(Build.BinariesDirectory)/tests
cd $(Build.BinariesDirectory)/tests
7z x $(Build.SourcesDirectory)/ci/redditclient.7z
cd ..
qmake $(Build.BinariesDirectory)\tests\redditclient
nmake
condition: |
and(
eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['TOOLCHAIN'], 'MSVC'),
ne(variables['MODULE'], ''),
ne(variables['VSVER'], '2022')
)
displayName: build test with qmake with MSVC with extra module
- bash: |
set -ex
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/redditclient.7z)
if [[ "6" -eq "${QT_VERSION:0:1}" ]]; then
(cd $(Build.BinariesDirectory)/tests/redditclient;patch -i redditclient_6.diff -p1)
fi
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/redditclient
make
condition: |
and(
eq( variables['TARGET'], 'desktop'),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
),
ne(variables['MODULE'], ''),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: Build test with qmake for Linux and macOS with extra module
##----------------------------------------------------
# wasm_32/single/multithread on linux and mac
- script: |
set -uex
git clone --depth=1 --branch=$(EMSDK_TAG) https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install $(EMSDK_VERSION)
./emsdk activate --embedded $(EMSDK_VERSION)
source $(Build.BinariesDirectory)/emsdk/emsdk_env.sh
mkdir $(Build.BinariesDirectory)/tests
if [[ $(QT_VERSION) = 6* ]]; then
OPENGLWINDOW_7Z="openglwindow_qt6.7z"
else
OPENGLWINDOW_7Z="openglwindow.7z"
fi
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/$OPENGLWINDOW_7Z)
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/openglwindow
make
workingDirectory: $(Build.BinariesDirectory)
condition: |
and(
startsWith( variables['ARCH'], 'wasm_' ),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
)
)
displayName: 'Build WebAssembler sample project on mac/linux'
# wasm_32/single/multithread on Windows cmd.exe
- powershell: |
git clone --depth=1 --branch=$(EMSDK_TAG) https://github.com/emscripten-core/emsdk.git
cd emsdk
.\emsdk install $(EMSDK_VERSION)
.\emsdk activate --embedded $(EMSDK_VERSION)
.\emsdk_env.bat
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
$env:Path += ";$(WIN_QT_BINDIR)"
echo "Add Qt/qmake to PATH at $(WIN_QT_BINDIR):"
echo "$env:Path"
if ('$(QT_VERSION)' -like '6*') {
7z x $(Build.SourcesDirectory)\ci\openglwindow_qt6.7z
echo "Inlined qmake.bat command is: $(WIN_AUTODESK_QT_BINDIR)\qmake -qtconf $(WIN_QT_BINDIR)\target_qt.conf $(Build.BinariesDirectory)\tests\openglwindow"
$(WIN_AUTODESK_QT_BINDIR)\qmake.exe -qtconf "$(WIN_QT_BINDIR)\target_qt.conf" $(Build.BinariesDirectory)\tests\openglwindow
7z x $(Build.SourcesDirectory)\ci\helloworld.7z
cd ..
qmake $(Build.BinariesDirectory)\tests\helloworld
jom
} elseif ( $env:TOOLCHAIN -eq 'MINGW' ) {
python -m aqt install-tool $(if (($QT_BASE_MIRROR + "") -ne "") { "-b $QT_BASE_MIRROR" } else {""}) `
--outputdir $(Build.BinariesDirectory)/Qt $(HOST) desktop $(MINGW_TOOL_NAME) qt.tools.$(MINGW_VARIANT)
if ($?) {
Write-Host 'Successfully installed tools_mingw'
} else {
7z x $(Build.SourcesDirectory)\ci\openglwindow.7z
echo "Qt5: run qmake.exe"
qmake $(Build.BinariesDirectory)\tests\openglwindow
throw 'Failed to install tools_mingw'
}
if ($false -eq $?) {
Write-Error "qmake failed."
Write-Host "##vso[task.logissue type=error]qmake failed."
exit(1)
Set-Item -Path Env:Path -Value ("$(Build.BinariesDirectory)\Qt\Tools\$(MINGW_FOLDER)\bin;$(WIN_QT_BINDIR);" + $Env:Path)
Write-Host "Path == " + $env:Path
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
7z x $(Build.SourcesDirectory)\ci\helloworld.7z
cd ..
qmake $(Build.BinariesDirectory)\tests\helloworld
mingw32-make
}
condition: |
and(
eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['MODULE'], ''),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: build test with qmake w/o extra module
env:
AQT_CONFIG: $(Build.SourcesDirectory)/ci/settings.ini
LOG_CFG: $(Build.SourcesDirectory)/ci/logging.ini
# When --archives non-empty
- script: |
set -ex
rm -rf $(Build.BinariesDirectory)/tests
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests && 7zr x $(Build.SourcesDirectory)/ci/helloworld_qttools.7z)
export PATH=$(QT_BINDIR):$PATH
qmake -d $(Build.BinariesDirectory)/tests/helloworld_qttools
make
condition: |
and(
eq( variables['TARGET'], 'desktop' ),
not( startsWith( variables['ARCH'], 'wasm_' ) ),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
),
contains(variables['SUBARCHIVES'], 'qttools'),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: build test with qmake for Linux and macOS with specific Qt modules (QT += uitools)
- powershell: |
if ( $env:TOOLCHAIN -eq 'MSVC' ) {
# Load modules from cache
$Env:PSModulePath = '$(MODULES_FOLDER)', $Env:PSModulePath -join [System.IO.Path]::PathSeparator
Write-Host $Env:PSModulePath
Import-Module "Pscx"
Import-Module "VSSetup"
Import-VisualStudioVars -VisualStudioVersion $(VSVER) -Architecture $(ARCHITECTURE)
$env:Path += ";$(WIN_QT_BINDIR)"
try { rm -r -fo $(Build.BinariesDirectory)\tests } catch { $Error.Clear() }
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
7z x $(Build.SourcesDirectory)\ci\helloworld_qttools.7z
qmake -d $(Build.BinariesDirectory)\tests\helloworld_qttools
nmake
} elseif ( $env:TOOLCHAIN -eq 'MINGW' ) {
Set-Item -Path Env:Path -Value ("$(Build.BinariesDirectory)\Qt\Tools\$(MINGW_FOLDER)\bin;$(WIN_QT_BINDIR);" + $Env:Path)
Write-Host "Path == " + $env:Path
if (![bool] (Get-Command -ErrorAction Ignore -Type Application mingw32-make)) {
python -m aqt install-tool $(if (($QT_BASE_MIRROR + "") -ne "") { "-b $QT_BASE_MIRROR" } else {""}) `
--outputdir $(Build.BinariesDirectory)/Qt $(HOST) desktop $(MINGW_TOOL_NAME) qt.tools.$(MINGW_VARIANT)
if ($?) {
Write-Host 'Successfully installed tools_mingw'
} else {
throw 'Failed to install tools_mingw'
}
}
make
if ($false -eq $?) {
Write-Error "make failed."
Write-Host "##vso[task.logissue type=error]nmake failed."
exit(1)
}
workingDirectory: $(Build.BinariesDirectory)
condition: |
and(
startsWith( variables['ARCH'], 'wasm_' ),
eq( variables['Agent.OS'], 'Windows_NT' )
try { rm -r -fo $(Build.BinariesDirectory)\tests } catch { $Error.Clear() }
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
7z x $(Build.SourcesDirectory)\ci\helloworld_qttools.7z
qmake -d $(Build.BinariesDirectory)\tests\helloworld_qttools
mingw32-make
}
condition: |
and(
eq( variables['Agent.OS'], 'Windows_NT'),
contains(variables['SUBARCHIVES'], 'qttools'),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: build test with qmake with specific Qt modules (QT += uitools)
env:
AQT_CONFIG: $(Build.SourcesDirectory)/ci/settings.ini
LOG_CFG: $(Build.SourcesDirectory)/ci/logging.ini
- powershell: |
# Load modules from cache
$Env:PSModulePath = '$(MODULES_FOLDER)', $Env:PSModulePath -join [System.IO.Path]::PathSeparator
Write-Host $Env:PSModulePath
Import-Module "Pscx"
Import-Module "VSSetup"
Import-VisualStudioVars -VisualStudioVersion $(VSVER) -Architecture $(ARCHITECTURE)
$env:Path += ";$(WIN_QT_BINDIR)"
echo Add Qt to PATH: $env:PATH
mkdir $(Build.BinariesDirectory)/tests
cd $(Build.BinariesDirectory)/tests
7z x $(Build.SourcesDirectory)/ci/redditclient.7z
cd ..
qmake $(Build.BinariesDirectory)\tests\redditclient
nmake
condition: |
and(
eq(variables['Agent.OS'], 'Windows_NT'),
eq(variables['TOOLCHAIN'], 'MSVC'),
ne(variables['MODULE'], ''),
ne(variables['VSVER'], '2022')
)
displayName: build test with qmake with MSVC with extra module
- bash: |
set -ex
mkdir $(Build.BinariesDirectory)/tests
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/redditclient.7z)
if [[ "6" -eq "${QT_VERSION:0:1}" ]]; then
(cd $(Build.BinariesDirectory)/tests/redditclient;patch -i redditclient_6.diff -p1)
fi
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/redditclient
make
condition: |
and(
eq( variables['TARGET'], 'desktop'),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
),
ne(variables['MODULE'], ''),
eq(variables['SUBCOMMAND'], 'install-qt')
)
displayName: Build test with qmake for Linux and macOS with extra module
##----------------------------------------------------
# wasm_32/single/multithread on linux and mac
- script: |
set -uex
git clone --depth=1 --branch=$(EMSDK_TAG) https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install $(EMSDK_VERSION)
./emsdk activate --embedded $(EMSDK_VERSION)
source $(Build.BinariesDirectory)/emsdk/emsdk_env.sh
mkdir $(Build.BinariesDirectory)/tests
if [[ $(QT_VERSION) = 6* ]]; then
OPENGLWINDOW_7Z="openglwindow_qt6.7z"
else
OPENGLWINDOW_7Z="openglwindow.7z"
fi
(cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/$OPENGLWINDOW_7Z)
export PATH=$(QT_BINDIR):$PATH
qmake $(Build.BinariesDirectory)/tests/openglwindow
make
workingDirectory: $(Build.BinariesDirectory)
condition: |
and(
startsWith( variables['ARCH'], 'wasm_' ),
or(
eq(variables['Agent.OS'], 'Linux'),
eq(variables['Agent.OS'], 'Darwin')
)
displayName: 'Build WebAssembler sample project on windows'
)
displayName: 'Build WebAssembler sample project on mac/linux'
# wasm_32/single/multithread on Windows cmd.exe
- powershell: |
git clone --depth=1 --branch=$(EMSDK_TAG) https://github.com/emscripten-core/emsdk.git
cd emsdk
.\emsdk install $(EMSDK_VERSION)
.\emsdk activate --embedded $(EMSDK_VERSION)
.\emsdk_env.bat
mkdir $(Build.BinariesDirectory)\tests
cd $(Build.BinariesDirectory)\tests
$env:Path += ";$(WIN_QT_BINDIR)"
echo "Add Qt/qmake to PATH at $(WIN_QT_BINDIR):"
echo "$env:Path"
if ('$(QT_VERSION)' -like '6*') {
7z x $(Build.SourcesDirectory)\ci\openglwindow_qt6.7z
echo "Inlined qmake.bat command is: $(WIN_AUTODESK_QT_BINDIR)\qmake -qtconf $(WIN_QT_BINDIR)\target_qt.conf $(Build.BinariesDirectory)\tests\openglwindow"
$(WIN_AUTODESK_QT_BINDIR)\qmake.exe -qtconf "$(WIN_QT_BINDIR)\target_qt.conf" $(Build.BinariesDirectory)\tests\openglwindow
} else {
7z x $(Build.SourcesDirectory)\ci\openglwindow.7z
echo "Qt5: run qmake.exe"
qmake $(Build.BinariesDirectory)\tests\openglwindow
}
if ($false -eq $?) {
Write-Error "qmake failed."
Write-Host "##vso[task.logissue type=error]qmake failed."
exit(1)
}
make
if ($false -eq $?) {
Write-Error "make failed."
Write-Host "##vso[task.logissue type=error]nmake failed."
exit(1)
}
workingDirectory: $(Build.BinariesDirectory)
condition: |
and(
startsWith( variables['ARCH'], 'wasm_' ),
eq( variables['Agent.OS'], 'Windows_NT' )
)
displayName: 'Build WebAssembler sample project on windows'

View File

@@ -1,4 +1,3 @@
import platform
import re
import sys
from pathlib import Path
@@ -16,9 +15,8 @@ from aqt.metadata import MetadataFactory, SimpleSpec, Version
def expected_help(actual, prefix=None):
expected = (
"usage: aqt [-h] [-c CONFIG]\n"
" {install-qt,install-tool,install-qt-commercial,install-doc,install-example,"
"install-src,"
"list-qt,list-qt-commercial,list-tool,list-doc,list-example,list-src,help,version}\n"
" {install-qt,install-tool,install-qt-official,list-qt-official,install-doc,install-example,"
"install-src,list-qt,list-tool,list-doc,list-example,list-src,help,version}\n"
" ...\n"
"\n"
"Another unofficial Qt Installer.\n"
@@ -34,9 +32,8 @@ def expected_help(actual, prefix=None):
" install-* subcommands are commands that install components\n"
" list-* subcommands are commands that show available components\n"
"\n"
" {install-qt,install-tool,install-qt-commercial,install-doc,install-example,"
"install-src,list-qt,list-qt-commercial,"
"list-tool,list-doc,list-example,list-src,help,version}\n"
" {install-qt,install-tool,install-qt-official,list-qt-official,install-doc,install-example,install-src,"
"list-qt,list-tool,list-doc,list-example,list-src,help,version}\n"
" Please refer to each help message by using '--help' "
"with each subcommand\n",
)
@@ -523,29 +520,3 @@ def test_get_autodesktop_dir_and_arch_non_android(
), "Expected autodesktop install message."
elif expect["instruct"]:
assert any("You can install" in line for line in err_lines), "Expected install instruction message."
@pytest.mark.parametrize(
"cmd, expected_arch, expected_err",
[
pytest.param(
"install-qt-commercial desktop {} 6.8.0",
{"windows": "win64_msvc2022_64", "linux": "linux_gcc_64", "mac": "clang_64"},
"No Qt account credentials found. Either provide --user and --password or",
),
],
)
def test_cli_login_qt_commercial(capsys, monkeypatch, cmd, expected_arch, expected_err):
"""Test commercial Qt installation command"""
# Detect current platform
current_platform = platform.system().lower()
arch = expected_arch[current_platform]
cmd = cmd.format(arch)
cli = Cli()
cli._setup_settings()
result = cli.run(cmd.split())
_, err = capsys.readouterr()
assert str(err).find(expected_err)
assert not result == 0

375
tests/test_commercial.py Normal file
View File

@@ -0,0 +1,375 @@
import os
import shutil
import sys
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Dict, List, Optional
import pytest
import requests
from aqt.commercial import CommercialInstaller, QtPackageInfo, QtPackageManager
from aqt.exceptions import DiskAccessNotPermitted
from aqt.helper import Settings, get_qt_account_path
from aqt.installer import Cli
from aqt.metadata import Version
class CompletedProcess:
def __init__(self, args, returncode):
self.args = args
self.returncode = returncode
self.stdout = None
self.stderr = None
# Test data
MOCK_XML_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
<availablepackages>
<package name="qt.qt6.680.gcc_64" displayname="Desktop gcc" version="6.8.0-0-202312011"/>
<package name="qt.qt6.680.addons.qtquick3d" displayname="Qt Quick 3D" version="6.8.0-0-202312011"/>
</availablepackages>"""
TEST_EMAIL = os.getenv("AQT_TEST_EMAIL")
TEST_PASSWORD = os.getenv("AQT_TEST_PASSWORD")
class MockResponse:
def __init__(self, status_code: int = 200, content: bytes = b"", text: str = "", headers: Dict = None):
self.status_code = status_code
self.content = content
self.text = text
self.headers = headers or {}
self.ok = status_code == 200
def raise_for_status(self):
if not self.ok:
raise requests.HTTPError(f"HTTP Error: {self.status_code}")
def iter_content(self, chunk_size=None):
yield self.content
@pytest.fixture
def mock_settings(monkeypatch):
"""Setup test settings"""
# Instead of trying to set properties directly, we should mock the property getter
monkeypatch.setattr(Settings, "qt_installer_timeout", property(lambda self: 60))
monkeypatch.setattr(Settings, "qt_installer_cache_path", property(lambda self: str(Path.home() / ".qt" / "cache")))
monkeypatch.setattr(Settings, "qt_installer_temp_path", property(lambda self: str(Path.home() / ".qt" / "temp")))
@pytest.fixture
def commercial_installer():
return CommercialInstaller(
target="desktop",
arch="gcc_64",
version="6.8.0",
username=TEST_EMAIL,
password=TEST_PASSWORD,
output_dir="./test_output",
)
@pytest.mark.enable_socket
@pytest.mark.parametrize(
"cmd, expected_arch, expected_err",
[
pytest.param(
"install-qt-official desktop {} 6.8.0",
{"windows": "win64_msvc2022_64", "linux": "linux_gcc_64", "mac": "clang_64"},
"No Qt account credentials found",
),
],
)
def test_cli_login_qt_commercial(capsys, monkeypatch, cmd, expected_arch, expected_err):
"""Test commercial Qt installation command"""
# Detect current platform
current_platform = sys.platform.lower()
arch = expected_arch[current_platform]
cmd = cmd.format(arch)
if get_qt_account_path().exists():
os.remove(get_qt_account_path())
cli = Cli()
cli._setup_settings()
cli.run(cmd.split())
out, err = capsys.readouterr()
assert expected_err in err or expected_err in out
def test_package_manager_init():
"""Test QtPackageManager initialization"""
manager = QtPackageManager(
arch="gcc_64",
version=Version("6.8.0"),
target="desktop",
username=TEST_EMAIL,
password=TEST_PASSWORD,
)
assert manager.arch == "gcc_64"
assert str(manager.version) == "6.8.0"
assert manager.target == "desktop"
assert manager.username == TEST_EMAIL
assert manager.password == TEST_PASSWORD
@pytest.mark.parametrize(
"xml_content, expected_packages",
[
(
MOCK_XML_RESPONSE,
[
QtPackageInfo(name="qt.qt6.680.gcc_64", displayname="Desktop gcc", version="6.8.0-0-202312011"),
QtPackageInfo(name="qt.qt6.680.addons.qtquick3d", displayname="Qt Quick 3D", version="6.8.0-0-202312011"),
],
)
],
)
def test_parse_packages_xml(xml_content: str, expected_packages: List[QtPackageInfo]):
"""Test parsing of package XML data"""
manager = QtPackageManager(arch="gcc_64", version=Version("6.8.0"), target="desktop")
manager._parse_packages_xml(xml_content)
assert len(manager.packages) == len(expected_packages)
for actual, expected in zip(manager.packages, expected_packages):
assert actual.name == expected.name
assert actual.displayname == expected.displayname
assert actual.version == expected.version
def test_commercial_installer_auto_answers():
"""Test generation of auto-answer options"""
auto_answers = CommercialInstaller.get_auto_answers()
assert "OperationDoesNotExistError=Ignore" in auto_answers
assert "OverwriteTargetDirectory=No" in auto_answers
assert "telemetry-question=No" in auto_answers
@pytest.mark.parametrize(
"installer_path, override, username, password, output_dir, no_unattended, expected_cmd",
[
(
"/path/to/installer",
None,
"user",
"pass",
"./output",
False,
[
"/path/to/installer",
"--accept-licenses",
"--accept-obligations",
"--confirm-command",
"--email",
"user",
"--pw",
"pass",
"--root",
str(Path("./output").absolute()),
"--auto-answer",
CommercialInstaller.get_auto_answers(),
],
),
(
"/path/to/installer",
["--override", "arg1", "arg2"],
None,
None,
None,
True,
["/path/to/installer", "--override", "arg1", "arg2"],
),
],
)
def test_build_command(
installer_path: str,
override: Optional[List[str]],
username: Optional[str],
password: Optional[str],
output_dir: Optional[str],
no_unattended: bool,
expected_cmd: List[str],
):
"""Test building of installer command"""
cmd = CommercialInstaller.build_command(
installer_path,
override=override,
username=username,
password=password,
output_dir=output_dir,
no_unattended=no_unattended,
)
assert cmd == expected_cmd
@pytest.mark.enable_socket
def test_commercial_installer_download(monkeypatch, commercial_installer):
"""Test downloading of commercial installer"""
def mock_requests_get(*args, **kwargs):
return MockResponse(content=b"installer_content")
monkeypatch.setattr(requests, "get", mock_requests_get)
with TemporaryDirectory() as temp_dir:
target_path = Path(temp_dir) / "qt-installer"
commercial_installer.download_installer(target_path, timeout=60)
assert target_path.exists()
assert target_path.read_bytes() == b"installer_content"
@pytest.mark.parametrize(
"modules, expected_command",
[
(None, ["install", "qt.qt6.680.gcc_64"]),
(["qtquick3d"], ["install", "qt.qt6.680.gcc_64", "qt.qt6.680.addons.qtquick3d"]),
(["all"], ["install", "qt.qt6.680.gcc_64", "qt.qt6.680.addons.qtquick3d"]),
],
)
def test_get_install_command(monkeypatch, modules: Optional[List[str]], expected_command: List[str]):
"""Test generation of install commands"""
manager = QtPackageManager(arch="gcc_64", version=Version("6.8.0"), target="desktop")
def mock_gather_packages(self, installer_path: str) -> None:
self.packages = [
QtPackageInfo(name="qt.qt6.680.gcc_64", displayname="Desktop gcc", version="6.8.0"),
QtPackageInfo(name="qt.qt6.680.addons.qtquick3d", displayname="Qt Quick 3D", version="6.8.0"),
]
monkeypatch.setattr(QtPackageManager, "gather_packages", mock_gather_packages)
command = manager.get_install_command(modules, "./temp")
assert command == expected_command
@pytest.mark.enable_socket
@pytest.mark.parametrize(
"cmd, arch_dict, details, expected_command",
[
(
"install-qt-official desktop {} 6.8.1 " "--outputdir ./install-qt-official --email {} --pw {}",
{"windows": "win64_msvc2022_64", "linux": "linux_gcc_64", "mac": "clang_64"},
["./install-qt-official", "qt6", "681"],
"qt-unified-{}-x64-online.run --email ******** --pw ******** --root {} "
"--accept-licenses --accept-obligations "
"--confirm-command "
"--auto-answer OperationDoesNotExistError=Ignore,OverwriteTargetDirectory=No,"
"stopProcessesForUpdates=Cancel,installationErrorWithCancel=Cancel,installationErrorWithIgnore=Ignore,"
"AssociateCommonFiletypes=Yes,telemetry-question=No install qt.{}.{}.{}",
),
(
"install-qt-official desktop {} 6.8.1 --outputdir ./install-qt-official --email {} --pw {}",
{"windows": "win64_msvc2022_64", "linux": "linux_gcc_64", "mac": "clang_64"},
["./install-qt-official", "qt6", "681"],
"qt-unified-{}-x64-online.run --email ******** --pw ******** --root {} "
"--accept-licenses --accept-obligations "
"--confirm-command "
"--auto-answer OperationDoesNotExistError=Ignore,OverwriteTargetDirectory=Yes,"
"stopProcessesForUpdates=Cancel,installationErrorWithCancel=Cancel,installationErrorWithIgnore=Ignore,"
"AssociateCommonFiletypes=Yes,telemetry-question=No install qt.{}.{}.{}",
),
],
)
def test_install_qt_commercial(
capsys, monkeypatch, cmd: str, arch_dict: dict[str, str], details: list[str], expected_command: str
) -> None:
"""Test commercial Qt installation command"""
def mock_safely_run(*args, **kwargs):
return CompletedProcess(args=args[0], returncode=0)
monkeypatch.setattr("aqt.commercial.safely_run", mock_safely_run)
current_platform = sys.platform.lower()
arch = arch_dict[current_platform]
abs_out = Path(details[0]).absolute()
# Get the email and password from the test parameters
email = TEST_EMAIL
password = TEST_PASSWORD
formatted_cmd = cmd.format(arch, email, password)
formatted_expected = expected_command.format(current_platform, abs_out, *details[1:], arch)
cli = Cli()
cli._setup_settings()
# First test the normal installation command
try:
cli.run(formatted_cmd.split())
except AttributeError:
out = " ".join(capsys.readouterr())
assert str(out).find(formatted_expected) >= 0
abs_out.joinpath(f"6.8.{str(details[2])[-1]}").mkdir(exist_ok=True, parents=True)
# Create a new command with the temp directory
new_cmd = (
f"install-qt-official desktop {arch} 6.8.{str(details[2])[-1]} --outputdir {abs_out} --email {email} "
f"--pw {password}"
)
# This should raise DiskAccessNotPermitted only for the first test (680)
if details[2] == "680":
with pytest.raises(DiskAccessNotPermitted) as exc_info:
cli.run(new_cmd.split())
assert "Target directory" in str(exc_info.value)
assert "already exists" in str(exc_info.value)
else:
cli.run(new_cmd.split())
def modify_qt_config(content):
"""
Takes content of INI file as string and returns modified content
"""
lines = content.splitlines()
in_qt_commercial = False
modified = []
for line in lines:
# Check if we're entering qtofficial section
if line.strip() == "[qtofficial]":
in_qt_commercial = True
# If in qtofficial section, look for the target line
if in_qt_commercial and "overwrite_target_directory : No" in line:
line = "overwrite_target_directory : Yes"
elif in_qt_commercial and "overwrite_target_directory : Yes" in line:
line = "overwrite_target_directory : No"
modified.append(line)
return "\n".join(modified)
script_dir = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(script_dir, "../aqt/settings.ini")
with open(config_path, "r") as f:
content = f.read()
modified_content = modify_qt_config(content)
with open(config_path, "w") as f:
f.write(modified_content)
Settings._initialize()
shutil.rmtree(abs_out)
@pytest.mark.parametrize(
"args, expected_error",
[
(["list-qt-official", "--bad-flag"], "usage: aqt [-h] [-c CONFIG]"),
],
)
def test_list_qt_commercial_errors(capsys, args, expected_error):
"""Test error handling in list-qt-official command"""
cli = Cli()
with pytest.raises(SystemExit):
cli.run(args)
_, err = capsys.readouterr()
assert expected_error in err

View File

@@ -2054,104 +2054,3 @@ def test_installer_passes_base_to_metadatafactory(
sys.stderr.write(err)
assert expect_out.match(err), err
class CompletedProcess:
def __init__(self, args, returncode):
self.args = args
self.returncode = returncode
self.stdout = None
self.stderr = None
@pytest.mark.enable_socket
@pytest.mark.parametrize(
"cmd, arch_dict, details, expected_command",
[
(
"install-qt-commercial desktop {} 6.8.0 " "--outputdir ./install-qt-commercial " "--user {} --password {}",
{"windows": "win64_msvc2022_64", "linux": "linux_gcc_64", "mac": "clang_64"},
["./install-qt-commercial", "qt6", "680"],
"qt-unified-{}-x64-online.run --email ******** --pw ******** --root {} "
"--accept-licenses --accept-obligations "
"--confirm-command "
"--auto-answer OperationDoesNotExistError=Ignore,OverwriteTargetDirectory=No,"
"stopProcessesForUpdates=Cancel,installationErrorWithCancel=Cancel,installationErrorWithIgnore=Ignore,"
"AssociateCommonFiletypes=Yes,telemetry-question=No install qt.{}.{}.{}",
),
(
"install-qt-commercial desktop {} 6.8.1 " "--outputdir ./install-qt-commercial " "--user {} --password {}",
{"windows": "win64_msvc2022_64", "linux": "linux_gcc_64", "mac": "clang_64"},
["./install-qt-commercial", "qt6", "681"],
"qt-unified-{}-x64-online.run --email ******** --pw ******** --root {} "
"--accept-licenses --accept-obligations "
"--confirm-command "
"--auto-answer OperationDoesNotExistError=Ignore,OverwriteTargetDirectory=Yes,"
"stopProcessesForUpdates=Cancel,installationErrorWithCancel=Cancel,installationErrorWithIgnore=Ignore,"
"AssociateCommonFiletypes=Yes,telemetry-question=No install qt.{}.{}.{}",
),
],
)
def test_install_qt_commercial(
capsys, monkeypatch, cmd: str, arch_dict: dict[str, str], details: list[str], expected_command: str
) -> None:
"""Test commercial Qt installation command"""
# Mock subprocess.run instead of run_static_subprocess_dynamically
def mock_subprocess_run(*args, **kwargs):
# This will be called instead of the real subprocess.run
return CompletedProcess(args=args[0], returncode=0)
# Patch subprocess.run directly
monkeypatch.setattr("subprocess.run", mock_subprocess_run)
current_platform = sys.platform.lower()
arch = arch_dict[current_platform]
abs_out = Path(details[0]).absolute()
formatted_cmd = cmd.format(arch, "vofab76634@gholar.com", "WxK43TdWCTmxsrrpnsWbjPfPXVq3mtLK")
formatted_expected = expected_command.format(current_platform, abs_out, *details[1:], arch)
cli = Cli()
cli._setup_settings()
try:
cli.run(formatted_cmd.split())
except AttributeError:
out = " ".join(capsys.readouterr())
assert str(out).find(formatted_expected) >= 0
def modify_qt_config(content):
"""
Takes content of INI file as string and returns modified content
"""
lines = content.splitlines()
in_qt_commercial = False
modified = []
for line in lines:
# Check if we're entering qtcommercial section
if line.strip() == "[qtcommercial]":
in_qt_commercial = True
# If in qtcommercial section, look for the target line
if in_qt_commercial and "overwrite_target_directory : No" in line:
line = "overwrite_target_directory : Yes"
elif in_qt_commercial and "overwrite_target_directory : Yes" in line:
line = "overwrite_target_directory : No"
modified.append(line)
return "\n".join(modified)
script_dir = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(script_dir, "../aqt/settings.ini")
with open(config_path, "r") as f:
content = f.read()
modified_content = modify_qt_config(content)
with open(config_path, "w") as f:
f.write(modified_content)

View File

@@ -1336,19 +1336,3 @@ def test_find_installed_qt_mingw_dir(expected_result: str, installed_files: List
actual_result = QtRepoProperty.find_installed_desktop_qt_dir(host, base_path, Version(qt_ver))
assert (actual_result.name if actual_result else None) == expected_result
# Test error cases
@pytest.mark.parametrize(
"args, expected_error",
[
(["list-qt-commercial", "--bad-flag"], "usage: aqt [-h] [-c CONFIG]"),
],
)
def test_list_qt_commercial_errors(capsys, args, expected_error):
"""Test error handling in list-qt-commercial command"""
cli = Cli()
with pytest.raises(SystemExit):
cli.run(args)
_, err = capsys.readouterr()
assert expected_error in err