Merged from trunk -r11833:11841
authorFabian Groffen <grobian@gentoo.org>
Sat, 15 Nov 2008 16:15:00 +0000 (16:15 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 15 Nov 2008 16:15:00 +0000 (16:15 -0000)
   | 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
pym/portage/dbapi/vartree.py

index 0dcf2f19335ba5a721ebbc19077007520706dd00..1d07875e5a35e9f7d9a523dc0d644a56c8a52ac2 100644 (file)
@@ -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
index 4ac7d26fa1a8c5325fa07e60368d08e603639130..cf22d5b7c4aef9ce6c82e8662a084b61106f420c 100644 (file)
@@ -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)