Merged from trunk 8085:8102
authorFabian Groffen <grobian@gentoo.org>
Sat, 13 Oct 2007 12:29:59 +0000 (12:29 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 13 Oct 2007 12:29:59 +0000 (12:29 -0000)
   | 8086    | Bug #195527 - Unconditionally detect file collisions and log |
   | zmedico | them as eerror messages via elog. This will allow us to      |
   |         | collect more file collision data but it won't be quite as    |
   |         | annoying as enabling collision-protect by default would be.  |

   | 8087    | Bug #195527 - Add some more information to the file          |
   | zmedico | collision eerror message to try and prevent user confusion:  |
   |         | - Hint that `equery belongs ` can be used to find the        |
   |         | installed package that owns a file. - Advise then NOT to     |
   |         | file a bug without reporting exactly which two packages      |
   |         | install the same file(s).                                    |

   | 8089    | s:this package wants:this package will:                      |
   | zmedico |                                                              |

   | 8091    | Remove a redundant call to elog_process().                   |
   | zmedico |                                                              |

   | 8093    | Bug #195370 - Filter some more bogus matches due to          |
   | zmedico | old-style virtuals.                                          |

   | 8096    | In dblink.treewalk(), use os.walk() instead of               |
   | zmedico | portage.listdir() in order to avoid cacheddir() bloat when   |
   |         | listing the files to be merged from ${D}.                    |

   | 8097    | Use os.listdir() instead of portage.listdir() in             |
   | zmedico | dblink.mergeme().                                            |

   | 8098    | Remove a chdir() call that's no longer needed for the        |
   | zmedico | collision-protect symlink code.                              |

   | 8100    | Make the file collision eerror message less verbose when in  |
   | zmedico | --quiet mode.                                                |

   | 8102    | Handle the PortageException that can be raised from          |
   | zmedico | portage.mail.send_mail().                                    |

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

pym/emerge/__init__.py
pym/portage/dbapi/vartree.py
pym/portage/elog/mod_mail.py

index a0c70fac6b8a151301846f0090081b7833ebcdeb..3308932dbd3f6e7cb96404c682e97f3ba040e09e 100644 (file)
@@ -3115,12 +3115,16 @@ class depgraph(object):
                                #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty"
                                #param is used for -u, where you still *do* want to see when something is being upgraded.
                                myoldbest=""
+                               installed_versions = vardb.match(portage.cpv_getkey(pkg_key))
                                if vardb.cpv_exists(pkg_key):
                                        addl="  "+yellow("R")+fetch+"  "
                                        if x[3] != "nomerge":
                                                if ordered:
                                                        counters.reinst += 1
-                               elif vardb.match(portage.dep_getkey(pkg_key)):
+                               # filter out old-style virtual matches
+                               elif installed_versions and \
+                                       portage.cpv_getkey(installed_versions[0]) == \
+                                       portage.cpv_getkey(pkg_key):
                                        mynewslot = mydbapi.aux_get(pkg_key, ["SLOT"])[0]
                                        slot_atom = "%s:%s" % \
                                                (portage.cpv_getkey(pkg_key), mynewslot)
index 207cca8bfafd3630505accb42e80dc123cb93f91..4fc590a467bcf9d508eefd0a357e32bb61e8489a 100644 (file)
@@ -1477,12 +1477,6 @@ class dblink(object):
        def _collision_protect(self, srcroot, destroot, mypkglist, mycontents, mysymlinks):
                        collision_ignore = set([normalize_path(myignore) for myignore in \
                                self.settings.get("COLLISION_IGNORE", "").split()])
-
-                       # the linkcheck only works if we are in srcroot
-                       mycwd = os.getcwd()
-                       os.chdir(srcroot)
-
-
                        mysymlinked_directories = [s + os.path.sep for s in mysymlinks]
                        del mysymlinks
 
@@ -1546,7 +1540,6 @@ class dblink(object):
                                                isowned = True
                                                break
                                if not isowned:
-                                       collisions.append(f)
                                        stopmerge = True
                                        if collision_ignore:
                                                if f in collision_ignore:
@@ -1556,7 +1549,9 @@ class dblink(object):
                                                                if f.startswith(myignore + os.path.sep):
                                                                        stopmerge = False
                                                                        break
-                       if stopmerge:
+                                       if stopmerge:
+                                               collisions.append(f)
+                       if stopmerge and "collision-protect" in self.settings.features:
                                print red("*")+" This package is blocked because it wants to overwrite"
                                print red("*")+" files belonging to other packages (see list below)."
                                print red("*")+" If you have no clue what this is all about report it "
@@ -1600,10 +1595,7 @@ class dblink(object):
                                        print "None of the installed packages claim the above file(s)."
                                        print
                                sys.exit(1)
-                       try:
-                               os.chdir(mycwd)
-                       except OSError:
-                               pass
+                       return collisions
 
        def _security_check(self, installed_instances):
                if not installed_instances:
@@ -1686,6 +1678,9 @@ class dblink(object):
                secondhand is a list of symlinks that have been skipped due to their target
                not existing; we will merge these symlinks at a later time.
                """
+
+               srcroot = normalize_path(srcroot).rstrip(os.path.sep) + os.path.sep
+
                if not os.path.isdir(srcroot):
                        writemsg("!!! Directory Not Found: D='%s'\n" % srcroot,
                                noiselevel=-1)
@@ -1736,25 +1731,26 @@ class dblink(object):
                #       has to be before the counter is written) - genone
                counter = self.vartree.dbapi.counter_tick(self.myroot, mycpv=self.mycpv)
 
-               myfilelist = None
-               mylinklist = None
+               myfilelist = []
+               mylinklist = []
+               def onerror(e):
+                       raise
+               for parent, dirs, files in os.walk(srcroot, onerror=onerror):
+                       for f in files:
+                               file_path = os.path.join(parent, f)
+                               file_mode = os.lstat(file_path).st_mode
+                               if stat.S_ISREG(file_mode):
+                                       myfilelist.append(file_path[len(srcroot):])
+                               elif stat.S_ISLNK(file_mode):
+                                       mylinklist.append(file_path[len(srcroot):])
 
                # Preserve old libs if they are still in use
                if slot_matches and "preserve-libs" in self.settings.features:
-                       myfilelist = listdir(srcroot, recursive=1, filesonly=1, followSymlinks=False)
-                       mylinklist = filter(os.path.islink, [os.path.join(srcroot, x) for x in listdir(srcroot, recursive=1, filesonly=0, followSymlinks=False)])
-                       mylinklist = [x[len(srcroot):] for x in mylinklist]
                        self._preserve_libs(srcroot, destroot, myfilelist+mylinklist, counter)
 
                # check for package collisions
-               if "collision-protect" in self.settings.features:
-                       if myfilelist == None:
-                               myfilelist = listdir(srcroot, recursive=1, filesonly=1, followSymlinks=False)
-                       if mylinklist == None:
-                               mylinklist = filter(os.path.islink, [os.path.join(srcroot, x) for x in listdir(srcroot, recursive=1, filesonly=0, followSymlinks=False)])
-                               mylinklist = [x[len(srcroot):] for x in mylinklist]
-                       self._collision_protect(srcroot, destroot, others_in_slot,
-                               myfilelist+mylinklist, mylinklist)
+               collisions = self._collision_protect(srcroot, destroot, others_in_slot,
+                       myfilelist+mylinklist, mylinklist)
 
                if True:
                        """ The merge process may move files out of the image directory,
@@ -1781,6 +1777,41 @@ class dblink(object):
                        use_cache=0, tree=self.treetype, mydbapi=mydbapi,
                        vartree=self.vartree)
 
+               if collisions:
+                       msg = "This package will overwrite one or more files that" + \
+                       " may belong to other packages (see list below)." + \
+                       " Add \"collision-protect\" to FEATURES in make.conf" + \
+                       " if you would like the merge to abort in cases like this."
+                       if self.settings.get("PORTAGE_QUIET") != "1":
+                               msg += " If you have determined that one or more of the" + \
+                               " files actually belong to another installed package then" + \
+                               " go to http://bugs.gentoo.org and report it as a bug." + \
+                               " Be sure to identify both this package and the other" + \
+                               " installed package in the bug report. Use a command such" + \
+                               " as \\`equery belongs <filename>\\` to identify the" + \
+                               " installed package that owns a file. Do NOT file a bug" + \
+                               " without reporting exactly which two packages install" + \
+                               " the same file(s)."
+
+                       self.settings["EBUILD_PHASE"] = "preinst"
+                       cmd = "source '%s/isolated-functions.sh' ; " % PORTAGE_BIN_PATH
+                       from textwrap import wrap
+                       msg = wrap(msg, 70)
+                       for line in msg:
+                               cmd += "eerror \"%s\" ; " % line
+                       cmd += "eerror ; "
+                       cmd += "eerror \"Detected file collision(s):\" ; "
+                       cmd += "eerror ; "
+
+                       from portage.output import colorize
+                       for f in collisions:
+                               cmd += "eerror \"     '%s'\" ; " % colorize("INFORM",
+                                       os.path.join(destroot, f.lstrip(os.path.sep)))
+
+                       from portage import process
+                       process.spawn(["bash", "-c", cmd],
+                               env=self.settings.environ())
+
                # XXX: Decide how to handle failures here.
                if a != os.EX_OK:
                        writemsg("!!! FAILED preinst: "+str(a)+"\n", noiselevel=-1)
@@ -1953,7 +1984,7 @@ class dblink(object):
                # this is supposed to merge a list of files.  There will be 2 forms of argument passing.
                if isinstance(stufftomerge, basestring):
                        #A directory is specified.  Figure out protection paths, listdir() it and process it.
-                       mergelist = listdir(join(srcroot, stufftomerge))
+                       mergelist = os.listdir(join(srcroot, stufftomerge))
                        offset = stufftomerge
                else:
                        mergelist = stufftomerge
index c9fa5b5639b1bb874db7c4217ae1ba8ac6b0a09d..922ea08465edb474f9ada34af0b1fc9c5240cc1e 100644 (file)
@@ -4,6 +4,8 @@
 # $Id$
 
 import portage.mail, socket
+from portage.exception import PortageException
+from portage.util import writemsg
 
 def process(mysettings, key, logentries, fulltext):
        if mysettings.has_key("PORTAGE_ELOG_MAILURI"):
@@ -32,6 +34,9 @@ def process(mysettings, key, logentries, fulltext):
        mysubject = mysubject.replace("${ACTION}", action)
 
        mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, fulltext)
-       portage.mail.send_mail(mysettings, mymessage)
+       try:
+               portage.mail.send_mail(mysettings, mymessage)
+       except PortageException, e:
+               writemsg("%s\n" % str(e), noiselevel=-1)
 
        return