Exemplo n.º 1
0
    def _fill_dependency_breakage(self, context: UpdateRequirementsContext):
        if bool(context.arch_config['check_dependency_breakage']) and (
                context.to_update or context.to_install):
            ti = time.time()
            self.logger.info("Begin: checking dependency breakage")

            required_by = pacman.map_required_by(
                context.to_update.keys()) if context.to_update else {}

            if context.to_install:
                required_by.update(
                    pacman.map_required_by(context.to_install.keys(),
                                           remote=True))

            reqs_not_in_transaction = set()
            reqs_in_transaction = set()

            transaction_pkgs = {
                *context.to_update.keys(), *context.to_install.keys()
            }

            for reqs in required_by.values():
                for r in reqs:
                    if r in transaction_pkgs:
                        reqs_in_transaction.add(r)
                    elif r in context.installed_names:
                        reqs_not_in_transaction.add(r)

            if not reqs_not_in_transaction and not reqs_in_transaction:
                return

            provided_versions = {}

            for p in context.provided_map:
                pkg_split = p.split('=')

                if len(pkg_split) > 1:
                    versions = provided_versions.get(pkg_split[0])

                    if versions is None:
                        versions = set()
                        provided_versions[pkg_split[0]] = versions

                    versions.add(pkg_split[1])

            if not provided_versions:
                return

            cannot_upgrade = set()

            for pkg, deps in pacman.map_required_dependencies(
                    *reqs_not_in_transaction).items():
                self._add_dependency_breakage(
                    pkgname=pkg,
                    pkgdeps=deps,
                    provided_versions=provided_versions,
                    cannot_upgrade=cannot_upgrade,
                    context=context)

            for pkg in reqs_in_transaction:
                data = context.pkgs_data[pkg]

                if data and data['d']:
                    self._add_dependency_breakage(
                        pkgname=pkg,
                        pkgdeps=data['d'],
                        provided_versions=provided_versions,
                        cannot_upgrade=cannot_upgrade,
                        context=context)

            if cannot_upgrade:
                cannot_upgrade.update(
                    self._add_dependents_as_cannot_upgrade(
                        context=context,
                        names=cannot_upgrade,
                        pkgs_available={
                            *context.to_update.values(),
                            *context.to_install.values()
                        }))

                for p in cannot_upgrade:
                    if p in context.to_update:
                        del context.to_update[p]

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

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

                    if p in context.pkgs_data:
                        del context.pkgs_data[p]

                    if p in context.to_install:
                        del context.to_install[p]

                    if p in context.repo_to_install:
                        del context.repo_to_install[p]

                    if p in context.aur_to_install:
                        del context.aur_to_install[p]

            tf = time.time()
            self.logger.info(
                "End: checking dependency breakage. Time: {0:.2f} seconds".
                format(tf - ti))
Exemplo n.º 2
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