Beispiel #1
0
    def __fill_provided_map(self, context: UpdateRequirementsContext):
        ti = time.time()
        self.logger.info("Filling provided names")
        context.installed_names = pacman.list_installed_names()
        installed_to_ignore = set()

        for pkgname in context.to_update:
            pacman.fill_provided_map(pkgname, pkgname, context.provided_map)
            installed_to_ignore.add(pkgname)

            pdata = context.pkgs_data.get(pkgname)
            if pdata and pdata['p']:
                pacman.fill_provided_map('{}={}'.format(pkgname, pdata['v']), pkgname, context.provided_map)
                for p in pdata['p']:
                    pacman.fill_provided_map(p, pkgname, context.provided_map)
                    split_provided = p.split('=')

                    if len(split_provided) > 1 and split_provided[0] != p:
                        pacman.fill_provided_map(split_provided[0], pkgname, context.provided_map)

        if installed_to_ignore:  # filling the provided names of the installed
            installed_to_query = context.installed_names.difference(installed_to_ignore)

            if installed_to_query:
                context.provided_map.update(pacman.map_provided(remote=False, pkgs=installed_to_query))

        tf = time.time()
        self.logger.info("Filling provided names took {0:.2f} seconds".format(tf - ti))
Beispiel #2
0
    def __fill_provided_map(self,
                            context: UpdateRequirementsContext,
                            pkgs: Dict[str, ArchPackage],
                            fill_installed: bool = True):
        if pkgs:
            ti = time.time()
            self.logger.info("Filling provided names")

            if not context.installed_names:
                context.installed_names = pacman.list_installed_names()

            installed_to_ignore = set()

            for pkgname in pkgs:
                pacman.fill_provided_map(pkgname, pkgname,
                                         context.provided_map)

                if fill_installed:
                    installed_to_ignore.add(pkgname)

                pdata = context.pkgs_data.get(pkgname)
                if pdata and pdata['p']:
                    pacman.fill_provided_map(
                        '{}={}'.format(pkgname, pdata['v']), pkgname,
                        context.provided_map)

                    ver_split = pdata['v'].split('-')

                    if len(ver_split) > 1:
                        pacman.fill_provided_map(
                            '{}={}'.format(pkgname, '-'.join(ver_split[0:-1])),
                            pkgname, context.provided_map)

                    for p in pdata['p']:
                        pacman.fill_provided_map(p, pkgname,
                                                 context.provided_map)
                        split_provided = p.split('=')

                        if len(split_provided) > 1 and split_provided[0] != p:
                            pacman.fill_provided_map(split_provided[0],
                                                     pkgname,
                                                     context.provided_map)

            if installed_to_ignore:  # filling the provided names of the installed
                installed_to_query = context.installed_names.difference(
                    installed_to_ignore)

                if installed_to_query:
                    context.provided_map.update(
                        pacman.map_provided(remote=False,
                                            pkgs=installed_to_query))

            tf = time.time()
            self.logger.info(
                "Filling provided names took {0:.2f} seconds".format(tf - ti))
Beispiel #3
0
    def summarize(self, pkgs: List[ArchPackage], root_password: str, arch_config: dict) -> UpgradeRequirements:
        res = UpgradeRequirements([], [], [], [])

        remote_provided_map = pacman.map_provided(remote=True)
        remote_repo_map = pacman.map_repositories()
        context = UpdateRequirementsContext(to_update={}, repo_to_update={}, aur_to_update={}, repo_to_install={},
                                            aur_to_install={}, to_install={}, pkgs_data={}, cannot_upgrade={},
                                            to_remove={}, installed_names=set(), provided_map={}, aur_index=set(),
                                            arch_config=arch_config, root_password=root_password,
                                            remote_provided_map=remote_provided_map, remote_repo_map=remote_repo_map)
        self.__fill_aur_index(context)

        aur_data = {}
        aur_srcinfo_threads = []
        for p in pkgs:
            context.to_update[p.name] = p
            if p.repository == 'aur':
                context.aur_to_update[p.name] = p
                t = Thread(target=self._fill_aur_pkg_update_data, args=(p, aur_data), daemon=True)
                t.start()
                aur_srcinfo_threads.append(t)
            else:
                context.repo_to_update[p.name] = p

        if context.aur_to_update:
            for t in aur_srcinfo_threads:
                t.join()

        self.logger.info("Filling updates data")

        if context.repo_to_update:
            context.pkgs_data.update(pacman.map_updates_data(context.repo_to_update.keys()))

        if aur_data:
            context.pkgs_data.update(aur_data)

        self.__fill_provided_map(context)

        if context.pkgs_data:
            self._fill_conflicts(context)

        try:
            if not self._fill_to_install(context):
                self.logger.info("The operation was cancelled by the user")
                return
        except PackageNotFoundException as e:
            self.logger.error("Package '{}' not found".format(e.name))
            return

        if context.to_update:
            installed_sizes = pacman.get_installed_size(list(context.to_update.keys()))

            sorted_pkgs = []

            if context.repo_to_update:  # only sorting by name ( pacman already knows the best order to perform the upgrade )
                sorted_pkgs.extend(context.repo_to_update.values())
                sorted_pkgs.sort(key=lambda pkg: pkg.name)

            if context.aur_to_update:  # adding AUR packages in the end
                sorted_aur = sorting.sort(context.aur_to_update.keys(), context.pkgs_data, context.provided_map)

                for aur_pkg in sorted_aur:
                    sorted_pkgs.append(context.aur_to_update[aur_pkg[0]])

            res.to_upgrade = [self._map_requirement(pkg, context, installed_sizes) for pkg in sorted_pkgs]

        if context.to_remove:
            res.to_remove = [p for p in context.to_remove.values()]

        if context.cannot_upgrade:
            res.cannot_upgrade = [d for d in context.cannot_upgrade.values()]

        if context.to_install:
            res.to_install = [self._map_requirement(p, context) for p in context.to_install.values()]

        return res
Beispiel #4
0
    def __update_context_based_on_to_remove(
            self, context: UpdateRequirementsContext):
        if context.to_remove:
            to_remove_provided = {}
            # filtering all package to synchronization from the transaction context
            to_sync = {
                *(context.to_update.keys() if context.to_update else set()),
                *(context.to_install.keys() if context.to_install else set())
            }
            if to_sync:  # checking if any packages to sync on the context rely on the 'to remove' ones
                to_remove_provided.update(
                    pacman.map_provided(remote=False,
                                        pkgs=context.to_remove.keys()))
                to_remove_from_sync = {
                }  # will store all packages that should be removed

                for pname in to_sync:
                    if pname in context.pkgs_data:
                        deps = context.pkgs_data[pname].get('d')

                        if deps:
                            required = set()

                            for pkg in context.to_remove:
                                for provided in to_remove_provided[pkg]:
                                    if provided in deps:
                                        required.add(pkg)
                                        break

                            if required:
                                to_remove_from_sync[pname] = required
                    else:
                        self.logger.warning(
                            "Conflict resolution: package '{}' marked to synchronization has no data loaded"
                        )

                if to_remove_from_sync:  # removing all these packages and their dependents from the context
                    self._add_to_remove(to_sync, to_remove_from_sync, context)

            # checking if the installed packages that are not in the transaction context rely on the current packages to be removed:
            current_to_remove = {*context.to_remove.keys()}
            required_by_installed = self.deps_analyser.map_all_required_by(
                current_to_remove, {*to_sync})

            if required_by_installed:
                # updating provided context:
                provided_not_mapped = set()
                for pkg in current_to_remove.difference(
                    {*to_remove_provided.keys()}):
                    if pkg not in context.pkgs_data:
                        provided_not_mapped.add(pkg)
                    else:
                        provided = context.pkgs_data[pkg].get('p')
                        if provided:
                            to_remove_provided[pkg] = provided
                        else:
                            provided_not_mapped.add(pkg)

                if provided_not_mapped:
                    to_remove_provided.update(
                        pacman.map_provided(remote=False,
                                            pkgs=provided_not_mapped))

                deps_no_data = {
                    dep
                    for dep in required_by_installed
                    if dep in context.pkgs_data
                }
                deps_nodata_deps = pacman.map_required_dependencies(
                    *deps_no_data) if deps_no_data else {}

                reverse_to_remove_provided = {
                    p: name
                    for name, provided in to_remove_provided.items()
                    for p in provided
                }

                for pkg in required_by_installed:
                    if pkg not in context.to_remove:
                        if pkg in context.pkgs_data:
                            dep_deps = context.pkgs_data[pkg].get('d')
                        else:
                            dep_deps = deps_nodata_deps.get(pkg)

                        if dep_deps:
                            source = ', '.join(
                                (reverse_to_remove_provided[d]
                                 for d in dep_deps
                                 if d in reverse_to_remove_provided))
                            reason = "{} '{}'".format(
                                self.i18n['arch.info.depends on'].capitalize(),
                                source if source else '?')
                            context.to_remove[pkg] = UpgradeRequirement(
                                pkg=ArchPackage(name=pkg,
                                                installed=True,
                                                i18n=self.i18n),
                                reason=reason)

            for name in context.to_remove:  # upgrading lists
                if name in context.pkgs_data:
                    del context.pkgs_data[name]

                if name in context.aur_to_update:
                    del context.aur_to_update[name]

                if name in context.repo_to_update:
                    del context.repo_to_update[name]

            removed_size = pacman.get_installed_size(
                [*context.to_remove.keys()])

            if removed_size:
                for name, size in removed_size.items():
                    if size is not None:
                        req = context.to_remove.get(name)
                        if req:
                            req.extra_size = size
