예제 #1
0
 def __init__(self, os_name, target, version, arch, subarchives=None,
              modules=None, mirror=None, logging=None, all_extra=False):
     self.version = version
     self.target = target
     self.arch = arch
     self.mirror = mirror
     self.os_name = os_name
     self.all_extra = all_extra
     self.arch_list = [item.get('arch') for item in Settings().qt_combinations]
     all_archives = (subarchives is None)
     if mirror is not None:
         self.has_mirror = True
         self.base = mirror + '/online/qtsdkrepository/'
     else:
         self.has_mirror = False
         self.base = self.BASE_URL
     if logging:
         self.logger = logging
     else:
         self.logger = getLogger('aqt')
     self.archives = []
     self.mod_list = []
     qt_ver_num = self.version.replace(".", "")
     self.qt_ver_base = self.version[0:1]
     if all_extra:
         self.all_extra = True
     else:
         for m in modules if modules is not None else []:
             self.mod_list.append("qt.qt{}.{}.{}.{}".format(self.qt_ver_base, qt_ver_num, m, arch))
             self.mod_list.append("qt.{}.{}.{}".format(qt_ver_num, m, arch))
     self._get_archives(qt_ver_num)
     if not all_archives:
         self.archives = list(filter(lambda a: a.name in subarchives, self.archives))
예제 #2
0
 def _check_modules_arg(self, qt_version, modules):
     if modules is None:
         return True
     available = Settings.available_modules(qt_version)
     if available is None:
         return False
     return all([m in available for m in modules])
