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)
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
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:
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:
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()
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":
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):
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
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:
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
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: