EAPI HOMEPAGE INHERITED IUSE KEYWORDS LICENSE
PDEPEND PROVIDE RDEPEND RESTRICT SLOT SRC_URI"
-READONLY_PORTAGE_VARS="D EBUILD EBUILD_PHASE ED \
- EBUILD_SH_ARGS EMERGE_FROM FILESDIR PORTAGE_BIN_PATH \
- PORTAGE_PYM_PATH PORTAGE_TMPDIR T WORKDIR"
+READONLY_PORTAGE_VARS="A CATEGORY D EBUILD 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"
+
+# Variables that portage sets but doesn't mark readonly.
+# In order to prevent changed values from causing unexpected
+# interference, they are filtered out of the environment when
+# it is saved or loaded (any mutations do not persist).
+PORTAGE_MUTABLE_FILTERED_VARS="AA"
# @FUNCTION: filter_readonly_variables
# @DESCRIPTION: [--filter-sandbox]
SANDBOX_DEBUG_LOG SANDBOX_DISABLED SANDBOX_LIB
SANDBOX_LOG"
filtered_vars="${readonly_bash_vars} ${READONLY_PORTAGE_VARS}
- BASH_[_[:alnum:]]*"
+ ${PORTAGE_MUTABLE_FILTERED_VARS} BASH_[_[:alnum:]]*"
if hasq --filter-sandbox $* ; then
filtered_vars="${filtered_vars} SANDBOX_[_[:alnum:]]*"
else
preprocess_ebuild_env() {
filter_readonly_variables --filter-sandbox < "${T}"/environment \
> "${T}"/environment.filtered
- mv "${T}"/environment.filtered "${T}"/environment
+ if [ $? -ne 0 ] ; then
+ rm -f "${T}/environment.filtered"
+ return 1
+ fi
+ mv "${T}"/environment.filtered "${T}"/environment || return $?
+ rm -f "${T}/environment.success" || return $?
# WARNING: Code inside this subshell should avoid making assumptions
# about variables or functions after source "${T}"/environment has been
# called. Any variables that need to be relied upon should already be
# filtered out above.
(
- source "${T}"/environment
+ source "${T}/environment" || exit $?
# It's remotely possible that save_ebuild_env() has been overridden
# by the above source command. To protect ourselves, we override it
# here with our own version. ${PORTAGE_BIN_PATH} is safe to use here
# because it's already filtered above.
- source "${PORTAGE_BIN_PATH}/isolated-functions.sh"
+ source "${PORTAGE_BIN_PATH}/isolated-functions.sh" || exit $?
# Rely on save_ebuild_env() to filter out any remaining variables
# and functions that could interfere with the current environment.
- save_ebuild_env
- ) | filter_readonly_variables > "${T}"/environment
+ save_ebuild_env || exit $?
+ touch "${T}/environment.success" || exit $?
+ ) | filter_readonly_variables > "${T}/environment.filtered"
+ if [ -e "${T}/environment.success" ] ; then
+ rm "${T}/environment.success"
+ mv "${T}/environment.filtered" "${T}/environment"
+ return $?
+ else
+ rm -f "${T}/environment.filtered"
+ fi
+ return 1
}
# === === === === === === === === === === === === === === === === === ===
fi
# Automatically try to load environment.bz2 whenever
-# "${T}/environment" does not exist.
-if ! hasq ${EBUILD_SH_ARGS} clean depend && \
+# "${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 [ -s "${T}/environment" ] ; then
- preprocess_ebuild_env
+ if [ $? -eq 0 ] && [ -s "${T}/environment" ] ; then
+ preprocess_ebuild_env || \
+ die "error processing '${EBUILD%/*}/environment.bz2'"
else
rm -f "${T}/environment"
fi
# 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
+ preprocess_ebuild_env || \
+ die "error processing environment"
fi
# Colon separated SANDBOX_* variables need to be cumulative.
for x in SANDBOX_DENY SANDBOX_READ SANDBOX_PREDICT SANDBOX_WRITE ; do
eval PORTAGE_${x}=\${!x}
done
- source "${T}"/environment
+ source "${T}"/environment || \
+ die "error sourcing environment"
for x in SANDBOX_DENY SANDBOX_PREDICT SANDBOX_READ SANDBOX_WRITE ; do
eval y=\${PORTAGE_${x}}
if [ "${y}" != "${!x}" ] ; then
# declare them only after it has already run.
if [ "${EBUILD_PHASE}" != "depend" ] ; then
declare -r ${READONLY_EBUILD_METADATA} ${READONLY_PORTAGE_VARS}
- for x in A AA CATEGORY EMERGE_FROM P PF PN PR PV PVR ; do
- [[ ${!x-UNSET_VAR} != UNSET_VAR ]] && declare -r ${x}
- done
- unset x
fi
if [ -n "${EBUILD_SH_ARGS}" ] ; then
# Save the env only for relevant phases.
if [ -n "${EBUILD_SH_ARGS}" ] && \
- ! hasq ${EBUILD_SH_ARGS} clean help info; then
+ ! hasq ${EBUILD_SH_ARGS} clean help info nofetch ; then
# Save current environment and touch a success file. (echo for success)
umask 002
save_ebuild_env | filter_readonly_variables > "${T}/environment"
procount=0
for x in config_protect:
x = os.path.join(target_root, x.lstrip(os.path.sep))
+ if not os.access(x, os.W_OK):
+ # Avoid Permission denied errors generated
+ # later by `find`.
+ continue
try:
mymode = os.lstat(x).st_mode
except OSError:
"PORTAGE_ECLASS_WARNING_ENABLE", "PORTAGE_ELOG_CLASSES",
"PORTAGE_ELOG_MAILFROM", "PORTAGE_ELOG_MAILSUBJECT",
"PORTAGE_ELOG_MAILURI", "PORTAGE_ELOG_SYSTEM", "PORTAGE_GPG_DIR",
- "PORTAGE_GPG_KEY", "PORTAGE_RSYNC_EXTRA_OPTS", "PORTAGE_RSYNC_OPTS",
+ "PORTAGE_GPG_KEY", "PORTAGE_PACKAGE_EMPTY_ABORT",
+ "PORTAGE_RSYNC_EXTRA_OPTS", "PORTAGE_RSYNC_OPTS",
"PORTAGE_RSYNC_RETRIES", "PORT_LOGDIR", "QUICKPKG_DEFAULT_OPTS",
"RESUMECOMMAND", "RESUMECOMMAND_HTTP", "RESUMECOMMAND_HTTP",
"RESUMECOMMAND_SFTP", "SYNC", "USE_EXPAND_HIDDEN", "USE_ORDER",
return d[k]
return x
- def pop(self, k, x=None):
- self.modifying()
- v = x
+ def pop(self, key, *args):
+ if len(args) > 1:
+ raise TypeError(
+ "pop expected at most 2 arguments, got " + \
+ repr(1 + len(args)))
+ v = self
for d in reversed(self.lookuplist):
- v = d.pop(k, v)
+ v = d.pop(key, v)
+ if v is self:
+ if args:
+ return args[0]
+ raise KeyError(key)
return v
def has_key(self,mykey):
mysettings.get("EBUILD_EXIT_STATUS_FILE"))
phase_retval = spawn(actionmap[mydo]["cmd"] % mydo, mysettings, debug=debug, logfile=logfile, **kwargs)
mysettings["EBUILD_PHASE"] = ""
- msg = _doebuild_exit_status_check(
- mydo, mysettings.get("EBUILD_EXIT_STATUS_FILE"))
+ msg = _doebuild_exit_status_check(mydo, mysettings)
if msg:
phase_retval = 1
from textwrap import wrap
mysettings["PORTAGE_LOG_FILE"] = os.path.join(
mysettings["T"], "build.log")
-def _doebuild_exit_status_check(mydo, exit_status_file):
+def _doebuild_exit_status_check(mydo, settings):
"""
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):
return None
def exit_status_check(retval):
if retval != os.EX_OK:
return retval
- msg = _doebuild_exit_status_check(
- mydo, mysettings.get("EBUILD_EXIT_STATUS_FILE"))
+ msg = _doebuild_exit_status_check(mydo, mysettings)
if msg:
retval = 1
from textwrap import wrap
myargs = [MISC_SH_BINARY, "preinst_bsdflags", "preinst_mask",
"preinst_sfperms", "preinst_selinux_labels",
"preinst_suid_scan"]
+ _doebuild_exit_status_unlink(
+ mysettings.get("EBUILD_EXIT_STATUS_FILE"))
mysettings["EBUILD_PHASE"] = ""
phase_retval = spawn(" ".join(myargs),
mysettings, debug=debug, free=1, logfile=logfile)
+ phase_retval = exit_status_check(phase_retval)
if phase_retval != os.EX_OK:
writemsg("!!! post preinst failed; exiting.\n",
noiselevel=-1)
# Post phase logic and tasks that have been factored out of
# ebuild.sh.
myargs = [MISC_SH_BINARY, "postinst_bsdflags"]
+ _doebuild_exit_status_unlink(
+ mysettings.get("EBUILD_EXIT_STATUS_FILE"))
mysettings["EBUILD_PHASE"] = ""
phase_retval = spawn(" ".join(myargs),
mysettings, debug=debug, free=1, logfile=logfile)
+ phase_retval = exit_status_check(phase_retval)
if phase_retval != os.EX_OK:
writemsg("!!! post postinst failed; exiting.\n",
noiselevel=-1)
elif mydo=="merge":
retval = spawnebuild("install", actionmap, mysettings, debug,
alwaysdep=1, logfile=logfile)
- if retval == os.EX_OK:
- retval = exit_status_check(retval)
- else:
+ retval = exit_status_check(retval)
+ if retval != os.EX_OK:
# The merge phase handles this already. Callers don't know how
# far this function got, so we have to call elog_process() here
# so that it's only called once.
if slot is None:
slot = ""
+ from portage.elog.messages import eerror as _eerror
+ def eerror(lines):
+ for l in lines:
+ _eerror(l, phase="preinst", key=self.settings.mycpv)
+
if slot != self.settings["SLOT"]:
writemsg("!!! WARNING: Expected SLOT='%s', got '%s'\n" % \
(self.settings["SLOT"], slot))
# to an infinite recursion loop.
mylinklist.append(file_path[len(srcroot):])
+ # If there are no files to merge, and an installed package in the same
+ # slot has files, it probably means that something went wrong.
+ if self.settings.get("PORTAGE_PACKAGE_EMPTY_ABORT") == "1" and \
+ not myfilelist and not mylinklist and others_in_slot:
+ installed_files = None
+ for other_dblink in others_in_slot:
+ installed_files = other_dblink.getcontents()
+ if not installed_files:
+ continue
+ from textwrap import wrap
+ wrap_width = 72
+ msg = []
+ d = (
+ self.mycpv,
+ other_dblink.mycpv
+ )
+ msg.extend(wrap(("The '%s' package will not install " + \
+ "any files, but the currently installed '%s'" + \
+ " package has the following files: ") % d, wrap_width))
+ msg.append("")
+ msg.extend(sorted(installed_files))
+ msg.append("")
+ msg.append("package %s NOT merged" % self.mycpv)
+ msg.append("")
+ msg.extend(wrap(
+ ("Manually run `emerge --unmerge =%s` " % \
+ other_dblink.mycpv) + "if you really want to " + \
+ "remove the above files. Set " + \
+ "PORTAGE_PACKAGE_EMPTY_ABORT=\"0\" in " + \
+ "/etc/make.conf if you do not want to " + \
+ "abort in cases like this.",
+ wrap_width))
+ eerror(msg)
+ if installed_files:
+ return 1
+
# Preserve old libs if they are still in use
if slot_matches and "preserve-libs" in self.settings.features:
self._preserve_libs(srcroot, destroot, myfilelist+mylinklist, counter)
self.settings, 0, 0, mydbapi)
prepare_build_dirs(destroot, self.settings, cleanup)
- from portage.elog.messages import eerror as _eerror
- def eerror(lines):
- for l in lines:
- _eerror(l, phase="preinst", key=self.settings.mycpv)
-
if collisions:
collision_protect = "collision-protect" in self.settings.features
msg = "This package will overwrite one or more files that" + \
del page
listing = parser.get_anchors()
else:
- raise Exception, "Unable to get listing: %s" % msg
+ import portage.exception
+ raise portage.exception.PortageException(
+ "Unable to get listing: %s %s" % (rc,msg))
elif protocol in ["ftp"]:
if address[-1] == '/':
olddir = conn.pwd()
sys.stderr.write("!!! Permission denied: '%s'\n" % cache_path)
return metadata[baseurl]["data"]
+ import portage.exception
try:
filelist = dir_get_list(baseurl, conn)
- except Exception, e:
- sys.stderr.write("!!! "+str(e)+"\n")
- sys.stderr.flush()
+ except portage.exception.PortageException, e:
+ sys.stderr.write("!!! Error connecting to '%s'.\n" % baseurl)
+ sys.stderr.write("!!! %s\n" % str(e))
+ del e
return metadata[baseurl]["data"]
tbz2list = match_in_array(filelist, suffix=".tbz2")
metalist = match_in_array(filelist, prefix="metadata.idx")