summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/_emerge/actions.py80
-rw-r--r--pym/_emerge/depgraph.py24
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: