diff options
-rw-r--r-- | pym/_emerge/actions.py | 80 | ||||
-rw-r--r-- | pym/_emerge/depgraph.py | 24 |
2 files changed, 62 insertions, 42 deletions
diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py index 6db7fb13c..24617a7cf 100644 --- a/pym/_emerge/actions.py +++ b/pym/_emerge/actions.py @@ -630,32 +630,44 @@ def calc_depclean(settings, trees, ldpath_mtimes, xterm_titles = "notitles" not in settings.features myroot = settings["ROOT"] root_config = trees[myroot]["root_config"] - getSetAtoms = root_config.setconfig.getSetAtoms + psets = root_config.setconfig.psets vardb = trees[myroot]["vartree"].dbapi deselect = myopts.get('--deselect') != 'n' - required_set_names = ("world",) + required_set_stack = ["world"] required_sets = {} set_args = [] - for s in required_set_names: - required_sets[s] = InternalPackageSet( - initial_atoms=getSetAtoms(s)) - - - # When removing packages, use a temporary version of world - # which excludes packages that are intended to be eligible for + # Recursively create InternalPackageSet instances for world + # and any sets nested within it. + while required_set_stack: + s = required_set_stack.pop() + if s in required_sets: + continue + pset = psets.get(s) + if pset is not None: + required_sets[s] = InternalPackageSet( + initial_atoms=pset.getAtoms()) + for n in pset.getNonAtoms(): + if n.startswith(SETPREFIX): + required_set_stack.append(n[len(SETPREFIX):]) + + # When removing packages, use a temporary version of world 'selected' + # set which excludes packages that are intended to be eligible for # removal. - world_temp_set = required_sets["world"] - system_set = root_config.sets["system"] + selected_set = required_sets["selected"] + protected_set = InternalPackageSet() + protected_set_name = '____depclean_protected_set____' + required_sets[protected_set_name] = protected_set + system_set = required_sets.get("system") - if not system_set or not world_temp_set: + if not system_set or not selected_set: if not system_set: writemsg_level("!!! You have no system list.\n", level=logging.ERROR, noiselevel=-1) - if not world_temp_set: + if not selected_set: writemsg_level("!!! You have no world file.\n", level=logging.WARNING, noiselevel=-1) @@ -678,7 +690,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, if args_set: if deselect: - world_temp_set.clear() + selected_set.clear() # Pull in everything that's installed but not matched # by an argument atom since we don't want to clean any @@ -688,23 +700,23 @@ def calc_depclean(settings, trees, ldpath_mtimes, try: if args_set.findAtomForPackage(pkg) is None: - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue except portage.exception.InvalidDependString as e: show_invalid_depstring_notice(pkg, pkg.metadata["PROVIDE"], str(e)) del e - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue elif action == "prune": if deselect: - world_temp_set.clear() + selected_set.clear() # Pull in everything that's installed since we don't # to prune a package if something depends on it. - world_temp_set.update(vardb.cp_all()) + protected_set.update(vardb.cp_all()) if not args_set: @@ -727,7 +739,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, highest_version = pkgs_for_cp[-1] if pkg == highest_version: # pkg is the highest version - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue if len(pkgs_for_cp) <= 1: @@ -737,27 +749,16 @@ def calc_depclean(settings, trees, ldpath_mtimes, try: if args_set.findAtomForPackage(pkg) is None: - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue except portage.exception.InvalidDependString as e: show_invalid_depstring_notice(pkg, pkg.metadata["PROVIDE"], str(e)) del e - world_temp_set.add("=" + pkg.cpv) + protected_set.add("=" + pkg.cpv) continue - set_args = {} - for s, package_set in required_sets.items(): - set_atom = SETPREFIX + s - set_arg = SetArg(arg=set_atom, set=package_set, - root_config=resolver._frozen_config.roots[myroot]) - set_args[s] = set_arg - for atom in set_arg.set: - resolver._dynamic_config._dep_stack.append( - Dependency(atom=atom, root=myroot, parent=set_arg)) - resolver._dynamic_config.digraph.add(set_arg, None) - - success = resolver._complete_graph() + success = resolver._complete_graph(required_sets={myroot:required_sets}) writemsg_level("\b\b... done!\n") resolver.display_problems() @@ -841,6 +842,13 @@ def calc_depclean(settings, trees, ldpath_mtimes, return -1 def create_cleanlist(): + + # Never display the special internal protected_set. + for node in graph: + if isinstance(node, SetArg) and node.name == protected_set_name: + graph.remove(node) + break + pkgs_to_remove = [] if action == "depclean": @@ -868,9 +876,6 @@ def calc_depclean(settings, trees, ldpath_mtimes, show_parents(pkg) elif action == "prune": - # Prune really uses all installed instead of world. It's not - # a real reverse dependency so don't display it as such. - graph.remove(set_args["world"]) for atom in args_set: for pkg in vardb.match_pkgs(atom): @@ -1062,7 +1067,8 @@ def calc_depclean(settings, trees, ldpath_mtimes, return 1, [], False, 0 writemsg_level("\nCalculating dependencies ") - success = resolver._complete_graph() + success = resolver._complete_graph( + required_sets={myroot:required_sets}) writemsg_level("\b\b... done!\n") resolver.display_problems() if not success: diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index 3d9df8890..54dc5bce1 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -2565,7 +2565,7 @@ class depgraph(object): in_graph = self._dynamic_config._slot_pkg_map[root].get(pkg.slot_atom) return pkg, in_graph - def _complete_graph(self): + def _complete_graph(self, required_sets=None): """ Add any deep dependencies of required sets (args, system, world) that have not been pulled into the graph yet. This ensures that the graph @@ -2576,6 +2576,10 @@ class depgraph(object): Since this method can consume enough time to disturb users, it is currently only enabled by the --complete-graph option. + + @param required_sets: contains required sets (currently only used + for depclean and prune removal operations) + @type required_sets: dict """ if "--buildpkgonly" in self._frozen_config.myopts or \ "recurse" not in self._dynamic_config.myparams: @@ -2598,11 +2602,16 @@ class depgraph(object): self._dynamic_config.myparams["deep"] = True for root in self._frozen_config.roots: - required_set_names = self._frozen_config._required_set_names.copy() + if required_sets is None or root not in required_sets: + required_set_names = self._frozen_config._required_set_names.copy() + else: + required_set_names = set(required_sets[root]) if root == self._frozen_config.target_root and \ (already_deep or "empty" in self._dynamic_config.myparams): required_set_names.difference_update(self._dynamic_config._sets) - if not required_set_names and not self._dynamic_config._ignored_deps: + if not required_set_names and \ + not self._dynamic_config._ignored_deps and \ + not self._dynamic_config._dep_stack: continue root_config = self._frozen_config.roots[root] setconfig = root_config.setconfig @@ -2618,11 +2627,16 @@ class depgraph(object): required_set_names.remove(arg.name) # Create new SetArg instances only when necessary. for s in required_set_names: - expanded_set = InternalPackageSet( - initial_atoms=setconfig.getSetAtoms(s)) + if required_sets is None or root not in required_sets: + expanded_set = InternalPackageSet( + initial_atoms=setconfig.getSetAtoms(s)) + else: + expanded_set = required_sets[root][s] atom = SETPREFIX + s args.append(SetArg(arg=atom, set=expanded_set, root_config=root_config)) + if root == self._frozen_config.target_root: + self._dynamic_config._sets[s] = expanded_set vardb = root_config.trees["vartree"].dbapi for arg in args: for atom in arg.set: |