예제 #3
0
def test_install_pool_exception(monkeypatch, capsys, make_exception,
                                settings_file, expect_end_msg, expect_return):
    def mock_installer_func(*args):
        raise eval(make_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(
        archives, arch, host, updates_url)
    monkeypatch.setattr("aqt.archives.getUrl", mock_get_url)
    monkeypatch.setattr("aqt.installer.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)
예제 #4
0
 def _setup_settings(self, args=None):
     # setup logging
     setup_logging()
     self.logger = getLogger("aqt.main")
     # setup settings
     if args is not None and args.config is not None:
         Settings.load_settings(args.config)
     else:
         config = os.getenv("AQT_CONFIG", None)
         if config is not None and os.path.exists(config):
             Settings.load_settings(config)
             self.logger.debug("Load configuration from {}".format(config))
         else:
             Settings.load_settings()
예제 #5
0
 def __init__(
     self,
     os_name,
     target,
     version,
     arch,
     base,
     subarchives=None,
     modules=None,
     logging=None,
     all_extra=False,
     timeout=(5, 5),
 ):
     self.version = version
     self.target = target
     self.arch = arch
     self.os_name = os_name
     self.all_extra = all_extra
     self.arch_list = [item.get("arch") for item in Settings().qt_combinations]
     all_archives = subarchives is None
     self.base = base
     if logging:
         self.logger = logging
     else:
         self.logger = getLogger("aqt")
     self.archives = []
     self.mod_list = []
     qt_ver_num = self.version.replace(".", "")
     self.qt_ver_base = self.version[0:1]
     if all_extra:
         self.all_extra = True
     else:
         for m in modules if modules is not None else []:
             self.mod_list.append(
                 "qt.qt{}.{}.{}.{}".format(self.qt_ver_base, qt_ver_num, m, arch)
             )
             self.mod_list.append("qt.{}.{}.{}".format(qt_ver_num, m, arch))
     self.timeout = timeout
     self._get_archives(qt_ver_num)
     if not all_archives:
         self.archives = list(filter(lambda a: a.name in subarchives, self.archives))
예제 #6
0
def setup():
    Settings.load_settings(
        os.path.join(os.path.dirname(__file__), "data", "settings.ini"))
예제 #7
0
    except (ArchiveConnectionError, ArchiveDownloadError) as e:
        logger.error(format(e))
        return 1


def get_tqdm(disable: bool):
    if disable:
        return lambda x: x

    from tqdm import tqdm as base_tqdm

    return lambda *a: base_tqdm(*a, disable=disable)


if __name__ == "__main__":
    Settings.load_settings()
    setup_logging()
    logger = logging.getLogger("aqt.generate_combos")

    json_filename = Path(__file__).parent.parent / "aqt/combinations.json"

    parser = argparse.ArgumentParser(
        description="Generate combinations.json from download.qt.io, "
        "compare with existing file, and write file to correct differences")
    parser.add_argument(
        "--write",
        help="write to combinations.json if changes detected",
        action="store_true",
    )
    parser.add_argument(
        "--no-tqdm",
예제 #8
0
 def __init__(self, env_key='AQT_CONFIG'):
     config = os.getenv(env_key, None)
     self.settings = Settings(config=config)
     self._create_parser()
예제 #9
0
class Cli:
    """CLI main class to parse command line argument and launch proper functions."""

    __slot__ = ['parser', 'combinations', 'logger']

    def __init__(self, env_key='AQT_CONFIG'):
        config = os.getenv(env_key, None)
        self.settings = Settings(config=config)
        self._create_parser()

    def _check_tools_arg_combination(self, os_name, tool_name, arch):
        for c in self.settings.tools_combinations:
            if c['os_name'] == os_name and c['tool_name'] == tool_name and c[
                    'arch'] == arch:
                return True
        return False

    def _check_qt_arg_combination(self, qt_version, os_name, target, arch):
        if qt_version.startswith(
                '5.15.0') and os_name == 'windows' and target == 'desktop':
            if arch in [
                    'win64_msvc2017_64', 'win32_msvc2017', 'win64_mingw73',
                    'win32_mingw73'
            ]:
                return False
        for c in self.settings.qt_combinations:
            if c['os_name'] == os_name and c['target'] == target and c[
                    'arch'] == arch:
                return True
        return False

    def _check_qt_arg_versions(self, qt_version):
        for ver in self.settings.available_versions:
            if ver == qt_version:
                return True
        return False

    def _set_sevenzip(self, args):
        sevenzip = args.external
        if sevenzip is None:
            return None

        try:
            subprocess.run([sevenzip, '--help'],
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL)
        except FileNotFoundError as e:
            raise Exception(
                'Specified 7zip command executable does not exist: {!r}'.
                format(sevenzip)) from e

        return sevenzip

    def _set_arch(self, args, oarch, os_name, target, qt_version):
        arch = oarch
        if arch is None:
            if os_name == "linux" and target == "desktop":
                arch = "gcc_64"
            elif os_name == "mac" and target == "desktop":
                arch = "clang_64"
            elif os_name == "mac" and target == "ios":
                arch = "ios"
            elif target == "android" and parse(qt_version) >= Version(
                    '5.14.0'):
                arch = "android"
        if arch == "":
            print("Please supply a target architecture.")
            args.print_help()
            exit(1)
        return arch

    def _check_mirror(self, mirror):
        if mirror is None:
            pass
        elif mirror.startswith('http://') or mirror.startswith(
                'https://') or mirror.startswith('ftp://'):
            pass
        else:
            return False
        return True

    def _check_modules_arg(self, qt_version, modules):
        if modules is None:
            return True
        available = self.settings.available_modules(qt_version)
        if available is None:
            return False
        return all([m in available for m in modules])

    def _run_common_part(self, output_dir=None, mirror=None):
        self.show_aqt_version()
        if output_dir is not None:
            output_dir = os.path.normpath(output_dir)
        if not self._check_mirror(mirror):
            self.parser.print_help()
            exit(1)

    def call_installer(self, qt_archives, target_dir, sevenzip):
        if target_dir is None:
            base_dir = os.getcwd()
        else:
            base_dir = target_dir
        tasks = []
        for arc in qt_archives.get_archives():
            tasks.append((arc, base_dir, sevenzip))
        pool = multiprocessing.Pool(self.settings.concurrency)
        pool.starmap(installer, tasks)

    def run_install(self, args):
        start_time = time.perf_counter()
        arch = args.arch
        target = args.target
        os_name = args.host
        qt_version = args.qt_version
        output_dir = args.outputdir
        if output_dir is None:
            base_dir = os.getcwd()
        else:
            base_dir = output_dir
        arch = self._set_arch(args, arch, os_name, target, qt_version)
        modules = args.modules
        sevenzip = self._set_sevenzip(args)
        mirror = args.base
        archives = args.archives
        self._run_common_part(output_dir, mirror)
        if not self._check_qt_arg_versions(qt_version):
            self.logger.warning(
                "Specified Qt version is unknown: {}.".format(qt_version))
        if not self._check_qt_arg_combination(qt_version, os_name, target,
                                              arch):
            self.logger.warning(
                "Specified target combination is not valid or unknown: {} {} {}"
                .format(os_name, target, arch))
        all_extra = True if modules is not None and 'all' in modules else False
        if not all_extra and not self._check_modules_arg(qt_version, modules):
            self.logger.warning("Some of specified modules are unknown.")
        try:
            qt_archives = QtArchives(os_name,
                                     target,
                                     qt_version,
                                     arch,
                                     subarchives=archives,
                                     modules=modules,
                                     mirror=mirror,
                                     logging=self.logger,
                                     all_extra=all_extra)
        except ArchiveDownloadError or ArchiveListError:
            exit(1)
        else:
            target_config = qt_archives.get_target_config()
            self.call_installer(qt_archives, output_dir, sevenzip)
            finisher(target_config, base_dir, self.logger)
        self.logger.info("Finished installation")
        self.logger.info("Time elasped: {time:.8f} second".format(
            time=time.perf_counter() - start_time))

    def _run_src_doc_examples(self, flavor, args):
        start_time = time.perf_counter()
        target = args.target
        os_name = args.host
        qt_version = args.qt_version
        output_dir = args.outputdir
        mirror = args.base
        sevenzip = self._set_sevenzip(args)
        modules = args.modules
        archives = args.archives
        self._run_common_part(output_dir, mirror)
        all_extra = True if modules is not None and 'all' in modules else False
        if not self._check_qt_arg_versions(qt_version):
            self.logger.warning(
                "Specified Qt version is unknown: {}.".format(qt_version))
        try:
            srcdocexamples_archives = SrcDocExamplesArchives(
                flavor,
                os_name,
                target,
                qt_version,
                subarchives=archives,
                modules=modules,
                mirror=mirror,
                logging=self.logger,
                all_extra=all_extra)
        except ArchiveDownloadError or ArchiveListError:
            exit(1)
        else:
            self.call_installer(srcdocexamples_archives, output_dir, sevenzip)
        self.logger.info("Finished installation")
        self.logger.info("Time elasped: {time:.8f} second".format(
            time=time.perf_counter() - start_time))

    def run_src(self, args):
        self._run_src_doc_examples('src', args)

    def run_examples(self, args):
        self._run_src_doc_examples('examples', args)

    def run_doc(self, args):
        self._run_src_doc_examples('doc', args)

    def run_tool(self, args):
        start_time = time.perf_counter()
        arch = args.arch
        tool_name = args.tool_name
        os_name = args.host
        output_dir = args.outputdir
        sevenzip = self._set_sevenzip(args)
        version = args.version
        mirror = args.base
        self._run_common_part(output_dir, mirror)
        if not self._check_tools_arg_combination(os_name, tool_name, arch):
            self.logger.warning(
                "Specified target combination is not valid: {} {} {}".format(
                    os_name, tool_name, arch))
        try:
            tool_archives = ToolArchives(os_name,
                                         tool_name,
                                         version,
                                         arch,
                                         mirror=mirror,
                                         logging=self.logger)
        except ArchiveDownloadError or ArchiveListError:
            exit(1)
        else:
            self.call_installer(tool_archives, output_dir, sevenzip)
        self.logger.info("Finished installation")
        self.logger.info("Time elasped: {time:.8f} second".format(
            time=time.perf_counter() - start_time))

    def run_list(self, args):
        self.show_aqt_version()
        pl = PackagesList(args.qt_version, args.host, args.target)
        print('List Qt packages in %s for %s' % (args.qt_version, args.host))
        table = Texttable()
        table.set_deco(Texttable.HEADER)
        table.set_cols_dtype(['t', 't'])
        table.set_cols_align(["l", "l"])
        table.header(["target type", "arch"])
        for entry in pl.get_list():
            if not entry.virtual:
                name_list = entry.name.split('.')
                table.add_row([entry.display_name, name_list[-1]])
        print(table.draw())

    def show_help(self, args):
        self.parser.print_help()

    def show_aqt_version(self):
        dist = importlib_metadata.distribution('aqtinstall')
        module_name = dist.entry_points[0].name
        py_version = platform.python_version()
        py_impl = platform.python_implementation()
        py_build = platform.python_compiler()
        self.logger.info("aqtinstall({}) v{} on Python {} [{} {}]".format(
            module_name, dist.version, py_version, py_impl, py_build))

    def _set_common_options(self, subparser):
        subparser.add_argument(
            '-O',
            '--outputdir',
            nargs='?',
            help='Target output directory(default current directory)')
        subparser.add_argument(
            '-b',
            '--base',
            nargs='?',
            help=
            "Specify mirror base url such as http://mirrors.ocf.berkeley.edu/qt/, "
            "where 'online' folder exist.")
        subparser.add_argument('-E',
                               '--external',
                               nargs='?',
                               help='Specify external 7zip command path.')
        subparser.add_argument('--internal',
                               action='store_true',
                               help='Use internal extractor.')

    def _set_module_options(self, subparser):
        subparser.add_argument('-m',
                               '--modules',
                               nargs='*',
                               help="Specify extra modules to install")
        subparser.add_argument(
            '--archives',
            nargs='*',
            help=
            "Specify subset packages to install (Default: all standard and extra modules)."
        )

    def _set_common_argument(self, subparser):
        subparser.add_argument("qt_version",
                               help="Qt version in the format of \"5.X.Y\"")
        subparser.add_argument('host',
                               choices=['linux', 'mac', 'windows'],
                               help="host os name")
        subparser.add_argument('target',
                               choices=['desktop', 'winrt', 'android', 'ios'],
                               help="target sdk")

    def _create_parser(self):
        parser = argparse.ArgumentParser(
            prog='aqt',
            description='Installer for Qt SDK.',
            formatter_class=argparse.RawTextHelpFormatter,
            add_help=True)
        parser.add_argument('--logging-conf',
                            type=argparse.FileType('r'),
                            nargs=1,
                            help="Logging configuration ini file.")
        parser.add_argument('--logger', nargs=1, help="Specify logger name")
        subparsers = parser.add_subparsers(
            title='subcommands',
            description='Valid subcommands',
            help='subcommand for aqt Qt installer')
        install_parser = subparsers.add_parser('install')
        install_parser.set_defaults(func=self.run_install)
        self._set_common_argument(install_parser)
        self._set_common_options(install_parser)
        install_parser.add_argument(
            'arch',
            nargs='?',
            help="\ntarget linux/desktop: gcc_64, wasm_32"
            "\ntarget mac/desktop:   clang_64, wasm_32"
            "\ntarget mac/ios:       ios"
            "\nwindows/desktop:      win64_msvc2019_64, win32_msvc2019"
            "\n                      win64_msvc2017_64, win32_msvc2017"
            "\n                      win64_msvc2015_64, win32_msvc2015"
            "\n                      win64_mingw73, win32_mingw73"
            "\n                      win32_mingw53"
            "\n                      wasm_32"
            "\nwindows/winrt:        win64_msvc2019_winrt_x64, win64_msvc2019_winrt_x86"
            "\n                      win64_msvc2017_winrt_x64, win64_msvc2017_winrt_x86"
            "\n                      win64_msvc2019_winrt_armv7"
            "\n                      win64_msvc2017_winrt_armv7"
            "\nandroid:              Qt 5.14:          android (optional)"
            "\n                      Qt 5.13 or below: android_x86_64, android_arm64_v8a"
            "\n                                        android_x86, android_armv7"
        )
        self._set_module_options(install_parser)
        #
        doc_parser = subparsers.add_parser('doc')
        doc_parser.set_defaults(func=self.run_doc)
        self._set_common_argument(doc_parser)
        self._set_common_options(doc_parser)
        self._set_module_options(doc_parser)
        #
        examples_parser = subparsers.add_parser('examples')
        examples_parser.set_defaults(func=self.run_examples)
        self._set_common_argument(examples_parser)
        self._set_common_options(examples_parser)
        self._set_module_options(examples_parser)
        #
        src_parser = subparsers.add_parser('src')
        src_parser.set_defaults(func=self.run_src)
        self._set_common_argument(src_parser)
        self._set_common_options(src_parser)
        self._set_module_options(src_parser)
        #
        tools_parser = subparsers.add_parser('tool')
        tools_parser.set_defaults(func=self.run_tool)
        tools_parser.add_argument('host',
                                  choices=['linux', 'mac', 'windows'],
                                  help="host os name")
        tools_parser.add_argument(
            'tool_name', help="Name of tool such as tools_ifw, tools_mingw")
        tools_parser.add_argument(
            "version", help="Tool version in the format of \"4.1.2\"")
        tools_parser.add_argument(
            'arch', help="Name of full tool name such as qt.tools.ifw.31")
        self._set_common_options(tools_parser)
        #
        list_parser = subparsers.add_parser('list')
        list_parser.set_defaults(func=self.run_list)
        self._set_common_argument(list_parser)
        help_parser = subparsers.add_parser('help')
        help_parser.set_defaults(func=self.show_help)
        parser.set_defaults(func=self.show_help)
        self.parser = parser

    def _setup_logging(self, args, env_key='LOG_CFG'):
        envconf = os.getenv(env_key, None)
        conf = None
        if args.logging_conf:
            conf = args.logging_conf
        elif envconf is not None:
            conf = envconf
        if conf is None or not os.path.exists(conf):
            conf = os.path.join(os.path.dirname(__file__), 'logging.ini')
        logging.config.fileConfig(conf)
        if args.logger is not None:
            self.logger = logging.getLogger(args.logger)
        else:
            self.logger = logging.getLogger('aqt')

    def run(self, arg=None):
        args = self.parser.parse_args(arg)
        self._setup_logging(args)
        return args.func(args)
예제 #10
0
class Cli:
    """CLI main class to parse command line argument and launch proper functions."""

    __slot__ = ["parser", "combinations", "logger"]

    def __init__(self, env_key="AQT_CONFIG"):
        config = os.getenv(env_key, None)
        self.settings = Settings(config=config)
        self._create_parser()

    def _check_tools_arg_combination(self, os_name, tool_name, arch):
        for c in self.settings.tools_combinations:
            if (
                c["os_name"] == os_name
                and c["tool_name"] == tool_name
                and c["arch"] == arch
            ):
                return True
        return False

    def _check_qt_arg_combination(self, qt_version, os_name, target, arch):
        if os_name == "windows" and target == "desktop":
            # check frequent mistakes
            if qt_version.startswith("5.15.") or qt_version.startswith("6."):
                if arch in [
                    "win64_msvc2017_64",
                    "win32_msvc2017",
                    "win64_mingw73",
                    "win32_mingw73",
                ]:
                    return False
            elif (
                qt_version.startswith("5.9.")
                or qt_version.startswith("5.10.")
                or qt_version.startswith("5.11.")
            ):
                if arch in [
                    "win64_mingw73",
                    "win32_mingw73",
                    "win64_mingw81",
                    "win32_mingw81",
                ]:
                    return False
            elif arch in [
                "win64_msvc2019_64",
                "win32_msvc2019",
                "win64_mingw81",
                "win32_mingw81",
            ]:
                return False
        for c in self.settings.qt_combinations:
            if c["os_name"] == os_name and c["target"] == target and c["arch"] == arch:
                return True
        return False

    def _check_qt_arg_versions(self, qt_version):
        for ver in self.settings.available_versions:
            if ver == qt_version:
                return True
        return False

    def _set_sevenzip(self, external):
        sevenzip = external
        if sevenzip is None:
            return None

        try:
            subprocess.run(
                [sevenzip, "--help"],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
            )
        except FileNotFoundError as e:
            raise Exception(
                "Specified 7zip command executable does not exist: {!r}".format(
                    sevenzip
                )
            ) from e

        return sevenzip

    def _set_arch(self, args, oarch, os_name, target, qt_version):
        arch = oarch
        if arch is None:
            if os_name == "linux" and target == "desktop":
                arch = "gcc_64"
            elif os_name == "mac" and target == "desktop":
                arch = "clang_64"
            elif os_name == "mac" and target == "ios":
                arch = "ios"
            elif target == "android" and parse(qt_version) >= Version("5.14.0"):
                arch = "android"
            else:
                print("Please supply a target architecture.")
                self.show_help(args)
                exit(1)
        if arch == "":
            print("Please supply a target architecture.")
            self.show_help(args)
            exit(1)
        return arch

    def _check_mirror(self, mirror):
        if mirror is None:
            pass
        elif (
            mirror.startswith("http://")
            or mirror.startswith("https://")
            or mirror.startswith("ftp://")
        ):
            pass
        else:
            return False
        return True

    def _check_modules_arg(self, qt_version, modules):
        if modules is None:
            return True
        available = self.settings.available_modules(qt_version)
        if available is None:
            return False
        return all([m in available for m in modules])

    def _run_common_part(self, output_dir=None, mirror=None):
        self.show_aqt_version()
        if output_dir is not None:
            output_dir = os.path.normpath(output_dir)
        if not self._check_mirror(mirror):
            self.parser.print_help()
            exit(1)

    def call_installer(self, qt_archives, target_dir, sevenzip, keep):
        if target_dir is None:
            base_dir = os.getcwd()
        else:
            base_dir = target_dir
        tasks = []
        for arc in qt_archives.get_archives():
            tasks.append((arc, base_dir, sevenzip, keep))
        pool = multiprocessing.Pool(self.settings.concurrency)
        pool.starmap(installer, tasks)
        pool.close()
        pool.join()

    def run_install(self, args):
        """Run install subcommand"""
        start_time = time.perf_counter()
        arch = args.arch
        target = args.target
        os_name = args.host
        qt_version = args.qt_version
        output_dir = args.outputdir
        keep = args.keep
        if output_dir is None:
            base_dir = os.getcwd()
        else:
            base_dir = output_dir
        if args.timeout is not None:
            timeout = (args.timeout, args.timeout)
        else:
            timeout = (5, 5)
        arch = self._set_arch(args, arch, os_name, target, qt_version)
        modules = args.modules
        sevenzip = self._set_sevenzip(args.external)
        if EXT7Z and sevenzip is None:
            # override when py7zr is not exist
            sevenzip = self._set_sevenzip("7z")
        if args.base is not None:
            base = args.base + "/online/qtsdkrepository/"
        else:
            base = BASE_URL
        archives = args.archives
        if args.noarchives:
            if modules is None:
                print(
                    "When specified option --no-archives, an option --modules is mandatory."
                )
                exit(1)
            if archives is not None:
                print(
                    "Option --archives and --no-archives  are conflicted. Aborting..."
                )
                exit(1)
            else:
                archives = modules
        else:
            if modules is not None and archives is not None:
                archives.append(modules)
        nopatch = args.noarchives or (
            archives is not None and "qtbase" not in archives
        )  # type: bool
        self._run_common_part(output_dir, base)
        if not self._check_qt_arg_versions(qt_version):
            self.logger.warning(
                "Specified Qt version is unknown: {}.".format(qt_version)
            )
        if not self._check_qt_arg_combination(qt_version, os_name, target, arch):
            self.logger.warning(
                "Specified target combination is not valid or unknown: {} {} {}".format(
                    os_name, target, arch
                )
            )
        all_extra = True if modules is not None and "all" in modules else False
        if not all_extra and not self._check_modules_arg(qt_version, modules):
            self.logger.warning("Some of specified modules are unknown.")
        try:
            qt_archives = QtArchives(
                os_name,
                target,
                qt_version,
                arch,
                base,
                subarchives=archives,
                modules=modules,
                logging=self.logger,
                all_extra=all_extra,
                timeout=timeout,
            )
        except ArchiveConnectionError:
            try:
                self.logger.warning(
                    "Connection to the download site failed and fallback to mirror site."
                )
                qt_archives = QtArchives(
                    os_name,
                    target,
                    qt_version,
                    arch,
                    random.choice(FALLBACK_URLS),
                    subarchives=archives,
                    modules=modules,
                    logging=self.logger,
                    all_extra=all_extra,
                    timeout=timeout,
                )
            except Exception:
                self.logger.error("Connection to the download site failed. Aborted...")
                exit(1)
        except ArchiveDownloadError or ArchiveListError or NoPackageFound:
            exit(1)
        target_config = qt_archives.get_target_config()
        self.call_installer(qt_archives, output_dir, sevenzip, keep)
        if not nopatch:
            Updater.update(target_config, base_dir, self.logger)
        self.logger.info("Finished installation")
        self.logger.info(
            "Time elasped: {time:.8f} second".format(
                time=time.perf_counter() - start_time
            )
        )

    def _run_src_doc_examples(self, flavor, args):
        start_time = time.perf_counter()
        target = args.target
        os_name = args.host
        qt_version = args.qt_version
        output_dir = args.outputdir
        keep = args.keep
        if args.base is not None:
            base = args.base + "/online/qtsdkrepository/"
        else:
            base = BASE_URL
        if args.timeout is not None:
            timeout = (args.timeout, args.timeout)
        else:
            timeout = (5, 5)
        sevenzip = self._set_sevenzip(args)
        modules = args.modules
        archives = args.archives
        self._run_common_part(output_dir, base)
        all_extra = True if modules is not None and "all" in modules else False
        if not self._check_qt_arg_versions(qt_version):
            self.logger.warning(
                "Specified Qt version is unknown: {}.".format(qt_version)
            )
        try:
            srcdocexamples_archives = SrcDocExamplesArchives(
                flavor,
                os_name,
                target,
                qt_version,
                base,
                subarchives=archives,
                modules=modules,
                logging=self.logger,
                all_extra=all_extra,
                timeout=timeout,
            )
        except ArchiveConnectionError:
            try:
                self.logger.warning(
                    "Connection to the download site failed and fallback to mirror site."
                )
                srcdocexamples_archives = SrcDocExamplesArchives(
                    flavor,
                    os_name,
                    target,
                    qt_version,
                    random.choice(FALLBACK_URLS),
                    subarchives=archives,
                    modules=modules,
                    logging=self.logger,
                    all_extra=all_extra,
                    timeout=timeout,
                )
            except Exception:
                self.logger.error("Connection to the download site failed. Aborted...")
                exit(1)
        except ArchiveDownloadError or ArchiveListError:
            exit(1)
        self.call_installer(srcdocexamples_archives, output_dir, sevenzip, keep)
        self.logger.info("Finished installation")
        self.logger.info(
            "Time elapsed: {time:.8f} second".format(
                time=time.perf_counter() - start_time
            )
        )

    def run_src(self, args):
        """Run src subcommand"""
        self._run_src_doc_examples("src", args)

    def run_examples(self, args):
        """Run example subcommand"""
        self._run_src_doc_examples("examples", args)

    def run_doc(self, args):
        """Run doc subcommand"""
        self._run_src_doc_examples("doc", args)

    def run_tool(self, args):
        """Run tool subcommand"""
        start_time = time.perf_counter()
        arch = args.arch
        tool_name = args.tool_name
        os_name = args.host
        output_dir = args.outputdir
        sevenzip = self._set_sevenzip(args.external)
        if EXT7Z and sevenzip is None:
            # override when py7zr is not exist
            sevenzip = self._set_sevenzip("7z")
        version = args.version
        keep = args.keep
        if args.base is not None:
            base = args.base + "/online/qtsdkrepository/"
        else:
            base = BASE_URL
        if args.timeout is not None:
            timeout = (args.timeout, args.timeout)
        else:
            timeout = (5, 5)
        self._run_common_part(output_dir, base)
        if not self._check_tools_arg_combination(os_name, tool_name, arch):
            self.logger.warning(
                "Specified target combination is not valid: {} {} {}".format(
                    os_name, tool_name, arch
                )
            )
        try:
            tool_archives = ToolArchives(
                os_name,
                tool_name,
                version,
                arch,
                base,
                logging=self.logger,
                timeout=timeout,
            )
        except ArchiveConnectionError:
            try:
                self.logger.warning(
                    "Connection to the download site failed and fallback to mirror site."
                )
                tool_archives = ToolArchives(
                    os_name,
                    tool_name,
                    version,
                    arch,
                    random.choice(FALLBACK_URLS),
                    logging=self.logger,
                    timeout=timeout,
                )
            except Exception:
                self.logger.error("Connection to the download site failed. Aborted...")
                exit(1)
        except ArchiveDownloadError or ArchiveListError:
            exit(1)
        self.call_installer(tool_archives, output_dir, sevenzip, keep)
        self.logger.info("Finished installation")
        self.logger.info(
            "Time elapsed: {time:.8f} second".format(
                time=time.perf_counter() - start_time
            )
        )

    def run_list(self, args):
        """Run list subcommand"""
        self.show_aqt_version()
        qt_version = args.qt_version
        host = args.host
        target = args.target
        try:
            pl = PackagesList(qt_version, host, target, BASE_URL)
        except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
            pl = PackagesList(qt_version, host, target, random.choice(FALLBACK_URLS))
        print("List Qt packages in %s for %s" % (args.qt_version, args.host))
        table = Texttable()
        table.set_deco(Texttable.HEADER)
        table.set_cols_dtype(["t", "t", "t"])
        table.set_cols_align(["l", "l", "l"])
        table.header(["target", "arch", "description"])
        for entry in pl.get_list():
            if qt_version[0:1] == "6" or not entry.virtual:
                archid = entry.name.split(".")[-1]
                table.add_row([entry.display_name, archid, entry.desc])
        print(table.draw())

    def show_help(self, args):
        """Display help message"""
        self.parser.print_help()

    def show_aqt_version(self):
        """Display version information"""
        py_version = platform.python_version()
        py_impl = platform.python_implementation()
        py_build = platform.python_compiler()
        self.logger.info(
            "aqtinstall(aqt) v{} on Python {} [{} {}]".format(
                aqt.__version__, py_version, py_impl, py_build
            )
        )

    def _set_common_options(self, subparser):
        subparser.add_argument(
            "-O",
            "--outputdir",
            nargs="?",
            help="Target output directory(default current directory)",
        )
        subparser.add_argument(
            "-b",
            "--base",
            nargs="?",
            help="Specify mirror base url such as http://mirrors.ocf.berkeley.edu/qt/, "
            "where 'online' folder exist.",
        )
        subparser.add_argument(
            "-E", "--external", nargs="?", help="Specify external 7zip command path."
        )
        subparser.add_argument(
            "--internal", action="store_true", help="Use internal extractor."
        )
        subparser.add_argument(
            "--timeout",
            nargs="?",
            type=float,
            help="Specify connection timeout for download site.(default: 5 sec)",
        )
        subparser.add_argument(
            "-k",
            "--keep",
            action="store_true",
            help="Keep downloaded archive when specified, otherwise remove after install",
        )

    def _set_module_options(self, subparser):
        subparser.add_argument(
            "-m", "--modules", nargs="*", help="Specify extra modules to install"
        )
        subparser.add_argument(
            "--archives",
            nargs="*",
            help="Specify subset packages to install (Default: all standard and extra modules).",
        )

    def _set_common_argument(self, subparser):
        subparser.add_argument("qt_version", help='Qt version in the format of "5.X.Y"')
        subparser.add_argument(
            "host", choices=["linux", "mac", "windows"], help="host os name"
        )
        subparser.add_argument(
            "target", choices=["desktop", "winrt", "android", "ios"], help="target sdk"
        )

    def _create_parser(self):
        parser = argparse.ArgumentParser(
            prog="aqt",
            description="Installer for Qt SDK.",
            formatter_class=argparse.RawTextHelpFormatter,
            add_help=True,
        )
        parser.add_argument(
            "--logging-conf",
            type=argparse.FileType("r"),
            nargs=1,
            help="Logging configuration ini file.",
        )
        parser.add_argument("--logger", nargs=1, help="Specify logger name")
        subparsers = parser.add_subparsers(
            title="subcommands",
            description="Valid subcommands",
            help="subcommand for aqt Qt installer",
        )
        install_parser = subparsers.add_parser("install")
        install_parser.set_defaults(func=self.run_install)
        self._set_common_argument(install_parser)
        self._set_common_options(install_parser)
        install_parser.add_argument(
            "arch",
            nargs="?",
            help="\ntarget linux/desktop: gcc_64, wasm_32"
            "\ntarget mac/desktop:   clang_64, wasm_32"
            "\ntarget mac/ios:       ios"
            "\nwindows/desktop:      win64_msvc2019_64, win32_msvc2019"
            "\n                      win64_msvc2017_64, win32_msvc2017"
            "\n                      win64_msvc2015_64, win32_msvc2015"
            "\n                      win64_mingw81, win32_mingw81"
            "\n                      win64_mingw73, win32_mingw73"
            "\n                      win32_mingw53"
            "\n                      wasm_32"
            "\nwindows/winrt:        win64_msvc2019_winrt_x64, win64_msvc2019_winrt_x86"
            "\n                      win64_msvc2017_winrt_x64, win64_msvc2017_winrt_x86"
            "\n                      win64_msvc2019_winrt_armv7"
            "\n                      win64_msvc2017_winrt_armv7"
            "\nandroid:              Qt 5.14:          android (optional)"
            "\n                      Qt 5.13 or below: android_x86_64, android_arm64_v8a"
            "\n                                        android_x86, android_armv7",
        )
        self._set_module_options(install_parser)
        install_parser.add_argument(
            "--noarchives",
            action="store_true",
            help="No base packages; allow mod amendment with --modules option.",
        )
        #
        doc_parser = subparsers.add_parser("doc")
        doc_parser.set_defaults(func=self.run_doc)
        self._set_common_argument(doc_parser)
        self._set_common_options(doc_parser)
        self._set_module_options(doc_parser)
        #
        examples_parser = subparsers.add_parser("examples")
        examples_parser.set_defaults(func=self.run_examples)
        self._set_common_argument(examples_parser)
        self._set_common_options(examples_parser)
        self._set_module_options(examples_parser)
        #
        src_parser = subparsers.add_parser("src")
        src_parser.set_defaults(func=self.run_src)
        self._set_common_argument(src_parser)
        self._set_common_options(src_parser)
        self._set_module_options(src_parser)
        #
        tools_parser = subparsers.add_parser("tool")
        tools_parser.set_defaults(func=self.run_tool)
        tools_parser.add_argument(
            "host", choices=["linux", "mac", "windows"], help="host os name"
        )
        tools_parser.add_argument(
            "tool_name", help="Name of tool such as tools_ifw, tools_mingw"
        )
        tools_parser.add_argument(
            "version", help='Tool version in the format of "4.1.2"'
        )
        tools_parser.add_argument(
            "arch", help="Name of full tool name such as qt.tools.ifw.31"
        )
        self._set_common_options(tools_parser)
        #
        list_parser = subparsers.add_parser("list")
        list_parser.set_defaults(func=self.run_list)
        self._set_common_argument(list_parser)
        help_parser = subparsers.add_parser("help")
        help_parser.set_defaults(func=self.show_help)
        parser.set_defaults(func=self.show_help)
        self.parser = parser

    def _setup_logging(self, args, env_key="LOG_CFG"):
        envconf = os.getenv(env_key, None)
        conf = None
        if args.logging_conf:
            conf = args.logging_conf
        elif envconf is not None:
            conf = envconf
        if conf is None or not os.path.exists(conf):
            conf = os.path.join(os.path.dirname(__file__), "logging.ini")
        logging.config.fileConfig(conf)
        if args.logger is not None:
            self.logger = logging.getLogger(args.logger)
        else:
            self.logger = logging.getLogger("aqt")

    def run(self, arg=None):
        args = self.parser.parse_args(arg)
        self._setup_logging(args)
        return args.func(args)
예제 #11
0
def setup_settings():
    Settings.load_settings()
예제 #12
0
def installer(
    qt_archive: QtPackage,
    base_dir: str,
    command: Optional[str],
    queue: multiprocessing.Queue,
    keep: bool = False,
    response_timeout: Optional[int] = None,
):
    """
    Installer function to download archive files and extract it.
    It is called through multiprocessing.Pool()
    """
    name = qt_archive.name
    url = qt_archive.archive_url
    hashurl = qt_archive.hashurl
    archive = qt_archive.archive
    start_time = time.perf_counter()
    # set defaults
    Settings.load_settings()
    # set logging
    setup_logging()  # XXX: why need to load again?
    qh = QueueHandler(queue)
    logger = getLogger()
    for handler in logger.handlers:
        handler.close()
        logger.removeHandler(handler)
    logger.addHandler(qh)
    #
    logger.debug("Download URL: {}".format(url))
    if response_timeout is None:
        timeout = (Settings.connection_timeout, Settings.response_timeout)
    else:
        timeout = (Settings.connection_timeout, response_timeout)
    hash = binascii.unhexlify(getUrl(hashurl, timeout))
    retry_on_errors(
        action=lambda: downloadBinaryFile(url, archive, "sha1", hash, timeout),
        acceptable_errors=(ArchiveChecksumError, ),
        num_retries=Settings.max_retries_on_checksum_error,
        name=f"Downloading {name}",
    )
    if command is None:
        with py7zr.SevenZipFile(archive, "r") as szf:
            szf.extractall(path=base_dir)
    else:
        if base_dir is not None:
            command_args = [
                command,
                "x",
                "-aoa",
                "-bd",
                "-y",
                "-o{}".format(base_dir),
                archive,
            ]
        else:
            command_args = [command, "x", "-aoa", "-bd", "-y", archive]
        try:
            proc = subprocess.run(command_args,
                                  stdout=subprocess.PIPE,
                                  check=True)
            logger.debug(proc.stdout)
        except subprocess.CalledProcessError as cpe:
            msg = "\n".join(
                filter(None, [
                    f"Extraction error: {cpe.returncode}", cpe.stdout,
                    cpe.stderr
                ]))
            raise ArchiveExtractionError(msg) from cpe
    if not keep:
        os.unlink(archive)
    logger.info("Finished installation of {} in {:.8f}".format(
        archive,
        time.perf_counter() - start_time))
    qh.flush()
    qh.close()
    logger.removeHandler(qh)