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))
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))
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
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
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