Beispiel #5
0
    def fill_providers_deps(
            self, missing_deps: List[Tuple[str,
                                           str]], provided_map: Dict[str,
                                                                     Set[str]],
            remote_repo_map: Dict[str, str], already_checked: Set[str],
            remote_provided_map: Dict[str, Set[str]], deps_data: Dict[str,
                                                                      dict],
            aur_idx: Iterable[str], sort: bool, watcher: ProcessWatcher,
            automatch_providers: bool) -> List[Tuple[str, str]]:
        """
        :param missing_deps:
        :param provided_map:
        :param remote_repo_map:
        :param already_checked:
        :param remote_provided_map:
        :param deps_data:
        :param aur_idx:
        :param sort:
        :param watcher:
        :param automatch_providers
        :return: all deps sorted or None if the user declined the providers options
        """

        deps_providers = map_providers(
            {data[0]
             for data in missing_deps if data[1] == '__several__'},
            remote_provided_map)

        if deps_providers:
            all_providers = set()

            for providers in deps_providers.values():
                all_providers.update(providers)

            providers_repos = pacman.map_repositories(all_providers)
            selected_providers = confirmation.request_providers(
                deps_providers, providers_repos, watcher, self.i18n)

            if not selected_providers:
                return
            else:
                providers_data = pacman.map_updates_data(
                    selected_providers
                )  # adding the chosen providers to re-check the missing deps
                provided_map.update(
                    pacman.map_provided(remote=True, pkgs=selected_providers)
                )  # adding the providers as "installed" packages

                providers_deps = self.map_missing_deps(
                    pkgs_data=providers_data,
                    provided_map=provided_map,
                    aur_index=aur_idx,
                    deps_checked=already_checked,
                    deps_data=deps_data,
                    sort=False,
                    remote_provided_map=remote_provided_map,
                    remote_repo_map=remote_repo_map,
                    watcher=watcher,
                    choose_providers=True,
                    automatch_providers=automatch_providers)

                # cleaning the already mapped providers deps:
                to_remove = []

                for idx, dep in enumerate(missing_deps):
                    if dep[1] == '__several__':
                        to_remove.append(idx)

                for idx, to_remove in enumerate(to_remove):
                    del missing_deps[to_remove - idx]

                missing_deps.extend(((p, providers_repos.get(p, 'aur'))
                                     for p in selected_providers))

                for dep in providers_deps:
                    if dep not in missing_deps and dep[1] != '__several__':
                        missing_deps.append(dep)

                deps_data.update(providers_data)

                if not self.fill_providers_deps(
                        missing_deps=missing_deps,
                        provided_map=provided_map,
                        remote_repo_map=remote_repo_map,
                        already_checked=already_checked,
                        aur_idx=aur_idx,
                        remote_provided_map=remote_provided_map,
                        deps_data=deps_data,
                        sort=False,
                        watcher=watcher,
                        automatch_providers=automatch_providers):
                    return

                if sort:
                    missing_to_sort = {
                        d[0]
                        for d in missing_deps if d[1] != '__several__'
                    }
                    return sorting.sort(missing_to_sort, deps_data,
                                        provided_map)

        return missing_deps
