From f508e99115617b1cdb395e07608ea7d2c73b97f3 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Sat, 15 Nov 2008 16:15:00 +0000 Subject: [PATCH] Merged from trunk -r11833:11841 | 11834 | Update docstring for dblink._find_libs_to_preserve(). | | zmedico | | | 11835 | Handle a corner case inside | | zmedico | dblink._add_preserve_libs_to_contents() in which a path to | | | be preserved doesn't exist in the contents of the installed | | | instance. | | 11836 | When adding parent directories to contents inside | | zmedico | dblink._add_preserve_libs_to_contents(), account for the | | | trailing slash on $ROOT in the while loop. | | 11837 | Add PROPERTIES=interactive support in depgraph.display() and | | zmedico | the PackageCounters class. | | 11838 | Move initialization of Scheduler._background from the | | zmedico | constructor to the merge() method so that a potential | | | InvalidDependString exception can be handled there, causing | | | merge() to return unsuccessfully. This avoids having to | | | raise an exception from the constructor. | | 11839 | Inside Scheduler._reverse_uninstall_edges(), iover all nodes | | zmedico | rather than just the merge list, because some uninstall | | | nodes may not be in the merge list since they will be | | | performed as part of an upgrade within a slot. This solves a | | | problem with Scheduler._choose_pkg() not parallelizing in | | | some cases when it should, due to an uninstall node not | | | having it's edge reversed like it's supposed to. | | 11840 | Make show_invalid_depstring_notice() send output to stderr | | zmedico | via writemsg_level(). | | 11841 | Remove unused formatter code in | | zmedico | show_invalid_depstring_notice(). | svn path=/main/branches/prefix/; revision=11940 --- pym/_emerge/__init__.py | 90 ++++++++++++++++++++++++------------ pym/portage/dbapi/vartree.py | 25 ++++++---- 2 files changed, 78 insertions(+), 37 deletions(-) diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 0dcf2f193..1d07875e5 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -4022,17 +4022,8 @@ class BlockerDB(object): def show_invalid_depstring_notice(parent_node, depstring, error_msg): - from formatter import AbstractFormatter, DumbWriter - f = AbstractFormatter(DumbWriter(maxcol=72)) - - print "\n\n!!! Invalid or corrupt dependency specification: " - print - print error_msg - print - print parent_node - print - print depstring - print + msg1 = "\n\n!!! Invalid or corrupt dependency specification: " + \ + "\n\n%s\n\n%s\n\n%s\n\n" % (error_msg, parent_node, depstring) p_type, p_root, p_key, p_status = parent_node msg = [] if p_status == "nomerge": @@ -4047,13 +4038,12 @@ def show_invalid_depstring_notice(parent_node, depstring, error_msg): msg.append("the problematic dependencies can be found in the ") msg.append("*DEPEND files located in '%s/'." % pkg_location) else: - msg.append("This package can not be installed. ") + msg.append("This package can not be installed. ") msg.append("Please notify the '%s' package maintainer " % p_key) msg.append("about this problem.") - for x in msg: - f.add_flowing_data(x) - f.end_paragraph(1) + msg2 = "".join("%s\n" % line for line in textwrap.wrap("".join(msg), 72)) + writemsg_level(msg1 + msg2, level=logging.ERROR, noiselevel=-1) class PackageVirtualDbapi(portage.dbapi): """ @@ -7451,6 +7441,22 @@ class depgraph(object): else: return colorize("PKG_NOMERGE", pkg_str) + try: + properties = flatten(use_reduce(paren_reduce( + pkg.metadata["PROPERTIES"]), uselist=pkg.use.enabled)) + except portage.exception.InvalidDependString, e: + if not pkg.installed: + show_invalid_depstring_notice(pkg, + pkg.metadata["PROPERTIES"], str(e)) + del e + return 1 + properties = [] + interactive = "interactive" in properties + if interactive and pkg.operation == "merge": + addl = colorize("WARN", "I") + addl[1:] + if ordered: + counters.interactive += 1 + if x[1]!="/": if myoldbest: myoldbest +=" " @@ -8210,6 +8216,7 @@ class PackageCounters(object): self.totalsize = 0 self.restrict_fetch = 0 self.restrict_fetch_satisfied = 0 + self.interactive = 0 def __str__(self): total_installs = self.upgrades + self.downgrades + self.newslot + self.new + self.reinst @@ -8242,6 +8249,9 @@ class PackageCounters(object): details.append("%s uninstall" % self.uninst) if self.uninst > 1: details[-1] += "s" + if self.interactive > 0: + details.append("%s %s" % (self.interactive, + colorize("WARN", "interactive"))) myoutput.append(", ".join(details)) if total_installs != 0: myoutput.append(")") @@ -9071,6 +9081,14 @@ class Scheduler(PollScheduler): def deallocate(self, settings): self._deallocate(settings) + class _unknown_internal_error(portage.exception.PortageException): + """ + Used internally to terminate scheduling. The specific reason for + the failure should have been dumped to stderr. + """ + def __init__(self, value=""): + portage.exception.PortageException.__init__(self, value) + def __init__(self, settings, trees, mtimedb, myopts, spinner, mergelist, favorites, digraph): PollScheduler.__init__(self) @@ -9102,8 +9120,6 @@ class Scheduler(PollScheduler): if max_jobs is None: max_jobs = 1 self._set_max_jobs(max_jobs) - background = self._background_mode() - self._background = background # The root where the currently running # portage instance is installed. @@ -9115,15 +9131,6 @@ class Scheduler(PollScheduler): self._config_pool = {} self._blocker_db = {} for root in trees: - root_config = trees[root]["root_config"] - if background: - root_config.settings.unlock() - root_config.settings["PORTAGE_BACKGROUND"] = "1" - root_config.settings.backup_changes("PORTAGE_BACKGROUND") - root_config.settings.lock() - - self.pkgsettings[root] = portage.config( - clone=trees[root]["vartree"].settings) self._config_pool[root] = [] self._blocker_db[root] = BlockerDB(trees[root]["root_config"]) @@ -9262,8 +9269,13 @@ class Scheduler(PollScheduler): if not (isinstance(task, Package) and \ task.operation == "merge"): continue - properties = flatten(use_reduce(paren_reduce( - task.metadata["PROPERTIES"]), uselist=task.use.enabled)) + try: + properties = flatten(use_reduce(paren_reduce( + task.metadata["PROPERTIES"]), uselist=task.use.enabled)) + except portage.exception.InvalidDependString, e: + show_invalid_depstring_notice(task, + task.metadata["PROPERTIES"], str(e)) + raise self._unknown_internal_error() if "interactive" in properties: interactive_tasks.append(task) return interactive_tasks @@ -9290,7 +9302,10 @@ class Scheduler(PollScheduler): graph = self._digraph - for node in self._mergelist: + # Iterate over all nodes rather than just the merge list, because + # some uninstall nodes may not be in the merge list since they will + # be performed as part of an upgrade within a slot. + for node in graph.all_nodes(): if not isinstance(node, Package) or \ node.operation != "uninstall": continue @@ -9636,6 +9651,23 @@ class Scheduler(PollScheduler): self._logger.log(" *** Resuming merge...") self._save_resume_list() + + try: + self._background = self._background_mode() + except self._unknown_internal_error: + return 1 + + for root in self.trees: + root_config = self.trees[root]["root_config"] + if self._background: + root_config.settings.unlock() + root_config.settings["PORTAGE_BACKGROUND"] = "1" + root_config.settings.backup_changes("PORTAGE_BACKGROUND") + root_config.settings.lock() + + self.pkgsettings[root] = portage.config( + clone=self.trees[root]["vartree"].settings) + rval = self._check_manifests() if rval != os.EX_OK: return rval diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 4ac7d26fa..cf22d5b7c 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -2999,8 +2999,8 @@ class dblink(object): def _find_libs_to_preserve(self): """ - Get CONTENTS entries for libraries to be preserved. Returns a - dict instance like that returned from getcontents(). + Get set of relative paths for libraries to be preserved. The file + paths are selected from self._installed_instance.getcontents(). """ if self._linkmap_broken or not \ (self._installed_instance is not None and \ @@ -3095,15 +3095,24 @@ class dblink(object): old_contents = self._installed_instance.getcontents() for f in list(preserve_paths): f_abs = os.path.join(root, f.lstrip(os.sep)) - new_contents[f_abs] = old_contents[f_abs] - if os.path.islink(f_abs): - obj_type = "sym" - else: - obj_type = "obj" + contents_entry = old_contents.get(f_abs) + if contents_entry is None: + # This will probably never happen, but it might if one of the + # paths returned from findConsumers() refers to one of the libs + # that should be preserved yet the path is not listed in the + # contents. Such a path might belong to some other package, so + # it shouldn't be preserved here. + showMessage(("!!! File '%s' will not be preserved " + \ + "due to missing contents entry\n") % (f_abs,), + level=logging.ERROR, noiselevel=-1) + preserve_paths.remove(f) + continue + new_contents[f_abs] = contents_entry + obj_type = contents_entry[0] showMessage(">>> needed %s %s\n" % (obj_type, f_abs)) # Add parent directories to contents if necessary. parent_dir = os.path.dirname(f_abs) - while parent_dir != root: + while len(parent_dir) > len(root): new_contents[parent_dir] = ["dir"] prev = parent_dir parent_dir = os.path.dirname(parent_dir) -- 2.26.2