def _start(self):
settings = self.settings
+ settings.pop("EBUILD_PHASE", None)
portage_bin_path = settings["PORTAGE_BIN_PATH"]
misc_sh_binary = os.path.join(portage_bin_path,
os.path.basename(portage.const.MISC_SH_BINARY))
def _set_returncode(self, wait_retval):
SpawnProcess._set_returncode(self, wait_retval)
- if self.phase != "clean":
+ if self.phase not in ("clean", "cleanrm"):
self.returncode = portage._doebuild_exit_status_check_and_log(
self.settings, self.phase, self.returncode)
return
root_config = self.roots[self.target_root]
world_set = root_config.sets["world"]
- world_set.lock()
- world_set.load() # maybe it's changed on disk
+
+ world_locked = False
+ if hasattr(world_set, "lock"):
+ world_set.lock()
+ world_locked = True
+
+ if hasattr(world_set, "load"):
+ world_set.load() # maybe it's changed on disk
+
args_set = self._sets["args"]
portdb = self.trees[self.target_root]["porttree"].dbapi
added_favorites = set()
colorize("INFORM", str(a))
if all_added:
world_set.update(all_added)
- world_set.unlock()
+
+ if world_locked:
+ world_set.unlock()
def loadResumeCommand(self, resume_data, skip_masked=False):
"""
not self._poll_event_handlers:
raise StopIteration(
"timeout is None and there are no poll() event handlers")
- self._poll_event_queue.extend(self._poll_obj.poll(timeout))
+
+ # The following error is known to occur with Linux kernel versions
+ # less than 2.6.24:
+ #
+ # select.error: (4, 'Interrupted system call')
+ #
+ # This error has been observed after a SIGSTOP, followed by SIGCONT.
+ # Treat it similar to EAGAIN if timeout is None, otherwise just return
+ # without any events.
+ while True:
+ try:
+ self._poll_event_queue.extend(self._poll_obj.poll(timeout))
+ break
+ except select.error, e:
+ writemsg_level("\n!!! select error: %s\n" % (e,),
+ level=logging.ERROR, noiselevel=-1)
+ del e
+ if timeout is not None:
+ break
def _next_poll_event(self, timeout=None):
"""
object.__setattr__(self, "_changed", False)
object.__setattr__(self, "_displayed", False)
object.__setattr__(self, "_last_display_time", 0)
+ object.__setattr__(self, "width", 80)
self.reset()
isatty = hasattr(out, "isatty") and out.isatty()
self._changed = True
self.display()
- def _load_avg_str(self, digits=2):
+ def _load_avg_str(self):
try:
avg = os.getloadavg()
except OSError, e:
return str(e)
+
+ max_avg = max(avg)
+
+ if max_avg < 10:
+ digits = 2
+ elif max_avg < 100:
+ digits = 1
+ else:
+ digits = 0
+
return ", ".join(("%%.%df" % digits ) % x for x in avg)
def display(self):
f.add_literal_data("Load avg: ")
f.add_literal_data(load_avg_str)
- self._update(color_output.getvalue())
- xtermTitle(" ".join(plain_output.getvalue().split()))
+ # Truncate to fit width, to avoid making the terminal scroll if the
+ # line overflows (happens when the load average is large).
+ plain_output = plain_output.getvalue()
+ if self._isatty and len(plain_output) > self.width:
+ # Use plain_output here since it's easier to truncate
+ # properly than the color output which contains console
+ # color codes.
+ self._update(plain_output[:self.width])
+ else:
+ self._update(color_output.getvalue())
+
+ xtermTitle(" ".join(plain_output.split()))
class Scheduler(PollScheduler):
for k in self._binpkg_opts.__slots__:
setattr(self._binpkg_opts, k, "--" + k.replace("_", "-") in myopts)
+ self.curval = 0
+ self._logger = self._emerge_log_class()
+ self._task_queues = self._task_queues_class()
+ for k in self._task_queues.allowed_keys:
+ setattr(self._task_queues, k,
+ SequentialTaskQueue())
+ self._status_display = JobStatusDisplay()
+ self._max_load = myopts.get("--load-average")
+ max_jobs = myopts.get("--jobs")
+ if max_jobs is None:
+ max_jobs = 1
+ self._set_max_jobs(max_jobs)
+ background = self._background_mode()
+ self._background = background
+
# The root where the currently running
# portage instance is installed.
self._running_root = trees["/"]["root_config"]
self._config_pool = {}
self._blocker_db = {}
for root in trees:
+ root_config = trees[root]["root_config"]
+ if background:
+ root_config.settings.unlock()
+ root_config.settings["PORTAGE_BACKGROUND"] = "1"
+ root_config.settings.backup_changes("PORTAGE_BACKGROUND")
+ root_config.settings.lock()
+
self.pkgsettings[root] = portage.config(
clone=trees[root]["vartree"].settings)
self._config_pool[root] = []
self._blocker_db[root] = BlockerDB(trees[root]["root_config"])
- self.curval = 0
- self._logger = self._emerge_log_class()
+
fetch_iface = self._fetch_iface_class(log_file=self._fetch_log,
schedule=self._schedule_fetch)
self._sched_iface = self._iface_class(
scheduleYield=self._schedule_yield,
unregister=self._unregister)
- self._task_queues = self._task_queues_class()
- for k in self._task_queues.allowed_keys:
- setattr(self._task_queues, k,
- SequentialTaskQueue())
-
self._prefetchers = weakref.WeakValueDictionary()
self._pkg_queue = []
self._completed_tasks = set()
- self._status_display = JobStatusDisplay()
-
self._failed_pkgs = []
self._failed_pkgs_all = []
self._failed_pkgs_die_msgs = []
curval=0, maxval=merge_count)
self._status_display.maxval = self._pkg_count.maxval
- max_jobs = myopts.get("--jobs")
- if max_jobs is None:
- max_jobs = 1
- self._set_max_jobs(max_jobs)
- background = self._background_mode()
- self._background = background
-
- self._max_load = myopts.get("--load-average")
-
# The load average takes some time to respond when new
# jobs are added, so we need to limit the rate of adding
# new jobs.
pkg_count = self._pkg_count
root_config = pkg.root_config
world_set = root_config.sets["world"]
- world_set.lock()
+ world_locked = False
+ if hasattr(world_set, "lock"):
+ world_set.lock()
+ world_locked = True
+
try:
- world_set.load() # maybe it's changed on disk
+ if hasattr(world_set, "load"):
+ world_set.load() # maybe it's changed on disk
+
atom = create_world_atom(pkg, args_set, root_config)
if atom:
- self._status_msg(('Recording %s in "world" ' + \
- 'favorites file...') % atom)
- logger.log(" === (%s of %s) Updating world file (%s)" % \
- (pkg_count.curval, pkg_count.maxval, pkg.cpv))
- world_set.add(atom)
+ if hasattr(world_set, "add"):
+ self._status_msg(('Recording %s in "world" ' + \
+ 'favorites file...') % atom)
+ logger.log(" === (%s of %s) Updating world file (%s)" % \
+ (pkg_count.curval, pkg_count.maxval, pkg.cpv))
+ world_set.add(atom)
+ else:
+ writemsg_level('\n!!! Unable to record %s in "world"\n' % \
+ (atom,), level=logging.WARN, noiselevel=-1)
finally:
- world_set.unlock()
+ if world_locked:
+ world_set.unlock()
def _pkg(self, cpv, type_name, root_config, installed=False):
"""
raise UninstallFailure(retval)
sys.exit(retval)
else:
- if clean_world:
+ if clean_world and hasattr(sets["world"], "cleanPackage"):
sets["world"].cleanPackage(vartree.dbapi, y)
emergelog(xterm_titles, " >>> unmerge success: "+y)
- if clean_world:
+ if clean_world and hasattr(sets["world"], "remove"):
for s in root_config.setconfig.active:
sets["world"].remove(SETPREFIX+s)
return 1
(eclasses_overridden[eclass_name], eclass_name),
noiselevel=-1)
writemsg(prefix + "\n", noiselevel=-1)
- msg = "It is best to avoid overridding eclasses from PORTDIR " + \
+ msg = "It is best to avoid overriding eclasses from PORTDIR " + \
"because it will trigger invalidation of cached ebuild metadata " + \
"that is distributed with the portage tree. If you must " + \
"override eclasses from PORTDIR then you are advised to add " + \
import sys
import copy
import errno
+ import logging
import os
import re
import shutil
"EMERGE_WARNING_DELAY", "FETCHCOMMAND", "FETCHCOMMAND_FTP",
"FETCHCOMMAND_HTTP", "FETCHCOMMAND_SFTP",
"GENTOO_MIRRORS", "NOCONFMEM", "O",
+ "PORTAGE_BACKGROUND",
"PORTAGE_BINHOST_CHUNKSIZE", "PORTAGE_CALLER",
"PORTAGE_ECLASS_WARNING_ENABLE", "PORTAGE_ELOG_CLASSES",
"PORTAGE_ELOG_MAILFROM", "PORTAGE_ELOG_MAILSUBJECT",
writemsg("File Not Found: '%s'\n" % str(e), noiselevel=-1)
return 1
+ _prepare_workdir(mysettings)
+ _prepare_features_dirs(mysettings)
+
+def _adjust_perms_msg(settings, msg):
+
+ def write(msg):
+ writemsg(msg, noiselevel=-1)
+
+ background = settings.get("PORTAGE_BACKGROUND") == "1"
+ log_path = settings.get("PORTAGE_LOG_FILE")
+ log_file = None
+
+ if background and log_path is not None:
+ try:
+ log_file = open(log_path, 'a')
+ except IOError:
+ def write(msg):
+ pass
+ else:
+ def write(msg):
+ log_file.write(msg)
+ log_file.flush()
+
+ try:
+ write(msg)
+ finally:
+ if log_file is not None:
+ log_file.close()
+
+def _prepare_features_dirs(mysettings):
+
features_dirs = {
"ccache":{
"basedir_var":"CCACHE_DIR",
not dirmode == (stat.S_IMODE(subdir_st.st_mode) & dirmode))):
droppriv_fix = True
break
+
if droppriv_fix:
- writemsg(colorize("WARN", " * ") + \
- "Adjusting permissions " + \
- "for FEATURES=userpriv: '%s'\n" % mydir,
- noiselevel=-1)
+ _adjust_perms_msg(mysettings,
+ colorize("WARN", " * ") + \
+ "Adjusting permissions " + \
+ "for FEATURES=userpriv: '%s'\n" % mydir)
elif modified:
- writemsg(colorize("WARN", " * ") + \
- "Adjusting permissions " + \
- "for FEATURES=%s: '%s'\n" % (myfeature, mydir),
- noiselevel=-1)
+ _adjust_perms_msg(mysettings,
+ colorize("WARN", " * ") + \
+ "Adjusting permissions " + \
+ "for FEATURES=%s: '%s'\n" % (myfeature, mydir))
+
if modified or kwargs["always_recurse"] or droppriv_fix:
def onerror(e):
raise # The feature is disabled if a single error
noiselevel=-1)
time.sleep(5)
+def _prepare_workdir(mysettings):
workdir_mode = 0700
try:
mode = mysettings["PORTAGE_WORKDIR_MODE"]
if phase_retval == os.EX_OK:
_doebuild_exit_status_unlink(
mysettings.get("EBUILD_EXIT_STATUS_FILE"))
+ mysettings.pop("EBUILD_PHASE", None)
phase_retval = spawn(
" ".join(_post_pkg_preinst_cmd(mysettings)),
mysettings, debug=debug, free=1, logfile=logfile)
if phase_retval == os.EX_OK:
_doebuild_exit_status_unlink(
mysettings.get("EBUILD_EXIT_STATUS_FILE"))
+ mysettings.pop("EBUILD_PHASE", None)
phase_retval = spawn(" ".join(_post_pkg_postinst_cmd(mysettings)),
mysettings, debug=debug, free=1, logfile=logfile)
phase_retval = exit_status_check(phase_retval)
def dep_wordreduce(mydeplist,mysettings,mydbapi,mode,use_cache=1):
"Reduces the deplist to ones and zeros"
deplist=mydeplist[:]
- for mypos in xrange(len(deplist)):
+ for mypos, token in enumerate(deplist):
if isinstance(deplist[mypos], list):
#recurse
deplist[mypos]=dep_wordreduce(deplist[mypos],mysettings,mydbapi,mode,use_cache=use_cache)
elif deplist[mypos]=="||":
pass
+ elif token[:1] == "!":
+ deplist[mypos] = False
else:
mykey = dep_getkey(deplist[mypos])
if mysettings and mykey in mysettings.pprovideddict and \
# process logs created during pre/postrm
elog_process(self.mycpv, self.settings, phasefilter=filter_unmergephases)
if retval == os.EX_OK:
- doebuild(myebuildpath, "cleanrm", self.myroot,
- self.settings, tree="vartree",
- mydbapi=self.vartree.dbapi,
- vartree=self.vartree)
+ if scheduler is None:
+ doebuild(myebuildpath, "cleanrm", self.myroot,
+ self.settings, tree="vartree",
+ mydbapi=self.vartree.dbapi,
+ vartree=self.vartree)
+ else:
+ scheduler.dblinkEbuildPhase(
+ self, self.vartree.dbapi,
+ myebuildpath, "cleanrm")
finally:
unlockdir(builddir_lock)
try:
if retval == os.EX_OK and "noclean" not in self.settings.features:
if myebuild is None:
myebuild = os.path.join(inforoot, self.pkg + ".ebuild")
- doebuild(myebuild, "clean", myroot, self.settings,
- tree=self.treetype, mydbapi=mydbapi, vartree=self.vartree)
+
+ if self._scheduler is None:
+ doebuild(myebuild, "clean", myroot,
+ self.settings, tree=self.treetype,
+ mydbapi=mydbapi, vartree=self.vartree)
+ else:
+ self._scheduler.dblinkEbuildPhase(
+ self, mydbapi, myebuild, "clean")
finally:
self.unlockdb()
return retval