Merged from trunk 6834:6860
authorFabian Groffen <grobian@gentoo.org>
Fri, 22 Jun 2007 08:31:09 +0000 (08:31 -0000)
committerFabian Groffen <grobian@gentoo.org>
Fri, 22 Jun 2007 08:31:09 +0000 (08:31 -0000)
   +------------------------------------------------------------------------+
   | 6835    | Add portageq command to list preserved libs                  |
   | genone  |                                                              |
   |---------+--------------------------------------------------------------|
   | 6836    | Get registry object from vardbapi directly instead of        |
   | genone  | creating another one                                         |
   |---------+--------------------------------------------------------------|
   | 6837    | For bug #181953, prevent the circular_blocks code from       |
   | zmedico | selecting a node that's already been selected by the normal  |
   |         | node selection process.                                      |
   |---------+--------------------------------------------------------------|
   | 6839    | Pass all the of the existing package databases into          |
   | zmedico | post_emerge() so that we can use them for news and           |
   |         | preserve-libs.                                               |
   |---------+--------------------------------------------------------------|
   | 6840    | Make display_news_notification() reuse the existing          |
   | zmedico | portdbapi instance.                                          |
   |---------+--------------------------------------------------------------|
   | 6841    | Pass existing portdbapi and vardbapi instances into the      |
   | zmedico | NewsManager constructor.                                     |
   |---------+--------------------------------------------------------------|
   | 6843    | Fix broken \!found logic so that any missing files are       |
   | zmedico | properly skipped.                                            |
   |---------+--------------------------------------------------------------|
   | 6846    | For bug #182105, fix the spelling of the fd_pipes paremeter. |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 6848    | For bug #182157, never chmod 0 symlinks before unlinking     |
   | zmedico | them.                                                        |
   |---------+--------------------------------------------------------------|
   | 6850    | For bug #182157, don't let unmerge-orphans unlink symlinks   |
   | zmedico | to directories since that can remove /lib and /usr/lib       |
   |         | symlinks.                                                    |
   |---------+--------------------------------------------------------------|
   | 6852    | Handle another case where removing a symlink to a directory  |
   | zmedico | can be harmful.                                              |
   |---------+--------------------------------------------------------------|
   | 6854    | For bug #182021, use active voice when notifying the user    |
   | zmedico | that superuser access is required.                           |
   |---------+--------------------------------------------------------------|
   | 6856    | Make repoman exit with nonzero status whenever there are qa  |
   | zmedico | issues (already does the same in commit mode). Thanks to     |
   |         | Daniel Gryniewicz <dang@gentoo.org> in bug #182166.          |
   |---------+--------------------------------------------------------------|
   | 6858    | Make the collision-protect loop check for existance of the   |
   | zmedico | destination file before checking if it's owned.              |
   |---------+--------------------------------------------------------------|
   | 6860    | Go ahead and unlink symlinks to directories when they're     |
   | zmedico | actually recorded as symlinks in the contents.               |
   +------------------------------------------------------------------------+

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

bin/portageq
bin/repoman
pym/emerge/__init__.py
pym/portage/dbapi/vartree.py
pym/portage/news.py
pym/portage/output.py

index 949fd159b2648a36f0e9d5a9f655fd4cdf0f7617..16c0c67c61c57a20037e18e3302cc640f81e7aaa 100755 (executable)
@@ -44,7 +44,6 @@ import types
 # and will automaticly add a command by the same name as the function!
 #
 
-
 def has_version(argv):
        """<root> <category/package>
        Return code 0 if it's available, 1 otherwise.
@@ -284,6 +283,24 @@ def get_repo_path(argv):
        for arg in arvg[1:]:
                print portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(argv[1])
 
+def list_preserved_libs(argv):
+       """<root>
+       Print a list of libraries preserved during a package update in the form
+       package: path. Returns 0 if no preserved libraries could be found, 
+       1 otherwise.
+       """
+
+       if len(argv) != 1:
+               print "ERROR: wrong number of arguments"
+               sys.exit(2)
+       mylibs = portage.db[argv[0]]["vartree"].dbapi.plib_registry.getPreservedLibs()
+       rValue = 0
+       for cpv in mylibs.keys():
+               for path in mylibs[cpv]:
+                       print "%s: %s" % (cpv, path)
+                       rValue = 1
+       return rValue
+
 #-----------------------------------------------------------------------------
 #
 # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
@@ -301,11 +318,12 @@ def usage(argv):
        # Show our commands -- we do this by scanning the functions in this
        # file, and formatting each functions documentation.
        #
-       for name in globals().keys():
-               # Drop python stuff, modules, and our own support functions.
-               if (name in ("usage", "__doc__", "__name__", "main", "os", "portage", "sys", "__builtins__", "types", "string","exithandler")):
-                       continue
+       commands = [x for x in globals().keys() if x not in \
+                               ("usage", "__doc__", "__name__", "main", "os", "portage", \
+                               "sys", "__builtins__", "types", "string","exithandler")]
+       commands.sort()
 
+       for name in commands:
                # Drop non-functions
                obj = globals()[name]
                if  (type(obj) != types.FunctionType):
index 6b53577a06162ddc9407aab628a8edbf369e67df..7410d8b4c74848d665f9c4105885ee1d2785ed95 100755 (executable)
@@ -1615,6 +1615,10 @@ if mymode!="commit":
                        print green("RepoMan sez:"),"\"OK for now, but I'll be back ...\""
        elif not dofail:
                print green("RepoMan sez:"),"\"If everyone were like you, I'd be out of business!\""
+       elif dofail:
+               print turquoise("Please fix these important QA issues first.")
+               print green("RepoMan sez:"),"\"Make your QA payment on time and you'll never see the likes of me.\"\n"
+               sys.exit(1)
        if quiet < 1:
                print
 elif "--pretend" not in myoptions:
index 8727583518d363d022ab83cb91de94794e489911..eab3fcd9ef11e03e2bf38ce403be79feeb53c40e 100644 (file)
@@ -31,7 +31,7 @@ except ImportError:
        import portage
 del os.environ["PORTAGE_LEGACY_GLOBALS"]
 from portage import digraph, portdbapi
-from portage.const import NEWS_LIB_PATH, CACHE_PATH
+from portage.const import NEWS_LIB_PATH, CACHE_PATH, PRIVATE_PATH
 
 import emerge.help
 import portage.xpak, commands, errno, re, socket, time, types
@@ -2121,8 +2121,16 @@ class depgraph:
                                        if not circular_blocks:
                                                circular_blocks = True
                                                blocker_deps = myblockers.leaf_nodes()
-                                       if blocker_deps:
-                                               selected_nodes = [blocker_deps.pop()]
+                                       while blocker_deps:
+                                               # Some of these nodes might have already been selected
+                                               # by the normal node selection process after the
+                                               # circular_blocks flag has been set.  Therefore, we
+                                               # have to verify that they're still in the graph so
+                                               # that they're not selected more than once.
+                                               node = blocker_deps.pop()
+                                               if mygraph.contains(node):
+                                                       selected_nodes = [node]
+                                                       break
 
                        if not selected_nodes:
                                # No leaf nodes are available, so we have a circular
@@ -3781,15 +3789,20 @@ def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
                                print " "+green("*")+" Processed",icount,"info files."
 
 
-def display_news_notification(settings):
-       target_root = settings["ROOT"]
+def display_news_notification(trees):
+       for target_root in trees:
+               if len(trees) > 1 and target_root != "/":
+                       break
+       settings = trees[target_root]["vartree"].settings
+       portdb = trees[target_root]["porttree"].dbapi
+       vardb = trees[target_root]["vartree"].dbapi
        NEWS_PATH = os.path.join("metadata", "news")
        UNREAD_PATH = os.path.join(target_root, NEWS_LIB_PATH, "news")
-       porttree = portdbapi(porttree_root=settings["PORTDIR"], mysettings=settings)
        newsReaderDisplay = False
 
-       for repo in porttree.getRepositories():
-               unreadItems = checkUpdatedNewsItems(target_root, NEWS_PATH, UNREAD_PATH, repo)
+       for repo in portdb.getRepositories():
+               unreadItems = checkUpdatedNewsItems(
+                       portdb, vardb, NEWS_PATH, UNREAD_PATH, repo)
                if unreadItems:
                        if not newsReaderDisplay:
                                newsReaderDisplay = True
@@ -3803,7 +3816,7 @@ def display_news_notification(settings):
                print "Use " + colorize("GOOD", "eselect news") + " to read news items."
                print
 
-def post_emerge(settings, mtimedb, retval):
+def post_emerge(trees, mtimedb, retval):
        """
        Misc. things to run at the end of a merge session.
        
