Beispiel #1
0
 def __init__(
     self,
     os_name: str,
     target: str,
     version_str: str,
     arch: str,
     base: str,
     subarchives: Optional[Iterable[str]] = None,
     modules: Optional[Iterable[str]] = None,
     all_extra: bool = False,
     is_include_base_package: bool = True,
     timeout=(5, 5),
 ):
     self.version: Version = Version(version_str)
     self.target: str = target
     self.arch: str = arch
     self.os_name: str = os_name
     self.all_extra: bool = all_extra
     self.arch_list: List[str] = [item.get("arch") for item in Settings.qt_combinations]
     self.base: str = posixpath.join(base, "online/qtsdkrepository")
     self.logger = getLogger("aqt.archives")
     self.archives: List[QtPackage] = []
     self.mod_list: Iterable[str] = modules or []
     self.is_include_base_package: bool = is_include_base_package
     self.timeout = timeout
     try:
         self._get_archives()
     except ArchiveDownloadError as e:
         self.handle_missing_updates_xml(e)
     should_install_all_archives = subarchives is None
     if not should_install_all_archives:
         self.archives = list(filter(lambda a: a.name in subarchives, self.archives))
Beispiel #2
0
def test_cli_invalid_version(capsys, invalid_version):
    """Checks that invalid version strings are handled properly"""

    # Ensure that invalid_version cannot be a semantic_version.Version
    with pytest.raises(ValueError):
        Version(invalid_version)

    cli = Cli()
    cli._setup_settings()

    matcher = re.compile(r"^INFO    : aqtinstall\(aqt\) v.* on Python 3.*\n"
                         r"(.*\n)*"
                         r"ERROR   :.*Invalid version: '" + invalid_version +
                         r"'! Please use the form '5\.X\.Y'\.\n.*")

    for cmd in (
        ("install", invalid_version, "mac", "desktop"),
        ("doc", invalid_version, "mac", "desktop"),
        ("list-qt", "mac", "desktop", "--arch", invalid_version),
    ):
        cli = Cli()
        assert cli.run(cmd) == 1
        out, err = capsys.readouterr()
        sys.stdout.write(out)
        sys.stderr.write(err)
        assert matcher.match(err)
Beispiel #3
0
 def __init__(
         self,
         os_name: str,
         target: str,
         version_str: str,
         arch: str,
         base: str,
         subarchives: Optional[Iterable[str]] = None,
         modules: Optional[Iterable[str]] = None,
         all_extra: bool = False,
         is_include_base_package: bool = True,
         timeout=(5, 5),
 ):
     self.version: Version = Version(version_str)
     self.target: str = target
     self.arch: str = arch
     self.os_name: str = os_name
     self.all_extra: bool = all_extra
     self.arch_list: List[str] = [
         item.get("arch") for item in Settings.qt_combinations
     ]
     self.base: str = base
     self.logger = getLogger("aqt.archives")
     self.archives: List[QtPackage] = []
     self.subarchives: Optional[Iterable[str]] = subarchives
     self.mod_list: Iterable[str] = modules or []
     self.is_include_base_package: bool = is_include_base_package
     self.timeout = timeout
     try:
         self._get_archives()
     except ArchiveDownloadError as e:
         self.handle_missing_updates_xml(e)
Beispiel #4
0
def test_list_architectures_and_modules(monkeypatch, version: str,
                                        extension: str, in_file: str,
                                        expect_out_file: str):
    archive_id = ArchiveId("qt", "windows", "desktop", extension)
    _xml = (Path(__file__).parent / "data" / in_file).read_text("utf-8")
    expect = json.loads(
        (Path(__file__).parent / "data" / expect_out_file).read_text("utf-8"))

    monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: _xml)

    for arch in expect["architectures"]:
        modules = MetadataFactory(archive_id).fetch_modules(
            Version(version), arch)
        assert modules == sorted(expect["modules_by_arch"][arch])

    arches = MetadataFactory(archive_id).fetch_arches(Version(version))
    assert arches == expect["architectures"]
Beispiel #5
0
 def _set_arch(arch: Optional[str], os_name: str, target: str,
               qt_version_or_spec: str) -> str:
     """Choose a default architecture, if one can be determined"""
     if arch is not None and arch != "":
         return arch
     if os_name == "linux" and target == "desktop":
         return "gcc_64"
     elif os_name == "mac" and target == "desktop":
         return "clang_64"
     elif os_name == "mac" and target == "ios":
         return "ios"
     elif target == "android":
         try:
             if Version(qt_version_or_spec) >= Version("5.14.0"):
                 return "android"
         except ValueError:
             pass
     raise CliInputError("Please supply a target architecture.",
                         should_show_help=True)
Beispiel #6
0
def test_list_src_doc_examples_modules(monkeypatch, win_5152_sde_xml_file,
                                       cmd_type: str, host: str, version: str,
                                       expected: Set[str]):
    monkeypatch.setattr(MetadataFactory, "fetch_http",
                        lambda self, _: win_5152_sde_xml_file)

    archive_id = ArchiveId("qt", host, "desktop", "src_doc_examples")
    modules = set(
        MetadataFactory(archive_id).fetch_modules_sde(cmd_type,
                                                      Version(version)))
    assert modules == expected
Beispiel #7
0
def default_desktop_arch_dir(host: str, version: Union[Version, str]) -> str:
    version: Version = version if isinstance(version,
                                             Version) else Version(version)
    if host == "linux":
        return "gcc_64"
    elif host == "mac":
        return "macos" if version in SimpleSpec(">=6.1.2") else "clang_64"
    else:  # Windows
        # This is a temporary solution. This arch directory cannot exist for many versions of Qt.
        # TODO: determine this dynamically
        return "mingw81_64"
Beispiel #8
0
 def _validate_version_str(version_str: str,
                           *,
                           allow_latest: bool = False,
                           allow_empty: bool = False):
     if (allow_latest and version_str == "latest") or (allow_empty
                                                       and not version_str):
         return
     try:
         Version(version_str)
     except ValueError as e:
         raise CliInputError(
             f"Invalid version: '{version_str}'! Please use the form '5.X.Y'."
         ) from e
Beispiel #9
0
    def _determine_qt_version(qt_version_or_spec: str, host: str, target: str,
                              arch: str) -> Version:
        def choose_highest(x: Optional[Version],
                           y: Optional[Version]) -> Optional[Version]:
            if x and y:
                return max(x, y)
            return x or y

        def opt_version_for_spec(ext: str,
                                 _spec: SimpleSpec) -> Optional[Version]:
            try:
                return MetadataFactory(ArchiveId("qt", host, target, ext),
                                       spec=_spec).getList().latest()
            except AqtException:
                return None

        try:
            return Version(qt_version_or_spec)
        except ValueError:
            pass
        try:
            spec = SimpleSpec(qt_version_or_spec)
        except ValueError as e:
            raise CliInputError(
                f"Invalid version or SimpleSpec: '{qt_version_or_spec}'\n" +
                SimpleSpec.usage()) from e
        else:
            version: Optional[Version] = None
            for ext in QtRepoProperty.possible_extensions_for_arch(arch):
                version = choose_highest(version,
                                         opt_version_for_spec(ext, spec))
            if not version:
                raise CliInputError(
                    f"No versions of Qt exist for spec={spec} with host={host}, target={target}, arch={arch}"
                )
            getLogger("aqt.installer").info(
                f"Resolved spec '{qt_version_or_spec}' to {version}")
            return version
