Add support for display of nested sets in --depclean and --prune reverse
authorZac Medico <zmedico@gentoo.org>
Mon, 19 Oct 2009 03:46:02 +0000 (03:46 -0000)
committerZac Medico <zmedico@gentoo.org>
Mon, 19 Oct 2009 03:46:02 +0000 (03:46 -0000)
dependency output. This also fixes a bug from the 'selected' set changes
which could cause the system set to be disregarded in some cases.
(trunk r14680)

svn path=/main/branches/2.1.7/; revision=14691

pym/_emerge/actions.py
pym/_emerge/depgraph.py

index 9ae7f0982ac63315c252cb809e51f023a83eef6f..c4d82e8bc885216225034ffa2d99424f4d1b7383 100644 (file)
@@ -633,32 +633,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)
 
@@ -681,7 +693,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
@@ -691,23 +703,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:
 
@@ -730,7 +742,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:
@@ -740,27 +752,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()
@@ -844,6 +845,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":
@@ -871,9 +879,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):
index d0151bfabb7753e4377419bd3f7dccff776739a4..2cc27f3c9ae4f09972bee3d3303a7878e9dfb9d2 100644 (file)
@@ -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: