From: Fabian Groffen Date: Sat, 3 Oct 2009 17:28:16 +0000 (-0000) Subject: Merged from trunk -r14472:14478 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=dfce2edf7f1e0b9b6d998246e38a5699d0181130;p=portage.git Merged from trunk -r14472:14478 | 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 --- diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index b6d01f9a3..19d351139 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -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 diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 2f9fb26df..66566e945 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -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)