Beispiel #10
0
def test_qt_archives_modules(monkeypatch, arch, requested_module_names,
                             has_nonexistent_modules: bool):
    def _mock(self, *args):
        return (Path(__file__).parent / "data" /
                "windows-5140-update.xml").read_text("utf-8")

    monkeypatch.setattr(QtArchives, "_download_update_xml", _mock)

    expect_json = json.loads((Path(__file__).parent / "data" /
                              "windows-5140-expect.json").read_text("utf-8"))
    expected = expect_json["modules_metadata_by_arch"][arch]
    base_expected = expect_json["qt_base_pkgs_by_arch"][arch]

    os_name, target, base, version = "windows", "desktop", "https://example.com", Version(
        "5.14.0")
    qt_base = "QT-BASE"

    def locate_module_data(haystack: Iterable[Dict[str, str]],
                           name: str) -> Dict[str, str]:
        if name == qt_base:
            return base_expected
        for mod_meta in haystack:
            if mod_meta["Name"] == f"qt.qt5.5140.{name}.{arch}":
                return mod_meta
        return {}

    def verify_qt_package_stride(pkgs: Iterable[QtPackage], expect: Dict[str,
                                                                         str]):
        # https://download.qt.io/online/qtsdkrepository/windows_x86/desktop/qt5_5140/
        # qt.qt5.5140.qtcharts.win32_mingw73/5.14.0-0-202108190846qtcharts-windows-win32_mingw73.7z

        url_begin = "online/qtsdkrepository/windows_x86/desktop/qt5_5140"
        expected_archive_url_pattern = re.compile(
            r"^" + re.escape(url_begin) + "/(" + expect["Name"] + ")/" +
            re.escape(expect["Version"]) + r"(.+\.7z)$")

        expected_7z_files = set(expect["DownloadableArchives"])
        for pkg in pkgs:
            if not expect["Description"]:
                assert not pkg.package_desc
            else:
                assert pkg.package_desc == expect["Description"]
            url_match = expected_archive_url_pattern.match(pkg.archive_path)
            assert url_match
            mod_name, archive_name = url_match.groups()
            assert pkg.archive == archive_name
            assert archive_name in expected_7z_files
            expected_7z_files.remove(archive_name)
        assert len(expected_7z_files
                   ) == 0, "Actual number of packages was fewer than expected"

    if has_nonexistent_modules:
        expect_help = [
            f"Please use 'aqt list-qt {os_name} {target} --modules {version} <arch>' to show modules available."
        ]
        for unexpected_module in requested_module_names:
            with pytest.raises(NoPackageFound) as e:
                mod_names = ("qtcharts", unexpected_module)
                QtArchives(os_name,
                           target,
                           str(version),
                           arch,
                           base,
                           modules=mod_names)
            assert e.type == NoPackageFound
            assert unexpected_module in str(
                e.value), "Message should include the missing module"
            assert e.value.suggested_action == expect_help
        return

    is_all_modules = "all" in requested_module_names
    qt_pkgs = QtArchives(os_name,
                         target,
                         str(version),
                         arch,
                         base,
                         modules=requested_module_names,
                         all_extra=is_all_modules).archives

    if is_all_modules:
        requested_module_names = [
            module["Name"].split(".")[-2] for module in expected
        ]

    unvisited_modules = {*requested_module_names, qt_base}

    # This assumes that qt_pkgs are in a specific order
    for pkg_update_name, qt_packages in groupby(qt_pkgs,
                                                lambda x: x.pkg_update_name):
        match = re.match(
            r"^qt\.qt5\.5140(\.addons\.\w+|\.\w+|)\." + arch + r"$",
            pkg_update_name)
        assert match, f"QtArchive includes package named '{pkg_update_name}' with unexpected naming convention"
        mod_name = match.group(1)
        mod_name = mod_name[1:] if mod_name else qt_base
        assert mod_name in unvisited_modules
        unvisited_modules.remove(mod_name)
        expected_meta = locate_module_data(expected, mod_name)
        verify_qt_package_stride(qt_packages, expected_meta)

    assert len(unvisited_modules
               ) == 0, f"Failed to produce packages for {unvisited_modules}"
Beispiel #11
0
def dir_for_version(ver: Version) -> str:
    return "5.9" if ver == Version(
        "5.9.0") else f"{ver.major}.{ver.minor}.{ver.patch}"
Beispiel #12
0
        hash_filename = str(urlparse(url).path.split("/")[-1])
        assert hash_filename.endswith(".sha256")
        filename = hash_filename[: -len(".sha256")]
        return f"{received_hash} {filename}"

    monkeypatch.setattr("aqt.helper.getUrl", mock_getUrl)

    with pytest.raises(ChecksumDownloadFailure) as e:
        get_hash("online/qtsdkrepository/some/path/to/archive.7z", "sha256", (5, 5))
    assert e.type == ChecksumDownloadFailure


@pytest.mark.parametrize(
    "version, expect",
    [
        ("1.33.1", Version(major=1, minor=33, patch=1)),
        (
            "1.33.1-202102101246",
            Version(major=1, minor=33, patch=1, build=("202102101246",)),
        ),
        (
            "1.33-202102101246",
            Version(major=1, minor=33, patch=0, build=("202102101246",)),
        ),
        ("2020-05-19-1", Version(major=2020, minor=0, patch=0, build=("05-19-1",))),
    ],
)
def test_helper_to_version_permissive(version, expect):
    assert Version.permissive(version) == expect

Beispiel #13
0
    QtRepoProperty,
    SimpleSpec,
    ToolData,
    Version,
    Versions,
    show_list,
    suggested_follow_up,
)

Settings.load_settings()


@pytest.mark.parametrize(
    "arch, version, expect",
    (
        ("wasm_32", Version("5.13.1"), "wasm"),
        ("mingw", Version("5.13.1"), ""),
        ("android_fake", Version("5.13.1"), ""),
        ("android_x86", Version("5.13.1"), ""),
        ("android_x86", Version("6.13.1"), "x86"),
        ("android_x86", Version("6.0.0"), "x86"),
    ),
)
def test_list_extension_for_arch(arch: str, version: Version, expect: str):
    ext = QtRepoProperty.extension_for_arch(arch, version >= Version("6.0.0"))
    assert ext == expect


