aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'portage_with_autodep/pym/_emerge/Scheduler.py')
-rw-r--r--portage_with_autodep/pym/_emerge/Scheduler.py399
1 files changed, 161 insertions, 238 deletions
diff --git a/portage_with_autodep/pym/_emerge/Scheduler.py b/portage_with_autodep/pym/_emerge/Scheduler.py
index 6412d82..30a7e10 100644
--- a/portage_with_autodep/pym/_emerge/Scheduler.py
+++ b/portage_with_autodep/pym/_emerge/Scheduler.py
@@ -1,4 +1,4 @@
-# Copyright 1999-2011 Gentoo Foundation
+# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from __future__ import print_function
@@ -7,10 +7,8 @@ from collections import deque
import gc
import gzip
import logging
-import shutil
import signal
import sys
-import tempfile
import textwrap
import time
import warnings
@@ -28,9 +26,12 @@ from portage.output import colorize, create_color_func, red
bad = create_color_func("BAD")
from portage._sets import SETPREFIX
from portage._sets.base import InternalPackageSet
-from portage.util import writemsg, writemsg_level
+from portage.util import ensure_dirs, writemsg, writemsg_level
+from portage.util.SlotObject import SlotObject
from portage.package.ebuild.digestcheck import digestcheck
from portage.package.ebuild.digestgen import digestgen
+from portage.package.ebuild.doebuild import (_check_temp_dir,
+ _prepare_self_update)
from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
import _emerge
@@ -44,6 +45,7 @@ from _emerge.create_depgraph_params import create_depgraph_params
from _emerge.create_world_atom import create_world_atom
from _emerge.DepPriority import DepPriority
from _emerge.depgraph import depgraph, resume_depgraph
+from _emerge.EbuildBuildDir import EbuildBuildDir
from _emerge.EbuildFetcher import EbuildFetcher
from _emerge.EbuildPhase import EbuildPhase
from _emerge.emergelog import emergelog
@@ -52,12 +54,9 @@ from _emerge._find_deep_system_runtime_deps import _find_deep_system_runtime_dep
from _emerge._flush_elog_mod_echo import _flush_elog_mod_echo
from _emerge.JobStatusDisplay import JobStatusDisplay
from _emerge.MergeListItem import MergeListItem
-from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
from _emerge.Package import Package
from _emerge.PackageMerge import PackageMerge
from _emerge.PollScheduler import PollScheduler
-from _emerge.RootConfig import RootConfig
-from _emerge.SlotObject import SlotObject
from _emerge.SequentialTaskQueue import SequentialTaskQueue
if sys.hexversion >= 0x3000000:
@@ -77,17 +76,12 @@ class Scheduler(PollScheduler):
frozenset(["--pretend",
"--fetchonly", "--fetch-all-uri"])
- _opts_no_restart = frozenset(["--buildpkgonly",
+ _opts_no_self_update = frozenset(["--buildpkgonly",
"--fetchonly", "--fetch-all-uri", "--pretend"])
- _bad_resume_opts = set(["--ask", "--changelog",
- "--resume", "--skipfirst"])
-
- class _iface_class(SlotObject):
+ class _iface_class(PollScheduler._sched_iface_class):
__slots__ = ("fetch",
- "output", "register", "schedule",
- "scheduleSetup", "scheduleUnpack", "scheduleYield",
- "unregister")
+ "scheduleSetup", "scheduleUnpack")
class _fetch_iface_class(SlotObject):
__slots__ = ("log_file", "schedule")
@@ -96,7 +90,7 @@ class Scheduler(PollScheduler):
("merge", "jobs", "ebuild_locks", "fetch", "unpack"), prefix="")
class _build_opts_class(SlotObject):
- __slots__ = ("buildpkg", "buildpkgonly",
+ __slots__ = ("buildpkg", "buildpkg_exclude", "buildpkgonly",
"fetch_all_uri", "fetchonly", "pretend")
class _binpkg_opts_class(SlotObject):
@@ -141,8 +135,9 @@ class Scheduler(PollScheduler):
portage.exception.PortageException.__init__(self, value)
def __init__(self, settings, trees, mtimedb, myopts,
- spinner, mergelist=None, favorites=None, graph_config=None):
- PollScheduler.__init__(self)
+ spinner, mergelist=None, favorites=None, graph_config=None,
+ uninstall_only=False):
+ PollScheduler.__init__(self, main=True)
if mergelist is not None:
warnings.warn("The mergelist parameter of the " + \
@@ -151,16 +146,22 @@ class Scheduler(PollScheduler):
DeprecationWarning, stacklevel=2)
self.settings = settings
- self.target_root = settings["ROOT"]
+ self.target_root = settings["EROOT"]
self.trees = trees
self.myopts = myopts
self._spinner = spinner
self._mtimedb = mtimedb
self._favorites = favorites
+ self._uninstall_only = uninstall_only
self._args_set = InternalPackageSet(favorites, allow_repo=True)
self._build_opts = self._build_opts_class()
+
for k in self._build_opts.__slots__:
- setattr(self._build_opts, k, "--" + k.replace("_", "-") in myopts)
+ setattr(self._build_opts, k, myopts.get("--" + k.replace("_", "-")))
+ self._build_opts.buildpkg_exclude = InternalPackageSet( \
+ initial_atoms=" ".join(myopts.get("--buildpkg-exclude", [])).split(), \
+ allow_wildcard=True, allow_repo=True)
+
self._binpkg_opts = self._binpkg_opts_class()
for k in self._binpkg_opts.__slots__:
setattr(self._binpkg_opts, k, "--" + k.replace("_", "-") in myopts)
@@ -202,10 +203,7 @@ class Scheduler(PollScheduler):
if max_jobs is None:
max_jobs = 1
self._set_max_jobs(max_jobs)
-
- # The root where the currently running
- # portage instance is installed.
- self._running_root = trees["/"]["root_config"]
+ self._running_root = trees[trees._running_eroot]["root_config"]
self.edebug = 0
if settings.get("PORTAGE_DEBUG", "") == "1":
self.edebug = 1
@@ -219,13 +217,11 @@ class Scheduler(PollScheduler):
fetch_iface = self._fetch_iface_class(log_file=self._fetch_log,
schedule=self._schedule_fetch)
self._sched_iface = self._iface_class(
- fetch=fetch_iface, output=self._task_output,
- register=self._register,
- schedule=self._schedule_wait,
+ fetch=fetch_iface,
scheduleSetup=self._schedule_setup,
scheduleUnpack=self._schedule_unpack,
- scheduleYield=self._schedule_yield,
- unregister=self._unregister)
+ **dict((k, getattr(self.sched_iface, k))
+ for k in self.sched_iface.__slots__))
self._prefetchers = weakref.WeakValueDictionary()
self._pkg_queue = []
@@ -277,7 +273,7 @@ class Scheduler(PollScheduler):
if self._parallel_fetch:
# clear out existing fetch log if it exists
try:
- open(self._fetch_log, 'w')
+ open(self._fetch_log, 'w').close()
except EnvironmentError:
pass
@@ -289,10 +285,37 @@ class Scheduler(PollScheduler):
self._running_portage = self._pkg(cpv, "installed",
self._running_root, installed=True)
+ def _handle_self_update(self):
+
+ if self._opts_no_self_update.intersection(self.myopts):
+ return os.EX_OK
+
+ for x in self._mergelist:
+ if not isinstance(x, Package):
+ continue
+ if x.operation != "merge":
+ continue
+ if x.root != self._running_root.root:
+ continue
+ if not portage.dep.match_from_list(
+ portage.const.PORTAGE_PACKAGE_ATOM, [x]):
+ continue
+ if self._running_portage is None or \
+ self._running_portage.cpv != x.cpv or \
+ '9999' in x.cpv or \
+ 'git' in x.inherited or \
+ 'git-2' in x.inherited:
+ rval = _check_temp_dir(self.settings)
+ if rval != os.EX_OK:
+ return rval
+ _prepare_self_update(self.settings)
+ break
+
+ return os.EX_OK
+
def _terminate_tasks(self):
self._status_display.quiet = True
- while self._running_tasks:
- task_id, task = self._running_tasks.popitem()
+ for task in list(self._running_tasks.values()):
task.cancel()
for q in self._task_queues.values():
q.clear()
@@ -304,10 +327,13 @@ class Scheduler(PollScheduler):
"""
self._set_graph_config(graph_config)
self._blocker_db = {}
+ dynamic_deps = self.myopts.get("--dynamic-deps", "y") != "n"
for root in self.trees:
+ if self._uninstall_only:
+ continue
if graph_config is None:
fake_vartree = FakeVartree(self.trees[root]["root_config"],
- pkg_cache=self._pkg_cache)
+ pkg_cache=self._pkg_cache, dynamic_deps=dynamic_deps)
fake_vartree.sync()
else:
fake_vartree = graph_config.trees[root]['vartree']
@@ -324,52 +350,6 @@ class Scheduler(PollScheduler):
self._set_graph_config(None)
gc.collect()
- def _poll(self, timeout=None):
-
- self._schedule()
-
- if timeout is None:
- while True:
- if not self._poll_event_handlers:
- self._schedule()
- if not self._poll_event_handlers:
- raise StopIteration(
- "timeout is None and there are no poll() event handlers")
- previous_count = len(self._poll_event_queue)
- PollScheduler._poll(self, timeout=self._max_display_latency)
- self._status_display.display()
- if previous_count != len(self._poll_event_queue):
- break
-
- elif timeout <= self._max_display_latency:
- PollScheduler._poll(self, timeout=timeout)
- if timeout == 0:
- # The display is updated by _schedule() above, so it would be
- # redundant to update it here when timeout is 0.
- pass
- else:
- self._status_display.display()
-
- else:
- remaining_timeout = timeout
- start_time = time.time()
- while True:
- previous_count = len(self._poll_event_queue)
- PollScheduler._poll(self,
- timeout=min(self._max_display_latency, remaining_timeout))
- self._status_display.display()
- if previous_count != len(self._poll_event_queue):
- break
- elapsed_time = time.time() - start_time
- if elapsed_time < 0:
- # The system clock has changed such that start_time
- # is now in the future, so just assume that the
- # timeout has already elapsed.
- break
- remaining_timeout = timeout - 1000 * elapsed_time
- if remaining_timeout <= 0:
- break
-
def _set_max_jobs(self, max_jobs):
self._max_jobs = max_jobs
self._task_queues.jobs.max_jobs = max_jobs
@@ -381,11 +361,11 @@ class Scheduler(PollScheduler):
Check if background mode is enabled and adjust states as necessary.
@rtype: bool
- @returns: True if background mode is enabled, False otherwise.
+ @return: True if background mode is enabled, False otherwise.
"""
background = (self._max_jobs is True or \
self._max_jobs > 1 or "--quiet" in self.myopts \
- or "--quiet-build" in self.myopts) and \
+ or self.myopts.get("--quiet-build") == "y") and \
not bool(self._opts_no_background.intersection(self.myopts))
if background:
@@ -398,7 +378,7 @@ class Scheduler(PollScheduler):
msg = [""]
for pkg in interactive_tasks:
pkg_str = " " + colorize("INFORM", str(pkg.cpv))
- if pkg.root != "/":
+ if pkg.root_config.settings["ROOT"] != "/":
pkg_str += " for " + pkg.root
msg.append(pkg_str)
msg.append("")
@@ -741,7 +721,6 @@ class Scheduler(PollScheduler):
self._status_msg("Starting parallel fetch")
prefetchers = self._prefetchers
- getbinpkg = "--getbinpkg" in self.myopts
for pkg in self._mergelist:
# mergelist can contain solved Blocker instances
@@ -749,15 +728,13 @@ class Scheduler(PollScheduler):
continue
prefetcher = self._create_prefetcher(pkg)
if prefetcher is not None:
- self._task_queues.fetch.add(prefetcher)
+ # This will start the first prefetcher immediately, so that
+ # self._task() won't discard it. This avoids a case where
+ # the first prefetcher is discarded, causing the second
+ # prefetcher to occupy the fetch queue before the first
+ # fetcher has an opportunity to execute.
prefetchers[pkg] = prefetcher
-
- # Start the first prefetcher immediately so that self._task()
- # won't discard it. This avoids a case where the first
- # prefetcher is discarded, causing the second prefetcher to
- # occupy the fetch queue before the first fetcher has an
- # opportunity to execute.
- self._task_queues.fetch.schedule()
+ self._task_queues.fetch.add(prefetcher)
def _create_prefetcher(self, pkg):
"""
@@ -785,100 +762,6 @@ class Scheduler(PollScheduler):
return prefetcher
- def _is_restart_scheduled(self):
- """
- Check if the merge list contains a replacement
- for the current running instance, that will result
- in restart after merge.
- @rtype: bool
- @returns: True if a restart is scheduled, False otherwise.
- """
- if self._opts_no_restart.intersection(self.myopts):
- return False
-
- mergelist = self._mergelist
-
- for i, pkg in enumerate(mergelist):
- if self._is_restart_necessary(pkg) and \
- i != len(mergelist) - 1:
- return True
-
- return False
-
- def _is_restart_necessary(self, pkg):
- """
- @return: True if merging the given package
- requires restart, False otherwise.
- """
-
- # Figure out if we need a restart.
- if pkg.root == self._running_root.root and \
- portage.match_from_list(
- portage.const.PORTAGE_PACKAGE_ATOM, [pkg]):
- if self._running_portage is None:
- return True
- elif pkg.cpv != self._running_portage.cpv or \
- '9999' in pkg.cpv or \
- 'git' in pkg.inherited or \
- 'git-2' in pkg.inherited:
- return True
- return False
-
- def _restart_if_necessary(self, pkg):
- """
- Use execv() to restart emerge. This happens
- if portage upgrades itself and there are
- remaining packages in the list.
- """
-
- if self._opts_no_restart.intersection(self.myopts):
- return
-
- if not self._is_restart_necessary(pkg):
- return
-
- if pkg == self._mergelist[-1]:
- return
-
- self._main_loop_cleanup()
-
- logger = self._logger
- pkg_count = self._pkg_count
- mtimedb = self._mtimedb
- bad_resume_opts = self._bad_resume_opts
-
- logger.log(" ::: completed emerge (%s of %s) %s to %s" % \
- (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root))
-
- logger.log(" *** RESTARTING " + \
- "emerge via exec() after change of " + \
- "portage version.")
-
- mtimedb["resume"]["mergelist"].remove(list(pkg))
- mtimedb.commit()
- portage.run_exitfuncs()
- # Don't trust sys.argv[0] here because eselect-python may modify it.
- emerge_binary = os.path.join(portage.const.PORTAGE_BIN_PATH, 'emerge')
- mynewargv = [emerge_binary, "--resume"]
- resume_opts = self.myopts.copy()
- # For automatic resume, we need to prevent
- # any of bad_resume_opts from leaking in
- # via EMERGE_DEFAULT_OPTS.
- resume_opts["--ignore-default-opts"] = True
- for myopt, myarg in resume_opts.items():
- if myopt not in bad_resume_opts:
- if myarg is True:
- mynewargv.append(myopt)
- elif isinstance(myarg, list):
- # arguments like --exclude that use 'append' action
- for x in myarg:
- mynewargv.append("%s=%s" % (myopt, x))
- else:
- mynewargv.append("%s=%s" % (myopt, myarg))
- # priority only needs to be adjusted on the first run
- os.environ["PORTAGE_NICENESS"] = "0"
- os.execv(mynewargv[0], mynewargv)
-
def _run_pkg_pretend(self):
"""
Since pkg_pretend output may be important, this method sends all
@@ -912,11 +795,48 @@ class Scheduler(PollScheduler):
root_config = x.root_config
settings = self.pkgsettings[root_config.root]
settings.setcpv(x)
- tmpdir = tempfile.mkdtemp()
- tmpdir_orig = settings["PORTAGE_TMPDIR"]
- settings["PORTAGE_TMPDIR"] = tmpdir
+
+ # setcpv/package.env allows for per-package PORTAGE_TMPDIR so we
+ # have to validate it for each package
+ rval = _check_temp_dir(settings)
+ if rval != os.EX_OK:
+ return rval
+
+ build_dir_path = os.path.join(
+ os.path.realpath(settings["PORTAGE_TMPDIR"]),
+ "portage", x.category, x.pf)
+ existing_buildir = os.path.isdir(build_dir_path)
+ settings["PORTAGE_BUILDDIR"] = build_dir_path
+ build_dir = EbuildBuildDir(scheduler=sched_iface,
+ settings=settings)
+ build_dir.lock()
+ current_task = None
try:
+
+ # Clean up the existing build dir, in case pkg_pretend
+ # checks for available space (bug #390711).
+ if existing_buildir:
+ if x.built:
+ tree = "bintree"
+ infloc = os.path.join(build_dir_path, "build-info")
+ ebuild_path = os.path.join(infloc, x.pf + ".ebuild")
+ else:
+ tree = "porttree"
+ portdb = root_config.trees["porttree"].dbapi
+ ebuild_path = portdb.findname(x.cpv, myrepo=x.repo)
+ if ebuild_path is None:
+ raise AssertionError(
+ "ebuild not found for '%s'" % x.cpv)
+ portage.package.ebuild.doebuild.doebuild_environment(
+ ebuild_path, "clean", settings=settings,
+ db=self.trees[settings['EROOT']][tree].dbapi)
+ clean_phase = EbuildPhase(background=False,
+ phase='clean', scheduler=sched_iface, settings=settings)
+ current_task = clean_phase
+ clean_phase.start()
+ clean_phase.wait()
+
if x.built:
tree = "bintree"
bintree = root_config.trees["bintree"].dbapi.bintree
@@ -935,6 +855,7 @@ class Scheduler(PollScheduler):
verifier = BinpkgVerifier(pkg=x,
scheduler=sched_iface)
+ current_task = verifier
verifier.start()
if verifier.wait() != os.EX_OK:
failures += 1
@@ -943,8 +864,8 @@ class Scheduler(PollScheduler):
if fetched:
bintree.inject(x.cpv, filename=fetched)
tbz2_file = bintree.getname(x.cpv)
- infloc = os.path.join(tmpdir, x.category, x.pf, "build-info")
- os.makedirs(infloc)
+ infloc = os.path.join(build_dir_path, "build-info")
+ ensure_dirs(infloc)
portage.xpak.tbz2(tbz2_file).unpackinfo(infloc)
ebuild_path = os.path.join(infloc, x.pf + ".ebuild")
settings.configdict["pkg"]["EMERGE_FROM"] = "binary"
@@ -964,7 +885,8 @@ class Scheduler(PollScheduler):
portage.package.ebuild.doebuild.doebuild_environment(ebuild_path,
"pretend", settings=settings,
- db=self.trees[settings["ROOT"]][tree].dbapi)
+ db=self.trees[settings['EROOT']][tree].dbapi)
+
prepare_build_dirs(root_config.root, settings, cleanup=0)
vardb = root_config.trees['vartree'].dbapi
@@ -976,14 +898,21 @@ class Scheduler(PollScheduler):
phase="pretend", scheduler=sched_iface,
settings=settings)
+ current_task = pretend_phase
pretend_phase.start()
ret = pretend_phase.wait()
if ret != os.EX_OK:
failures += 1
portage.elog.elog_process(x.cpv, settings)
finally:
- shutil.rmtree(tmpdir)
- settings["PORTAGE_TMPDIR"] = tmpdir_orig
+ if current_task is not None and current_task.isAlive():
+ current_task.cancel()
+ current_task.wait()
+ clean_phase = EbuildPhase(background=False,
+ phase='clean', scheduler=sched_iface, settings=settings)
+ clean_phase.start()
+ clean_phase.wait()
+ build_dir.unlock()
if failures:
return 1
@@ -1003,6 +932,10 @@ class Scheduler(PollScheduler):
except self._unknown_internal_error:
return 1
+ rval = self._handle_self_update()
+ if rval != os.EX_OK:
+ return rval
+
for root in self.trees:
root_config = self.trees[root]["root_config"]
@@ -1131,10 +1064,8 @@ class Scheduler(PollScheduler):
# If only one package failed then just show it's
# whole log for easy viewing.
failed_pkg = self._failed_pkgs_all[-1]
- build_dir = failed_pkg.build_dir
log_file = None
-
- log_paths = [failed_pkg.build_log]
+ log_file_real = None
log_path = self._locate_failure_log(failed_pkg)
if log_path is not None:
@@ -1145,6 +1076,7 @@ class Scheduler(PollScheduler):
pass
else:
if log_path.endswith('.gz'):
+ log_file_real = log_file
log_file = gzip.GzipFile(filename='',
mode='rb', fileobj=log_file)
@@ -1157,6 +1089,8 @@ class Scheduler(PollScheduler):
noiselevel=-1)
finally:
log_file.close()
+ if log_file_real is not None:
+ log_file_real.close()
failure_log_shown = True
# Dump mod_echo output now since it tends to flood the terminal.
@@ -1228,9 +1162,6 @@ class Scheduler(PollScheduler):
def _locate_failure_log(self, failed_pkg):
- build_dir = failed_pkg.build_dir
- log_file = None
-
log_paths = [failed_pkg.build_log]
for log_path in log_paths:
@@ -1272,7 +1203,7 @@ class Scheduler(PollScheduler):
# Skip this if $ROOT != / since it shouldn't matter if there
# are unsatisfied system runtime deps in this case.
- if pkg.root != '/':
+ if pkg.root_config.settings["ROOT"] != "/":
return
completed_tasks = self._completed_tasks
@@ -1350,8 +1281,6 @@ class Scheduler(PollScheduler):
if pkg.installed:
return
- self._restart_if_necessary(pkg)
-
# Call mtimedb.commit() after each merge so that
# --resume still works after being interrupted
# by reboot, sigkill or similar.
@@ -1411,12 +1340,16 @@ class Scheduler(PollScheduler):
def _merge(self):
+ if self._opts_no_background.intersection(self.myopts):
+ self._set_max_jobs(1)
+
self._add_prefetchers()
self._add_packages()
- pkg_queue = self._pkg_queue
failed_pkgs = self._failed_pkgs
portage.locks._quiet = self._background
portage.elog.add_listener(self._elog_listener)
+ display_timeout_id = self.sched_iface.timeout_add(
+ self._max_display_latency, self._status_display.display)
rval = os.EX_OK
try:
@@ -1425,6 +1358,7 @@ class Scheduler(PollScheduler):
self._main_loop_cleanup()
portage.locks._quiet = False
portage.elog.remove_listener(self._elog_listener)
+ self.sched_iface.source_remove(display_timeout_id)
if failed_pkgs:
rval = failed_pkgs[-1].returncode
@@ -1505,7 +1439,7 @@ class Scheduler(PollScheduler):
merge order
@type later: set
@rtype: bool
- @returns: True if the package is dependent, False otherwise.
+ @return: True if the package is dependent, False otherwise.
"""
graph = self._digraph
@@ -1553,24 +1487,7 @@ class Scheduler(PollScheduler):
return temp_settings
def _deallocate_config(self, settings):
- self._config_pool[settings["ROOT"]].append(settings)
-
- def _main_loop(self):
-
- # Only allow 1 job max if a restart is scheduled
- # due to portage update.
- if self._is_restart_scheduled() or \
- self._opts_no_background.intersection(self.myopts):
- self._set_max_jobs(1)
-
- while self._schedule():
- self._poll_loop()
-
- while True:
- self._schedule()
- if not self._is_work_scheduled():
- break
- self._poll_loop()
+ self._config_pool[settings['EROOT']].append(settings)
def _keep_scheduling(self):
return bool(not self._terminated_tasks and self._pkg_queue and \
@@ -1583,6 +1500,8 @@ class Scheduler(PollScheduler):
while True:
+ state_change = 0
+
# When the number of jobs and merges drops to zero,
# process a single merge from _merge_wait_queue if
# it's not empty. We only process one since these are
@@ -1593,37 +1512,34 @@ class Scheduler(PollScheduler):
not self._task_queues.merge):
task = self._merge_wait_queue.popleft()
task.addExitListener(self._merge_wait_exit_handler)
+ self._merge_wait_scheduled.append(task)
self._task_queues.merge.add(task)
self._status_display.merges = len(self._task_queues.merge)
- self._merge_wait_scheduled.append(task)
+ state_change += 1
- self._schedule_tasks_imp()
- self._status_display.display()
+ if self._schedule_tasks_imp():
+ state_change += 1
- state_change = 0
- for q in self._task_queues.values():
- if q.schedule():
- state_change += 1
+ 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._build_opts.fetchonly and \
not self._is_work_scheduled() and \
self._task_queues.fetch:
+ # Since this happens asynchronously, it doesn't count in
+ # state_change (counting it triggers an infinite loop).
self._task_queues.fetch.clear()
- state_change += 1
if not (state_change or \
(self._merge_wait_queue and not self._jobs and
not self._task_queues.merge)):
break
- return self._keep_scheduling()
-
def _job_delay(self):
"""
@rtype: bool
- @returns: True if job scheduling should be delayed, False otherwise.
+ @return: True if job scheduling should be delayed, False otherwise.
"""
if self._jobs and self._max_load is not None:
@@ -1641,7 +1557,7 @@ class Scheduler(PollScheduler):
def _schedule_tasks_imp(self):
"""
@rtype: bool
- @returns: True if state changed, False otherwise.
+ @return: True if state changed, False otherwise.
"""
state_change = 0
@@ -1709,7 +1625,14 @@ class Scheduler(PollScheduler):
"installed", pkg.root_config, installed=True,
operation="uninstall")
- prefetcher = self._prefetchers.pop(pkg, None)
+ try:
+ prefetcher = self._prefetchers.pop(pkg, None)
+ except KeyError:
+ # KeyError observed with PyPy 1.8, despite None given as default.
+ # Note that PyPy 1.8 has the same WeakValueDictionary code as
+ # CPython 2.7, so it may be possible for CPython to raise KeyError
+ # here as well.
+ prefetcher = None
if prefetcher is not None and not prefetcher.isAlive():
try:
self._task_queues.fetch._task_queue.remove(prefetcher)
@@ -1738,7 +1661,7 @@ class Scheduler(PollScheduler):
pkg = failed_pkg.pkg
msg = "%s to %s %s" % \
(bad("Failed"), action, colorize("INFORM", pkg.cpv))
- if pkg.root != "/":
+ if pkg.root_config.settings["ROOT"] != "/":
msg += " %s %s" % (preposition, pkg.root)
log_path = self._locate_failure_log(failed_pkg)
@@ -1791,7 +1714,7 @@ class Scheduler(PollScheduler):
Use the current resume list to calculate a new one,
dropping any packages with unsatisfied deps.
@rtype: bool
- @returns: True if successful, False otherwise.
+ @return: True if successful, False otherwise.
"""
print(colorize("GOOD", "*** Resuming merge..."))
@@ -1868,7 +1791,7 @@ class Scheduler(PollScheduler):
pkg = task
msg = "emerge --keep-going:" + \
" %s" % (pkg.cpv,)
- if pkg.root != "/":
+ if pkg.root_config.settings["ROOT"] != "/":
msg += " for %s" % (pkg.root,)
msg += " dropped due to unsatisfied dependency."
for line in textwrap.wrap(msg, msg_width):