@@ -3813,9 +3826,9 @@ def post_emerge(settings, mtimedb, retval):
        Commit mtimeDB
        Display preserved libs warnings
        Exit Emerge
-       
-       @param settings: Configuration settings (typically portage.settings)
-       @type settings: portage.config()
+
+       @param trees: A dictionary mapping each ROOT to it's package databases
+       @type trees: dict
        @param mtimedb: The mtimeDB to store data needed across merge invocations
        @type mtimedb: MtimeDB class instance
        @param retval: Emerge's return value
@@ -3824,7 +3837,11 @@ def post_emerge(settings, mtimedb, retval):
        @returns:
        1.  Calls sys.exit(retval)
        """
-       target_root = settings["ROOT"]
+       for target_root in trees:
+               if len(trees) > 1 and target_root != "/":
+                       break
+       vardbapi = trees[target_root]["vartree"].dbapi
+       settings = vardbapi.settings
        info_mtimes = mtimedb["info"]
 
        # Load the most current variables from ${ROOT}/etc/profile.env
@@ -3846,13 +3863,11 @@ def post_emerge(settings, mtimedb, retval):
                chk_updated_info_files(normalize_path(target_root + EPREFIX), infodirs, info_mtimes, retval)
        chk_updated_cfg_files(normalize_path(target_root + EPREFIX), config_protect)
        
-       display_news_notification(settings)
+       display_news_notification(trees)
        
-       from portage.dbapi.vartree import PreservedLibsRegistry
-       plib_registry = PreservedLibsRegistry(os.path.join(target_root, CACHE_PATH, "preserved_libs_registry"))
-       if plib_registry.hasEntries():
+       if vardbapi.plib_registry.hasEntries():
                print colorize("WARN", "!!!") + " existing preserved libs:"
-               plibdata = plib_registry.getPreservedLibs()
+               plibdata = vardbapi.plib_registry.getPreservedLibs()
                for cpv in plibdata.keys():
                        print colorize("WARN", ">>>") + " package: %s" % cpv
                        for f in plibdata[cpv]:
@@ -3898,13 +3913,15 @@ def chk_updated_cfg_files(target_root, config_protect):
                        #print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
                        print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
 
-def checkUpdatedNewsItems( root, NEWS_PATH, UNREAD_PATH, repo_id ):
+def checkUpdatedNewsItems(portdb, vardb, NEWS_PATH, UNREAD_PATH, repo_id):
        """
        Examines news items in repodir + '/' + NEWS_PATH and attempts to find unread items
        Returns the number of unread (yet relevent) items.
        
-       @param root:
-       @type root:
+       @param portdb: a portage tree database
+       @type portdb: pordbapi
+       @param vardb: an installed package database
+       @type vardb: vardbapi
        @param NEWS_PATH:
        @type NEWS_PATH:
        @param UNREAD_PATH:
@@ -3917,7 +3934,7 @@ def checkUpdatedNewsItems( root, NEWS_PATH, UNREAD_PATH, repo_id ):
        
        """
        from portage.news import NewsManager
-       manager = NewsManager( root, NEWS_PATH, UNREAD_PATH )
+       manager = NewsManager(portdb, vardb, NEWS_PATH, UNREAD_PATH)
        return manager.getUnreadItems( repo_id, update=True )
 
 def is_valid_package_atom(x):
@@ -4454,7 +4471,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                print red(" * ")+"To update portage, run 'emerge portage'."
                print
        
-       display_news_notification(settings)
+       display_news_notification(trees)
 
 def action_metadata(settings, portdb, myopts):
        portage.writemsg_stdout("\n>>> Updating Portage cache:      ")
@@ -5647,12 +5664,12 @@ def emerge_main():
                                if "--ask" in myopts:
                                        myopts["--pretend"] = True
                                        del myopts["--ask"]
-                                       print ("%s access would be required... " + \
+                                       print ("%s access is required... " + \
                                                "adding --pretend to options.\n") % access_desc
                                        if portage.secpass < 1 and not need_superuser:
                                                portage_group_warning()
                                else:
-                                       sys.stderr.write(("emerge: %s access would be " + \
+                                       sys.stderr.write(("emerge: %s access is " + \
                                                "required.\n\n") % access_desc)
                                        if portage.secpass < 1 and not need_superuser:
                                                portage_group_warning()
@@ -5734,25 +5751,25 @@ def emerge_main():
                if 1 == unmerge(settings, myopts, vartree, myaction, myfiles,
                        mtimedb["ldpath"]):
                        if "--pretend" not in myopts:
-                               post_emerge(settings, mtimedb, 0)
+                               post_emerge(trees, mtimedb, os.EX_OK)
 
        elif "depclean"==myaction:
                validate_ebuild_environment(trees)
                action_depclean(settings, trees, mtimedb["ldpath"],
                        myopts, spinner)
                if "--pretend" not in myopts:
-                       post_emerge(settings, mtimedb, 0)
+                       post_emerge(trees, mtimedb, os.EX_OK)
        # "update", "system", or just process files:
        else:
                validate_ebuild_environment(trees)
                if "--pretend" not in myopts:
-                       display_news_notification(settings)
+                       display_news_notification(trees)
                action_build(settings, trees, mtimedb,
                        myopts, myaction, myfiles, spinner)
                if "--pretend" not in myopts:
-                       post_emerge(settings, mtimedb, 0)
+                       post_emerge(trees, mtimedb, os.EX_OK)
                else:
-                       display_news_notification(settings)
+                       display_news_notification(trees)
 
 if __name__ == "__main__":
        retval = emerge_main()
index 04591b1cca7d681fa682d4a9ea3225ca3f9f83f2..9cc678c6200e567ff644e51eb40cec0e403fab56 100644 (file)
@@ -189,8 +189,8 @@ class vardbapi(dbapi):
                self._aux_cache_filename = os.path.join(self.root,
                        CACHE_PATH.lstrip(os.path.sep), "vdb_metadata.pickle")
 
-               self.libmap = LibraryPackageMap(os.path.join(self.root, CACHE_PATH, "library_consumers"), self)
-               self.plib_registry = PreservedLibsRegistry(os.path.join(self.root, CACHE_PATH, "preserved_libs_registry"))
+               self.libmap = LibraryPackageMap(os.path.join(self.root, CACHE_PATH.lstrip(os.sep), "library_consumers"), self)
+               self.plib_registry = PreservedLibsRegistry(os.path.join(self.root, PRIVATE_PATH, "preserved_libs_registry"))
 
        def getpath(self, mykey, filename=None):
                rValue = os.path.join(self.root, VDB_PATH, mykey)
@@ -1181,12 +1181,8 @@ class dblink(object):
                                except (OSError, AttributeError):
                                        pass
                                islink = lstatobj is not None and stat.S_ISLNK(lstatobj.st_mode)
-                               if not unmerge_orphans and statobj is None:
-                                       if not islink:
-                                               #we skip this if we're dealing with a symlink
-                                               #because os.stat() will operate on the
-                                               #link target rather than the link itself.
-                                               writemsg_stdout("--- !found " + str(pkgfiles[objkey][0]) + " %s\n" % obj)
+                               if lstatobj is None:
+                                               writemsg_stdout("--- !found %s %s\n" % (file_type, obj))
                                                continue
                                # next line includes a tweak to protect modules from being unmerged,
                                # but we don't protect modules from being overwritten if they are
@@ -1197,13 +1193,16 @@ class dblink(object):
                                        writemsg_stdout("--- cfgpro %s %s\n" % (pkgfiles[objkey][0], obj))
                                        continue
 
+                               # Don't unlink symlinks to directories here since that can
+                               # remove /lib and /usr/lib symlinks.
                                if unmerge_orphans and \
                                        lstatobj and not stat.S_ISDIR(lstatobj.st_mode) and \
+                                       not (islink and statobj and stat.S_ISDIR(statobj.st_mode)) and \
                                        not self.isprotected(obj):
                                        try:
                                                # Remove permissions to ensure that any hardlinks to
                                                # suid/sgid files are rendered harmless.
-                                               if statobj:
+                                               if statobj and not islink:
                                                        os.chmod(obj, 0)
                                                os.unlink(obj)
                                        except EnvironmentError, e:
@@ -1225,6 +1224,13 @@ class dblink(object):
                                        if not islink:
                                                writemsg_stdout("--- !sym   %s %s\n" % ("sym", obj))
                                                continue
+                                       # Go ahead and unlink symlinks to directories here when
+                                       # they're actually recorded as symlinks in the contents.
+                                       # Normally, symlinks such as /lib -> lib64 are not recorded
+                                       # as symlinks in the contents of a package.  If a package
+                                       # installs something into ${D}/lib/, it is recorded in the
+                                       # contents as a directory even if it happens to correspond
+                                       # to a symlink when it's merged to the live filesystem.
                                        try:
                                                os.unlink(obj)
                                                writemsg_stdout("<<<        %s %s\n" % ("sym", obj))
@@ -1411,6 +1417,15 @@ class dblink(object):
                                i = i + 1
                                if i % 1000 == 0:
                                        print str(i)+" files checked ..."
+                               dest_path = normalize_path(
+                                       os.path.join(destroot, f.lstrip(os.path.sep)))
+                               try:
+                                       dest_lstat = os.lstat(dest_path)
+                               except EnvironmentError, e:
+                                       if e.errno != errno.ENOENT:
+                                               raise
+                                       del e
+                                       continue
                                if f[0] != "/":
                                        f="/"+f
                                isowned = False
index 3cfb5de12b966cf82d4f6da478d358637cf3be99..0288058760c68758d0442678cd1b9bc7250b9cc7 100644 (file)
@@ -4,7 +4,6 @@
 # $Id$
 
 from portage.const import INCREMENTALS, PROFILE_PATH, NEWS_LIB_PATH
-from portage import config, vartree, vardbapi, portdbapi
 from portage.util import ensure_dirs, apply_permissions
 from portage.data import portage_gid
 from portage.locks import lockfile, unlockfile, lockdir, unlockdir
@@ -26,17 +25,16 @@ class NewsManager(object):
 
        TIMESTAMP_FILE = "news-timestamp"
 
-       def __init__(self, root, NEWS_PATH, UNREAD_PATH, LANGUAGE_ID='en'):
+       def __init__(self, portdb, vardb, NEWS_PATH, UNREAD_PATH, LANGUAGE_ID='en'):
                self.NEWS_PATH = NEWS_PATH
                self.UNREAD_PATH = UNREAD_PATH
-               self.TIMESTAMP_PATH = os.path.join(root, NEWS_LIB_PATH, NewsManager.TIMESTAMP_FILE)
-               self.target_root = root
+               self.TIMESTAMP_PATH = os.path.join(vardb.root,
+                       NEWS_LIB_PATH, NewsManager.TIMESTAMP_FILE)
+               self.target_root = vardb.root
                self.LANGUAGE_ID = LANGUAGE_ID
-               self.config = config(config_root = os.environ.get("PORTAGE_CONFIGROOT", "/"),
-                               target_root = root, config_incrementals = INCREMENTALS)
-               self.vdb = vardbapi(settings = self.config, root = root,
-                       vartree = vartree(root = root, settings = self.config))
-               self.portdb = portdbapi(porttree_root = self.config["PORTDIR"], mysettings = self.config)
+               self.config = vardb.settings
+               self.vdb = vardb
+               self.portdb = portdb
 
                # Ensure that the unread path exists and is writable.
                dirmode  = 02070
index 301832cccab6c8cc3984f2707ab76abeb5f3c78a..7efde92a957741d2b5d77afe33a70631ed05389f 100644 (file)
@@ -202,7 +202,7 @@ def xtermTitleReset():
                                        shell = find_binary("sh")
                                if shell:
                                        spawn([shell, "-c", prompt_command], env=os.environ,
-                                               fdpipes={0:sys.stdin.fileno(),1:sys.stderr.fileno(),
+                                               fd_pipes={0:sys.stdin.fileno(),1:sys.stderr.fileno(),
                                                2:sys.stderr.fileno()})
                                else:
                                        os.system(prompt_command)