@pytest.mark.parametrize(
    "arch, expect",
    (
Beispiel #14
0
                                             "clang_64")


def test_cli_check_version():
    cli = Cli()
    cli._setup_settings()
    assert cli._check_qt_arg_versions("5.12.0")
    assert not cli._check_qt_arg_versions("5.12")


@pytest.mark.parametrize(
    "host, target, arch, version_or_spec, expected_version, is_bad_spec",
    (
        ("windows", "desktop", "wasm_32", "6.1", None, False),
        ("windows", "desktop", "wasm_32", "5.12", None, False),
        ("windows", "desktop", "wasm_32", "5.13", Version("5.13.2"), False),
        ("windows", "desktop", "wasm_32", "5", Version("5.15.2"), False),
        ("windows", "desktop", "wasm_32", "<5.14.5", Version("5.14.2"), False),
        ("windows", "desktop", "mingw32", "6.0", Version("6.0.3"), False),
        ("windows", "winrt", "mingw32", "6", None, False),
        ("windows", "winrt", "mingw32", "bad spec", None, True),
        ("windows", "android", "android_x86", "6", Version("6.1.0"), False),
        ("windows", "desktop", "android_x86", "6", Version("6.1.0"),
         False),  # does not validate arch
        ("windows", "desktop", "android_fake", "6", Version("6.1.0"),
         False),  # does not validate arch
    ),
)
def test_cli_determine_qt_version(monkeypatch, host, target, arch,
                                  version_or_spec: str,
                                  expected_version: Version,
Beispiel #15
0
 def version(self):
     return Version.permissive(self.full_version)
Beispiel #16
0
 def _version_str(self) -> str:
     return ("{0.major}{0.minor}" if self.version == Version("5.9.0") else "{0.major}{0.minor}{0.patch}").format(
         self.version
     )
Beispiel #17
0
 def _arch_ext(self) -> str:
     ext = QtRepoProperty.extension_for_arch(self.arch, self.version >= Version("6.0.0"))
     return ("_" + ext) if ext else ""
Beispiel #18
0
def test_list_extension_for_arch(arch: str, version: Version, expect: str):
    ext = QtRepoProperty.extension_for_arch(arch, version >= Version("6.0.0"))
    assert ext == expect
Beispiel #19
0
def test_helper_to_version_permissive(version, expect):
    assert Version.permissive(version) == expect
Beispiel #20
0
 def update(cls, target: TargetConfig, base_dir: str):
     """
     Make Qt configuration files, qt.conf and qtconfig.pri.
     And update pkgconfig and patch Qt5Core and qmake
     """
     logger = getLogger("aqt.updater")
     arch = target.arch
     version = Version(target.version)
     os_name = target.os_name
     version_dir = "5.9" if version == Version("5.9.0") else target.version
     if arch is None:
         arch_dir = ""
     elif arch.startswith("win64_mingw"):
         arch_dir = arch[6:] + "_64"
     elif arch.startswith("win32_mingw"):
         arch_dir = arch[6:] + "_32"
     elif arch.startswith("win"):
         m = re.match(r"win\d{2}_(msvc\d{4})_(winrt_x\d{2})", arch)
         if m:
             a, b = m.groups()
             arch_dir = b + "_" + a
         else:
             arch_dir = arch[6:]
     elif version in SimpleSpec(
             ">=6.1.2") and os_name == "mac" and arch == "clang_64":
         arch_dir = "macos"
     else:
         arch_dir = arch
     try:
         prefix = pathlib.Path(base_dir) / version_dir / arch_dir
         updater = Updater(prefix, logger)
         updater.set_license(base_dir, version_dir, arch_dir)
         if target.arch not in [
                 "ios",
                 "android",
                 "wasm_32",
                 "android_x86_64",
                 "android_arm64_v8a",
                 "android_x86",
                 "android_armv7",
         ]:  # desktop version
             updater.make_qtconf(base_dir, version_dir, arch_dir)
             updater.patch_qmake()
             if target.os_name == "linux":
                 updater.patch_pkgconfig("/home/qt/work/install",
                                         target.os_name)
                 updater.patch_libtool("/home/qt/work/install/lib",
                                       target.os_name)
             elif target.os_name == "mac":
                 updater.patch_pkgconfig("/Users/qt/work/install",
                                         target.os_name)
                 updater.patch_libtool("/Users/qt/work/install/lib",
                                       target.os_name)
             elif target.os_name == "windows":
                 updater.make_qtenv2(base_dir, version_dir, arch_dir)
             if version < Version("5.14.0"):
                 updater.patch_qtcore(target)
         elif version in SimpleSpec(">=5.0,<6.0"):
             updater.patch_qmake()
         else:  # qt6 non-desktop
             updater.patch_qmake_script(base_dir, version_dir,
                                        target.os_name)
             updater.patch_target_qt_conf(base_dir, version_dir, arch_dir,
                                          target.os_name)
     except IOError as e:
         raise UpdaterError(f"Updater caused an IO error: {e}") from e