From: Fabian Groffen Date: Fri, 22 Jun 2007 08:31:09 +0000 (-0000) Subject: Merged from trunk 6834:6860 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=13680f6e9996bac715d958d45a4cc4c9da6e18bd;p=portage.git Merged from trunk 6834:6860 +------------------------------------------------------------------------+ | 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 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 --- diff --git a/bin/portageq b/bin/portageq index 949fd159b..16c0c67c6 100755 --- a/bin/portageq +++ b/bin/portageq @@ -44,7 +44,6 @@ import types # and will automaticly add a command by the same name as the function! # - def has_version(argv): """ 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): + """ + 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): diff --git a/bin/repoman b/bin/repoman index 6b53577a0..7410d8b4c 100755 --- a/bin/repoman +++ b/bin/repoman @@ -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: diff --git a/pym/emerge/__init__.py b/pym/emerge/__init__.py index 872758351..eab3fcd9e 100644 --- a/pym/emerge/__init__.py +++ b/pym/emerge/__init__.py @@ -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() diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 04591b1cc..9cc678c62 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -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 diff --git a/pym/portage/news.py b/pym/portage/news.py index 3cfb5de12..028805876 100644 --- a/pym/portage/news.py +++ b/pym/portage/news.py @@ -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 diff --git a/pym/portage/output.py b/pym/portage/output.py index 301832ccc..7efde92a9 100644 --- a/pym/portage/output.py +++ b/pym/portage/output.py @@ -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)