fi
# return shell-true/shell-false if exists.
# Takes single depend-type atoms.
+ PYTHONPATH="${PORTAGE_PYM_PATH}:${PYTHONPATH}" \
"${PORTAGE_BIN_PATH}"/portageq has_version "${ROOT}" "$1"
local retval=$?
case "${retval}" in
if [ "${EBUILD_PHASE}" == "depend" ]; then
die "portageq calls are not allowed in the global scope"
fi
+ PYTHONPATH="${PORTAGE_PYM_PATH}:${PYTHONPATH}" \
"${PORTAGE_BIN_PATH}/portageq" "$@"
}
fi
# returns the best/most-current match.
# Takes single depend-type atoms.
+ PYTHONPATH="${PORTAGE_PYM_PATH}:${PYTHONPATH}" \
"${PORTAGE_BIN_PATH}/portageq" 'best_version' "${ROOT}" "$1"
}
EAPI HOMEPAGE INHERITED IUSE KEYWORDS LICENSE
PDEPEND PROVIDE RDEPEND RESTRICT SLOT SRC_URI"
-READONLY_PORTAGE_VARS="A CATEGORY D EBUILD EBUILD_PHASE \
+READONLY_PORTAGE_VARS="A CATEGORY D EBUILD EBUILD_ENV_FILE EBUILD_PHASE \
EBUILD_SH_ARGS EMERGE_FROM FILESDIR P PF PN \
PORTAGE_BIN_PATH PORTAGE_PYM_PATH PORTAGE_MUTABLE_FILTERED_VARS \
PORTAGE_TMPDIR PR PV PVR T WORKDIR ED"
unset BIN_PATH BIN BODY FUNC_SRC
fi
-# Automatically try to load environment.bz2 whenever
-# "${T}/environment" does not exist, except for phases
-# such as nofetch that do not require ${T} to exist.
-if ! hasq ${EBUILD_SH_ARGS} clean depend nofetch && \
- [ ! -f "${T}/environment" ] ; then
- bzip2 -dc "${EBUILD%/*}"/environment.bz2 > \
- "${T}/environment" 2> /dev/null
- if [ $? -eq 0 ] && [ -s "${T}/environment" ] ; then
- preprocess_ebuild_env || \
- die "error processing '${EBUILD%/*}/environment.bz2'"
- else
- rm -f "${T}/environment"
- fi
-fi
-
if hasq ${EBUILD_SH_ARGS} clean ; then
true
elif ! hasq ${EBUILD_PHASE} depend && [ -f "${T}"/environment ] ; then
- if [ "${PN}" == "portage" ] && [ -n "${EBUILD_SH_ARGS}" ] ; then
- # When portage reinstalls itself, during inst/rm phases, the
- # environment may have been saved by a different version of ebuild.sh,
- # so it can't trusted that it's been properly filtered. Therefore,
- # always preprocess the environment when ${PN} == portage.
- preprocess_ebuild_env || \
- die "error processing environment"
- fi
+ # The environment may have been extracted from environment.bz2 or
+ # may have come from another version of ebuild.sh or something.
+ # In any case, preprocess it to prevent any potential interference.
+ preprocess_ebuild_env || \
+ die "error processing environment"
# Colon separated SANDBOX_* variables need to be cumulative.
for x in SANDBOX_DENY SANDBOX_READ SANDBOX_PREDICT SANDBOX_WRITE ; do
eval PORTAGE_${x}=\${!x}
virtuals ...etc you look in here.
"""
+ # Preserve backupenv values that are initialized in the config
+ # constructor. Also, preserve XARGS since it is set by the
+ # portage.data module.
+ _environ_whitelist = frozenset([
+ "FEATURES", "PORTAGE_BIN_PATH",
+ "PORTAGE_CONFIGROOT", "PORTAGE_DEPCACHEDIR",
+ "PORTAGE_GID", "PORTAGE_INST_GID", "PORTAGE_INST_UID",
+ "PORTAGE_PYM_PATH", "PORTDIR_OVERLAY", "ROOT", "USE_ORDER",
+ "XARGS",
+ ])
+
# Filter selected variables in the config.environ() method so that
# they don't needlessly propagate down into the ebuild environment.
_environ_filter = []
self.already_in_regenerate = 0
+ self._filter_calling_env = False
self.locked = 0
self.mycpv = None
self.puse = []
self._use_wildcards = False
if clone:
+ self._filter_calling_env = copy.deepcopy(clone._filter_calling_env)
self.incrementals = copy.deepcopy(clone.incrementals)
self.profile_path = copy.deepcopy(clone.profile_path)
self.user_profile_dir = copy.deepcopy(clone.user_profile_dir)
"return our locally-maintained environment"
mydict={}
environ_filter = self._environ_filter
+ filter_calling_env = self._filter_calling_env
+ environ_whitelist = self._environ_whitelist
+ env_d = self.configdict["env.d"]
for x in self:
if x in environ_filter:
continue
writemsg("!!! Non-string value in config: %s=%s\n" % \
(x, myvalue), noiselevel=-1)
continue
+ if filter_calling_env and \
+ x not in environ_whitelist:
+ if myvalue == env_d.get(x) or \
+ myvalue == os.environ.get(x):
+ continue
mydict[x] = myvalue
if not mydict.has_key("HOME") and mydict.has_key("BUILD_PREFIX"):
writemsg("*** HOME not set. Setting to "+mydict["BUILD_PREFIX"]+"\n")
mysettings["EBUILD_PHASE"] = mydo
_doebuild_exit_status_unlink(
mysettings.get("EBUILD_EXIT_STATUS_FILE"))
- phase_retval = spawn(actionmap[mydo]["cmd"] % mydo, mysettings, debug=debug, logfile=logfile, **kwargs)
- mysettings["EBUILD_PHASE"] = ""
+ filter_calling_env_state = mysettings._filter_calling_env
+ if os.path.exists(os.path.join(mysettings["T"], "environment")):
+ mysettings._filter_calling_env = True
+ try:
+ phase_retval = spawn(actionmap[mydo]["cmd"] % mydo,
+ mysettings, debug=debug, logfile=logfile, **kwargs)
+ finally:
+ mysettings["EBUILD_PHASE"] = ""
+ mysettings._filter_calling_env = filter_calling_env_state
msg = _doebuild_exit_status_check(mydo, mysettings)
if msg:
phase_retval = 1
apply_secpass_permissions(fpath, uid=myuid, gid=mygid,
mode=mystat.st_mode, stat_cached=mystat,
follow_links=False)
- mycommand = " ".join([MISC_SH_BINARY, "install_qa_check", "install_symlink_html_docs"])
+ # Note: PORTAGE_BIN_PATH may differ from the global
+ # constant when portage is reinstalling itself.
+ 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,
+ "install_qa_check", "install_symlink_html_docs"])
qa_retval = spawn(mycommand, mysettings, debug=debug, logfile=logfile, **kwargs)
if qa_retval:
writemsg("!!! install_qa_check failed; exiting.\n",
mysplit=mysettings["PATH"].split(":")
else:
mysplit=[]
- if PORTAGE_BIN_PATH not in mysplit:
- mysettings["PATH"]=PORTAGE_BIN_PATH+":"+mysettings["PATH"]
+ # Note: PORTAGE_BIN_PATH may differ from the global constant
+ # when portage is reinstalling itself.
+ portage_bin_path = mysettings["PORTAGE_BIN_PATH"]
+ if portage_bin_path not in mysplit:
+ mysettings["PATH"] = portage_bin_path + ":" + mysettings["PATH"]
# Sandbox needs cannonical paths.
mysettings["PORTAGE_TMPDIR"] = os.path.realpath(
Returns an error string if the shell appeared
to exit unsuccessfully, None otherwise.
"""
- if settings.get("ROOT") == "/" and \
- settings.get("PN") == "portage":
- # portage upgrade or downgrade invalidates this check
- # since ebuild.sh portage version may differ from the
- # current instance that is running in python.
- return None
exit_status_file = settings.get("EBUILD_EXIT_STATUS_FILE")
if not exit_status_file or \
os.path.exists(exit_status_file):
eerror(l, phase=mydo, key=mysettings.mycpv)
return retval
+ # Note: PORTAGE_BIN_PATH may differ from the global
+ # constant when portage is reinstalling itself.
+ portage_bin_path = mysettings["PORTAGE_BIN_PATH"]
+ ebuild_sh_binary = os.path.join(portage_bin_path,
+ os.path.basename(EBUILD_SH_BINARY))
+ misc_sh_binary = os.path.join(portage_bin_path,
+ os.path.basename(MISC_SH_BINARY))
+
logfile=None
builddir_lock = None
tmpdir = None
tmpdir_orig = None
+ filter_calling_env_state = mysettings._filter_calling_env
try:
if mydo in ("digest", "manifest", "help"):
# Temporarily exempt the depend phase from manifest checks, in case
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(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(ebuild_sh_binary + " depend", mysettings,
droppriv=droppriv)
# Validate dependency metadata here to ensure that ebuilds with invalid
if logfile and not os.access(os.path.dirname(logfile), os.W_OK):
logfile = None
if have_build_dirs:
+ env_file = os.path.join(mysettings["T"], "environment")
+ env_stat = None
+ saved_env = None
+ try:
+ env_stat = os.stat(env_file)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ if not env_stat:
+ saved_env = os.path.join(
+ os.path.dirname(myebuild), "environment.bz2")
+ if not os.path.isfile(saved_env):
+ saved_env = None
+ if saved_env:
+ retval = os.system(
+ "bzip2 -dc '%s' > '%s'" % (saved_env, env_file))
+ try:
+ env_stat = os.stat(env_file)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ if os.WIFEXITED(retval) and \
+ os.WEXITSTATUS(retval) == os.EX_OK and \
+ env_stat and env_stat.st_size > 0:
+ pass
+ else:
+ writemsg("!!! Error extracting saved environment: '%s'" % \
+ saved_env, noiselevel=-1)
+ try:
+ os.unlink(env_file)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ env_stat = None
+ if env_stat:
+ mysettings._filter_calling_env = True
+ del env_file, env_stat, saved_env
_doebuild_exit_status_unlink(
mysettings.get("EBUILD_EXIT_STATUS_FILE"))
else:
# 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(ebuild_sh_binary + " clean", mysettings,
debug=debug, free=1, logfile=None)
elif mydo == "help":
- return spawn(EBUILD_SH_BINARY + " " + mydo, mysettings,
+ return spawn(ebuild_sh_binary + " " + mydo, mysettings,
debug=debug, free=1, logfile=logfile)
elif mydo == "setup":
infodir = os.path.join(
"""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(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(" ".join((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 = [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(" ".join((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 = [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(ebuild_sh_binary + " " + mydo,
mysettings, debug=debug, free=1, logfile=logfile)
retval = exit_status_check(retval)
return retval
# mod_echo module might push the original message off of the
# top of the terminal and prevent the user from being able to
# see it.
- mysettings["EBUILD_PHASE"] = "unpack"
- cmd = "source '%s/isolated-functions.sh' ; " % PORTAGE_BIN_PATH
- cmd += "eerror \"Fetch failed for '%s'\"" % mycpv
- portage.process.spawn(["bash", "-c", cmd],
- env=mysettings.environ())
+ from portage.elog.messages import eerror
+ eerror("Fetch failed for '%s'" % mycpv,
+ phase="unpack", key=mycpv)
from portage.elog import elog_process
elog_process(mysettings.mycpv, mysettings)
return 1
fakeroot = "fakeroot" in mysettings.features
- ebuild_sh = EBUILD_SH_BINARY + " %s"
- misc_sh = MISC_SH_BINARY + " dyn_%s"
+ ebuild_sh = ebuild_sh_binary + " %s"
+ misc_sh = misc_sh_binary + " dyn_%s"
# args are for the to spawn function
actionmap = {
return retval
finally:
+ mysettings._filter_calling_env = filter_calling_env_state
if tmpdir:
mysettings["PORTAGE_TMPDIR"] = tmpdir_orig
shutil.rmtree(tmpdir)
# with ROOT != "/", so we wipe out the "backupenv" for the
# config that is associated with ROOT == "/" and regenerate
# it's incrementals.
-
# Preserve backupenv values that are initialized in the config
# constructor. Also, preserve XARGS since it is set by the
# portage.data module.
- backupenv_whitelist = set(["FEATURES", "PORTAGE_BIN_PATH",
- "PORTAGE_CONFIGROOT", "PORTAGE_DEPCACHEDIR",
- "PORTAGE_GID", "PORTAGE_INST_GID", "PORTAGE_INST_UID",
- "PORTAGE_PYM_PATH", "PORTDIR_OVERLAY", "ROOT", "USE_ORDER",
- "XARGS"])
+
+ backupenv_whitelist = settings._environ_whitelist
backupenv = settings.configdict["backupenv"]
for k, v in os.environ.iteritems():
if k in backupenv_whitelist:
outfile.flush()
outfile.close()
+ # 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.
+ reinstall_self = False
+ if self.myroot == "/" and \
+ "sys-apps" == self.cat and \
+ "portage" == pkgsplit(self.pkg)[0]:
+ reinstall_self = True
+
for dblnk in others_in_slot:
- if dblnk.mycpv != self.mycpv:
+ 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
others_in_slot.remove(dblnk) # dblnk will unmerge itself now
dblnk.unmerge(trimworld=0, ldpath_mtimes=prev_mtimes,
others_in_slot=others_in_slot)
+ # TODO: Check status and abort if necessary.
+ dblnk.delete()
writemsg_stdout(">>> Original instance of package unmerged safely.\n")
- break
+ if not reinstall_self:
+ break
# We hold both directory locks.
self.dbdir = self.dbpkgdir
writemsg_stdout(zing + " " + mydest + "\n")
def merge(self, mergeroot, inforoot, myroot, myebuild=None, cleanup=0,
+ mydbapi=None, prev_mtimes=None):
+ """
+ If portage is reinstalling itself, create temporary
+ copies of PORTAGE_BIN_PATH and PORTAGE_PYM_PATH in order
+ to avoid relying on the new versions which may be
+ incompatible. Register an atexit hook to clean up the
+ temporary directories. Pre-load elog modules here since
+ we won't be able to later if they get unmerged (happens
+ when namespace changes).
+ """
+ if self.myroot == "/" and \
+ "sys-apps" == self.cat and \
+ "portage" == pkgsplit(self.pkg)[0]:
+ settings = self.settings
+ base_path_orig = os.path.dirname(settings["PORTAGE_BIN_PATH"])
+ from tempfile import mkdtemp
+ import shutil
+ base_path_tmp = mkdtemp()
+ from portage.process import atexit_register
+ atexit_register(shutil.rmtree, base_path_tmp)
+ dir_perms = 0755
+ for subdir in "bin", "pym":
+ var_name = "PORTAGE_%s_PATH" % subdir.upper()
+ var_orig = settings[var_name]
+ var_new = os.path.join(base_path_tmp, subdir)
+ settings[var_name] = var_new
+ settings.backup_changes(var_name)
+ shutil.copytree(var_orig, var_new, symlinks=True)
+ os.chmod(var_new, dir_perms)
+ os.chmod(base_path_tmp, dir_perms)
+ # This serves so pre-load the modules.
+ elog_process(self.mycpv, self.settings,
+ phasefilter=filter_mergephases)
+
+ return self._merge(mergeroot, inforoot,
+ myroot, myebuild=myebuild, cleanup=cleanup,
+ mydbapi=mydbapi, prev_mtimes=prev_mtimes)
+
+ def _merge(self, mergeroot, inforoot, myroot, myebuild=None, cleanup=0,
mydbapi=None, prev_mtimes=None):
retval = -1
self.lockdb()