mirror of
https://github.com/miurahr/aqtinstall.git
synced 2025-12-18 05:04:38 +03:00
Fix WASM (#846)
* Rewrite WASM support * Add WASM tests to CI, update CI to test more the latest versions, add auto EMSDK version detection function * Fix some mistakes, typos, moved emsdk version function into BuildJob * Fix issue related to extensions interfering with wasm on 6.8+ * Fix tests * Remove dep on Version in CI * Remove safety before patch * handle cases where extensions don't exist. for example with windows desktop 6.8.1 win64_msvc2022_arm64_cross_compiled both qtwebengine and qtpdf don't exist. Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * for --long-modules assume extension doesn't exist on download error. Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * for --modules assume extension doesn't exist for download failures. Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * reformat with black Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * fix flake8 regression that doesn't occur locally. Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * Fix autodesktop by also updating the OS when searching for a valid desktop version to download * Fix extension issue, reduce the possible retry for getting extensions to prevent server spam * Fix CI asking for msvc2019 on 6.8+ but its no longer supported * Make CI use C++20 and MSVC2022 * Fix linux build * Update runners to windows-2022 Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * Fix patching Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * Add back the semantic version changes to prevent crashes, add tests for it * Update checks * Cast 'https://mirrors.ustc.edu.cn' to the shadow realm * Again * Update settings.ini * Update settings.ini * Update settings.ini * Remove one_rep on silent * Update settings.ini * Restore master settings, remove hash check * ci: Use specific mirror Attempt to work around download errors in Azure due to Qt's official download site often redirecting to mirrors to which the network connection is unstable Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * Re enable hash checking * Treat read timeout error during download as connection error Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> * Add test for modules in WASM with autodesktop * Fix format * Fix test * Make '--autodesktop' trigger its own install process, and test it * Fix older autodesktop tests * Add mock update files for 680 wasm, add test for wasm 680 autodesktop * Passes the additional tests * Fix format * Improve coverage, fix format * Fix tests and improve logging or install * Fix format * Fix regression in other tests * Use flavor * Fix line len * Fix codeql * Fix list-qt for WASM arch on 6.5.x and 6.6.x, restore to original download URL * Fix test error * Revert ci settings URL as it is never used by clients, only in CI * Add comment for clarity in ci/settings.ini --------- Signed-off-by: Alexandre 'Kidev' Poumaroux <1204936+Kidev@users.noreply.github.com> Co-authored-by: tsteven4 <13596209+tsteven4@users.noreply.github.com> Co-authored-by: J.D. Purcell <jdpurcell@gmail.com>
This commit is contained in:
committed by
GitHub
parent
673b1695db
commit
a09b5cee28
@@ -152,15 +152,19 @@ class MockArchive:
|
||||
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)
|
||||
|
||||
# Use `self.contents` to write qmake binary, qmake script, QtCore binaries, etc
|
||||
# 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 = "."
|
||||
@@ -192,22 +196,54 @@ def make_mock_geturl_download_archive(
|
||||
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([archive.xml_package_update() for archive in standard_archives])
|
||||
"\n".join([_generate_package_update_xml(archive) for archive in standard_archives])
|
||||
)
|
||||
desktop_xml = "<Updates>\n{}\n</Updates>".format(
|
||||
"\n".join([archive.xml_package_update() for archive in desktop_archives])
|
||||
"\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([archive.xml_package_update() for archive in standard_archives]),
|
||||
"\n".join([archive.xml_package_update() for archive in desktop_archives]),
|
||||
"\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):
|
||||
# Edge case where both standard and desktop come from the same Updates.xml: ie msvc2019_arm64 and msvc2019_64
|
||||
return merged_xml
|
||||
for xml, updates_url in (
|
||||
(standard_xml, standard_updates_url),
|
||||
@@ -223,11 +259,21 @@ def make_mock_geturl_download_archive(
|
||||
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):
|
||||
@@ -261,11 +307,18 @@ def disable_multiprocessing(monkeypatch):
|
||||
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-windows-{arch}.7z",
|
||||
filename_7z=f"qtcharts-{os_name}-{arch}.7z", # Use os_name lookup
|
||||
update_xml_name=f"{prefix}.{ver.replace('.', '')}.{addons}qtcharts.{arch}",
|
||||
version=ver,
|
||||
# arch_dir: filled in later
|
||||
contents=(
|
||||
PatchedFile(
|
||||
filename="modules/Charts.json",
|
||||
@@ -279,7 +332,7 @@ def qtcharts_module(ver: str, arch: str) -> MockArchive:
|
||||
"compiler_target": "",
|
||||
"compiler_version": "1.2.3.4",
|
||||
"cross_compiled": false,
|
||||
"target_system": "Windows"
|
||||
"target_system": "{os_name.title()}"
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
@@ -293,11 +346,17 @@ def qtcharts_module(ver: str, arch: str) -> MockArchive:
|
||||
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-windows-{arch}.7z",
|
||||
filename_7z=f"qtlocation-{os_name}-{arch}.7z", # Use os_name lookup
|
||||
update_xml_name=f"{prefix}.{ver.replace('.', '')}.{addons}qtpositioning.{arch}",
|
||||
version=ver,
|
||||
# arch_dir: filled in later
|
||||
contents=(
|
||||
PatchedFile(
|
||||
filename="modules/Positioning.json",
|
||||
@@ -311,7 +370,7 @@ def qtpositioning_module(ver: str, arch: str) -> MockArchive:
|
||||
"compiler_target": "",
|
||||
"compiler_version": "1.2.3.4",
|
||||
"cross_compiled": false,
|
||||
"target_system": "Windows"
|
||||
"target_system": "{os_name.title()}"
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
@@ -722,6 +781,7 @@ def tool_archive(host: str, tool_name: str, variant: str, date: datetime = datet
|
||||
r"INFO : Time elapsed: .* second"
|
||||
),
|
||||
),
|
||||
# --autodesktop test edited
|
||||
(
|
||||
"install-qt windows desktop 6.5.2 win64_msvc2019_arm64 --autodesktop".split(),
|
||||
"windows",
|
||||
@@ -729,7 +789,10 @@ def tool_archive(host: str, tool_name: str, variant: str, date: datetime = datet
|
||||
"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": "windows_x86/desktop/qt6_652/Updates.xml",
|
||||
"desk": "windows_x86/desktop/qt6_652/Updates.xml",
|
||||
},
|
||||
{
|
||||
"std": [
|
||||
MockArchive(
|
||||
@@ -800,18 +863,16 @@ def tool_archive(host: str, tool_name: str, variant: str, date: datetime = datet
|
||||
},
|
||||
re.compile(
|
||||
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
||||
r"INFO : You are installing the MSVC Arm64 version of Qt, which requires that the desktop version of "
|
||||
r"Qt is also installed. Now installing Qt: desktop 6.5.2 win64_msvc2019_64\n"
|
||||
r"INFO : You are installing the MSVC Arm64 version of Qt\n"
|
||||
r"INFO : Downloading qtbase...\n"
|
||||
r"Finished installation of qtbase-windows-win64_msvc2019_arm64.7z in .*\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"Finished installation of qtbase-windows-win64_msvc2019_64.7z in .*\n"
|
||||
r"INFO : Patching .*6\.5\.2[/\\]msvc2019_arm64[/\\]bin[/\\]qmake.bat\n"
|
||||
r"INFO : Patching .*6\.5\.2[/\\]msvc2019_arm64[/\\]bin[/\\]qtpaths.bat\n"
|
||||
r"INFO : Patching .*6\.5\.2[/\\]msvc2019_arm64[/\\]bin[/\\]qmake6.bat\n"
|
||||
r"INFO : Patching .*6\.5\.2[/\\]msvc2019_arm64[/\\]bin[/\\]qtpaths6.bat\n"
|
||||
r"INFO : Finished installation\n"
|
||||
r"INFO : Time elapsed: .* second"
|
||||
r"(?:.*\n)*$"
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -1031,6 +1092,7 @@ def tool_archive(host: str, tool_name: str, variant: str, date: datetime = datet
|
||||
r"INFO : Time elapsed: .* second"
|
||||
),
|
||||
),
|
||||
# --autodesktop test edited
|
||||
(
|
||||
"install-qt mac ios 6.1.2 --autodesktop".split(),
|
||||
"mac",
|
||||
@@ -1038,14 +1100,16 @@ def tool_archive(host: str, tool_name: str, variant: str, date: datetime = datet
|
||||
"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": "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=(
|
||||
# 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"
|
||||
@@ -1082,15 +1146,15 @@ def tool_archive(host: str, tool_name: str, variant: str, date: datetime = datet
|
||||
},
|
||||
re.compile(
|
||||
r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n"
|
||||
r"INFO : You are installing the ios version of Qt, which requires that the desktop version of "
|
||||
r"Qt is also installed. Now installing Qt: desktop 6\.1\.2 clang_64\n"
|
||||
r"INFO : You are installing the ios version of Qt\n"
|
||||
r"INFO : Downloading qtbase...\n"
|
||||
r"Finished installation of qtbase-mac-ios.7z in .*\n"
|
||||
r"(?:.*\n)*?"
|
||||
r"INFO : Patching .*?[/\\]6\.1\.2[/\\]ios[/\\]bin[/\\]qmake\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"Finished installation of qtbase-mac-clang_64.7z in .*\n"
|
||||
r"INFO : Patching .*6\.1\.2[/\\]ios[/\\]bin[/\\]qmake\n"
|
||||
r"INFO : Finished installation\n"
|
||||
r"INFO : Time elapsed: .* second"
|
||||
r"(?:.*\n)*$"
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -1341,6 +1405,303 @@ def test_install(
|
||||
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/(?:qmake|qtpaths)(?:6)?\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",
|
||||
(
|
||||
@@ -1427,8 +1788,14 @@ def test_install_nonexistent_archives(monkeypatch, capsys, cmd, xml_file: Option
|
||||
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.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()
|
||||
|
||||
Reference in New Issue
Block a user