summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2007-07-18 04:03:38 +0000
committerZac Medico <zmedico@gentoo.org>2007-07-18 04:03:38 +0000
commit9676a2aa192bf640d70fe4a9aff6005996659057 (patch)
tree3f18cc8b0731ce6a0a6a82c8ce2cc186adaff04e
parentebd42fc6da1aca53badec4b34f118d7f106f3835 (diff)
downloadportage-9676a2aa192bf640d70fe4a9aff6005996659057.tar.gz
portage-9676a2aa192bf640d70fe4a9aff6005996659057.tar.bz2
portage-9676a2aa192bf640d70fe4a9aff6005996659057.zip
Use the --depclean algorithm to make --prune safe. The old unsafe --prune will be used if the --nodeps option is specified.
svn path=/main/trunk/; revision=7305
-rw-r--r--pym/emerge/__init__.py89
-rw-r--r--pym/portage/dbapi/virtual.py5
2 files changed, 78 insertions, 16 deletions
diff --git a/pym/emerge/__init__.py b/pym/emerge/__init__.py
index d0091f9ae..a5fc25543 100644
--- a/pym/emerge/__init__.py
+++ b/pym/emerge/__init__.py
@@ -5237,7 +5237,7 @@ def action_search(settings, portdb, vartree, myopts, myfiles, spinner):
searchinstance.output()
def action_depclean(settings, trees, ldpath_mtimes,
- myopts, spinner):
+ myopts, action, myfiles, spinner):
# Kill packages that aren't explicitly merged or are required as a
# dependency of another package. World file is explicit.
@@ -5258,9 +5258,10 @@ def action_depclean(settings, trees, ldpath_mtimes,
msg.append("consequence, it is often necessary to run\n")
msg.append(good("`emerge --update --newuse --deep world`") + " prior to depclean.\n")
- portage.writemsg_stdout("\n")
- for x in msg:
- portage.writemsg_stdout(colorize("BAD", "*** WARNING *** ") + x)
+ if action == "depclean":
+ portage.writemsg_stdout("\n")
+ for x in msg:
+ portage.writemsg_stdout(colorize("BAD", "*** WARNING *** ") + x)
xterm_titles = "notitles" not in settings.features
myroot = settings["ROOT"]
@@ -5276,6 +5277,7 @@ def action_depclean(settings, trees, ldpath_mtimes,
syslist = list(system_set)
world_set = WorldSet("world", myroot)
worldlist = list(world_set)
+ args_set = InternalPackageSet()
fakedb = portage.fakedbapi(settings=settings)
myvarlist = vardb.cpv_all()
@@ -5292,16 +5294,44 @@ def action_depclean(settings, trees, ldpath_mtimes,
if "--pretend" not in myopts:
countdown(int(settings["EMERGE_WARNING_DELAY"]), ">>> Depclean")
- if not "--pretend" in myopts: #just check pretend, since --ask implies pretend
+ if action == "depclean":
emergelog(xterm_titles, " >>> depclean")
+ elif action == "prune":
+ for x in myfiles:
+ if not is_valid_package_atom(x):
+ portage.writemsg("!!! '%s' is not a valid package atom.\n" % x,
+ noiselevel=-1)
+ portage.writemsg("!!! Please check ebuild(5) for full details.\n")
+ return
+ try:
+ atom = portage.dep_expand(x, mydb=vardb, settings=settings)
+ except ValueError, e:
+ print "!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify"
+ print "!!! one of the following fully-qualified ebuild names instead:\n"
+ for i in e[0]:
+ print " " + colorize("INFORM", i)
+ print
+ return
+ args_set.add(atom)
if "--quiet" not in myopts:
print "\nCalculating dependencies ",
soft = 0
hard = 1
- remaining_atoms = [(atom, 'world', hard) for atom in worldlist if vardb.match(atom)]
- remaining_atoms += [(atom, 'system', hard) for atom in syslist if vardb.match(atom)]
+ remaining_atoms = []
+ if action == "depclean":
+ for atom in worldlist:
+ if vardb.match(atom):
+ remaining_atoms.append((atom, 'world', hard))
+ for atom in syslist:
+ if vardb.match(atom):
+ remaining_atoms.append((atom, 'system', hard))
+ elif action == "prune":
+ # Pull in everything that's installed since we don't want to prune a
+ # package if something depends on it.
+ remaining_atoms.extend((atom, 'world', hard) for atom in vardb.cp_all())
+
unresolveable = {}
aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
metadata_keys = ["PROVIDE", "SLOT", "USE"]
@@ -5313,7 +5343,25 @@ def action_depclean(settings, trees, ldpath_mtimes,
if not atom.startswith("!") and priority == hard:
unresolveable.setdefault(atom, []).append(parent)
continue
- if len(pkgs) > 1 and parent != "world":
+ prune_this = False
+ if action == "prune":
+ for pkg in pkgs:
+ metadata = dict(izip(metadata_keys,
+ vardb.aux_get(pkg, metadata_keys)))
+ try:
+ arg_atom = args_set.findAtomForPackage(pkg, metadata)
+ except portage.exception.InvalidDependString, e:
+ file_path = os.path.join(myroot, VDB_PATH, pkg, "PROVIDE")
+ portage.writemsg("\n\nInvalid PROVIDE: %s\n" % str(s),
+ noiselevel=-1)
+ portage.writemsg("See '%s'\n" % file_path,
+ noiselevel=-1)
+ del e
+ continue
+ if arg_atom:
+ prune_this = True
+ break
+ if len(pkgs) > 1 and (parent != "world" or prune_this):
# Prune all but the best matching slot, since that's all that a
# deep world update would pull in. Don't prune if this atom comes
# directly from world though, since world atoms are greedy when
@@ -5379,6 +5427,7 @@ def action_depclean(settings, trees, ldpath_mtimes,
print
for atom in unresolveable:
print atom, "required by", " ".join(unresolveable[atom])
+ if unresolveable and action == "depclean":
print
print "Have you forgotten to run " + good("`emerge --update --newuse --deep world`") + " prior to"
print "depclean? It may be necessary to manually uninstall packages that no longer"
@@ -5388,12 +5437,27 @@ def action_depclean(settings, trees, ldpath_mtimes,
print
return
- cleanlist = [pkg for pkg in vardb.cpv_all() if not fakedb.cpv_exists(pkg)]
+ cleanlist = []
+ if action == "depclean":
+ for pkg in vardb.cpv_all():
+ if not fakedb.cpv_exists(pkg):
+ cleanlist.append(pkg)
+ elif action == "prune":
+ for atom in args_set:
+ for pkg in vardb.match(atom):
+ if not fakedb.cpv_exists(pkg):
+ cleanlist.append(pkg)
+ if not cleanlist:
+ portage.writemsg_stdout(
+ ">>> No packages selected for removal by %s\n" % action)
if len(cleanlist):
unmerge(settings, myopts, trees[settings["ROOT"]]["vartree"],
"unmerge", cleanlist, ldpath_mtimes)
+ if action == "prune":
+ return
+
print "Packages installed: "+str(len(myvarlist))
print "Packages in world: "+str(len(worldlist))
print "Packages in system: "+str(len(syslist))
@@ -6179,7 +6243,8 @@ def emerge_main():
validate_ebuild_environment(trees)
action_search(settings, portdb, trees["/"]["vartree"],
myopts, myfiles, spinner)
- elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction:
+ elif myaction in ("clean", "unmerge") or \
+ (myaction == "prune" and "--nodeps" in myopts):
validate_ebuild_environment(trees)
vartree = trees[settings["ROOT"]]["vartree"]
if 1 == unmerge(settings, myopts, vartree, myaction, myfiles,
@@ -6187,10 +6252,10 @@ def emerge_main():
if "--pretend" not in myopts:
post_emerge(trees, mtimedb, os.EX_OK)
- elif "depclean"==myaction:
+ elif myaction in ("depclean", "prune"):
validate_ebuild_environment(trees)
action_depclean(settings, trees, mtimedb["ldpath"],
- myopts, spinner)
+ myopts, myaction, myfiles, spinner)
if "--pretend" not in myopts:
post_emerge(trees, mtimedb, os.EX_OK)
# "update", "system", or just process files:
diff --git a/pym/portage/dbapi/virtual.py b/pym/portage/dbapi/virtual.py
index 983e39b7f..467eb032c 100644
--- a/pym/portage/dbapi/virtual.py
+++ b/pym/portage/dbapi/virtual.py
@@ -39,10 +39,7 @@ class fakedbapi(dbapi):
return self.cpdict[mycp]
def cp_all(self):
- returnme=[]
- for x in self.cpdict:
- returnme.extend(self.cpdict[x])
- return returnme
+ return list(self.cpdict)
def cpv_all(self):
return self.cpvdict.keys()