Merged from trunk 7307:7340
authorFabian Groffen <grobian@gentoo.org>
Sat, 21 Jul 2007 19:19:50 +0000 (19:19 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 21 Jul 2007 19:19:50 +0000 (19:19 -0000)
   +------------------------------------------------------------------------+
   | 7308    | With --prune and --depclean, if --verbose is enabled then    |
   | zmedico | show reverse dependencies for each package that is matched   |
   |         | by an atom from the command line. This allows the user to    |
   |         | see why a package will not be unmerged.                      |
   |---------+--------------------------------------------------------------|
   | 7309    | Make --prune bail out like depclean does if there are        |
   | zmedico | unresolved dependencies. Notify the user that they can use   |
   |         | --nodeps in that case.                                       |
   |---------+--------------------------------------------------------------|
   | 7310    | Make --prune try to prune all slotted packages if no atoms   |
   | zmedico | are given (that's how it already works with --nodeps).       |
   |---------+--------------------------------------------------------------|
   | 7312    | For bug #151653, make --prune keep the highest version       |
   | zmedico | whenever possible (even when there is one with a higher      |
   |         | counter installed).                                          |
   |---------+--------------------------------------------------------------|
   | 7313    | Fix --prune so that it always correctly accounts for COUNTER |
   | zmedico | when dealing with packages in the same slot.                 |
   |---------+--------------------------------------------------------------|
   | 7315    | Update --prune docs for bug #151653.                         |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7317    | Document --prune and --depclean enhancements.                |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7319    | For bug #185504, document profiles/repo_name.                |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7321    | If the fetcher reported success and the file is too small,   |
   | zmedico | don't attempt to resume. Upstream probably changed the       |
   |         | distfile and we need to show a digest verification failure   |
   |         | so the user gets a clue.                                     |
   |---------+--------------------------------------------------------------|
   | 7325    | When digest verification of a distfile fails, rename instead |
   | zmedico | of unlinking it in case it's a large download and the user   |
   |         | wants to salvage it due to a bad digest.                     |
   |---------+--------------------------------------------------------------|
   | 7327    | Hint about --nodeps if --prune doesn't find anything to      |
   | zmedico | prune. Also enable reverse dependency display for global     |
   |         | depclean.                                                    |
   |---------+--------------------------------------------------------------|
   | 7329    | Optimize PackageSet._updateAtomMap() for the case where one  |
   | zmedico | or more atoms are added and none are removed.                |
   |---------+--------------------------------------------------------------|
   | 7330    | For bug #185930, direct all FETCHCOMMAND output to stdout.   |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7332    | Just show [0] instead of [0=>0] in the repo display.         |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7334    | Prune really uses all installed instead of world. It's not a |
   | zmedico | real reverse dependency so don't display it as such.         |
   |---------+--------------------------------------------------------------|
   | 7336    | Make --prune and --depclean return before calculating        |
   | zmedico | dependencies if atoms are given but they don't match any     |
   |         | packages.                                                    |
   |---------+--------------------------------------------------------------|
   | 7338    | For bug #185153, in commit mode do the "Fetching trivial     |
   | zmedico | updates" routine before the qa scan.                         |
   |---------+--------------------------------------------------------------|
   | 7340    | For bug #169500, detect when the cvs server puts /Attic/     |
   | zmedico | inside the $Header path and automatically correct it.        |
   +------------------------------------------------------------------------+

svn path=/main/branches/prefix/; revision=7342

RELEASE-NOTES
bin/repoman
man/emerge.1
man/portage.5
pym/emerge/__init__.py
pym/emerge/help.py
pym/portage/__init__.py
pym/portage/sets/__init__.py

index 030ebfd1f6cca202f372d54efc3f3787c5baf005..f6989a14db878ab86c1c67290b6e1084f2974e63 100644 (file)
@@ -37,6 +37,12 @@ portage-2.1.3
   world file and prevent matching packages from being removed.  A slot atom
   will be recorded in the world file for any atom that is precise enough to
   identify a specific slot.
+* For safer operation, emerge --prune will not unmerge packages that have
+  reverse dependencies. Use --verbose to display reverse dependencies. Use
+  --nodeps to completely ignore dependencies.
+* emerge --depclean now accepts atoms and will unmerge only the specified
+  packages if nothing depends on them. Use --verbose to display reverse
+  dependencies.
 
 portage-2.1.2
 ==================================
index 6809bc980af9a7b96c6fcafdf809be2855fb3ff7..4f00f95d0e2a0c685ac57e37ee5aa7f6689f9dd2 100755 (executable)
@@ -589,12 +589,6 @@ for x in range(0,repolevel-1):
 
 def caterror(mycat):
        err(mycat+" is not an official category.  Skipping QA checks in this directory.\nPlease ensure that you add "+catdir+" to "+repodir+"/profiles/categories\nif it is a new category.")
-if mymode == "manifest":
-       pass
-elif "--pretend" in myoptions:
-       print green("\nRepoMan does a once-over of the neighborhood...")
-elif quiet < 1:
-       print green("\nRepoMan scours the neighborhood...")
 
 def parse_use_local_desc(mylines, usedict=None):
        """returns a dict of the form {cpv:set(flags)}"""
@@ -816,6 +810,62 @@ def x11_deprecation_check(depstr):
                                return True
        return False
 
+if mymode == "commit":
+       retval = ("","")
+       if isCvs:
+               print
+               print "Performing a " + green("cvs -n up") + \
+                       " with a little magic grep to check for updates."
+               retval = getstatusoutput("cvs -n up 2>&1 | " + \
+                       "egrep '^[^\?] .*' | " + \
+                       "egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'")
+
+       if isSvn:
+               print
+               print "Performing a "+green("svn status -u") + \
+                       " with a little magic grep to check for updates."
+               retval=getstatusoutput("svn status -u 2>&1 | " + \
+                       "egrep -v '^.  +.*/digest-[^/]+' | " + \
+                       "head -n-1")
+
+       mylines=retval[1].splitlines()
+       myupdates=[]
+       for x in mylines:
+               if not x:
+                       continue
+               if x[0] not in "UPMARD": # Updates,Patches,Modified,Added,Removed/Replaced(svn),Deleted(svn)
+                       print red("!!! Please fix the following issues reported " + \
+                               "from vcs: ")+green("(U,P,M,A,R,D are ok)")
+                       print red("!!! Note: This is a pretend/no-modify pass...")
+                       print retval[1]
+                       print
+                       sys.exit(1)
+               elif isCvs and x[0] in ["U","P"]:
+                       myupdates.append(x[2:])
+               elif isSvn and x[8] == '*':
+                       myupdates.append(x[9:].lstrip(" 1234567890"))
+       
+       if myupdates:
+               print green("Fetching trivial updates...")
+               if "--pretend" in myoptions:
+                       print "(cvs/svn up "+" ".join(myupdates)+")"
+                       retval = os.EX_OK
+               else:
+                       if isCvs:
+                               retval=os.system("cvs up "+" ".join(myupdates))
+                       elif isSvn:
+                               retval=os.system("svn update "+" ".join(myupdates))
+               if retval != os.EX_OK:
+                       print "!!! cvs/svn exited with an error. Terminating."
+                       sys.exit(retval)
+
+if mymode == "manifest":
+       pass
+elif "--pretend" in myoptions:
+       print green("\nRepoMan does a once-over of the neighborhood...")
+elif quiet < 1:
+       print green("\nRepoMan scours the neighborhood...")
+
 dofail = 0
 arch_caches={}
 arch_xmatch_caches = {}
@@ -1729,47 +1779,6 @@ elif "--pretend" not in myoptions:
                print
                sys.exit(1)
 
-       retval=["",""]
-       if isCvs:
-               print "Performing a "+green("cvs -n up")+" with a little magic grep to check for updates."
-               retval=getstatusoutput("cvs -n up 2>&1 | egrep '^[^\?] .*' | egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'")
-       if isSvn:
-               print "Performing a "+green("svn status -u")+" with a little magic grep to check for updates."
-               retval=getstatusoutput("svn status -u 2>&1 | egrep -v '^.  +.*/digest-[^/]+' | head -n-1")
-
-       mylines=retval[1].split("\n")
-       myupdates=[]
-       for x in mylines:
-               if not x:
-                       continue
-               if x[0] not in "UPMARD": # Updates,Patches,Modified,Added,Removed/Replaced(svn),Deleted(svn)
-                       print red("!!! Please fix the following issues reported from cvs: ")+green("(U,P,M,A,R,D are ok)")
-                       if isCvs:
-                               print red("!!! Note: This is a pretend/no-modify pass...")
-                       if isSvn:
-                               print red("!!! Note: This your local checkout has been modified!")
-                       print retval[1]
-                       print
-                       sys.exit(1)
-               elif isCvs and x[0] in ["U","P"]:
-                       myupdates+=[x[2:]]
-               elif isSvn and x[8] == '*':
-                       myupdates+=[x[9:].lstrip(" 1234567890")]
-       
-       if myupdates:
-               print green("Fetching trivial updates...")
-               if "--pretend" in myoptions:
-                       print "(cvs/svn up "+" ".join(myupdates)+")"
-                       retval=0
-               else:
-                       if isCvs:
-                               retval=os.system("cvs up "+" ".join(myupdates))
-                       elif isSvn:
-                               retval=os.system("svn update "+" ".join(myupdates))
-               if retval!=0:
-                       print "!!! cvs/svn exited with an error. Terminating."
-                       sys.exit(retval)
-       
        if isCvs:
                mycvstree=portage.cvstree.getentries("./",recursive=1)
                mychanged=portage.cvstree.findchanged(mycvstree,recursive=1,basedir="./")
@@ -1785,8 +1794,7 @@ elif "--pretend" not in myoptions:
 
        if isCvs or isSvn:
                if not (mychanged or mynew or myremoved):
-                       print
-                       print green("RepoMan sez:"), "\"Doing nothing is not always good for QA.\"\n"
+                       print green("RepoMan sez:"), "\"Doing nothing is not always good for QA.\""
                        print
                        print "(Didn't find any changed files...)"
                        print
@@ -1969,6 +1977,23 @@ elif "--pretend" not in myoptions:
                        else:
                                raise portage.exception.PortageException("!!! gpg exited with '" + str(rValue) + "' status")
 
+       # When files are removed and re-added, the cvs server will put /Attic/
+       # inside the $Header path. This code detects the problem and corrects it
+       # so that the Manifest will generate correctly. See bug #169500.
+       from portage.util import write_atomic
+       cvs_header = re.compile(r'^#\s*\$Header.*\$$')
+       for x in myheaders:
+               f = open(x)
+               mylines = f.readlines()
+               f.close()
+               modified = False
+               for i, line in enumerate(mylines):
+                       if cvs_header.match(line) and "/Attic/" in line:
+                               mylines[i] = line.replace("/Attic/", "/")
+                               modified = True
+               if modified:
+                       write_atomic(x, "".join(mylines))
+
        manifest_commit_required = True
        if myheaders or myupdates or myremoved or mynew:
                myfiles=myheaders+myupdates+myremoved+mynew
index fed38d86e57afce404f7f1ec27fb1d0ca6e255e9..6d6d7ca47226d61e06eb31e65b88ace8a7620cbd 100644 (file)
@@ -125,12 +125,10 @@ package data.  It does not populate cache for the overlays listed in
 PORTDIR_OVERLAY.  In order to generate cache for overlays, use \fB\-\-regen\fR.
 .TP
 .BR "\-\-prune " (\fB\-P\fR)
-\fBWARNING: This action can remove important packages!\fR  Prune looks at each
-installed package and attempts to \fBremove\fR all but the \fBmost recently 
-installed version.  \fRPrune ignores \fBslots\fR, if you require a slot\-aware
-Prune use \fB emerge \-\-clean\fR.  Prune may inadvertently remove important 
-packages from your system.  Use \fB\-\-clean\fR instead unless you really 
-know what you're doing.
+\fBWARNING: This action can remove important packages!\fR  Removes all but the
+highest installed version of a package from your system. This action doesn't
+verify the possible binary compatibility between versions and can thus remove
+essential dependencies from your system.
 .TP
 .BR \-\-regen
 Causes portage to check and update the dependency cache of all ebuilds in the 
index e1855efbbef3de08053cafcaae5a3d42e1400b34..78b2623d626685eda2f478b1afd918e9369baee3 100644 (file)
@@ -62,6 +62,7 @@ info_pkgs
 info_vars
 package.mask
 profiles.desc
+repo_name
 thirdpartymirrors
 use.desc
 use.local.desc
@@ -608,6 +609,11 @@ m68k  default-linux/m68k         dev
 x86   default-linux/x86/2004.3   stable
 .fi
 .TP
+.BR repo_name
+The first line of the file should define a unique repository name. The name
+may contain any of the characters [A\-Za\-z0\-9_\-]. It must not begin with a
+hyphen.
+.TP
 .BR thirdpartymirrors
 Controls the mapping of mirror:// style URLs to actual lists of 
 mirrors.  Keeps us from overloading a single server.
index 147e0463fce72c3f4923064dfcfd059c713e1585..dbd84672e1ccdea66dc4b6ab0352b57433c4b9d3 100644 (file)
@@ -2954,9 +2954,12 @@ class depgraph(object):
                                                if repo_name_prev:
                                                        repo_path_prev = portdb.getRepositoryPath(
                                                                repo_name_prev)
-                                               repoadd = "%s=>%s" % (
-                                                       repo_display.repoStr(repo_path_prev),
-                                                       repo_display.repoStr(repo_path_real))
+                                               if repo_path_prev == repo_path_real:
+                                                       repoadd = repo_display.repoStr(repo_path_real)
+                                               else:
+                                                       repoadd = "%s=>%s" % (
+                                                               repo_display.repoStr(repo_path_prev),
+                                                               repo_display.repoStr(repo_path_real))
                                        if repoadd:
                                                verboseadd += teal("[%s]" % repoadd)
 
@@ -4023,9 +4026,32 @@ def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files,
                                                if y not in pkgmap[mykey]["selected"]:
                                                        pkgmap[mykey]["selected"].append(y)
                                                        numselected=numselected+len(mymatch)
-       
+                       elif unmerge_action == "prune":
+                               if len(mymatch) == 1:
+                                       continue
+                               best_version = mymatch[0]
+                               best_slot = vartree.getslot(best_version)
+                               best_counter = vartree.dbapi.cpv_counter(best_version)
+                               for mypkg in mymatch[1:]:
+                                       myslot = vartree.getslot(mypkg)
+                                       mycounter = vartree.dbapi.cpv_counter(mypkg)
+                                       if (myslot == best_slot and mycounter > best_counter) or \
+                                               mypkg == portage.best([mypkg, best_version]):
+                                               if myslot == best_slot:
+                                                       if mycounter < best_counter:
+                                                               # On slot collision, keep the one with the
+                                                               # highest counter since it is the most
+                                                               # recently installed.
+                                                               continue
+                                               best_version = mypkg
+                                               best_slot = myslot
+                                               best_counter = mycounter
+                               pkgmap[mykey]["protected"].append(best_version)
+                               pkgmap[mykey]["selected"] = [mypkg for mypkg in mymatch \
+                                       if mypkg != best_version]
+                               numselected = numselected + len(pkgmap[mykey]["selected"])
                        else:
-                               #unmerge_action in ["prune", clean"]
+                               # unmerge_action == "clean"
                                slotmap={}
                                for mypkg in mymatch:
                                        if unmerge_action=="clean":
@@ -5362,6 +5388,15 @@ def action_depclean(settings, trees, ldpath_mtimes,
                                print
                                return
                        args_set.add(atom)
+               matched_packages = False
+               for x in args_set:
+                       if vardb.match(x):
+                               matched_packages = True
+                               break
+               if not matched_packages:
+                       portage.writemsg_stdout(
+                               ">>> No packages selected for removal by %s\n" % action)
+                       return
 
        if "--quiet" not in myopts:
                print "\nCalculating dependencies  ",
@@ -5380,10 +5415,16 @@ def action_depclean(settings, trees, ldpath_mtimes,
                # 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())
+               if not myfiles:
+                       # Try to prune everything that's slotted.
+                       for cp in vardb.cp_all():
+                               if len(vardb.cp_list(cp)) > 1:
+                                       args_set.add(cp)
 
        unresolveable = {}
        aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
        metadata_keys = ["PROVIDE", "SLOT", "USE"]
+       graph = digraph()
 
        while remaining_atoms:
                atom, parent, priority = remaining_atoms.pop()
@@ -5443,6 +5484,7 @@ def action_depclean(settings, trees, ldpath_mtimes,
                                pkgs = visible_in_portdb
                        pkgs = [portage.best(pkgs)]
                for pkg in pkgs:
+                       graph.add(pkg, parent)
                        if fakedb.cpv_exists(pkg):
                                continue
                        spinner.update()
@@ -5496,16 +5538,29 @@ def action_depclean(settings, trees, ldpath_mtimes,
                print
                for atom in unresolveable:
                        print atom, "required by", " ".join(unresolveable[atom])
-       if unresolveable and action == "depclean":
+       if unresolveable:
                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"
+               print "%s?  It may be necessary to manually uninstall packages that no longer" % action
                print "exist in the portage tree since it may not be possible to satisfy their"
                print "dependencies.  Also, be aware of the --with-bdeps option that is documented"
                print "in " + good("`man emerge`") + "."
                print
+               if action == "prune":
+                       print "If you would like to ignore dependencies then use %s." % \
+                               good("--nodeps")
                return
 
+       def show_parents(child_node):
+               parent_nodes = graph.parent_nodes(child_node)
+               parent_nodes.sort()
+               msg = []
+               msg.append("  %s pulled in by:\n" % str(child_node))
+               for parent_node in parent_nodes:
+                       msg.append("    %s\n" % str(parent_node))
+               msg.append("\n")
+               portage.writemsg_stdout("".join(msg), noiselevel=-1)
+
        cleanlist = []
        if action == "depclean":
                if myfiles:
@@ -5518,20 +5573,39 @@ def action_depclean(settings, trees, ldpath_mtimes,
                                except portage.exception.InvalidDependString:
                                        # this error has already been displayed by now
                                        continue
-                               if arg_atom and not fakedb.cpv_exists(pkg):
-                                       cleanlist.append(pkg)
+                               if arg_atom:
+                                       if not fakedb.cpv_exists(pkg):
+                                               cleanlist.append(pkg)
+                                       elif "--verbose" in myopts:
+                                               show_parents(pkg)
                else:
                        for pkg in vardb.cpv_all():
                                if not fakedb.cpv_exists(pkg):
                                        cleanlist.append(pkg)
+                               elif "--verbose" in myopts:
+                                       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("world")
                for atom in args_set:
                        for pkg in vardb.match(atom):
                                if not fakedb.cpv_exists(pkg):
                                        cleanlist.append(pkg)
-               if not cleanlist:
+                               elif "--verbose" in myopts:
+                                       show_parents(pkg)
+
+       if not cleanlist:
+               portage.writemsg_stdout(
+                       ">>> No packages selected for removal by %s\n" % action)
+               if "--verbose" not in myopts:
                        portage.writemsg_stdout(
-                               ">>> No packages selected for removal by %s\n" % action)
+                               ">>> To see reverse dependencies, use %s\n" % \
+                                       good("--verbose"))
+               if action == "prune":
+                       portage.writemsg_stdout(
+                               ">>> To ignore dependencies, use %s\n" % \
+                                       good("--nodeps"))
 
        if len(cleanlist):
                unmerge(settings, myopts, trees[settings["ROOT"]]["vartree"],
index 7502d423d6630ec717b7a6ca5962645f98177f78..def367fd5e1683211e9c65291332d600cce168fa 100644 (file)
@@ -87,7 +87,7 @@ def help(myaction,myopts,havecolor=1):
                print
                print "       "+green("--prune")+" ("+green("-P")+" short option)"
                print "              "+turquoise("WARNING: This action can remove important packages!")
-               print "              Removes all but the most recently installed version of a package"
+               print "              Removes all but the highest installed version of a package"
                print "              from your system. This action doesn't verify the possible binary"
                print "              compatibility between versions and can thus remove essential"
                print "              dependencies from your system."
index be46009d4e5bdb0e8ec8a74beae40578700cfb18..6f1df54ee50ad85d867c7a16d4b6d494286f7a67 100644 (file)
@@ -2774,9 +2774,15 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, locks_in_subdir=".locks",
                                                                if reason[0] == "Insufficient data for checksum verification":
                                                                        return 0
                                                                if can_fetch and not restrict_fetch:
-                                                                       writemsg("Refetching...\n\n",
-                                                                               noiselevel=-1)
-                                                                       os.unlink(myfile_path)
+                                                                       from tempfile import mkstemp
+                                                                       fd, temp_filename = mkstemp("",
+                                                                               myfile + "._checksum_failure_.",
+                                                                               mysettings["DISTDIR"])
+                                                                       os.close(fd)
+                                                                       os.rename(myfile_path, temp_filename)
+                                                                       writemsg_stdout("Refetching... " + \
+                                                                               "File renamed to '%s'\n\n" % \
+                                                                               temp_filename, noiselevel=-1)
                                                        else:
                                                                eout = portage.output.EOutput()
                                                                eout.quiet = \
@@ -2842,6 +2848,14 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, locks_in_subdir=".locks",
                                        myfetch = [varexpand(x, mydict=variables) for x in lexer]
 
                                        spawn_keywords = {}
+                                       # Redirect all output to stdout since some fetchers like
+                                       # wget pollute stderr (if portage detects a problem then it
+                                       # can send it's own message to stderr).
+                                       spawn_keywords["fd_pipes"] = {
+                                               0:sys.stdin.fileno(),
+                                               1:sys.stdout.fileno(),
+                                               2:sys.stdout.fileno()
+                                       }
                                        if "userfetch" in mysettings.features and \
                                                os.getuid() == 0 and portage_gid and portage_uid:
                                                spawn_keywords.update({
@@ -2849,7 +2863,7 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, locks_in_subdir=".locks",
                                                        "gid"    : portage_gid,
                                                        "groups" : userpriv_groups,
                                                        "umask"  : 002})
-
+                                       myret = -1
                                        try:
 
                                                if mysettings.selinux_enabled():
@@ -2898,7 +2912,15 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, locks_in_subdir=".locks",
                                                else:
                                                        # no exception?  file exists. let digestcheck() report
                                                        # an appropriately for size or checksum errors
-                                                       if (mystat[stat.ST_SIZE]<mydigests[myfile]["size"]):
+
+                                                       # If the fetcher reported success and the file is
+                                                       # too small, it's probably because the digest is
+                                                       # bad (upstream changed the distfile).  In this
+                                                       # case we don't want to attempt to resume. Show a
+                                                       # digest verification failure to that the user gets
+                                                       # a clue about what just happened.
+                                                       if myret != os.EX_OK and \
+                                                               mystat.st_size < mydigests[myfile]["size"]:
                                                                # Fetch failed... Try the next one... Kill 404 files though.
                                                                if (mystat[stat.ST_SIZE]<100000) and (len(myfile)>4) and not ((myfile[-5:]==".html") or (myfile[-4:]==".htm")):
                                                                        html404=re.compile("<title>.*(not found|404).*</title>",re.I|re.M)
@@ -2931,8 +2953,15 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, locks_in_subdir=".locks",
                                                                                (reason[1], reason[2]), noiselevel=-1)
                                                                        if reason[0] == "Insufficient data for checksum verification":
                                                                                return 0
-                                                                       writemsg("Removing corrupt distfile...\n", noiselevel=-1)
-                                                                       os.unlink(mysettings["DISTDIR"]+"/"+myfile)
+                                                                       from tempfile import mkstemp
+                                                                       fd, temp_filename = mkstemp("",
+                                                                               myfile + "._checksum_failure_.",
+                                                                               mysettings["DISTDIR"])
+                                                                       os.close(fd)
+                                                                       os.rename(myfile_path, temp_filename)
+                                                                       writemsg_stdout("Refetching... " + \
+                                                                               "File renamed to '%s'\n\n" % \
+                                                                               temp_filename, noiselevel=-1)
                                                                        fetched=0
                                                                else:
                                                                        eout = portage.output.EOutput()
index 29dc60c07670fe91ea37aaf972ec288fcf52a3ea..3e1fbdb2e3ed65d78adb1351ff2acd47034f2eb0 100644 (file)
@@ -77,9 +77,12 @@ class PackageSet(object):
                else:
                        return ""
        
-       def _updateAtomMap(self):
-               self._atommap.clear()
-               for a in self._atoms:
+       def _updateAtomMap(self, atoms=None):
+               """Update self._atommap for specific atoms or all atoms."""
+               if not atoms:
+                       self._atommap.clear()
+                       atoms = self._atoms
+               for a in atoms:
                        cp = dep_getkey(a)
                        self._atommap.setdefault(cp, set())
                        self._atommap[cp].add(a)
@@ -118,7 +121,7 @@ class EditablePackageSet(PackageSet):
        def update(self, atoms):
                self.getAtoms()
                self._atoms.update(atoms)
-               self._updateAtomMap()
+               self._updateAtomMap(atoms=atoms)
                self.write()
        
        def add(self, atom):