Use the --depclean algorithm to make --prune safe. The old unsafe --prune will be...
authorZac Medico <zmedico@gentoo.org>
Wed, 18 Jul 2007 04:03:38 +0000 (04:03 -0000)
committerZac Medico <zmedico@gentoo.org>
Wed, 18 Jul 2007 04:03:38 +0000 (04:03 -0000)
svn path=/main/trunk/; revision=7305

pym/emerge/__init__.py
pym/portage/dbapi/virtual.py

index d0091f9ae54951309abb7cf825e94c5c285891ec..a5fc255436305298cbb670c0d9e9df08411efe7c 100644 (file)
@@ -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:
index 983e39b7f4ae6ebd957eb7e62ef46c17f306a157..467eb032c4f72d99df5c30dcc4941232ebbfb006 100644 (file)
@@ -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()