Beispiel #6
0
    def fill_providers_deps(
            self, missing_deps: List[Tuple[str,
                                           str]], provided_map: Dict[str,
                                                                     Set[str]],
            remote_repo_map: Dict[str, str], already_checked: Set[str],
            remote_provided_map: Dict[str, Set[str]], deps_data: Dict[str,
                                                                      dict],
            aur_idx: Iterable[str], sort: bool, watcher: ProcessWatcher,
            automatch_providers: bool, prefer_repository_provider: bool
    ) -> Optional[List[Tuple[str, str]]]:
        """
        :param missing_deps:
        :param provided_map:
        :param remote_repo_map:
        :param already_checked:
        :param remote_provided_map:
        :param deps_data:
        :param aur_idx:
        :param sort:
        :param watcher:
        :param automatch_providers
        :param prefer_repository_provider
        :return: all deps sorted or None if the user declined the providers options
        """

        deps_providers = map_providers(
            {data[0]
             for data in missing_deps if data[1] == '__several__'},
            remote_provided_map)

        if deps_providers:
            providers_repos = {}
            repos_providers = set()

            for providers in deps_providers.values():
                for provider in providers:
                    if remote_repo_map.get(provider) == 'aur':
                        providers_repos[provider] = 'aur'
                    else:
                        repos_providers.add(provider)

            providers_repos.update(pacman.map_repositories(repos_providers))
            selected_providers = confirmation.request_providers(
                deps_providers, providers_repos, watcher, self.i18n)

            if not selected_providers:
                return
            else:
                # adding the chosen providers for re-checking the missing dependencies
                repo_selected, aur_selected = set(), set()

                for provider in selected_providers:
                    if provider in repos_providers:
                        repo_selected.add(provider)
                    else:
                        aur_selected.add(provider)

                providers_data = dict()

                if repo_selected:
                    providers_data.update(
                        pacman.map_updates_data(repo_selected))
                    # adding the providers as "installed" packages
                    provided_map.update(
                        pacman.map_provided(remote=True, pkgs=repo_selected))

                if aur_selected:
                    for pkgname, pkgdata in self.aur_client.gen_updates_data(
                            aur_selected):
                        providers_data[pkgname] = pkgdata
                        for provider in pkgdata[
                                'p']:  # adding the providers as "installed" packages
                            currently_provided = provided_map.get(
                                provider, set())
                            provided_map[provider] = currently_provided
                            currently_provided.add(pkgname)

                providers_deps = self.map_missing_deps(
                    pkgs_data=providers_data,
                    provided_map=provided_map,
                    aur_index=aur_idx,
                    deps_checked=already_checked,
                    deps_data=deps_data,
                    sort=False,
                    remote_provided_map=remote_provided_map,
                    remote_repo_map=remote_repo_map,
                    watcher=watcher,
                    choose_providers=True,
                    automatch_providers=automatch_providers,
                    prefer_repository_provider=prefer_repository_provider)

                if providers_deps is None:  # it means the user called off the installation process
                    return

                # cleaning the already mapped providers deps:
                to_remove = []

                for idx, dep in enumerate(missing_deps):
                    if dep[1] == '__several__':
                        to_remove.append(idx)

                for idx, to_remove in enumerate(to_remove):
                    del missing_deps[to_remove - idx]

                missing_deps.extend(((p, providers_repos.get(p, 'aur'))
                                     for p in selected_providers))

                for dep in providers_deps:
                    if dep not in missing_deps and dep[1] != '__several__':
                        missing_deps.append(dep)

                deps_data.update(providers_data)

                if not self.fill_providers_deps(
                        missing_deps=missing_deps,
                        provided_map=provided_map,
                        remote_repo_map=remote_repo_map,
                        already_checked=already_checked,
                        aur_idx=aur_idx,
                        remote_provided_map=remote_provided_map,
                        deps_data=deps_data,
                        sort=False,
                        watcher=watcher,
                        automatch_providers=automatch_providers,
                        prefer_repository_provider=prefer_repository_provider):
                    return

                if sort:
                    missing_to_sort = {
                        d[0]
                        for d in missing_deps if d[1] != '__several__'
                    }
                    return sorting.sort(missing_to_sort, deps_data,
                                        provided_map)

        return missing_deps