__slots__ = ("fetchonly", "pkg",)
- _env_vars = ("FETCHCOMMAND", "RESUMECOMMAND")
+ _env_vars = ("FETCHCOMMAND", "GENTOO_MIRRORS", "RESUMECOMMAND")
def _start(self):
myuse = pkg.use.enabled
jbigkey = pkg
depth = pkg.depth + 1
+ removal_action = "remove" in self.myparams
edepend={}
depkeys = ["DEPEND","RDEPEND","PDEPEND"]
edepend["RDEPEND"] = ""
edepend["PDEPEND"] = ""
bdeps_satisfied = False
- if mytype in ("installed", "binary"):
+
+ if pkg.built and not removal_action:
if self.myopts.get("--with-bdeps", "n") == "y":
# Pull in build time deps as requested, but marked them as
# "satisfied" since they are not strictly required. This allows
# built packages do not have build time dependencies.
edepend["DEPEND"] = ""
+ if removal_action and self.myopts.get("--with-bdeps", "y") == "n":
+ edepend["DEPEND"] = ""
+
deps = (
("/", edepend["DEPEND"],
self._priority(buildtime=True, satisfied=bdeps_satisfied)),
"--fetchonly", "--fetch-all-uri",
"--nodeps", "--pretend"])
+ _opts_no_background = \
+ frozenset(["--pretend",
+ "--fetchonly", "--fetch-all-uri"])
+
_opts_no_restart = frozenset(["--buildpkgonly",
"--fetchonly", "--fetch-all-uri", "--pretend"])
kwargs.pop("short_msg", None)
emergelog(self.xterm_titles, *pargs, **kwargs)
+ class _failed_pkg(SlotObject):
+ __slots__ = ("log_path", "pkg", "returncode")
+
def __init__(self, settings, trees, mtimedb, myopts,
spinner, mergelist, favorites, digraph):
PollScheduler.__init__(self)
@returns: True if background mode is enabled, False otherwise.
"""
background = (self._max_jobs > 1 or "--quiet" in self.myopts) and \
- "--pretend" not in self.myopts
+ not bool(self._opts_no_background.intersection(self.myopts))
self._status_display.quiet = \
not background or \
if not failed_pkgs:
break
- for failed_pkg, returncode in failed_pkgs:
- mergelist.remove(list(failed_pkg))
+ for failed_pkg in failed_pkgs:
+ mergelist.remove(list(failed_pkg.pkg))
self._failed_pkgs_all.extend(failed_pkgs)
del failed_pkgs[:]
def _eerror(lines):
for l in lines:
- eerror(l, phase="other", key=failed_pkg.cpv)
+ eerror(l, phase="other", key=failed_pkg.pkg.cpv)
msg = []
msg.append("One or more packages have been " + \
self._logger.log(" *** Finished. Cleaning up...")
+ if failed_pkgs:
+ self._failed_pkgs_all.extend(failed_pkgs)
+ del failed_pkgs[:]
+
background = self._background
- if self._failed_pkgs_all and background and \
+ failure_log_shown = False
+ if background and len(self._failed_pkgs_all) == 1:
+ # If only one package failed then just show it's
+ # whole log for easy viewing.
+ failed_pkg = self._failed_pkgs_all[-1]
+ log_path = failed_pkg.log_path
+ if log_path is not None:
+ try:
+ log_file = open(log_path, 'rb')
+ except IOError:
+ pass
+ else:
+ try:
+ for line in log_file:
+ writemsg_level(line, noiselevel=-1)
+ finally:
+ log_file.close()
+ failure_log_shown = True
+
+ if background and not failure_log_shown and \
+ self._failed_pkgs_all and \
self._failed_pkgs_die_msgs and \
not _flush_elog_mod_echo():
for line in wrap(msg, 72):
writemsg("%s%s\n" % (prefix, line), noiselevel=-1)
writemsg(prefix + "\n", noiselevel=-1)
- for pkg, returncode in self._failed_pkgs_all:
+ for failed_pkg in self._failed_pkgs_all:
writemsg("%s\t%s\n" % (prefix,
- colorize("INFORM", str(pkg))),
+ colorize("INFORM", str(failed_pkg.pkg))),
noiselevel=-1)
writemsg(prefix + "\n", noiselevel=-1)
def _do_merge_exit(self, merge):
pkg = merge.merge.pkg
if merge.returncode != os.EX_OK:
- self._failed_pkgs.append((pkg, merge.returncode))
+ log_path = merge.merge.settings.get("PORTAGE_LOG_FILE")
+ self._failed_pkgs.append(self._failed_pkg(
+ log_path=log_path, pkg=pkg, returncode=merge.returncode))
self._status_display.failed = len(self._failed_pkgs)
return
self._task_queues.merge.add(merge)
self._status_display.merges = len(self._task_queues.merge)
else:
- self._failed_pkgs.append((build.pkg, build.returncode))
+ log_path = build.settings.get("PORTAGE_LOG_FILE")
+ self._failed_pkgs.append(self._failed_pkg(
+ log_path=log_path, pkg=build.pkg, returncode=build.returncode))
self._status_display.failed = len(self._failed_pkgs)
self._deallocate_config(build.settings)
self._jobs -= 1
self._main_loop_cleanup()
portage.elog._emerge_elog_listener = None
if failed_pkgs:
- pkg, rval = failed_pkgs[-1]
+ rval = failed_pkgs[-1].returncode
return rval
# Only allow 1 job max if a restart is scheduled
# due to portage update.
if self._is_restart_scheduled() or \
- "--pretend" in self.myopts:
+ self._opts_no_background.intersection(self.myopts):
self._set_max_jobs(1)
merge_queue = self._task_queues.merge
remaining, state_change = self._schedule_tasks_imp()
self._task_queues.merge.schedule()
self._status_display.display()
+
+ # Cancel prefetchers if they're the only reason
+ # the main poll loop is still running.
+ if self._failed_pkgs and \
+ not (self._jobs or self._task_queues.merge):
+ self._task_queues.fetch.clear()
+
return remaining
def _schedule_tasks_imp(self):
unresolvable = set()
for dep in resolver._initially_unsatisfied_deps:
- if isinstance(dep.parent, Package):
+ if isinstance(dep.parent, Package) and \
+ (dep.priority > UnmergeDepPriority.SOFT):
unresolvable.add((dep.atom, dep.parent.cpv))
+
if not unresolvable:
return False
settings["NOCOLOR"] = "true"
settings.backup_changes("NOCOLOR")
+def ionice(settings):
+
+ ionice_cmd = settings.get("PORTAGE_IONICE_COMMAND")
+ if ionice_cmd:
+ ionice_cmd = shlex.split(ionice_cmd)
+ if not ionice_cmd:
+ return
+
+ from portage.util import varexpand
+ variables = {"PID" : str(os.getpid())}
+ cmd = [varexpand(x, mydict=variables) for x in ionice_cmd]
+
+ try:
+ rval = portage.process.spawn(cmd, env=os.environ)
+ except portage.exception.CommandNotFound:
+ # The OS kernel probably doesn't support ionice,
+ # so return silently.
+ return
+
+ if rval != os.EX_OK:
+ out = portage.output.EOutput()
+ out.eerror("PORTAGE_IONICE_COMMAND returned %d" % (rval,))
+ out.eerror("See the make.conf(5) man page for PORTAGE_IONICE_COMMAND usage instructions.")
+
def emerge_main():
global portage # NFC why this is necessary now - genone
portage._disable_legacy_globals()
settings, trees, mtimedb = load_emerge_config()
portdb = trees[settings["ROOT"]]["porttree"].dbapi
+ ionice(settings)
+
try:
os.nice(int(settings.get("PORTAGE_NICENESS", "0")))
except (OSError, ValueError), e:
(self.infile, str(e)), noiselevel=-1)
return (newfile, StringIO.StringIO())
+class _insert_newline_eof(file):
+ """
+ Read functions insert anywhere from 0 and 2 newlines just before eof.
+ This is useful as a workaround for avoiding a silent error in shlex that
+ is triggered by a source statement at the end of the file without a
+ trailing newline after the source statement.
+ """
+
+ def read(self, *args):
+ if hasattr(self, "_got_eof"):
+ return ""
+ rval = file.read(self, *args)
+ if rval and not args and rval[-1:] != "\n":
+ rval += "\n"
+ if not rval:
+ self._got_eof = True
+ return "\n"
+ return rval
+
+ def readline(self, *args):
+ if hasattr(self, "_got_eof"):
+ return ""
+ rval = file.readline(self, *args)
+ if rval and rval[-1:] != "\n":
+ rval += "\n"
+ if not rval:
+ self._got_eof = True
+ rval = "\n"
+ return rval
+
+ def readlines(self, *args):
+ if hasattr(self, "_got_eof"):
+ return []
+ lines = file.readlines(self, *args)
+ if lines and lines[-1][-1:] != "\n":
+ lines[-1] += "\n"
+ return lines
+
def getconfig(mycfg, tolerant=0, allow_sourcing=False, expand=True):
if isinstance(expand, dict):
# Some existing variable definitions have been
expand_map = {}
mykeys = {}
try:
- f=open(mycfg,'r')
+ f = _insert_newline_eof(mycfg, 'rb')
except IOError, e:
if e.errno == PermissionDenied.errno:
raise PermissionDenied(mycfg)