def _fill_conflicts(self, context: UpdateRequirementsContext, blacklist: Iterable[str] = None): self.logger.info("Checking conflicts") root_conflict = self._filter_and_map_conflicts(context) sub_conflict = pacman.get_dependencies_to_remove( root_conflict.keys(), context.root_password) if root_conflict else None to_remove_map = {} if sub_conflict: for dep, source in sub_conflict.items(): if dep not in to_remove_map and (not blacklist or dep not in blacklist): req = ArchPackage(name=dep, installed=True, i18n=self.i18n) to_remove_map[dep] = req reason = "{} '{}'".format( self.i18n['arch.info.depends on'].capitalize(), source) context.to_remove[dep] = UpgradeRequirement(req, reason) if root_conflict: for dep, source in root_conflict.items(): if dep not in to_remove_map and (not blacklist or dep not in blacklist): req = ArchPackage(name=dep, installed=True, i18n=self.i18n) to_remove_map[dep] = req reason = "{} '{}'".format( self.i18n['arch.info.conflicts with'].capitalize(), source) context.to_remove[dep] = UpgradeRequirement(req, reason) if to_remove_map: for name in to_remove_map.keys(): # 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([*to_remove_map.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
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
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