mirror of
https://github.com/miurahr/aqtinstall.git
synced 2025-12-16 20:27:05 +03:00
2245 lines
102 KiB
Python
2245 lines
102 KiB
Python
import errno
|
|
import hashlib
|
|
import logging
|
|
import os
|
|
import posixpath
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import tarfile
|
|
import textwrap
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from tempfile import TemporaryDirectory
|
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
|
|
|
|
import py7zr
|
|
import pytest
|
|
|
|
from aqt.archives import QtPackage
|
|
from aqt.exceptions import ArchiveDownloadError, ArchiveExtractionError
|
|
from aqt.helper import Settings
|
|
from aqt.installer import Cli, installer
|
|
|
|
|
|
class MockMultiprocessingContext:
|
|
"""
|
|
By default, monkeypatch will only patch objects in the main process.
|
|
When multiprocessing is used, child processes will not be patched.
|
|
This class forces all work to be done in the main process, so that all
|
|
patched objects remain patched.
|
|
|
|
NOTE: This probably isn't the right way to solve the problem, but it is
|
|
the only way I have found to solve it.
|
|
"""
|
|
|
|
def __init__(self, *args):
|
|
pass
|
|
|
|
class Pool:
|
|
def __init__(self, *args):
|
|
pass
|
|
|
|
def starmap(self, func: Callable, func_args: List[Tuple], *args):
|
|
for set_of_args in func_args:
|
|
func(*set_of_args)
|
|
|
|
def close(self):
|
|
pass
|
|
|
|
def join(self):
|
|
pass
|
|
|
|
def terminate(self):
|
|
pass
|
|
|
|
|
|
class MockMultiprocessingManager:
|
|
class Queue:
|
|
def __init__(self, *args):
|
|
pass
|
|
|
|
def put_nowait(self, log_record: Optional[logging.LogRecord]):
|
|
# NOTE: This is certainly not the right way to do this, but it works locally
|
|
if not log_record or log_record.levelno < logging.INFO:
|
|
return
|
|
print(log_record.message, file=sys.stderr)
|
|
|
|
def get(self, *args):
|
|
return None
|
|
|
|
|
|
GET_URL_TYPE = Callable[[str, Any], str]
|
|
DOWNLOAD_ARCHIVE_TYPE = Callable[[str, str, str, bytes, Any], None]
|
|
LIST_OF_FILES_AND_CONTENTS = Iterable[Dict[str, str]]
|
|
|
|
|
|
@dataclass
|
|
class PatchedFile:
|
|
filename: str
|
|
unpatched_content: str
|
|
patched_content: Optional[str] = None # When None, the file is expected not to be patched.
|
|
|
|
def expected_content(self, **kwargs) -> str:
|
|
if not self.patched_content:
|
|
return self.unpatched_content
|
|
return self.patched_content.format(**kwargs)
|
|
|
|
|
|
@dataclass
|
|
class MockArchive:
|
|
filename_7z: str
|
|
update_xml_name: str
|
|
contents: Iterable[PatchedFile]
|
|
version: str = ""
|
|
arch_dir: str = ""
|
|
should_install: bool = True
|
|
extract_target: Optional[str] = None
|
|
date: datetime = datetime.now()
|
|
|
|
def xml_package_update(self) -> str:
|
|
if self.extract_target:
|
|
return textwrap.dedent(
|
|
f"""\
|
|
<PackageUpdate>
|
|
<Name>{self.update_xml_name}</Name>
|
|
<Version>{self.version}-0-{self.date.strftime("%Y%m%d%H%M")}</Version>
|
|
<Description>none</Description>
|
|
<DownloadableArchives>{self.filename_7z}</DownloadableArchives>
|
|
<Operations>
|
|
<Operation name="Extract">
|
|
<Argument>{self.extract_target}</Argument>
|
|
<Argument>{self.filename_7z}</Argument>
|
|
</Operation>
|
|
</Operations>
|
|
</PackageUpdate>"""
|
|
)
|
|
else:
|
|
return textwrap.dedent(
|
|
f"""\
|
|
<PackageUpdate>
|
|
<Name>{self.update_xml_name}</Name>
|
|
<Version>{self.version}-0-{self.date.strftime("%Y%m%d%H%M")}</Version>
|
|
<Description>none</Description>
|
|
<DownloadableArchives>{self.filename_7z}</DownloadableArchives>
|
|
</PackageUpdate>"""
|
|
)
|
|
|
|
def write_compressed_archive(self, dest: Path) -> None:
|
|
def open_writable_archive():
|
|
if self.filename_7z.endswith(".7z"):
|
|
return py7zr.SevenZipFile(dest / self.filename_7z, "w")
|
|
elif self.filename_7z.endswith(".tar.xz"):
|
|
return tarfile.open(dest / self.filename_7z, "w:xz")
|
|
# elif self.filename_7z.endswith(".zip"):
|
|
# return tarfile.open(dest / "DUMMY-NOT-USED", "w")
|
|
else:
|
|
assert False, "Archive type not supported"
|
|
|
|
def write_to_archive(arc, src, arcname):
|
|
if self.filename_7z.endswith(".7z"):
|
|
arc.writeall(path=src, arcname=arcname)
|
|
elif self.filename_7z.endswith(".tar.xz"):
|
|
arc.add(name=src, arcname=arcname)
|
|
# elif self.filename_7z.endswith(".zip"):
|
|
# shutil.make_archive(str(dest / self.filename_7z), "zip", src)
|
|
|
|
with TemporaryDirectory() as temp_dir, open_writable_archive() as archive:
|
|
# if the Updates.xml file uses Operations/Operation[@name='Extract'] elements then the names
|
|
# of archive members do not include the version and arch_dir path segments, instead they are
|
|
# supplied by an Argument element which is used when the archive is extracted.
|
|
temp_path = Path(temp_dir)
|
|
arch_dir = self.arch_dir if not self.extract_target else ""
|
|
|
|
# Create directories first
|
|
for folder in ("bin", "lib", "mkspecs"):
|
|
(temp_path / arch_dir / folder).mkdir(parents=True, exist_ok=True)
|
|
|
|
# Write all content files and make executable if in bin/
|
|
for patched_file in self.contents:
|
|
full_path = temp_path / arch_dir / patched_file.filename
|
|
if not full_path.parent.exists():
|
|
full_path.parent.mkdir(parents=True)
|
|
full_path.write_text(patched_file.unpatched_content, "utf_8")
|
|
if "bin/" in patched_file.filename:
|
|
# Make all files in bin executable
|
|
full_path.chmod(full_path.stat().st_mode | 0o111)
|
|
|
|
if self.extract_target:
|
|
archive_name = "."
|
|
else:
|
|
archive_name = "5.9" if self.version == "5.9.0" else self.version
|
|
write_to_archive(archive, temp_path, arcname=archive_name)
|
|
|
|
|
|
def make_mock_geturl_download_archive(
|
|
*,
|
|
standard_archives: List[MockArchive],
|
|
desktop_archives: Optional[List[MockArchive]] = None,
|
|
extpdf_archives: Optional[List[MockArchive]] = None,
|
|
extweb_archives: Optional[List[MockArchive]] = None,
|
|
standard_updates_url: str,
|
|
desktop_updates_url: str = "",
|
|
extpdf_updates_url: str = "",
|
|
extweb_updates_url: str = "",
|
|
) -> Tuple[GET_URL_TYPE, DOWNLOAD_ARCHIVE_TYPE]:
|
|
"""
|
|
Returns a mock 'getUrl' and a mock 'downloadArchive' function.
|
|
"""
|
|
if desktop_archives is None:
|
|
desktop_archives = []
|
|
if extpdf_archives is None:
|
|
extpdf_archives = []
|
|
if extweb_archives is None:
|
|
extweb_archives = []
|
|
for _archive in [*standard_archives, *desktop_archives, *extpdf_archives, *extweb_archives]:
|
|
assert re.match(r".*\.(7z|tar\.xz)$", _archive.filename_7z), "Unsupported file type"
|
|
|
|
def _generate_package_update_xml(archive: MockArchive) -> str:
|
|
"""Helper to generate package XML with proper addon structure for Qt 6.8"""
|
|
is_qt68_addon = (
|
|
archive.version.startswith("6.8")
|
|
and "addons" in archive.update_xml_name
|
|
and not archive.update_xml_name.endswith(("_64", "_arm64", "_32", "wasm_singlethread"))
|
|
)
|
|
|
|
return textwrap.dedent(
|
|
f"""\
|
|
<PackageUpdate>
|
|
<Name>{archive.update_xml_name}</Name>
|
|
<Version>{archive.version}-0-{archive.date.strftime("%Y%m%d%H%M")}</Version>
|
|
<Description>{getattr(archive, 'package_desc', 'none')}</Description>
|
|
<DownloadableArchives>{archive.filename_7z}</DownloadableArchives>
|
|
{f'<Dependencies>qt.qt6.680.gcc_64</Dependencies>' if is_qt68_addon else ''}
|
|
</PackageUpdate>"""
|
|
)
|
|
|
|
standard_xml = "<Updates>\n{}\n</Updates>".format(
|
|
"\n".join([_generate_package_update_xml(archive) for archive in standard_archives])
|
|
)
|
|
desktop_xml = "<Updates>\n{}\n</Updates>".format(
|
|
"\n".join([_generate_package_update_xml(archive) for archive in desktop_archives])
|
|
)
|
|
extpdf_xml = "<Updates>\n{}\n</Updates>".format("\n".join([archive.xml_package_update() for archive in extpdf_archives]))
|
|
extweb_xml = "<Updates>\n{}\n</Updates>".format("\n".join([archive.xml_package_update() for archive in extweb_archives]))
|
|
merged_xml = "<Updates>\n{}{}\n</Updates>".format(
|
|
"\n".join([_generate_package_update_xml(archive) for archive in standard_archives]),
|
|
"\n".join([_generate_package_update_xml(archive) for archive in desktop_archives]),
|
|
)
|
|
|
|
# Empty extension XML response
|
|
empty_extension_xml = "<Updates></Updates>"
|
|
|
|
# Extension URLs and their corresponding XMLs for Qt {}+
|
|
qt68_extensions = {
|
|
# Desktop extensions
|
|
"/extensions/qtwebengine/680/x86_64/": empty_extension_xml,
|
|
"/extensions/qtpdf/680/x86_64/": empty_extension_xml,
|
|
# WASM extensions
|
|
"/extensions/qtwebengine/680/wasm_singlethread/": empty_extension_xml,
|
|
"/extensions/qtpdf/680/wasm_singlethread/": empty_extension_xml,
|
|
}
|
|
|
|
def mock_getUrl(url: str, *args, **kwargs) -> str:
|
|
# Handle main Updates.xml files
|
|
if standard_updates_url == desktop_updates_url and url.endswith(standard_updates_url):
|
|
return merged_xml
|
|
for xml, updates_url in (
|
|
(standard_xml, standard_updates_url),
|
|
(desktop_xml, desktop_updates_url),
|
|
(extpdf_xml, extpdf_updates_url),
|
|
(extweb_xml, extweb_updates_url),
|
|
):
|
|
basename = posixpath.dirname(updates_url)
|
|
if not updates_url:
|
|
continue
|
|
elif url.endswith(updates_url):
|
|
return xml
|
|
elif basename in url and url.endswith(".sha256"):
|
|
filename = url.split("/")[-1][: -len(".sha256")]
|
|
return f"{hashlib.sha256(bytes(xml, 'utf-8')).hexdigest()} {filename}"
|
|
|
|
# Handle extension URLs
|
|
for ext_path, ext_xml in qt68_extensions.items():
|
|
if ext_path in url:
|
|
if url.endswith(".sha256"):
|
|
return f"{hashlib.sha256(bytes(ext_xml, 'utf-8')).hexdigest()} Updates.xml"
|
|
elif url.endswith("Updates.xml"):
|
|
return ext_xml
|
|
|
|
"""
|
|
extensions urls may or may not exist.
|
|
"""
|
|
if "/extensions/" in url:
|
|
raise ArchiveDownloadError(f"Failed to retrieve file at {url}\nServer response code: 404, reason: Not Found")
|
|
|
|
assert False, f"No mocked url available for '{url}'"
|
|
|
|
def mock_download_archive(url: str, out: str, *args):
|
|
"""Make a mocked 7z archive at out_filename"""
|
|
|
|
def locate_archive() -> MockArchive:
|
|
for archive in [*standard_archives, *desktop_archives, *extpdf_archives, *extweb_archives]:
|
|
if Path(out).name == archive.filename_7z:
|
|
return archive
|
|
assert False, "Requested an archive that was not mocked"
|
|
|
|
locate_archive().write_compressed_archive(Path(out).parent)
|
|
|
|
return mock_getUrl, mock_download_archive
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def disable_multiprocessing(monkeypatch):
|
|
# This blocks all multiprocessing, which would otherwise spawn processes that are not monkeypatched
|
|
monkeypatch.setattr(
|
|
"aqt.installer.multiprocessing.get_context",
|
|
lambda *args: MockMultiprocessingContext(),
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
"aqt.installer.multiprocessing.Manager",
|
|
MockMultiprocessingManager,
|
|
)
|
|
|
|
|
|
def qtcharts_module(ver: str, arch: str) -> MockArchive:
|
|
addons = "addons." if ver[0] == "6" else ""
|
|
prefix = "qt" if ver.startswith("5.9.") else f"qt.qt{ver[0]}"
|
|
os_name = {
|
|
"linux_gcc_64": "linux",
|
|
"gcc_64": "linux",
|
|
"linux_gcc_arm64": "linux",
|
|
"wasm_singlethread": "windows", # Keep windows for wasm
|
|
"wasm_multithread": "windows",
|
|
}.get(arch, "windows")
|
|
|
|
return MockArchive(
|
|
filename_7z=f"qtcharts-{os_name}-{arch}.7z", # Use os_name lookup
|
|
update_xml_name=f"{prefix}.{ver.replace('.', '')}.{addons}qtcharts.{arch}",
|
|
version=ver,
|
|
contents=(
|
|
PatchedFile(
|
|
filename="modules/Charts.json",
|
|
unpatched_content=textwrap.dedent(
|
|
f"""\
|
|
{{
|
|
"module_name": "Charts",
|
|
"version": "{ver}",
|
|
"built_with": {{
|
|
"compiler_id": "GNU",
|
|
"compiler_target": "",
|
|
"compiler_version": "1.2.3.4",
|
|
"cross_compiled": false,
|
|
"target_system": "{os_name.title()}"
|
|
}}
|
|
}}
|
|
"""
|
|
),
|
|
patched_content=None, # it doesn't get patched
|
|
),
|
|
),
|
|
)
|
|
|
|
|
|
def qtpositioning_module(ver: str, arch: str) -> MockArchive:
|
|
addons = "addons." if ver[0] == "6" else ""
|
|
prefix = "qt" if ver.startswith("5.9.") else f"qt.qt{ver[0]}"
|
|
os_name = {
|
|
"linux_gcc_64": "linux",
|
|
"gcc_64": "linux",
|
|
"linux_gcc_arm64": "linux",
|
|
"wasm_singlethread": "windows", # Keep windows for wasm
|
|
"wasm_multithread": "windows",
|
|
}.get(arch, "windows")
|
|
return MockArchive(
|
|
filename_7z=f"qtlocation-{os_name}-{arch}.7z", # Use os_name lookup
|
|
update_xml_name=f"{prefix}.{ver.replace('.', '')}.{addons}qtpositioning.{arch}",
|
|
version=ver,
|
|
contents=(
|
|
PatchedFile(
|
|
filename="modules/Positioning.json",
|
|
unpatched_content=textwrap.dedent(
|
|
f"""\
|
|
{{
|
|
"module_name": "Positioning",
|
|
"version": "{ver}",
|
|
"built_with": {{
|
|
"compiler_id": "GNU",
|
|
"compiler_target": "",
|
|
"compiler_version": "1.2.3.4",
|
|
"cross_compiled": false,
|
|
"target_system": "{os_name.title()}"
|
|
}}
|
|
}}
|
|
"""
|
|
),
|
|
patched_content=None, # it doesn't get patched
|
|
),
|
|
),
|
|
)
|
|
|
|
|
|
def plain_qtbase_archive(update_xml_name: str, arch: str, host: str = "windows", should_install: bool = True) -> MockArchive:
|
|
return MockArchive(
|
|
filename_7z=f"qtbase-{host}-{arch}.7z",
|
|
update_xml_name=update_xml_name,
|
|
contents=(
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
should_install=should_install,
|
|
)
|
|
|
|
|
|
def tool_archive(host: str, tool_name: str, variant: str, date: datetime = datetime.now()) -> MockArchive:
|
|
return MockArchive(
|
|
filename_7z=f"{tool_name}-{host}-{variant}.7z",
|
|
update_xml_name=variant,
|
|
contents=(
|
|
PatchedFile(
|
|
filename=f"bin/{tool_name}-{variant}.exe",
|
|
unpatched_content="Some executable binary file",
|
|
patched_content=None, # it doesn't get patched
|
|
),
|
|
),
|
|
should_install=True,
|
|
date=date,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd, host, target, version, arch, arch_dir, updates_url, archives, expect_out",
|
|
(
|
|
(
|
|
"install-tool linux desktop tools_qtcreator qt.tools.qtcreator".split(),
|
|
"linux",
|
|
"desktop",
|
|
"1.2.3-0-197001020304",
|
|
{"std": ""},
|
|
{"std": ""},
|
|
{"std": "linux_x64/desktop/tools_qtcreator/Updates.xml"},
|
|
{"std": [tool_archive("linux", "tools_qtcreator", "qt.tools.qtcreator")]},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qt.tools.qtcreator...\n"
|
|
r"Finished installation of tools_qtcreator-linux-qt.tools.qtcreator.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-tool linux desktop sdktool qt.tools.qtcreator".split(),
|
|
"linux",
|
|
"desktop",
|
|
"10.0.1-0-202305050734",
|
|
{"std": ""},
|
|
{"std": ""},
|
|
{"std": "linux_x64/desktop/sdktool/Updates.xml"},
|
|
{"std": [tool_archive("linux", "sdktool", "qt.tools.qtcreator")]},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qt.tools.qtcreator...\n"
|
|
r"Finished installation of sdktool-linux-qt.tools.qtcreator.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
( # Mixing --modules with --archives
|
|
"install-qt windows desktop 5.14.0 win32_mingw73 -m qtcharts --archives qtbase".split(),
|
|
"windows",
|
|
"desktop",
|
|
"5.14.0",
|
|
{"std": "win32_mingw73"},
|
|
{"std": "mingw73_32"},
|
|
{"std": "windows_x86/desktop/qt5_5140/Updates.xml"},
|
|
{
|
|
"std": [
|
|
plain_qtbase_archive("qt.qt5.5140.win32_mingw73", "win32_mingw73"),
|
|
MockArchive(
|
|
filename_7z="qtcharts-windows-win32_mingw73.7z",
|
|
update_xml_name="qt.qt5.5140.qtcharts.win32_mingw73",
|
|
contents=(PatchedFile(filename="lib/qtcharts.h", unpatched_content="... charts ...\n"),),
|
|
should_install=True,
|
|
),
|
|
MockArchive(
|
|
filename_7z="qtlottie-windows-win32_mingw73.7z",
|
|
update_xml_name="qt.qt5.5140.qtlottie.win32_mingw73",
|
|
contents=(PatchedFile(filename="lib/qtlottie.h", unpatched_content="... lottie ...\n"),),
|
|
should_install=False,
|
|
),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-windows-win32_mingw73.7z in .*\n"
|
|
r"INFO : Downloading qtcharts...\n"
|
|
r"Finished installation of qtcharts-windows-win32_mingw73.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-src windows desktop 5.14.2".split(),
|
|
"windows",
|
|
"desktop",
|
|
"5.14.2",
|
|
{"std": ""},
|
|
{"std": ""},
|
|
{"std": "windows_x86/desktop/qt5_5142_src_doc_examples/Updates.xml"},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-everywhere-src-5.14.2.7z",
|
|
update_xml_name="qt.qt5.5142.src",
|
|
version="5.14.2",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="Src/qtbase/QtBaseSource.cpp",
|
|
unpatched_content="int main(){ return 0; }",
|
|
patched_content=None, # not patched
|
|
),
|
|
),
|
|
),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"WARNING : The parameter 'target' with value 'desktop' is deprecated "
|
|
r"and marked for removal in a future version of aqt\.\n"
|
|
r"In the future, please omit this parameter\.\n"
|
|
r"INFO : Downloading qtbase\.\.\.\n"
|
|
r"Finished installation of qtbase-everywhere-src-5\.14\.2\.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-src linux desktop 6.5.0".split(),
|
|
"linux",
|
|
"desktop",
|
|
"6.5.0",
|
|
{"std": ""},
|
|
{"std": ""},
|
|
{"std": "linux_x64/desktop/qt6_650_src_doc_examples/Updates.xml"},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-everywhere-src-6.5.0.tar.xz",
|
|
update_xml_name="qt.qt6.650.src",
|
|
version="6.5.0",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="Src/qtbase/QtBaseSource.cpp",
|
|
unpatched_content="int main(){ return 0; }",
|
|
patched_content=None, # not patched
|
|
),
|
|
),
|
|
),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"WARNING : The parameter 'target' with value 'desktop' is deprecated "
|
|
r"and marked for removal in a future version of aqt\.\n"
|
|
r"In the future, please omit this parameter\.\n"
|
|
r"INFO : Downloading qtbase\.\.\.\n"
|
|
r"([^\n]*Extracting may be unsafe; consider updating Python to 3.11.4 or greater\n)?"
|
|
r"Finished installation of qtbase-everywhere-src-6\.5\.0\.tar\.xz in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-src windows 5.14.2".split(),
|
|
"windows",
|
|
"desktop",
|
|
"5.14.2",
|
|
{"std": ""},
|
|
{"std": ""},
|
|
{"std": "windows_x86/desktop/qt5_5142_src_doc_examples/Updates.xml"},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-everywhere-src-5.14.2.7z",
|
|
update_xml_name="qt.qt5.5142.src",
|
|
version="5.14.2",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="Src/qtbase/QtBaseSource.cpp",
|
|
unpatched_content="int main(){ return 0; }",
|
|
patched_content=None, # not patched
|
|
),
|
|
),
|
|
)
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase\.\.\.\n"
|
|
r"Finished installation of qtbase-everywhere-src-5\.14\.2\.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt windows desktop 5.9.0 win32_mingw53".split(),
|
|
"windows",
|
|
"desktop",
|
|
"5.9.0",
|
|
{"std": "win32_mingw53"},
|
|
{"std": "mingw53_32"},
|
|
{"std": "windows_x86/desktop/qt5_59/Updates.xml"},
|
|
{"std": [plain_qtbase_archive("qt.59.win32_mingw53", "win32_mingw53")]},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-windows-win32_mingw53.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt windows desktop 5.14.0 win32_mingw73".split(),
|
|
"windows",
|
|
"desktop",
|
|
"5.14.0",
|
|
{"std": "win32_mingw73"},
|
|
{"std": "mingw73_32"},
|
|
{"std": "windows_x86/desktop/qt5_5140/Updates.xml"},
|
|
{"std": [plain_qtbase_archive("qt.qt5.5140.win32_mingw73", "win32_mingw73")]},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-windows-win32_mingw73.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt windows desktop 5.14.0 win64_mingw73 -m qtcharts".split(),
|
|
"windows",
|
|
"desktop",
|
|
"5.14.0",
|
|
{"std": "win64_mingw73"},
|
|
{"std": "mingw73_64"},
|
|
{"std": "windows_x86/desktop/qt5_5140/Updates.xml"},
|
|
{
|
|
"std": [
|
|
plain_qtbase_archive("qt.qt5.5140.win64_mingw73", "win64_mingw73"),
|
|
qtcharts_module("5.14.0", "win64_mingw73"),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-windows-win64_mingw73.7z in .*\n"
|
|
r"INFO : Downloading qtcharts...\n"
|
|
r"Finished installation of qtcharts-windows-win64_mingw73.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt windows desktop 6.2.0 win64_mingw73 -m qtpositioning --noarchives".split(),
|
|
"windows",
|
|
"desktop",
|
|
"6.2.0",
|
|
{"std": "win64_mingw73"},
|
|
{"std": "mingw73_64"},
|
|
{"std": "windows_x86/desktop/qt6_620/Updates.xml"},
|
|
{
|
|
"std": [
|
|
plain_qtbase_archive("qt.qt6.620.win64_mingw73", "win64_mingw73", should_install=False),
|
|
qtpositioning_module("6.2.0", "win64_mingw73"),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtlocation...\n"
|
|
r"Finished installation of qtlocation-windows-win64_mingw73.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt windows desktop 6.1.0 win64_mingw81 -m qtcharts".split(),
|
|
"windows",
|
|
"desktop",
|
|
"6.1.0",
|
|
{"std": "win64_mingw81"},
|
|
{"std": "mingw81_64"},
|
|
{"std": "windows_x86/desktop/qt6_610/Updates.xml"},
|
|
{
|
|
"std": [
|
|
plain_qtbase_archive("qt.qt6.610.win64_mingw81", "win64_mingw81"),
|
|
qtcharts_module("6.1.0", "win64_mingw81"),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-windows-win64_mingw81.7z in .*\n"
|
|
r"INFO : Downloading qtcharts...\n"
|
|
r"Finished installation of qtcharts-windows-win64_mingw81.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
( # Duplicates in the modules list
|
|
"install-qt windows desktop 6.1.0 win64_mingw81 -m qtcharts qtcharts qtcharts".split(),
|
|
"windows",
|
|
"desktop",
|
|
"6.1.0",
|
|
{"std": "win64_mingw81"},
|
|
{"std": "mingw81_64"},
|
|
{"std": "windows_x86/desktop/qt6_610/Updates.xml"},
|
|
{
|
|
"std": [
|
|
plain_qtbase_archive("qt.qt6.610.win64_mingw81", "win64_mingw81"),
|
|
qtcharts_module("6.1.0", "win64_mingw81"),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-windows-win64_mingw81.7z in .*\n"
|
|
r"INFO : Downloading qtcharts...\n"
|
|
r"Finished installation of qtcharts-windows-win64_mingw81.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt windows android 6.1.0 android_armv7".split(),
|
|
"windows",
|
|
"android",
|
|
"6.1.0",
|
|
{"std": "android_armv7"},
|
|
{"std": "android_armv7"},
|
|
{"std": "windows_x86/android/qt6_610_armv7/Updates.xml"},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-windows-android_armv7.7z",
|
|
update_xml_name="qt.qt6.610.android_armv7",
|
|
contents=(
|
|
# Qt 6 non-desktop should patch qconfig.pri, qmake script and target_qt.conf
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/target_qt.conf",
|
|
unpatched_content="Prefix=/Users/qt/work/install/target\n"
|
|
"HostPrefix=../../\n"
|
|
"HostData=target\n",
|
|
patched_content="Prefix={base_dir}{sep}6.1.0{sep}android_armv7{sep}target\n"
|
|
"HostPrefix=../../mingw1234_64\n"
|
|
"HostData=../android_armv7\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.1.0\\mingw1234_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"WARNING : You are installing the android version of Qt, which requires that the desktop version of "
|
|
r"Qt is also installed. You can install it with the following command:\n"
|
|
r" `aqt install-qt windows desktop 6.1.0 win64_mingw1234`\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-windows-android_armv7.7z in .*\n"
|
|
r"INFO : Patching .*6\.1\.0[/\\]android_armv7[/\\]bin[/\\]qmake.bat\n"
|
|
r"INFO : Patching .*6\.1\.0[/\\]android_armv7[/\\]bin[/\\]target_qt.conf\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
# --autodesktop test edited
|
|
(
|
|
"install-qt windows desktop 6.5.2 win64_msvc2019_arm64 --autodesktop".split(),
|
|
"windows",
|
|
"desktop",
|
|
"6.5.2",
|
|
{"std": "win64_msvc2019_arm64", "desk": "win64_msvc2019_64"},
|
|
{"std": "msvc2019_arm64", "desk": "msvc2019_64"},
|
|
{
|
|
"std": "windows_x86/desktop/qt6_652/Updates.xml",
|
|
"desk": "windows_x86/desktop/qt6_652/Updates.xml",
|
|
},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-windows-win64_msvc2019_arm64.7z",
|
|
update_xml_name="qt.qt6.652.win64_msvc2019_arm64",
|
|
contents=(
|
|
# Qt 6 msvc-arm64 should patch qconfig.pri, qmake script and target_qt.conf
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/target_qt.conf",
|
|
unpatched_content="Prefix=/Users/qt/work/install/target\n"
|
|
"HostPrefix=../../\n"
|
|
"HostData=target\n",
|
|
patched_content="Prefix={base_dir}{sep}6.5.2{sep}msvc2019_arm64{sep}target\n"
|
|
"HostPrefix=../../msvc2019_64\n"
|
|
"HostData=../msvc2019_arm64\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.5.2\\msvc2019_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qtpaths.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.5.2\\msvc2019_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake6.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.5.2\\msvc2019_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qtpaths6.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.5.2\\msvc2019_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
),
|
|
],
|
|
"desk": [plain_qtbase_archive("qt.qt6.652.win64_msvc2019_64", "win64_msvc2019_64", host="windows")],
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : You are installing the MSVC Arm64 version of Qt\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"(?:.*\n)*?"
|
|
r"(INFO : Patching .*?[/\\]6\.5\.2[/\\]msvc2019_arm64[/\\]bin[/\\](?:qmake|qtpaths)(?:6)?\.bat\n)*"
|
|
r"INFO : \n"
|
|
r"INFO : Autodesktop will now install windows desktop 6\.5\.2 "
|
|
r"win64_msvc2019_64 as required by MSVC Arm64\n"
|
|
r"INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"(?:.*\n)*$"
|
|
),
|
|
),
|
|
(
|
|
"install-qt linux android 6.4.1 android_arm64_v8a".split(),
|
|
"linux",
|
|
"android",
|
|
"6.4.1",
|
|
{"std": "android_arm64_v8a"},
|
|
{"std": "android_arm64_v8a"},
|
|
{"std": "linux_x64/android/qt6_641_arm64_v8a/Updates.xml"},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-MacOS-MacOS_12-Clang-Android-Android_ANY-ARM64.7z",
|
|
update_xml_name="qt.qt6.641.android_arm64_v8a",
|
|
contents=(
|
|
# Qt 6 non-desktop should patch qconfig.pri, qmake script and target_qt.conf
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="mkspecs/qdevice.pri",
|
|
unpatched_content="blah blah blah...\n"
|
|
"DEFAULT_ANDROID_NDK_HOST = mac-x86_64\n"
|
|
"blah blah blah...\n",
|
|
patched_content="blah blah blah...\n"
|
|
"DEFAULT_ANDROID_NDK_HOST = linux-x86_64\n"
|
|
"blah blah blah...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/target_qt.conf",
|
|
unpatched_content="Prefix=/Users/qt/work/install/target\n"
|
|
"HostPrefix=../../\n"
|
|
"HostData=target\n"
|
|
"HostLibraryExecutables=./bin\n"
|
|
"HostLibraryExecutables=./libexec\n",
|
|
patched_content="Prefix={base_dir}{sep}6.4.1{sep}android_arm64_v8a{sep}target\n"
|
|
"HostPrefix=../../gcc_64\n"
|
|
"HostData=../android_arm64_v8a\n"
|
|
"HostLibraryExecutables=./libexec\n"
|
|
"HostLibraryExecutables=./libexec\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/home/qt/work/install/bin\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}/6.4.1/gcc_64/bin\n"
|
|
"{base_dir}/6.4.1/gcc_64/bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qtpaths",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/home/qt/work/install/bin\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}/6.4.1/gcc_64/bin\n"
|
|
"{base_dir}/6.4.1/gcc_64/bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"WARNING : You are installing the android version of Qt, which requires that the desktop version of "
|
|
r"Qt is also installed. You can install it with the following command:\n"
|
|
r" `aqt install-qt linux desktop 6\.4\.1 gcc_64`\n"
|
|
r"INFO : Downloading qtbase\.\.\.\n"
|
|
r"Finished installation of qtbase-MacOS-MacOS_12-Clang-Android-Android_ANY-ARM64\.7z in .*\n"
|
|
r"INFO : Patching .*6\.4\.1[/\\]android_arm64_v8a[/\\]bin[/\\]qmake\n"
|
|
r"INFO : Patching .*6\.4\.1[/\\]android_arm64_v8a[/\\]bin[/\\]qtpaths\n"
|
|
r"INFO : Patching .*6\.4\.1[/\\]android_arm64_v8a[/\\]bin[/\\]target_qt.conf\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt linux android 6.3.0 android_arm64_v8a".split(),
|
|
"linux",
|
|
"android",
|
|
"6.3.0",
|
|
{"std": "android_arm64_v8a"},
|
|
{"std": "android_arm64_v8a"},
|
|
{"std": "linux_x64/android/qt6_630_arm64_v8a/Updates.xml"},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-linux-android_arm64_v8a.7z",
|
|
update_xml_name="qt.qt6.630.android_arm64_v8a",
|
|
contents=(
|
|
# Qt 6 non-desktop should patch qconfig.pri, qmake script and target_qt.conf
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/target_qt.conf",
|
|
unpatched_content="Prefix=/home/qt/work/install/target\n"
|
|
"HostPrefix=../../\n"
|
|
"HostData=target\n",
|
|
patched_content="Prefix={base_dir}{sep}6.3.0{sep}android_arm64_v8a{sep}target\n"
|
|
"HostPrefix=../../gcc_64\n"
|
|
"HostData=../android_arm64_v8a\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/home/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}/6.3.0/gcc_64/bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qtpaths",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/home/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}/6.3.0/gcc_64/bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"WARNING : You are installing the android version of Qt, which requires that the desktop version of "
|
|
r"Qt is also installed. You can install it with the following command:\n"
|
|
r" `aqt install-qt linux desktop 6\.3\.0 gcc_64`\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-linux-android_arm64_v8a.7z in .*\n"
|
|
r"INFO : Patching .*6\.3\.0[/\\]android_arm64_v8a[/\\]bin[/\\]qmake\n"
|
|
r"INFO : Patching .*6\.3\.0[/\\]android_arm64_v8a[/\\]bin[/\\]qtpaths\n"
|
|
r"INFO : Patching .*6\.3\.0[/\\]android_arm64_v8a[/\\]bin[/\\]target_qt.conf\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt mac ios 6.1.2".split(),
|
|
"mac",
|
|
"ios",
|
|
"6.1.2",
|
|
{"std": "ios"},
|
|
{"std": "ios"},
|
|
{"std": "mac_x64/ios/qt6_612/Updates.xml"},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-mac-ios.7z",
|
|
update_xml_name="qt.qt6.612.ios",
|
|
contents=(
|
|
# Qt 6 non-desktop should patch qconfig.pri, qmake script and target_qt.conf
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/target_qt.conf",
|
|
unpatched_content="Prefix=/Users/qt/work/install/target\n"
|
|
"HostPrefix=../../\n"
|
|
"HostData=target\n",
|
|
patched_content="Prefix={base_dir}{sep}6.1.2{sep}ios{sep}target\n"
|
|
"HostPrefix=../../macos\n"
|
|
"HostData=../ios\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}/6.1.2/macos/bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
),
|
|
]
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"WARNING : You are installing the ios version of Qt, which requires that the desktop version of Qt is "
|
|
r"also installed. You can install it with the following command:\n"
|
|
r" `aqt install-qt mac desktop 6\.1\.2 clang_64`\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-mac-ios.7z in .*\n"
|
|
r"INFO : Patching .*6\.1\.2[/\\]ios[/\\]bin[/\\]qmake\n"
|
|
r"INFO : Patching .*6\.1\.2[/\\]ios[/\\]bin[/\\]target_qt.conf\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
# --autodesktop test edited
|
|
(
|
|
"install-qt mac ios 6.1.2 --autodesktop".split(),
|
|
"mac",
|
|
"ios",
|
|
"6.1.2",
|
|
{"std": "ios", "desk": "clang_64"},
|
|
{"std": "ios", "desk": "macos"},
|
|
{
|
|
"std": "mac_x64/ios/qt6_612/Updates.xml",
|
|
"desk": "mac_x64/desktop/qt6_612/Updates.xml",
|
|
},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-mac-ios.7z",
|
|
update_xml_name="qt.qt6.612.ios",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/target_qt.conf",
|
|
unpatched_content="Prefix=/Users/qt/work/install/target\n"
|
|
"HostPrefix=../../\n"
|
|
"HostData=target\n",
|
|
patched_content="Prefix={base_dir}{sep}6.1.2{sep}ios{sep}target\n"
|
|
"HostPrefix=../../macos\n"
|
|
"HostData=../ios\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}/6.1.2/macos/bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
),
|
|
],
|
|
"desk": [plain_qtbase_archive("qt.qt6.612.clang_64", "clang_64", host="mac")],
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : You are installing the ios version of Qt\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"(?:.*\n)*?"
|
|
r"INFO : Patching .*?[/\\]6\.1\.2[/\\]ios[/\\]bin[/\\]qmake\n"
|
|
r"INFO : Patching .*?[/\\]6\.1\.2[/\\]ios[/\\]bin[/\\]target_qt.conf\n"
|
|
r"INFO : \n"
|
|
r"INFO : Autodesktop will now install mac desktop 6\.1\.2 clang_64 as required by ios\n"
|
|
r"INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"(?:.*\n)*$"
|
|
),
|
|
),
|
|
(
|
|
"install-qt windows desktop 6.2.4 wasm_32".split(),
|
|
"windows",
|
|
"desktop",
|
|
"6.2.4",
|
|
{"std": "wasm_32"},
|
|
{"std": "wasm_32"},
|
|
{"std": "windows_x86/desktop/qt6_624_wasm/Updates.xml"},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-windows-wasm_32.7z",
|
|
update_xml_name="qt.qt6.624.wasm_32",
|
|
contents=(
|
|
# Qt 6 non-desktop should patch qconfig.pri, qmake script and target_qt.conf
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/target_qt.conf",
|
|
unpatched_content="Prefix=/Users/qt/work/install/target\n"
|
|
"HostPrefix=../../\n"
|
|
"HostData=target\n",
|
|
patched_content="Prefix={base_dir}{sep}6.2.4{sep}wasm_32{sep}target\n"
|
|
"HostPrefix=../../mingw1234_64\n"
|
|
"HostData=../wasm_32\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.2.4\\mingw1234_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qtpaths.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.2.4\\mingw1234_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
),
|
|
],
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"WARNING : You are installing the Qt6-WASM version of Qt, which requires that the desktop version of "
|
|
r"Qt is also installed. You can install it with the following command:\n"
|
|
r" `aqt install-qt windows desktop 6\.2\.4 win64_mingw1234`\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-windows-wasm_32\.7z in .*\n"
|
|
r"INFO : Patching .*6\.2\.4[/\\]wasm_32[/\\]bin[/\\]qmake.bat\n"
|
|
r"INFO : Patching .*6\.2\.4[/\\]wasm_32[/\\]bin[/\\]qtpaths.bat\n"
|
|
r"INFO : Patching .*6\.2\.4[/\\]wasm_32[/\\]bin[/\\]target_qt.conf\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
( # extensions availability: qtpdf and qtwebengine
|
|
"install-qt windows desktop 6.8.1 win64_msvc2022_64 -m qtwebengine".split(),
|
|
"windows",
|
|
"desktop",
|
|
"6.8.1",
|
|
{"std": "win64_msvc2022_64", "extpdf": "win64_msvc2022_64", "extweb": "win64_msvc2022_64"},
|
|
{"std": "msvc2022_64", "extpdf": "msvc2022_64", "extweb": "msvc2022_64"},
|
|
{
|
|
"std": "windows_x86/desktop/qt6_681/qt6_681/Updates.xml",
|
|
"extpdf": "windows_x86/extensions/qtpdf/681/msvc2022_64/Updates.xml",
|
|
"extweb": "windows_x86/extensions/qtwebengine/681/msvc2022_64/Updates.xml",
|
|
},
|
|
{
|
|
"std": [
|
|
plain_qtbase_archive(
|
|
"qt.qt6.681.win64_msvc2022_64",
|
|
"Windows-Windows_11_23H2-X86_64",
|
|
host="Windows-Windows_11_23H2-MSVC2022",
|
|
)
|
|
],
|
|
"extpdf": [
|
|
MockArchive(
|
|
filename_7z="qtpdf-Windows-Windows_11_23H2-MSVC2022-Windows-Windows_11_23H2-X86_64.7z",
|
|
update_xml_name="extensions.qtpdf.681.win64_msvc2022_64",
|
|
contents=(),
|
|
should_install=False,
|
|
extract_target="@TargetDir@/6.8.1/msvc2022_64",
|
|
),
|
|
],
|
|
"extweb": [
|
|
MockArchive(
|
|
filename_7z="qtwebengine-Windows-Windows_11_23H2-MSVC2022-Windows-Windows_11_23H2-X86_64.7z",
|
|
update_xml_name="extensions.qtwebengine.681.win64_msvc2022_64",
|
|
contents=(
|
|
PatchedFile(filename="lib/Qt6WebEngineCore.prl", unpatched_content="... qtwebengine ...\n"),
|
|
),
|
|
should_install=False,
|
|
extract_target="@TargetDir@/6.8.1/msvc2022_64",
|
|
),
|
|
],
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Found extension qtwebengine\n"
|
|
r"INFO : Found extension qtpdf\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of "
|
|
r"qtbase-Windows-Windows_11_23H2-MSVC2022-Windows-Windows_11_23H2-X86_64.7z in .*\n"
|
|
r"INFO : Downloading qtwebengine...\n"
|
|
r"Finished installation of "
|
|
r"qtwebengine-Windows-Windows_11_23H2-MSVC2022-Windows-Windows_11_23H2-X86_64.7z in .*\n"
|
|
r"INFO : Patching .*/6.8.1/msvc2022_64/lib/Qt6WebEngineCore.prl\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
( # extension availability: qtpdf only
|
|
"install-qt windows desktop 6.8.1 win64_mingw -m qtpdf".split(),
|
|
"windows",
|
|
"desktop",
|
|
"6.8.1",
|
|
{"std": "win64_mingw", "extpdf": "win64_mingw"},
|
|
{"std": "mingw_64", "extpdf": "mingw_64"},
|
|
{
|
|
"std": "windows_x86/desktop/qt6_681/qt6_681/Updates.xml",
|
|
"extpdf": "windows_x86/extensions/qtpdf/681/mingw/Updates.xml",
|
|
},
|
|
{
|
|
"std": [
|
|
plain_qtbase_archive(
|
|
"qt.qt6.681.win64_mingw",
|
|
"Windows-Windows_10_22H2-X86_64",
|
|
host="Windows-Windows_10_22H2-Mingw",
|
|
)
|
|
],
|
|
"extpdf": [
|
|
MockArchive(
|
|
filename_7z="qtpdf-Windows-Windows_10_22H2-Mingw-Windows-Windows_10_22H2-X86_64.7z",
|
|
update_xml_name="extensions.qtpdf.681.win64_mingw",
|
|
contents=(),
|
|
should_install=False,
|
|
extract_target="@TargetDir@/6.8.1/mingw_64",
|
|
),
|
|
],
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Found extension qtpdf\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of qtbase-Windows-Windows_10_22H2-Mingw-Windows-Windows_10_22H2-X86_64.7z in .*\n"
|
|
r"INFO : Downloading qtpdf...\n"
|
|
r"Finished installation of qtpdf-Windows-Windows_10_22H2-Mingw-Windows-Windows_10_22H2-X86_64.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
( # extensions availability: qtpdf and qtwebengine
|
|
"install-qt windows desktop 6.10.0 win64_msvc2022_arm64_cross_compiled -m qtwebengine".split(),
|
|
"windows",
|
|
"desktop",
|
|
"6.10.0",
|
|
{
|
|
"std": "win64_msvc2022_arm64_cross_compiled",
|
|
"extpdf": "win64_msvc2022_arm64_cross_compiled",
|
|
"extweb": "win64_msvc2022_arm64_cross_compiled",
|
|
},
|
|
{"std": "msvc2022_arm64", "extpdf": "msvc2022_arm64", "extweb": "msvc2022_arm64"},
|
|
{
|
|
"std": "windows_x86/desktop/qt6_6100/qt6_6100/Updates.xml",
|
|
"extpdf": "windows_x86/extensions/qtpdf/6100/msvc2022_arm64/Updates.xml",
|
|
"extweb": "windows_x86/extensions/qtwebengine/6100/msvc2022_arm64/Updates.xml",
|
|
},
|
|
{
|
|
"std": [
|
|
MockArchive(
|
|
filename_7z="qtbase-Windows-Windows_11_24H2-MSVC2022-Windows-Windows_11_24H2-ARM64.7z",
|
|
update_xml_name="qt.qt6.6100.win64_msvc2022_arm64_cross_compiled",
|
|
contents=(
|
|
# Qt 6 non-desktop should patch qconfig.pri, qmake script and target_qt.conf
|
|
PatchedFile(
|
|
filename="mkspecs/qconfig.pri",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = Not OpenSource\n"
|
|
"QT_LICHECK = Not Empty\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"QT_EDITION = OpenSource\n"
|
|
"QT_LICHECK =\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.10.0\\msvc2022_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qtpaths.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.10.0\\msvc2022_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qmake6.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.10.0\\msvc2022_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/qtpaths6.bat",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"/Users/qt/work/install/bin\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"{base_dir}\\6.10.0\\msvc2022_64\\bin\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
PatchedFile(
|
|
filename="bin/target_qt.conf",
|
|
unpatched_content="... blah blah blah ...\n"
|
|
"HostPrefix=../../\n"
|
|
"... blah blah blah ...\n",
|
|
patched_content="... blah blah blah ...\n"
|
|
"HostPrefix=../../msvc2022_64\n"
|
|
"... blah blah blah ...\n",
|
|
),
|
|
),
|
|
),
|
|
],
|
|
"extpdf": [
|
|
MockArchive(
|
|
filename_7z="qtpdf-Windows-Windows_11_24H2-MSVC2022-Windows-Windows_11_24H2-ARM64.7z",
|
|
update_xml_name="extensions.qtpdf.6100.win64_msvc2022_arm64_cross_compiled",
|
|
contents=(),
|
|
should_install=False,
|
|
extract_target="@TargetDir@/6.10.0/msvc2022_arm64",
|
|
),
|
|
],
|
|
"extweb": [
|
|
MockArchive(
|
|
filename_7z="qtwebengine-Windows-Windows_11_24H2-MSVC2022-Windows-Windows_11_24H2-ARM64.7z",
|
|
update_xml_name="extensions.qtwebengine.6100.win64_msvc2022_arm64_cross_compiled",
|
|
contents=(
|
|
PatchedFile(filename="lib/Qt6WebEngineCore.prl", unpatched_content="... qtwebengine ...\n"),
|
|
),
|
|
should_install=False,
|
|
extract_target="@TargetDir@/6.10.0/msvc2022_arm64",
|
|
),
|
|
],
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"WARNING : You are installing the MSVC Arm64 version of Qt, which requires that the desktop version of "
|
|
r"Qt is also installed. You can install it with the following command:\n"
|
|
r" `aqt install-qt windows desktop 6\.10\.0 win64_msvc2022_64`\n"
|
|
r"INFO : Found extension qtwebengine\n"
|
|
r"INFO : Found extension qtpdf\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of "
|
|
r"qtbase-Windows-Windows_11_24H2-MSVC2022-Windows-Windows_11_24H2-ARM64.7z in .*\n"
|
|
r"INFO : Downloading qtwebengine...\n"
|
|
r"Finished installation of "
|
|
r"qtwebengine-Windows-Windows_11_24H2-MSVC2022-Windows-Windows_11_24H2-ARM64.7z in .*\n"
|
|
r"INFO : Patching .*/6.10.0/msvc2022_arm64/bin/qmake.bat\n"
|
|
r"INFO : Patching .*/6.10.0/msvc2022_arm64/bin/qtpaths.bat\n"
|
|
r"INFO : Patching .*/6.10.0/msvc2022_arm64/bin/qmake6.bat\n"
|
|
r"INFO : Patching .*/6.10.0/msvc2022_arm64/bin/qtpaths6.bat\n"
|
|
r"INFO : Patching .*/6.10.0/msvc2022_arm64/bin/target_qt.conf\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
( # extensions availability: qtpdf and qtwebengine
|
|
"install-qt windows_arm64 desktop 6.10.0 win64_msvc2022_arm64 -m qtwebengine".split(),
|
|
"windows_arm64",
|
|
"desktop",
|
|
"6.10.0",
|
|
{"std": "win64_msvc2022_arm64", "extpdf": "win64_msvc2022_arm64", "extweb": "win64_msvc2022_arm64"},
|
|
{"std": "msvc2022_arm64", "extpdf": "msvc2022_arm64", "extweb": "msvc2022_arm64"},
|
|
{
|
|
"std": "windows_arm64/desktop/qt6_6100/qt6_6100/Updates.xml",
|
|
"extpdf": "windows_arm64/extensions/qtpdf/6100/msvc2022_arm64/Updates.xml",
|
|
"extweb": "windows_arm64/extensions/qtwebengine/6100/msvc2022_arm64/Updates.xml",
|
|
},
|
|
{
|
|
"std": [
|
|
plain_qtbase_archive(
|
|
"qt.qt6.6100.win64_msvc2022_arm64",
|
|
"Windows-Windows_11_23H2-AARCH64",
|
|
host="Windows-Windows_11_23H2-MSVC2022",
|
|
)
|
|
],
|
|
"extpdf": [
|
|
MockArchive(
|
|
filename_7z="qtpdf-Windows-Windows_11_24H2-MSVC2022-Windows-Windows_11_24H2-ARM64.7z",
|
|
update_xml_name="extensions.qtpdf.6100.win64_msvc2022_arm64",
|
|
contents=(),
|
|
should_install=False,
|
|
extract_target="@TargetDir@/6.10.0/msvc2022_arm64",
|
|
),
|
|
],
|
|
"extweb": [
|
|
MockArchive(
|
|
filename_7z="qtwebengine-Windows-Windows_11_24H2-MSVC2022-Windows-Windows_11_24H2-ARM64.7z",
|
|
update_xml_name="extensions.qtwebengine.6100.win64_msvc2022_arm64",
|
|
contents=(
|
|
PatchedFile(filename="lib/Qt6WebEngineCore.prl", unpatched_content="... qtwebengine ...\n"),
|
|
),
|
|
should_install=False,
|
|
extract_target="@TargetDir@/6.10.0/msvc2022_arm64",
|
|
),
|
|
],
|
|
},
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Found extension qtwebengine\n"
|
|
r"INFO : Found extension qtpdf\n"
|
|
r"INFO : Downloading qtbase...\n"
|
|
r"Finished installation of "
|
|
r"qtbase-Windows-Windows_11_23H2-MSVC2022-Windows-Windows_11_23H2-AARCH64.7z in .*\n"
|
|
r"INFO : Downloading qtwebengine...\n"
|
|
r"Finished installation of "
|
|
r"qtwebengine-Windows-Windows_11_24H2-MSVC2022-Windows-Windows_11_24H2-ARM64.7z in .*\n"
|
|
r"INFO : Patching .*/6.10.0/msvc2022_arm64/lib/Qt6WebEngineCore.prl\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
),
|
|
)
|
|
def test_install(
|
|
monkeypatch,
|
|
capsys,
|
|
cmd: List[str],
|
|
host: str,
|
|
target: str,
|
|
version: str,
|
|
arch: Dict[str, str],
|
|
arch_dir: Dict[str, str],
|
|
updates_url: Dict[str, str],
|
|
archives: Dict[str, List[MockArchive]],
|
|
expect_out, # type: re.Pattern
|
|
):
|
|
# For convenience, fill in version and arch dir: prevents repetitive data declarations
|
|
std_archives = archives["std"]
|
|
for i in range(len(std_archives)):
|
|
std_archives[i].version = version
|
|
std_archives[i].arch_dir = arch_dir["std"]
|
|
desktop_archives = archives.get("desk", [])
|
|
for i in range(len(desktop_archives)):
|
|
desktop_archives[i].version = version
|
|
desktop_archives[i].arch_dir = arch_dir["desk"]
|
|
extpdf_archives = archives.get("extpdf", [])
|
|
for i in range(len(extpdf_archives)):
|
|
extpdf_archives[i].version = version
|
|
extpdf_archives[i].arch_dir = arch_dir["extpdf"]
|
|
extweb_archives = archives.get("extweb", [])
|
|
for i in range(len(extweb_archives)):
|
|
extweb_archives[i].version = version
|
|
extweb_archives[i].arch_dir = arch_dir["extweb"]
|
|
|
|
mock_get_url, mock_download_archive = make_mock_geturl_download_archive(
|
|
standard_archives=std_archives,
|
|
desktop_archives=desktop_archives,
|
|
extpdf_archives=extpdf_archives,
|
|
extweb_archives=extweb_archives,
|
|
standard_updates_url=updates_url.get("std", ""),
|
|
desktop_updates_url=updates_url.get("desk", ""),
|
|
extpdf_updates_url=updates_url.get("extpdf", ""),
|
|
extweb_updates_url=updates_url.get("extweb", ""),
|
|
)
|
|
monkeypatch.setattr("aqt.archives.getUrl", mock_get_url)
|
|
monkeypatch.setattr("aqt.helper.getUrl", mock_get_url)
|
|
monkeypatch.setattr("aqt.installer.downloadBinaryFile", mock_download_archive)
|
|
monkeypatch.setattr(
|
|
"aqt.metadata.MetadataFactory.fetch_arches",
|
|
lambda *args: [{"windows": "win64_mingw1234", "linux": "gcc_64", "mac": "clang_64"}[host]],
|
|
)
|
|
|
|
with TemporaryDirectory() as output_dir:
|
|
cli = Cli()
|
|
cli._setup_settings()
|
|
|
|
assert 0 == cli.run(cmd + ["--outputdir", output_dir])
|
|
|
|
out, err = capsys.readouterr()
|
|
sys.stdout.write(out)
|
|
sys.stderr.write(err)
|
|
|
|
assert expect_out.match(err)
|
|
|
|
for key in arch_dir.keys():
|
|
installed_path = Path(output_dir) / version / arch_dir[key]
|
|
if version == "5.9.0":
|
|
installed_path = Path(output_dir) / "5.9" / arch_dir[key]
|
|
assert installed_path.is_dir()
|
|
for archive in archives[key]:
|
|
if not archive.should_install:
|
|
continue
|
|
for patched_file in archive.contents:
|
|
file_path = installed_path / patched_file.filename
|
|
assert file_path.is_file()
|
|
if file_path.name == "qmake":
|
|
assert os.access(file_path, os.X_OK), "qmake file must be executable"
|
|
|
|
expect_content = patched_file.expected_content(base_dir=output_dir, sep=os.sep)
|
|
actual_content = file_path.read_text(encoding="utf_8")
|
|
assert actual_content == expect_content
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"version, str_version, wasm_arch",
|
|
[
|
|
("6.8.0", "680", "wasm_singlethread"),
|
|
],
|
|
)
|
|
def test_install_qt6_wasm_autodesktop(monkeypatch, capsys, version, str_version, wasm_arch):
|
|
"""Test installing Qt 6.8 WASM with autodesktop, which requires special handling for addons"""
|
|
|
|
# WASM archives
|
|
wasm_archives = [
|
|
# WASM base package
|
|
MockArchive(
|
|
filename_7z=f"qtbase-{wasm_arch}.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.{wasm_arch}", # Base doesn't have addons
|
|
version=version,
|
|
arch_dir=wasm_arch,
|
|
contents=(),
|
|
),
|
|
# WASM modules - add 'addons' to match XML structure
|
|
MockArchive(
|
|
filename_7z="qtcharts-Windows-Windows_10_22H2-Clang-Windows-WebAssembly-X86_64.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.addons.qtcharts.{wasm_arch}",
|
|
version=version,
|
|
arch_dir=wasm_arch,
|
|
contents=(),
|
|
),
|
|
MockArchive(
|
|
filename_7z="qtquick3d-Windows-Windows_10_22H2-Clang-Windows-WebAssembly-X86_64.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.addons.qtquick3d.{wasm_arch}",
|
|
version=version,
|
|
arch_dir=wasm_arch,
|
|
contents=(),
|
|
),
|
|
]
|
|
|
|
# Desktop archives for each possible host OS
|
|
desk_archives_by_host = {
|
|
"linux": (
|
|
[
|
|
plain_qtbase_archive(f"qt.qt6.{str_version}.linux_gcc_64", "linux_gcc_64", host="linux"),
|
|
MockArchive(
|
|
filename_7z="qtcharts-linux-gcc_64.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.qtcharts.gcc_64",
|
|
version=version,
|
|
arch_dir="gcc_64",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="modules/Charts.json",
|
|
unpatched_content='{"module_name": "Charts"}',
|
|
patched_content=None,
|
|
),
|
|
),
|
|
),
|
|
MockArchive(
|
|
filename_7z="qtquick3d-linux-gcc_64.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.qtquick3d.gcc_64",
|
|
version=version,
|
|
arch_dir="gcc_64",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="modules/Quick3D.json",
|
|
unpatched_content='{"module_name": "Quick3D"}',
|
|
patched_content=None,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
"linux_x64",
|
|
"gcc_64",
|
|
),
|
|
"darwin": (
|
|
[
|
|
plain_qtbase_archive(f"qt.qt6.{str_version}.clang_64", "clang_64", host="mac"),
|
|
MockArchive(
|
|
filename_7z="qtcharts-mac-clang_64.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.qtcharts.clang_64",
|
|
version=version,
|
|
arch_dir="clang_64",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="modules/Charts.json",
|
|
unpatched_content='{"module_name": "Charts"}',
|
|
patched_content=None,
|
|
),
|
|
),
|
|
),
|
|
MockArchive(
|
|
filename_7z="qtquick3d-mac-clang_64.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.qtquick3d.clang_64",
|
|
version=version,
|
|
arch_dir="clang_64",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="modules/Quick3D.json",
|
|
unpatched_content='{"module_name": "Quick3D"}',
|
|
patched_content=None,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
"mac_x64",
|
|
"clang_64",
|
|
),
|
|
"win32": (
|
|
[
|
|
plain_qtbase_archive(f"qt.qt6.{str_version}.win64_mingw", "win64_mingw", host="windows"),
|
|
MockArchive(
|
|
filename_7z="qtcharts-windows-win64_mingw.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.qtcharts.win64_mingw",
|
|
version=version,
|
|
arch_dir="mingw_64",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="modules/Charts.json",
|
|
unpatched_content='{"module_name": "Charts"}',
|
|
patched_content=None,
|
|
),
|
|
),
|
|
),
|
|
MockArchive(
|
|
filename_7z="qtquick3d-windows-win64_mingw.7z",
|
|
update_xml_name=f"qt.qt6.{str_version}.qtquick3d.win64_mingw",
|
|
version=version,
|
|
arch_dir="mingw_64",
|
|
contents=(
|
|
PatchedFile(
|
|
filename="modules/Quick3D.json",
|
|
unpatched_content='{"module_name": "Quick3D"}',
|
|
patched_content=None,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
"windows_x86",
|
|
"mingw_64",
|
|
),
|
|
}
|
|
|
|
if sys.platform.startswith("linux"):
|
|
desktop_archives, platform_dir, desk_arch = desk_archives_by_host["linux"]
|
|
elif sys.platform == "darwin":
|
|
desktop_archives, platform_dir, desk_arch = desk_archives_by_host["darwin"]
|
|
else:
|
|
desktop_archives, platform_dir, desk_arch = desk_archives_by_host["win32"]
|
|
|
|
def mock_get_url(url: str, *args, **kwargs) -> str:
|
|
wasm_base = f"all_os/wasm/qt6_{str_version}/qt6_{str_version}_{wasm_arch}"
|
|
desktop_base = f"{platform_dir}/desktop/qt6_{str_version}/qt6_{str_version}"
|
|
|
|
if url.endswith(".sha256"):
|
|
base = url[:-7] # Remove .sha256
|
|
if any(base.endswith(path) for path in [f"{wasm_base}/Updates.xml", f"{desktop_base}/Updates.xml"]):
|
|
# For main Updates.xml files, read the appropriate file and generate its hash
|
|
if "wasm" in base:
|
|
xml = (Path(__file__).parent / "data" / "all_os-680-wasm-single-update.xml").read_text()
|
|
else:
|
|
if platform_dir == "linux_x64":
|
|
xml = (Path(__file__).parent / "data" / "linux-680-desktop-update.xml").read_text()
|
|
else:
|
|
xml = (Path(__file__).parent / "data" / "windows-680-desktop-update.xml").read_text()
|
|
return f"{hashlib.sha256(bytes(xml, 'utf-8')).hexdigest()} Updates.xml"
|
|
return f"{hashlib.sha256(b'mock').hexdigest()} {url.split('/')[-1][:-7]}"
|
|
|
|
# Handle extension URLs for Qt 6.8
|
|
if "/extensions/" in url:
|
|
if url.endswith("Updates.xml"):
|
|
return "<Updates></Updates>"
|
|
if url.endswith(".sha256"):
|
|
return f"{hashlib.sha256(b'mock').hexdigest()} Updates.xml"
|
|
|
|
# Handle main Updates.xml files
|
|
if url.endswith(f"{wasm_base}/Updates.xml"):
|
|
return (Path(__file__).parent / "data" / "all_os-680-wasm-single-update.xml").read_text()
|
|
elif url.endswith(f"{desktop_base}/Updates.xml"):
|
|
if platform_dir == "linux_x64":
|
|
return (Path(__file__).parent / "data" / "linux-680-desktop-update.xml").read_text()
|
|
else:
|
|
return (Path(__file__).parent / "data" / "windows-680-desktop-update.xml").read_text()
|
|
|
|
assert False, f"No mocked url available for '{url}'"
|
|
|
|
def mock_download_archive(url: str, out: Path, *args, **kwargs):
|
|
try:
|
|
# Try to match against our known archives first
|
|
for archives in (wasm_archives, desktop_archives):
|
|
for archive in archives:
|
|
if Path(out).name == archive.filename_7z:
|
|
archive.write_compressed_archive(Path(out).parent)
|
|
return
|
|
|
|
# For unknown archives, create basic structure
|
|
with py7zr.SevenZipFile(out, "w") as archive:
|
|
# Determine if this is a desktop archive and get the appropriate arch
|
|
arch_dir = wasm_arch
|
|
for desk_indicator in ["gcc_64", "clang_64", "mingw"]:
|
|
if desk_indicator in url:
|
|
if "linux" in url.lower():
|
|
arch_dir = "gcc_64"
|
|
elif "mac" in url.lower():
|
|
arch_dir = "clang_64"
|
|
else:
|
|
arch_dir = "mingw_64"
|
|
break
|
|
|
|
# Set the appropriate path prefix
|
|
prefix = f"6.8.0/{arch_dir}"
|
|
|
|
basic_files = {
|
|
f"{prefix}/mkspecs/qconfig.pri": "QT_EDITION = OpenSource\nQT_LICHECK =\n",
|
|
f"{prefix}/bin/target_qt.conf": "Prefix=...\n", # Basic config
|
|
f"{prefix}/bin/qmake": '#!/bin/sh\necho "Mock qmake"\n',
|
|
f"{prefix}/bin/qmake6": '#!/bin/sh\necho "Mock qmake6"\n',
|
|
f"{prefix}/bin/qtpaths": '#!/bin/sh\necho "Mock qtpaths"\n',
|
|
f"{prefix}/bin/qtpaths6": '#!/bin/sh\necho "Mock qtpaths6"\n',
|
|
f"{prefix}/lib/dummy": "", # Empty file in lib
|
|
}
|
|
for filepath, content in basic_files.items():
|
|
archive.writestr(content.encode("utf-8"), filepath)
|
|
|
|
except Exception as e:
|
|
sys.stderr.write(f"Warning: Error in mock_download_archive: {e}\n")
|
|
# Even in case of error, create minimal structure
|
|
with py7zr.SevenZipFile(out, "w") as archive:
|
|
# Determine if this is a desktop archive
|
|
if any(desk_indicator in url for desk_indicator in ["gcc_64", "clang_64", "mingw"]):
|
|
if "linux" in url.lower():
|
|
prefix = "6.8.0/gcc_64"
|
|
elif "mac" in url.lower():
|
|
prefix = "6.8.0/clang_64"
|
|
else:
|
|
prefix = "6.8.0/mingw_64"
|
|
else:
|
|
prefix = f"6.8.0/{wasm_arch}"
|
|
|
|
archive.writestr(b"QT_EDITION = OpenSource\nQT_LICHECK =\n", f"{prefix}/mkspecs/qconfig.pri")
|
|
archive.writestr(b'#!/bin/sh\necho "Mock qmake6"\n', f"{prefix}/bin/qmake6")
|
|
archive.writestr(b'#!/bin/sh\necho "Mock qmake"\n', f"{prefix}/bin/qmake")
|
|
archive.writestr(b'#!/bin/sh\necho "Mock qtpaths6"\n', f"{prefix}/bin/qtpaths6")
|
|
archive.writestr(b'#!/bin/sh\necho "Mock qtpaths"\n', f"{prefix}/bin/qtpaths")
|
|
archive.writestr(b"Prefix=...\n", f"{prefix}/bin/target_qt.conf")
|
|
return
|
|
|
|
# Setup mocks
|
|
monkeypatch.setattr("aqt.archives.getUrl", mock_get_url)
|
|
monkeypatch.setattr("aqt.helper.getUrl", mock_get_url)
|
|
monkeypatch.setattr("aqt.installer.downloadBinaryFile", mock_download_archive)
|
|
|
|
# Run the installation
|
|
with TemporaryDirectory() as output_dir:
|
|
cli = Cli()
|
|
cli._setup_settings()
|
|
|
|
result = cli.run(
|
|
[
|
|
"install-qt",
|
|
"all_os",
|
|
"wasm",
|
|
version,
|
|
wasm_arch,
|
|
"-m",
|
|
"qtcharts",
|
|
"qtquick3d",
|
|
"--autodesktop",
|
|
"--outputdir",
|
|
output_dir,
|
|
]
|
|
)
|
|
|
|
assert result == 0
|
|
|
|
# Check output format
|
|
out, err = capsys.readouterr()
|
|
sys.stdout.write(out)
|
|
sys.stderr.write(err)
|
|
|
|
# Use regex that works for all platforms
|
|
expected_pattern = re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.*? on Python 3.*?\n"
|
|
r"INFO : You are installing the Qt6-WASM version of Qt\n"
|
|
r"(?:INFO : Found extension .*?\n)*"
|
|
r"(?:INFO : Downloading (?:qt[^\n]*|icu[^\n]*)\n"
|
|
r"Finished installation of .*?\.7z in \d+\.\d+\n)*"
|
|
r"(?:INFO : Patching (?:/tmp/[^/]+|[A-Za-z]:[\\/].*?)/6\.8\.0/wasm_singlethread/bin/"
|
|
r"(?:qmake(?:6)?|qtpaths(?:6)?|target_qt\.conf)\n)*"
|
|
r"INFO : \n"
|
|
r"INFO : Autodesktop will now install linux desktop 6\.8\.0 linux_gcc_64 as required by Qt6-WASM\n"
|
|
r"INFO : aqtinstall\(aqt\) v.*? on Python 3.*?\n"
|
|
r"(?:INFO : Found extension .*?\n)*"
|
|
r"(?:INFO : Downloading (?:qt[^\n]*|icu[^\n]*)\n"
|
|
r"Finished installation of .*?\.7z in \d+\.\d+\n)*"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: \d+\.\d+ second\n$"
|
|
)
|
|
|
|
assert expected_pattern.match(err)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd, xml_file, expected",
|
|
(
|
|
(
|
|
"install-qt windows desktop 5.16.0 win32_mingw73",
|
|
None,
|
|
"ERROR : Failed to locate XML data for Qt version '5.16.0'.\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-qt windows desktop' to show versions available.\n",
|
|
),
|
|
(
|
|
"install-qt windows desktop 5.15.0 bad_arch",
|
|
"windows-5150-update.xml",
|
|
"ERROR : The packages ['qt_base'] were not found while parsing XML of package information!\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-qt windows desktop --arch 5.15.0' to show architectures available.\n",
|
|
),
|
|
(
|
|
"install-qt windows desktop 5.15.0 win32_mingw73 -m nonexistent foo",
|
|
"windows-5150-update.xml",
|
|
"ERROR : The packages ['foo', 'nonexistent', 'qt_base'] were not found"
|
|
" while parsing XML of package information!\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-qt windows desktop --arch 5.15.0' to show architectures available.\n"
|
|
"* Please use 'aqt list-qt windows desktop --modules 5.15.0 <arch>' to show modules available.\n",
|
|
),
|
|
(
|
|
"install-doc windows desktop 5.15.0 -m nonexistent foo",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
"WARNING : The parameter 'target' with value 'desktop' is deprecated"
|
|
" and marked for removal in a future "
|
|
"version of aqt.\n"
|
|
"In the future, please omit this parameter.\n"
|
|
"ERROR : The packages ['doc', 'foo', 'nonexistent'] were not found"
|
|
" while parsing XML of package information!\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-doc windows 5.15.0 --modules' to show modules available.\n",
|
|
),
|
|
(
|
|
"install-doc windows 5.15.0 -m nonexistent foo",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
"ERROR : The packages ['doc', 'foo', 'nonexistent'] were not found"
|
|
" while parsing XML of package information!\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-doc windows 5.15.0 --modules' to show modules available.\n",
|
|
),
|
|
(
|
|
"install-example windows 5.15.0 -m nonexistent foo",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
"ERROR : The packages ['examples', 'foo', 'nonexistent'] were not found"
|
|
" while parsing XML of package information!\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-example windows 5.15.0 --modules' to show modules available.\n",
|
|
),
|
|
(
|
|
"install-tool windows desktop tools_vcredist nonexistent",
|
|
"windows-desktop-tools_vcredist-update.xml",
|
|
"ERROR : The package 'nonexistent' was not found while parsing XML of package information!\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-tool windows desktop tools_vcredist' to show tool variants available.\n",
|
|
),
|
|
(
|
|
"install-tool windows desktop tools_nonexistent nonexistent",
|
|
None,
|
|
"ERROR : Failed to locate XML data for the tool 'tools_nonexistent'.\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-tool windows desktop' to show tools available.\n",
|
|
),
|
|
(
|
|
"install-tool windows desktop tools_nonexistent",
|
|
None,
|
|
"ERROR : Failed to locate XML data for the tool 'tools_nonexistent'.\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-tool windows desktop' to check what tools are available.\n",
|
|
),
|
|
),
|
|
)
|
|
def test_install_nonexistent_archives(monkeypatch, capsys, cmd, xml_file: Optional[str], expected):
|
|
xml = (Path(__file__).parent / "data" / xml_file).read_text("utf-8") if xml_file else ""
|
|
|
|
def mock_get_url(url, *args, **kwargs):
|
|
if not xml_file:
|
|
raise ArchiveDownloadError(f"Failed to retrieve file at {url}\nServer response code: 404, reason: Not Found")
|
|
return xml
|
|
|
|
monkeypatch.setattr("aqt.archives.getUrl", mock_get_url)
|
|
monkeypatch.setattr(
|
|
"aqt.archives.get_hash",
|
|
lambda *args, **kwargs: hashlib.sha256(bytes(xml, "utf-8")).hexdigest(),
|
|
)
|
|
monkeypatch.setattr(
|
|
"aqt.metadata.get_hash",
|
|
lambda *args, **kwargs: hashlib.sha256(bytes(xml, "utf-8")).hexdigest(),
|
|
)
|
|
monkeypatch.setattr("aqt.metadata.getUrl", mock_get_url)
|
|
|
|
cli = Cli()
|
|
cli._setup_settings()
|
|
assert cli.run(cmd.split()) == 1
|
|
|
|
out, err = capsys.readouterr()
|
|
actual = err[err.index("\n") + 1 :]
|
|
assert actual == expected, "{0} != {1}".format(actual, expected)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"exception, settings_file, expect_end_msg, expect_return",
|
|
(
|
|
(
|
|
RuntimeError(),
|
|
"../aqt/settings.ini",
|
|
"===========================PLEASE FILE A BUG REPORT===========================\n"
|
|
"You have discovered a bug in aqt.\n"
|
|
"Please file a bug report at https://github.com/miurahr/aqtinstall/issues\n"
|
|
"Please remember to include a copy of this program's output in your report.",
|
|
Cli.UNHANDLED_EXCEPTION_CODE,
|
|
),
|
|
(
|
|
KeyboardInterrupt(),
|
|
"../aqt/settings.ini",
|
|
"WARNING : Caught KeyboardInterrupt, terminating installer workers\n"
|
|
"ERROR : Installer halted by keyboard interrupt.",
|
|
1,
|
|
),
|
|
(
|
|
MemoryError(),
|
|
"../aqt/settings.ini",
|
|
"WARNING : Caught MemoryError, terminating installer workers\n"
|
|
"ERROR : Out of memory when downloading and extracting archives in parallel.\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please reduce your 'concurrency' setting (see "
|
|
"https://aqtinstall.readthedocs.io/en/stable/configuration.html#configuration)\n"
|
|
"* Please try using the '--external' flag to specify an alternate 7z extraction tool "
|
|
"(see https://aqtinstall.readthedocs.io/en/latest/cli.html#cmdoption-list-tool-external)",
|
|
1,
|
|
),
|
|
(
|
|
MemoryError(),
|
|
"data/settings_no_concurrency.ini",
|
|
"WARNING : Caught MemoryError, terminating installer workers\n"
|
|
"ERROR : Out of memory when downloading and extracting archives.\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please free up more memory.\n"
|
|
"* Please try using the '--external' flag to specify an alternate 7z extraction tool "
|
|
"(see https://aqtinstall.readthedocs.io/en/latest/cli.html#cmdoption-list-tool-external)",
|
|
1,
|
|
),
|
|
(
|
|
OSError(errno.ENOSPC, "No space left on device"),
|
|
"../aqt/settings.ini",
|
|
"WARNING : Caught OSError, terminating installer workers\n"
|
|
"ERROR : Insufficient disk space to complete installation.\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Check available disk space.\n"
|
|
"* Check size requirements for installation.",
|
|
1,
|
|
),
|
|
(
|
|
OSError(),
|
|
"../aqt/settings.ini",
|
|
"===========================PLEASE FILE A BUG REPORT===========================\n"
|
|
"You have discovered a bug in aqt.\n"
|
|
"Please file a bug report at https://github.com/miurahr/aqtinstall/issues\n"
|
|
"Please remember to include a copy of this program's output in your report.",
|
|
Cli.UNHANDLED_EXCEPTION_CODE,
|
|
),
|
|
(
|
|
PermissionError(),
|
|
"../aqt/settings.ini",
|
|
"WARNING : Caught PermissionError, terminating installer workers\n"
|
|
f"ERROR : Failed to write to base directory at {os.getcwd()}\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Check that the destination is writable and does not already contain files owned by another user.",
|
|
1,
|
|
),
|
|
),
|
|
)
|
|
def test_install_pool_exception(monkeypatch, capsys, exception, settings_file, expect_end_msg, expect_return):
|
|
def mock_installer_func(*args):
|
|
raise exception
|
|
|
|
host, target, ver, arch = "windows", "desktop", "6.1.0", "win64_mingw81"
|
|
updates_url = "windows_x86/desktop/qt6_610/Updates.xml"
|
|
archives = [plain_qtbase_archive("qt.qt6.610.win64_mingw81", "win64_mingw81")]
|
|
|
|
cmd = ["install-qt", host, target, ver, arch]
|
|
mock_get_url, mock_download_archive = make_mock_geturl_download_archive(
|
|
standard_archives=archives, standard_updates_url=updates_url
|
|
)
|
|
monkeypatch.setattr("aqt.archives.getUrl", mock_get_url)
|
|
monkeypatch.setattr("aqt.helper.getUrl", mock_get_url)
|
|
monkeypatch.setattr("aqt.installer.installer", mock_installer_func)
|
|
|
|
Settings.load_settings(str(Path(__file__).parent / settings_file))
|
|
cli = Cli()
|
|
assert expect_return == cli.run(cmd)
|
|
out, err = capsys.readouterr()
|
|
assert err.rstrip().endswith(expect_end_msg)
|
|
|
|
|
|
def test_install_installer_archive_extraction_err(monkeypatch):
|
|
def mock_extractor_that_fails(*args, **kwargs):
|
|
raise subprocess.CalledProcessError(returncode=1, cmd="some command", output="out", stderr="err")
|
|
|
|
monkeypatch.setattr("aqt.installer.get_hash", lambda *args, **kwargs: "")
|
|
monkeypatch.setattr("aqt.installer.downloadBinaryFile", lambda *args: None)
|
|
monkeypatch.setattr("aqt.installer.subprocess.run", mock_extractor_that_fails)
|
|
|
|
with pytest.raises(ArchiveExtractionError) as err, TemporaryDirectory() as temp_dir:
|
|
with open(Path(temp_dir) / "archive", "w"):
|
|
pass
|
|
installer(
|
|
qt_package=QtPackage(
|
|
"name",
|
|
"base_url",
|
|
"archive_path",
|
|
"archive",
|
|
"archive_install_path",
|
|
"package_desc",
|
|
"pkg_update_name",
|
|
),
|
|
base_dir=temp_dir,
|
|
command="some_nonexistent_7z_extractor",
|
|
queue=MockMultiprocessingManager.Queue(),
|
|
archive_dest=Path(temp_dir),
|
|
settings_ini=Settings.configfile,
|
|
keep=False,
|
|
)
|
|
assert err.type == ArchiveExtractionError
|
|
err_msg = format(err.value).rstrip()
|
|
assert err_msg == "Extraction error: 1\nout\nerr"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd, host, target, version, arch, arch_dir, base_url, updates_url, archives, expect_out",
|
|
(
|
|
(
|
|
"install-tool linux desktop tools_qtcreator qt.tools.qtcreator".split(),
|
|
"linux",
|
|
"desktop",
|
|
"1.2.3-0-197001020304",
|
|
"",
|
|
"",
|
|
"https://www.alt.qt.mirror.com",
|
|
"linux_x64/desktop/tools_qtcreator/Updates.xml",
|
|
[tool_archive("linux", "tools_qtcreator", "qt.tools.qtcreator")],
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Downloading qt.tools.qtcreator...\n"
|
|
r"Finished installation of tools_qtcreator-linux-qt.tools.qtcreator.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt windows desktop 5.12 win32_mingw73".split(),
|
|
"windows",
|
|
"desktop",
|
|
"5.12.10",
|
|
"win32_mingw73",
|
|
"mingw73_32",
|
|
"https://www.alt.qt.mirror.com",
|
|
"windows_x86/desktop/qt5_51210/Updates.xml",
|
|
[plain_qtbase_archive("qt.qt5.51210.win32_mingw73", "win32_mingw73")],
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Resolved spec '5\.12' to 5\.12\.10\n"
|
|
r"INFO : Downloading qtbase\.\.\.\n"
|
|
r"Finished installation of qtbase-windows-win32_mingw73\.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
(
|
|
"install-qt linux_arm64 desktop 6.7 linux_gcc_arm64".split(),
|
|
"linux_arm64",
|
|
"desktop",
|
|
"6.7.0",
|
|
"linux_gcc_arm64",
|
|
"gcc_arm64",
|
|
"https://www.alt.qt.mirror.com",
|
|
"linux_arm64/desktop/qt6_670/Updates.xml",
|
|
[plain_qtbase_archive("qt.qt6.670.linux_gcc_arm64", "linux_gcc_arm64", host="linux_arm64")],
|
|
re.compile(
|
|
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
|
r"INFO : Resolved spec '6\.7' to 6\.7\.0\n"
|
|
r"INFO : Downloading qtbase\.\.\.\n"
|
|
r"Finished installation of qtbase-linux_arm64-linux_gcc_arm64\.7z in .*\n"
|
|
r"INFO : Finished installation\n"
|
|
r"INFO : Time elapsed: .* second"
|
|
),
|
|
),
|
|
),
|
|
)
|
|
def test_installer_passes_base_to_metadatafactory(
|
|
monkeypatch,
|
|
capsys,
|
|
cmd: List[str],
|
|
host: str,
|
|
target: str,
|
|
version: str,
|
|
arch: str,
|
|
arch_dir: str,
|
|
base_url: str,
|
|
updates_url: str,
|
|
archives: List[MockArchive],
|
|
expect_out, # type: re.Pattern
|
|
):
|
|
# For convenience, fill in version and arch dir: prevents repetitive data declarations
|
|
for i in range(len(archives)):
|
|
archives[i].version = version
|
|
archives[i].arch_dir = arch_dir
|
|
|
|
basic_mock_get_url, mock_download_archive = make_mock_geturl_download_archive(
|
|
standard_archives=archives, standard_updates_url=updates_url
|
|
)
|
|
|
|
def mock_get_url(url: str, *args, **kwargs) -> str:
|
|
# If we are fetching an index.html file, get it from tests/data/
|
|
if host == "linux_arm64":
|
|
repo_dir = "linux_arm64"
|
|
elif host == "windows":
|
|
repo_dir = "windows_x86"
|
|
else:
|
|
repo_dir = f"{host}_x64"
|
|
if url == f"{base_url}/online/qtsdkrepository/{repo_dir}/{target}/":
|
|
return (Path(__file__).parent / "data" / f"{host}-{target}.html").read_text("utf-8")
|
|
|
|
# Intercept and check the base url, but only if it's not a hash.
|
|
# Hashes must come from trusted mirrors only.
|
|
if not url.endswith(".sha256"):
|
|
assert url.startswith(base_url)
|
|
|
|
return basic_mock_get_url(url, *args, **kwargs)
|
|
|
|
monkeypatch.setattr("aqt.archives.getUrl", mock_get_url)
|
|
monkeypatch.setattr("aqt.helper.getUrl", mock_get_url)
|
|
monkeypatch.setattr("aqt.installer.downloadBinaryFile", mock_download_archive)
|
|
|
|
monkeypatch.setattr("aqt.metadata.getUrl", mock_get_url)
|
|
|
|
with TemporaryDirectory() as output_dir:
|
|
cli = Cli()
|
|
cli._setup_settings()
|
|
|
|
assert 0 == cli.run(cmd + ["--base", base_url, "--outputdir", output_dir])
|
|
|
|
out, err = capsys.readouterr()
|
|
sys.stdout.write(out)
|
|
sys.stderr.write(err)
|
|
|
|
assert expect_out.match(err), err
|