Merged from trunk -r14472:14478
authorFabian Groffen <grobian@gentoo.org>
Sat, 3 Oct 2009 17:28:16 +0000 (17:28 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 3 Oct 2009 17:28:16 +0000 (17:28 -0000)
   | 14474   | Bug #287333 - If posible, use ebuild from tree when checking |
   | zmedico | for keyword mask on installed packages.                      |

   | 14476   | Bug #285832 - When updates are missed due to dependencies    |
   | zmedico | that have been masked by backtracking, abbreviate output in  |
   |         | order to avoid terminal flooding.                            |

   | 14477   | Don't use a fork inside _test_pty_eof() because it gives     |
   | zmedico | inconsistent results.                                        |

   | 14478   | Fix race condition when using a fork inside _test_pty_eof(). |
   | zmedico |                                                              |

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

pym/_emerge/depgraph.py
pym/portage/__init__.py

index b6d01f9a3ce07bdaf46f5d49f151e8ad62a4d9ac..19d351139242a27d68871e9717077c5b09df042e 100644 (file)
@@ -318,9 +318,19 @@ class depgraph(object):
                        return
 
                write = sys.stderr.write
+               backtrack_masked = []
 
                for pkg, parent_atoms in missed_updates:
 
+                       try:
+                               for parent, root, atom in parent_atoms:
+                                       self._show_unsatisfied_dep(root, atom, myparent=parent,
+                                               check_backtrack=True)
+                       except self._backtrack_mask:
+                               # This is displayed below in abbreviated form.
+                               backtrack_masked.append((pkg, parent_atoms))
+                               continue
+
                        write("\n!!! The following update has been skipped " + \
                                "due to unsatisfied dependencies:\n\n")
 
@@ -333,6 +343,18 @@ class depgraph(object):
                                self._show_unsatisfied_dep(root, atom, myparent=parent)
                                write("\n")
 
+               if backtrack_masked:
+                       # These are shown in abbreviated form, in order to avoid terminal
+                       # flooding from mask messages as reported in bug #285832.
+                       write("\n!!! The following update(s) have been skipped " + \
+                               "due to unsatisfied dependencies\n" + \
+                               "!!! triggered by backtracking:\n\n")
+                       for pkg, parent_atoms in backtrack_masked:
+                               write(str(pkg.slot_atom))
+                               if pkg.root != '/':
+                                       write(" for %s" % (pkg.root,))
+                               write("\n")
+
                sys.stderr.flush()
 
        def _show_missed_update_slot_conflicts(self, missed_updates):
@@ -1993,7 +2015,14 @@ class depgraph(object):
 
                return selected_atoms
 
-       def _show_unsatisfied_dep(self, root, atom, myparent=None, arg=None):
+       def _show_unsatisfied_dep(self, root, atom, myparent=None, arg=None,
+               check_backtrack=False):
+               """
+               When check_backtrack=True, no output is produced and
+               the method either returns or raises _backtrack_mask if
+               a matching package has been masked by backtracking.
+               """
+               backtrack_mask = False
                atom_set = InternalPackageSet(initial_atoms=(atom,))
                xinfo = '"%s"' % atom
                if arg:
@@ -2038,6 +2067,7 @@ class depgraph(object):
                                                        self._dynamic_config._runtime_pkg_mask[pkg]
                                                mreasons.append('backtracking: %s' % \
                                                        ', '.join(sorted(backtrack_reasons)))
+                                               backtrack_mask = True
                                        if mreasons:
                                                masked_pkg_instances.add(pkg)
                                        if atom.use:
@@ -2047,6 +2077,12 @@ class depgraph(object):
                                masked_packages.append(
                                        (root_config, pkgsettings, cpv, metadata, mreasons))
 
+               if check_backtrack:
+                       if backtrack_mask:
+                               raise self._backtrack_mask()
+                       else:
+                               return
+
                missing_use_reasons = []
                missing_iuse_reasons = []
                for pkg in missing_use:
@@ -2332,18 +2368,17 @@ class depgraph(object):
                                                                        different_version = avail_pkg
                                                                        break
                                                        if different_version is not None:
-
-                                                               if installed and \
-                                                                       pkgsettings._getMissingKeywords(
-                                                                       pkg.cpv, pkg.metadata):
-                                                                       continue
-
                                                                # If the ebuild no longer exists or it's
                                                                # keywords have been dropped, reject built
                                                                # instances (installed or binary).
                                                                # If --usepkgonly is enabled, assume that
                                                                # the ebuild status should be ignored.
-                                                               if not usepkgonly:
+                                                               if usepkgonly:
+                                                                       if installed and \
+                                                                               pkgsettings._getMissingKeywords(
+                                                                               pkg.cpv, pkg.metadata):
+                                                                               continue
+                                                               else:
                                                                        try:
                                                                                pkg_eb = self._pkg(
                                                                                        pkg.cpv, "ebuild", root_config)
@@ -4934,6 +4969,13 @@ class depgraph(object):
                graph in order to avoid making a potentially unsafe decision.
                """
 
+       class _backtrack_mask(_internal_exception):
+               """
+               This is raised by _show_unsatisfied_dep() when it's called with
+               check_backtrack=True and a matching package has been masked by
+               backtracking.
+               """
+
        def need_restart(self):
                return self._dynamic_config._need_restart
 
index 2f9fb26df574d5f87b4134b3412ef17b27d65a59..66566e94584d291ed2624e6ce1f23c8cf5c2bbb8 100644 (file)
@@ -3762,6 +3762,8 @@ def _test_pty_eof():
        Raises an EnvironmentError from openpty() if it fails.
        """
 
+       use_fork = False
+
        import array, fcntl, pty, select, termios
        test_string = 2 * "blah blah blah\n"
        test_string = _unicode_decode(test_string,
@@ -3781,19 +3783,29 @@ def _test_pty_eof():
        termios.tcsetattr(slave_fd, termios.TCSANOW, mode)
 
        # Simulate a subprocess writing some data to the
-       # slave end of the pipe, and then exiting. Do a
-       # real fork here since otherwise os.close(slave_fd)
-       # would block on some platforms such as Darwin.
-       pids = process.spawn_bash(_unicode_encode("echo -n '%s'" % test_string,
-               encoding='utf_8', errors='strict'), env=os.environ,
-               fd_pipes={0:sys.stdin.fileno(), 1:slave_fd, 2:slave_fd},
-               returnpid=True)
-       if isinstance(pids, int):
-               os.close(master_fd)
-               os.close(slave_fd)
-               raise EnvironmentError('spawn failed')
+       # slave end of the pipe, and then exiting.
+       pid = None
+       if use_fork:
+               pids = process.spawn_bash(_unicode_encode("echo -n '%s'" % test_string,
+                       encoding='utf_8', errors='strict'), env=os.environ,
+                       fd_pipes={0:sys.stdin.fileno(), 1:slave_fd, 2:slave_fd},
+                       returnpid=True)
+               if isinstance(pids, int):
+                       os.close(master_fd)
+                       os.close(slave_fd)
+                       raise EnvironmentError('spawn failed')
+               pid = pids[0]
+       else:
+               os.write(slave_fd, _unicode_encode(test_string,
+                       encoding='utf_8', errors='strict'))
        os.close(slave_fd)
 
+       # If using a fork, we must wait for the child here,
+       # in order to avoid a race condition that would
+       # lead to inconsistent results.
+       if pid is not None:
+               os.waitpid(pid, 0)
+
        master_file = os.fdopen(master_fd, 'rb')
        eof = False
        data = []
@@ -3823,7 +3835,6 @@ def _test_pty_eof():
                        data.append(_unicode_decode(buf.tostring(),
                                encoding='utf_8', errors='strict'))
 
-       os.waitpid(pids[0], 0)
        master_file.close()
 
        return test_string == ''.join(data)