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")
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):
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:
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:
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:
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)
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
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,
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 = []
data.append(_unicode_decode(buf.tostring(),
encoding='utf_8', errors='strict'))
- os.waitpid(pids[0], 0)
master_file.close()
return test_string == ''.join(data)