# Make sure we have this USE flag in IUSE
if ! hasq "${u}" ${IUSE} ${E_IUSE} && \
+ ! hasq "+${u}" ${IUSE} ${E_IUSE} && \
+ ! hasq "-${u}" ${IUSE} ${E_IUSE} && \
! hasq "${u}" ${PORTAGE_ARCHLIST} selinux && \
[[ ${u} != prefix ]] && \
[[ ${u} != arch_* ]] && \
eerror "If you need support, post the topmost build error, and the call stack if relevant."
[[ -n ${PORTAGE_LOG_FILE} ]] \
&& eerror "A complete build log is located at '${PORTAGE_LOG_FILE}'."
- [ -f "${T}/environment" ] && \
+ if [ -f "${T}/environment" ] ; then
eerror "The ebuild environment file is located at '${T}/environment'."
+ elif [ -d "${T}" ] ; then
+ {
+ set
+ export
+ } > "${T}/die.env"
+ eerror "The ebuild environment file is located at '${T}/die.env'."
+ fi
if [[ -n ${EBUILD_OVERLAY_ECLASSES} ]] ; then
eerror "This ebuild used the following eclasses from overlays:"
local x
unset COLORTERM DISPLAY EDITOR LESS LESSOPEN LOGNAME LS_COLORS PAGER \
TERM TERMCAP USER
+ # other variables inherited from the calling environment
+ unset CVS_RSH ECHANGELOG_USER GPG_AGENT_INFO \
+ SSH_AGENT_PID SSH_AUTH_SOCK STY WINDOW XAUTHORITY
+
# There's no need to bloat environment.bz2 with internally defined
# functions and variables, so filter them out if possible.
not sys.stdout.isatty():
nocolor()
+def warn(txt):
+ print "repoman: " + txt
+
+def err(txt):
+ warn(txt)
+ sys.exit(1)
+
def exithandler(signum=None, frame=None):
logging.fatal("Interrupted; exiting...")
sys.exit(1)
repodir = os.path.dirname(repodir)
def caterror(mycat):
- err(mycat+" is not an official category. Skipping QA checks in this directory.\nPlease ensure that you add "+catdir+" to "+repodir+"/profiles/categories\nif it is a new category.")
+ warn(mycat + " is not an official category. " + \
+ "Skipping QA checks in this directory.\n" + \
+ "Please ensure that you add " + catdir + \
+ " to " + repodir + "/profiles/categories\nif it is a new category.")
def parse_use_local_desc(mylines, usedict=None):
"""returns a dict of the form {cpv:set(flags)}"""
self.pkgsettings[root] = portage.config(
clone=trees[root]["vartree"].settings)
self.curval = 0
+ self._spawned_pids = []
def merge(self, mylist, favorites, mtimedb):
+ try:
+ return self._merge(mylist, favorites, mtimedb)
+ finally:
+ if self._spawned_pids:
+ from portage import process
+ process.spawned_pids.extend(self._spawned_pids)
+ self._spawned_pids = []
+
+ def _poll_child_processes(self):
+ """
+ After each merge, collect status from child processes
+ in order to clean up zombies (such as the parallel-fetch
+ process).
+ """
+ spawned_pids = self._spawned_pids
+ if not spawned_pids:
+ return
+ for pid in list(spawned_pids):
+ try:
+ if os.waitpid(pid, os.WNOHANG) == (0, 0):
+ continue
+ except OSError:
+ # This pid has been cleaned up elsewhere,
+ # so remove it from our list.
+ pass
+ spawned_pids.remove(pid)
+
+ def _merge(self, mylist, favorites, mtimedb):
from portage.elog import elog_process
from portage.elog.filtering import filter_mergephases
failed_fetches = []
print red("!!!")+" you have it disabled, thus parallel-fetching is being disabled"
print red("!!!")
elif len(mymergelist) > 1:
- print ">>> starting parallel fetching"
fetch_log = EPREFIX+"/var/log/emerge-fetch.log"
logfile = open(fetch_log, "w")
fd_pipes = {1:logfile.fileno(), 2:logfile.fileno()}
fetch_args.append(myopt)
else:
fetch_args.append(myopt +"="+ myarg)
- portage.process.spawn(fetch_args, env=fetch_env,
- fd_pipes=fd_pipes, returnpid=True)
+ self._spawned_pids.extend(
+ portage.process.spawn(
+ fetch_args, env=fetch_env,
+ fd_pipes=fd_pipes, returnpid=True))
logfile.close() # belongs to the spawned process
del fetch_log, logfile, fd_pipes, fetch_env, fetch_args, \
resume_opts
+ print ">>> starting parallel fetching pid %d" % \
+ self._spawned_pids[-1]
metadata_keys = [k for k in portage.auxdbkeys \
if not k.startswith("UNUSED_")] + ["USE"]
# Figure out if we need a restart.
mysplit=portage.pkgsplit(x[2])
if mysplit[0] == "sys-apps/portage" and x[1] == "/":
- myver=mysplit[1]+"-"+mysplit[2]
- if myver[-3:]=='-r0':
- myver=myver[:-3]
- if (myver != portage.VERSION) and \
- "livecvsportage" not in self.settings.features and \
+ if "livecvsportage" not in self.settings.features and \:
EPREFIX == BPREFIX:
if len(mymergelist) > mergecount:
emergelog(xterm_titles,
# due to power failure, SIGKILL, etc...
mtimedb.commit()
self.curval += 1
+ self._poll_child_processes()
if "--pretend" not in self.myopts:
emergelog(xterm_titles, " *** Finished. Cleaning up...")
"TERM", "TERMCAP", "USER",
]
+ # other variables inherited from the calling environment
+ _environ_whitelist += [
+ "CVS_RSH", "ECHANGELOG_USER",
+ "GPG_AGENT_INFO",
+ "SSH_AGENT_PID", "SSH_AUTH_SOCK",
+ "STY", "WINDOW", "XAUTHORITY",
+ ]
+
_environ_whitelist = frozenset(_environ_whitelist)
# Filter selected variables in the config.environ() method so that
# misc variables inherited from the calling environment
_environ_filter += [
- "CVS_RSH", "ECHANGELOG_USER",
- "GPG_AGENT_INFO", "INFOPATH", "MANPATH",
- "SSH_AGENT_PID", "SSH_AUTH_SOCK",
- "STY", "WINDOW", "XAUTHORITY",
+ "INFOPATH", "MANPATH",
"HOST", "GROUP", "LOGNAME", "MAIL", "REMOTEHOST",
"SECURITYSESSIONID",
"TERMINFO", "TERM_PROGRAM", "TERM_PROGRAM_VERSION",
pass
return self._selinux_enabled
+def _shell_quote(s):
+ """
+ Quote a string in double-quotes and use backslashes to
+ escape any backslashes, double-quotes, dollar signs, or
+ backquotes in the string.
+ """
+ for letter in "\\\"$`":
+ if letter in s:
+ s = s.replace(letter, "\\" + letter)
+ return "\"%s\"" % s
+
# In some cases, openpty can be slow when it fails. Therefore,
# stop trying to use it after the first failure.
_disable_openpty = False
portage_bin_path = mysettings["PORTAGE_BIN_PATH"]
misc_sh_binary = os.path.join(portage_bin_path,
os.path.basename(MISC_SH_BINARY))
- mycommand = " ".join([misc_sh_binary,
+ mycommand = " ".join([_shell_quote(misc_sh_binary),
"install_qa_check", "install_symlink_html_docs"])
qa_retval = spawn(mycommand, mysettings, debug=debug, logfile=logfile, **kwargs)
if qa_retval:
mysettings["dbkey"] = ""
pr, pw = os.pipe()
fd_pipes = {0:0, 1:1, 2:2, 9:pw}
- mypids = spawn(ebuild_sh_binary + " depend", mysettings,
+ mypids = spawn(_shell_quote(ebuild_sh_binary) + " depend",
+ mysettings,
fd_pipes=fd_pipes, returnpid=True, droppriv=droppriv)
os.close(pw) # belongs exclusively to the child process now
maxbytes = 1024
mysettings["dbkey"] = \
os.path.join(mysettings.depcachedir, "aux_db_key_temp")
- return spawn(ebuild_sh_binary + " depend", mysettings,
+ return spawn(_shell_quote(ebuild_sh_binary) + " depend",
+ mysettings,
droppriv=droppriv)
# Validate dependency metadata here to ensure that ebuilds with invalid
saved_env = None
if saved_env:
retval = os.system(
- "bzip2 -dc '%s' > '%s'" % (saved_env, env_file))
+ "bzip2 -dc %s > %s" % \
+ (_shell_quote(saved_env),
+ _shell_quote(env_file)))
try:
env_stat = os.stat(env_file)
except OSError, e:
env_stat and env_stat.st_size > 0:
pass
else:
- writemsg("!!! Error extracting saved environment: '%s'" % \
+ writemsg(("!!! Error extracting saved " + \
+ "environment: '%s'\n") % \
saved_env, noiselevel=-1)
try:
os.unlink(env_file)
# if any of these are being called, handle them -- running them out of
# the sandbox -- and stop now.
if mydo in ["clean","cleanrm"]:
- return spawn(ebuild_sh_binary + " clean", mysettings,
+ return spawn(_shell_quote(ebuild_sh_binary) + " clean", mysettings,
debug=debug, free=1, logfile=None)
elif mydo == "help":
- return spawn(ebuild_sh_binary + " " + mydo, mysettings,
- debug=debug, free=1, logfile=logfile)
+ return spawn(_shell_quote(ebuild_sh_binary) + " " + mydo,
+ mysettings, debug=debug, free=1, logfile=logfile)
elif mydo == "setup":
infodir = os.path.join(
mysettings["PORTAGE_BUILDDIR"], "build-info")
"""Load USE flags for setup phase of a binary package.
Ideally, the environment.bz2 would be used instead."""
mysettings.load_infodir(infodir)
- retval = spawn(ebuild_sh_binary + " " + mydo, mysettings,
+ retval = spawn(
+ _shell_quote(ebuild_sh_binary) + " " + mydo, mysettings,
debug=debug, free=1, logfile=logfile)
retval = exit_status_check(retval)
if secpass >= 2:
filemode=060, filemask=0)
return retval
elif mydo == "preinst":
- phase_retval = spawn(" ".join((ebuild_sh_binary, mydo)),
+ phase_retval = spawn(
+ _shell_quote(ebuild_sh_binary) + " " + mydo,
mysettings, debug=debug, free=1, logfile=logfile)
phase_retval = exit_status_check(phase_retval)
if phase_retval == os.EX_OK:
# Post phase logic and tasks that have been factored out of
# ebuild.sh.
- myargs = [misc_sh_binary, "preinst_bsdflags", "preinst_mask",
+ myargs = [_shell_quote(misc_sh_binary),
+ "preinst_bsdflags", "preinst_mask",
"preinst_sfperms", "preinst_selinux_labels",
"preinst_suid_scan"]
_doebuild_exit_status_unlink(
return phase_retval
elif mydo == "postinst":
mysettings.load_infodir(mysettings["O"])
- phase_retval = spawn(" ".join((ebuild_sh_binary, mydo)),
+ phase_retval = spawn(
+ _shell_quote(ebuild_sh_binary) + " " + mydo,
mysettings, debug=debug, free=1, logfile=logfile)
phase_retval = exit_status_check(phase_retval)
if phase_retval == os.EX_OK:
# Post phase logic and tasks that have been factored out of
# ebuild.sh.
- myargs = [misc_sh_binary, "postinst_bsdflags"]
+ myargs = [_shell_quote(misc_sh_binary), "postinst_bsdflags"]
_doebuild_exit_status_unlink(
mysettings.get("EBUILD_EXIT_STATUS_FILE"))
mysettings["EBUILD_PHASE"] = ""
return phase_retval
elif mydo in ("prerm", "postrm", "config", "info"):
mysettings.load_infodir(mysettings["O"])
- retval = spawn(ebuild_sh_binary + " " + mydo,
+ retval = spawn(
+ _shell_quote(ebuild_sh_binary) + " " + mydo,
mysettings, debug=debug, free=1, logfile=logfile)
retval = exit_status_check(retval)
return retval
fakeroot = "fakeroot" in mysettings.features
- ebuild_sh = ebuild_sh_binary + " %s"
- misc_sh = misc_sh_binary + " dyn_%s"
+ ebuild_sh = _shell_quote(ebuild_sh_binary) + " %s"
+ misc_sh = _shell_quote(misc_sh_binary) + " dyn_%s"
# args are for the to spawn function
actionmap = {
backupenv_whitelist = settings._environ_whitelist
backupenv = settings.configdict["backupenv"]
+ env_d = settings.configdict["env.d"]
for k, v in os.environ.iteritems():
if k in backupenv_whitelist:
continue
- if v == backupenv.get(k):
- del backupenv[k]
+ if k in env_d or \
+ v == backupenv.get(k):
+ backupenv.pop(k, None)
settings.regenerate()
settings.lock()
settings.validate()
outfile.flush()
outfile.close()
+ # These caches are populated during collision-protect and the data
+ # they contain is now invalid. It's very important to invalidate
+ # the contents_inodes cache so that FEATURES=unmerge-orphans
+ # doesn't unmerge anything that belongs to this package that has
+ # just been merged.
+ others_in_slot.append(self) # self has just been merged
+ for dblnk in others_in_slot:
+ dblnk.contentscache = None
+ dblnk._contents_inodes = None
+
# If portage is reinstalling itself, remove the old
# version now since we want to use the temporary
# PORTAGE_BIN_PATH that will be removed when we return.
"portage" == pkgsplit(self.pkg)[0]:
reinstall_self = True
- for dblnk in others_in_slot:
+ for dblnk in list(others_in_slot):
+ if dblnk is self:
+ continue
if dblnk.mycpv != self.mycpv and \
not reinstall_self:
continue
writemsg_stdout(">>> Safely unmerging already-installed instance...\n")
- # These caches are populated during collision-protect and the data
- # they contain is now invalid. It's very important to invalidate
- # the contents_inodes cache so that FEATURES=unmerge-orphans
- # doesn't unmerge anything that belongs to this package that has
- # just been merged.
- self.contentscache = None
- self._contents_inodes = None
- others_in_slot.append(self) # self has just been merged
others_in_slot.remove(dblnk) # dblnk will unmerge itself now
dblnk.unmerge(trimworld=0, ldpath_mtimes=prev_mtimes,
others_in_slot=others_in_slot)
"""
if self.myroot == "/" and \
"sys-apps" == self.cat and \
- "portage" == pkgsplit(self.pkg)[0]:
+ "portage" == pkgsplit(self.pkg)[0] and \
+ "livecvsportage" not in self.settings.features:
settings = self.settings
base_path_orig = os.path.dirname(settings["PORTAGE_BIN_PATH"])
from tempfile import mkdtemp
return "".join(rValue)
_elog_mod_imports = {}
+def _load_mod(name):
+ global _elog_mod_imports
+ m = _elog_mod_imports.get(name)
+ if m is None:
+ m = __import__(name)
+ for comp in name.split(".")[1:]:
+ m = getattr(m, comp)
+ _elog_mod_imports[name] = m
+ return m
+
_elog_atexit_handlers = []
_preserve_logentries = {}
def elog_process(cpv, mysettings, phasefilter=None):
- global _elog_mod_imports
+
logsystems = mysettings.get("PORTAGE_ELOG_SYSTEM","").split()
for s in logsystems:
# allow per module overrides of PORTAGE_ELOG_CLASSES
# - is nicer than _ for module names, so allow people to use it.
s = s.replace("-", "_")
try:
- name = "portage.elog.mod_" + s
- m = _elog_mod_imports.get(name)
- if m is None:
- m = __import__(name)
- for comp in name.split(".")[1:]:
- m = getattr(m, comp)
- _elog_mod_imports[name] = m
+ _load_mod("portage.elog.mod_" + s)
except ImportError:
pass
# - is nicer than _ for module names, so allow people to use it.
s = s.replace("-", "_")
try:
- # FIXME: ugly ad.hoc import code
- # TODO: implement a common portage module loader
- name = "portage.elog.mod_" + s
- m = _elog_mod_imports.get(name)
- if m is None:
- m = __import__(name)
- for comp in name.split(".")[1:]:
- m = getattr(m, comp)
- _elog_mod_imports[name] = m
+ m = _load_mod("portage.elog.mod_" + s)
def timeout_handler(signum, frame):
raise PortageException("Timeout in elog_process for system '%s'" % s)
import signal