Merged from trunk 8661:8696
authorFabian Groffen <grobian@gentoo.org>
Sun, 2 Dec 2007 21:19:10 +0000 (21:19 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sun, 2 Dec 2007 21:19:10 +0000 (21:19 -0000)
   | 8662    | Remove some unsafe assumptions from preprocess_ebuild_env()  |
   | zmedico | and note the remaining assumption that save_ebuild_env() is  |
   |         | not overridden by the environment being loaded.              |

   | 8663    | Make preprocess_ebuild_env() reload a known good version of  |
   | zmedico | save_ebuild_env() in order to avoid making an assumption     |
   |         | that it hasn't been overridden.                              |

   | 8666    | Filter _RC_GET_KV_CACHE from the saved environment.          |
   | zmedico |                                                              |

   | 8668    | Bug #124041 - Make emerge show an informative warning        |
   | zmedico | message when one or more eclasses override eclasses from     |
   |         | PORTDIR. The warning can be permanently disabled by setting  |
   |         | PORTAGE_ECLASS_WARNING_ENABLE="0" in /etc/make.conf.         |

   | 8670    | * Move filtering of a bunch of portage config variables from |
   | zmedico | save_ebuild_env() to config.environ(). * Add EMERGE_FROM to  |
   |         | the READONLY_PORTAGE_VARS list.                              |

   | 8672    | Add NOCONFMEM to config._environ_filter.                     |
   | zmedico |                                                              |

   | 8674    | unset ECLASS along with the other variables from inherit().  |
   | zmedico |                                                              |

   | 8676    | Filter more misc environment variables.                      |
   | zmedico |                                                              |

   | 8678    | Make diefunc() show the path of ${T}/environment since it's  |
   | zmedico | usually in the stack trace and the user is likely to be      |
   |         | interested in it.                                            |

   | 8680    | Automatically try to load environment.bz2 whenever           |
   | zmedico | "${T}/environment" does not exist, except for "clean" and    |
   |         | "depend" phases.                                             |

   | 8682    | Bug #200313 - Detect and report when an ebuild phase exits   |
   | zmedico | unexpectedly. This is type of behavior is known to be        |
   |         | triggered by things such as failed variable assignments (bug |
   |         | #190128) or bad substitution errors (bug #200313). We use a  |
   |         | EBUILD_EXIT_STATUS_FILE environment variable to specify a    |
   |         | file that the shell code is supposed to create when it exits |
   |         | in a normal manner. If the file does not get created like    |
   |         | it's supposed to be then we can conclude that the shell has  |
   |         | exited in some unexpected way.                               |

   | 8683    | --buildpkgonly will not merge anything, so it cancels all    |
   | zmedico | binary package options.                                      |

   | 8686    | Check if ${EBUILD_EXIT_STATUS_FILE} is empty before          |
   | zmedico | attempting to use it.                                        |

   | 8688    | Implement config.pop().                                      |
   | zmedico |                                                              |

   | 8690    | Make config.pop() properly call config.modifying().          |
   | zmedico |                                                              |

   | 8692    | * In doebuild(), don't create directories for the "clean" or |
   | zmedico | "unmerge". * Fix dyn_clean() to clean the status file and    |
   |         | return early when appropriate.                               |

   | 8694    | Fix grammar.                                                 |
   | zmedico |                                                              |

   | 8696    | Make doebuild skip directory creation for the "cleanrm"      |
   | zmedico | command.                                                     |

svn path=/main/branches/prefix/; revision=8809

bin/ebuild.sh
bin/isolated-functions.sh
bin/misc-functions.sh
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/eclass_cache.py

index f8b33f69889c4c1bcca1f154ff81abd12a79c4b6..e24bcc9491cae5a8c1c52dff6a8f2bb7eabffeab 100755 (executable)
@@ -680,8 +680,9 @@ dyn_clean() {
        if [ -z "${PORTAGE_BUILDDIR}" ]; then
                echo "Aborting clean phase because PORTAGE_BUILDDIR is unset!"
                return 1
+       elif [ ! -d "${PORTAGE_BUILDDIR}" ] ; then
+               return 0
        fi
-
        if type -P chflags > /dev/null ; then
                chflags -R noschg,nouchg,nosappnd,nouappnd "${PORTAGE_BUILDDIR}"
                chflags -R nosunlnk,nouunlnk "${PORTAGE_BUILDDIR}" 2>/dev/null
@@ -696,6 +697,7 @@ dyn_clean() {
        fi
 
        if ! hasq keepwork $FEATURES; then
+               rm -rf "${PORTAGE_BUILDDIR}/.exit_status"
                rm -rf "${PORTAGE_BUILDDIR}/.logid"
                rm -rf "${PORTAGE_BUILDDIR}/.unpacked"
                rm -rf "${PORTAGE_BUILDDIR}/.compiled"
@@ -1361,8 +1363,9 @@ READONLY_EBUILD_METADATA="DEPEND DESCRIPTION
        EAPI HOMEPAGE INHERITED IUSE KEYWORDS LICENSE
        PDEPEND PROVIDE RDEPEND RESTRICT SLOT SRC_URI"
 
-READONLY_PORTAGE_VARS="D EBUILD EBUILD_PHASE EBUILD_SH_ARGS FILESDIR \
-       PORTAGE_BIN_PATH PORTAGE_PYM_PATH PORTAGE_TMPDIR T WORKDIR"
+READONLY_PORTAGE_VARS="D EBUILD EBUILD_PHASE ED \
+       EBUILD_SH_ARGS EMERGE_FROM FILESDIR PORTAGE_BIN_PATH \
+       PORTAGE_PYM_PATH PORTAGE_TMPDIR T WORKDIR"
 
 # @FUNCTION: filter_readonly_variables
 # @DESCRIPTION: [--filter-sandbox]
@@ -1418,91 +1421,23 @@ preprocess_ebuild_env() {
        filter_readonly_variables --filter-sandbox < "${T}"/environment \
                > "${T}"/environment.filtered
        mv "${T}"/environment.filtered "${T}"/environment
+       # 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
-               # 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
-       )
-}
 
-# @FUNCTION: save_ebuild_env
-# @DESCRIPTION:
-# echo the current environment to stdout, filtering out redundant info.
-save_ebuild_env() {
-       (
+               # 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"
 
-               # misc variables set by bash
-               unset BASH HOSTTYPE IFS MACHTYPE OLDPWD \
-                       OPTERR OPTIND OSTYPE PS4 PWD SHELL
-
-               # misc variables inherited from the calling environment
-               unset COLORTERM DISPLAY EDITOR LESS LESSOPEN LOGNAME LS_COLORS PAGER \
-                       TERM TERMCAP USER
-
-               # There's no need to bloat environment.bz2 with internally defined
-               # functions and variables, so filter them out if possible.
-
-               unset -f dump_trace diefunc quiet_mode vecho elog_base eqawarn elog \
-                       esyslog einfo einfon ewarn eerror ebegin _eend eend KV_major \
-                       KV_minor KV_micro KV_to_int get_KV unset_colors set_colors has \
-                       hasv hasq qa_source qa_call addread addwrite adddeny addpredict \
-                       lchown lchgrp esyslog use usev useq has_version portageq \
-                       best_version use_with use_enable register_die_hook check_KV \
-                       keepdir unpack strip_duplicate_slashes econf einstall gen_wrapper \
-                       dyn_setup dyn_unpack dyn_clean into insinto exeinto docinto \
-                       insopts diropts exeopts libopts abort_handler abort_compile \
-                       abort_test abort_install dyn_compile dyn_test dyn_install \
-                       dyn_preinst dyn_help debug-print debug-print-function \
-                       debug-print-section inherit EXPORT_FUNCTIONS newdepend newrdepend \
-                       newpdepend do_newdepend remove_path_entry killparent \
-                       save_ebuild_env filter_readonly_variables preprocess_ebuild_env \
-                       source_all_bashrcs ebuild_phase ebuild_phase_with_hooks
-
-               # portage config variables and variables set directly by portage
-               unset ACCEPT_KEYWORDS AUTOCLEAN BAD BRACKET BUILD_PREFIX CLEAN_DELAY \
-                       COLLISION_IGNORE COLS CONFIG_PROTECT CONFIG_PROTECT_MASK \
-                       DISTCC_DIR DISTDIR DOC_SYMLINKS_DIR EBUILD_MASTER_PID \
-                       ECLASSDIR ECLASS_DEPTH EMERGE_DEFAULT_OPTS \
-                       EMERGE_WARNING_DELAY ENDCOL FAKEROOTKEY FEATURES \
-                       FETCHCOMMAND FETCHCOMMAND_FTP FETCHCOMMAND_HTTP FETCHCOMMAND_SFTP \
-                       GENTOO_MIRRORS GOOD HILITE HOME IMAGE \
-                       KV LAST_E_CMD LAST_E_LEN LD_PRELOAD MOPREFIX \
-                       NORMAL O PATH PKGDIR PKGUSE PKG_LOGDIR PKG_TMPDIR \
-                       PORTAGE_ACTUAL_DISTDIR PORTAGE_ARCHLIST PORTAGE_BASHRC \
-                       PORTAGE_BINHOST_CHUNKSIZE PORTAGE_BINPKG_TMPFILE \
-                       PORTAGE_BUILDDIR PORTAGE_CALLER \
-                       PORTAGE_COLORMAP PORTAGE_CONFIGROOT PORTAGE_DEBUG \
-                       PORTAGE_DEPCACHEDIR PORTAGE_ELOG_CLASSES PORTAGE_ELOG_MAILFROM \
-                       PORTAGE_ELOG_MAILSUBJECT PORTAGE_ELOG_MAILURI PORTAGE_ELOG_SYSTEM \
-                       PORTAGE_GID PORTAGE_GPG_DIR PORTAGE_GPG_KEY PORTAGE_INST_GID \
-                       PORTAGE_INST_UID PORTAGE_LOG_FILE PORTAGE_MASTER_PID \
-                       PORTAGE_REPO_NAME PORTAGE_RESTRICT \
-                       PORTAGE_RSYNC_EXTRA_OPTS PORTAGE_RSYNC_OPTS \
-                       PORTAGE_RSYNC_RETRIES PORTAGE_TMPFS PORTAGE_WORKDIR_MODE PORTDIR \
-                       PORTDIR_OVERLAY PORT_LOGDIR PROFILE_PATHS PWORKDIR \
-                       QUICKPKG_DEFAULT_OPTS QA_INTERCEPTORS \
-                       RC_DEFAULT_INDENT RC_DOT_PATTERN RC_ENDCOL \
-                       RC_INDENTATION READONLY_EBUILD_METADATA READONLY_PORTAGE_VARS \
-                       RESUMECOMMAND RESUMECOMMAND_HTTP \
-                       RESUMECOMMAND_HTTP RESUMECOMMAND_SFTP ROOT ROOTPATH RPMDIR \
-                       STARTDIR SYNC TMP TMPDIR USE_EXPAND \
-                       USE_EXPAND_HIDDEN USE_ORDER WARN XARGS
-
-               # Prefix additions
-               unset DEFAULT_PATH DISTDIR EROOT ED HOME INFOPATH MANPATH
-
-               # Paranoia
-               unset \
-                       CVS_RSH ECHANGELOG_USER GENTOO_MIRRORS GROUP HOST HOSTNAME \
-                       LOGNAME MAIL PORTAGE_GROUP PORTAGE_USER REMOTEHOST \
-                       SECURITYSESSIONID SSH_AGENT_PID SSH_AUTH_SOCK STY TERMINFO \
-                       TERM_PROGRAM TERM_PROGRAM_VERSION USER VENDOR \
-                       __CF_USER_TEXT_ENCODING dir srcdir \
-
-               set
-               export
-       )
+               # 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
 }
 
 # === === === === === === === === === === === === === === === === === ===
@@ -1609,8 +1544,10 @@ if hasq "depend" "${EBUILD_SH_ARGS}"; then
        unset BIN_PATH BIN BODY FUNC_SRC
 fi
 
-if hasq ${EBUILD_PHASE} config info prerm setup \
-       && [ ! -f "${T}/environment" ] ; then
+# Automatically try to load environment.bz2 whenever
+# "${T}/environment" does not exist.
+if ! hasq ${EBUILD_SH_ARGS} clean depend && \
+       [ ! -f "${T}/environment" ] ; then
        bzip2 -dc "${EBUILD%/*}"/environment.bz2 > \
                "${T}/environment" 2> /dev/null
        if [ -s "${T}/environment" ] ; then
@@ -1678,7 +1615,7 @@ else
        RDEPEND="${RDEPEND} ${E_RDEPEND}"
        PDEPEND="${PDEPEND} ${E_PDEPEND}"
 
-       unset E_IUSE E_DEPEND E_RDEPEND E_PDEPEND
+       unset ECLASS E_IUSE E_DEPEND E_RDEPEND E_PDEPEND
 
        if [ "${EBUILD_PHASE}" != "depend" ] ; then
                # Make IUSE defaults backward compatible with all the old shell code.
@@ -1812,7 +1749,8 @@ if [ -n "${EBUILD_SH_ARGS}" ] ; then
                        9>&-
                fi
                set +f
-               #make sure it is writable by our group:
+               [ -n "${EBUILD_EXIT_STATUS_FILE}" ] && \
+                       touch "${EBUILD_EXIT_STATUS_FILE}" &>/dev/null
                exit 0
                ;;
        *)
@@ -1823,6 +1761,8 @@ if [ -n "${EBUILD_SH_ARGS}" ] ; then
                exit 1
                ;;
        esac
+       [ -n "${EBUILD_EXIT_STATUS_FILE}" ] && \
+               touch "${EBUILD_EXIT_STATUS_FILE}" &>/dev/null
 fi
 
 # Save the env only for relevant phases.
index 3d54a01d70fc00e867f4412a6cab56e55ae3724c..f08793c9349a0797479aa8c97f90b5a060cb27d9 100755 (executable)
@@ -98,6 +98,8 @@ diefunc() {
        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" ] && \
+               eerror "The ebuild environment file is located at '${T}/environment'."
        if [[ -n ${EBUILD_OVERLAY_ECLASSES} ]] ; then
                eerror "This ebuild used the following eclasses from overlays:"
                local x
@@ -122,6 +124,9 @@ diefunc() {
                done
        fi
 
+       [ -n "${EBUILD_EXIT_STATUS_FILE}" ] && \
+               touch "${EBUILD_EXIT_STATUS_FILE}" &>/dev/null
+
        # subshell die support
        kill -s SIGTERM ${EBUILD_MASTER_PID}
        exit 1
@@ -381,4 +386,66 @@ hasq() {
        [[ " ${*:2} " == *" $1 "* ]]
 }
 
+# @FUNCTION: save_ebuild_env
+# @DESCRIPTION:
+# echo the current environment to stdout, filtering out redundant info.
+save_ebuild_env() {
+       (
+
+               # misc variables set by bash
+               unset BASH HOSTNAME HOSTTYPE IFS MACHTYPE OLDPWD \
+                       OPTERR OPTIND OSTYPE PS4 PWD SHELL SHLVL
+
+               # misc variables inherited from the calling environment
+               unset COLORTERM DISPLAY EDITOR LESS LESSOPEN LOGNAME LS_COLORS PAGER \
+                       TERM TERMCAP USER
+               unset GROUP
+
+               # There's no need to bloat environment.bz2 with internally defined
+               # functions and variables, so filter them out if possible.
+
+               unset -f dump_trace diefunc quiet_mode vecho elog_base eqawarn elog \
+                       esyslog einfo einfon ewarn eerror ebegin _eend eend KV_major \
+                       KV_minor KV_micro KV_to_int get_KV unset_colors set_colors has \
+                       hasv hasq qa_source qa_call addread addwrite adddeny addpredict \
+                       lchown lchgrp esyslog use usev useq has_version portageq \
+                       best_version use_with use_enable register_die_hook check_KV \
+                       keepdir unpack strip_duplicate_slashes econf einstall gen_wrapper \
+                       dyn_setup dyn_unpack dyn_clean into insinto exeinto docinto \
+                       insopts diropts exeopts libopts abort_handler abort_compile \
+                       abort_test abort_install dyn_compile dyn_test dyn_install \
+                       dyn_preinst dyn_help debug-print debug-print-function \
+                       debug-print-section inherit EXPORT_FUNCTIONS newdepend newrdepend \
+                       newpdepend do_newdepend remove_path_entry killparent \
+                       save_ebuild_env filter_readonly_variables preprocess_ebuild_env \
+                       source_all_bashrcs ebuild_phase ebuild_phase_with_hooks
+
+               # portage config variables and variables set directly by portage
+               unset BAD BRACKET BUILD_PREFIX COLS \
+                       DISTCC_DIR DISTDIR DOC_SYMLINKS_DIR \
+                       EBUILD_EXIT_STATUS_FILE EBUILD_MASTER_PID \
+                       ECLASSDIR ECLASS_DEPTH ENDCOL FAKEROOTKEY FEATURES \
+                       GOOD HILITE HOME IMAGE \
+                       KV LAST_E_CMD LAST_E_LEN LD_PRELOAD MOPREFIX \
+                       NORMAL PATH PKGDIR PKGUSE PKG_LOGDIR PKG_TMPDIR \
+                       PORTAGE_ACTUAL_DISTDIR PORTAGE_ARCHLIST PORTAGE_BASHRC \
+                       PORTAGE_BINPKG_TMPFILE PORTAGE_BUILDDIR \
+                       PORTAGE_COLORMAP PORTAGE_CONFIGROOT PORTAGE_DEBUG \
+                       PORTAGE_DEPCACHEDIR PORTAGE_GID PORTAGE_INST_GID \
+                       PORTAGE_INST_UID PORTAGE_LOG_FILE PORTAGE_MASTER_PID \
+                       PORTAGE_REPO_NAME PORTAGE_RESTRICT PORTAGE_WORKDIR_MODE PORTDIR \
+                       PORTDIR_OVERLAY PROFILE_PATHS PWORKDIR QA_INTERCEPTORS \
+                       RC_DEFAULT_INDENT RC_DOT_PATTERN RC_ENDCOL \
+                       RC_INDENTATION READONLY_EBUILD_METADATA READONLY_PORTAGE_VARS \
+                       ROOT ROOTPATH RPMDIR STARTDIR TMP TMPDIR USE_EXPAND \
+                       WARN XARGS _RC_GET_KV_CACHE
+
+               # Prefix additions
+               unset DEFAULT_PATH EROOT PORTAGE_GROUP PORTAGE_USER
+
+               set
+               export
+       )
+}
+
 true
index f97470c01dc54fb2c085ee85d0b7ba84de88ae75..7255f8d285761c020bc2b6f576a16a2e798fbd82 100644 (file)
@@ -679,4 +679,7 @@ if [ -n "${MISC_FUNCTIONS_ARGS}" ]; then
        done
 fi
 
+[ -n "${EBUILD_EXIT_STATUS_FILE}" ] && \
+       touch "${EBUILD_EXIT_STATUS_FILE}" &>/dev/null
+
 :
index 66f81cca079b274fea6246a33e5ab3a4e5f74e9e..ad6febb0438a893852b263f84e21bff124004913 100644 (file)
@@ -6893,10 +6893,39 @@ def emerge_main():
        if "--quiet" not in myopts:
                portage.deprecated_profile_check()
 
-       #Freeze the portdbapi for enhanced performance:
-       for myroot in trees:
-               trees[myroot]["porttree"].dbapi.freeze()
-               del myroot
+       eclasses_overridden = {}
+       for mytrees in trees.itervalues():
+               mydb = mytrees["porttree"].dbapi
+               # Freeze the portdbapi for performance (memoize all xmatch results).
+               mydb.freeze()
+               eclasses_overridden.update(mydb.eclassdb._master_eclasses_overridden)
+       del mytrees, mydb
+
+       if eclasses_overridden and \
+               settings.get("PORTAGE_ECLASS_WARNING_ENABLE") != "0":
+               prefix = bad(" * ")
+               if len(eclasses_overridden) == 1:
+                       writemsg(prefix + "Overlay eclass overrides " + \
+                               "eclass from PORTDIR:\n", noiselevel=-1)
+               else:
+                       writemsg(prefix + "Overlay eclasses override " + \
+                               "eclasses from PORTDIR:\n", noiselevel=-1)
+               writemsg(prefix + "\n", noiselevel=-1)
+               for eclass_name in sorted(eclasses_overridden):
+                       writemsg(prefix + "  '%s/%s.eclass'\n" % \
+                               (eclasses_overridden[eclass_name], eclass_name),
+                               noiselevel=-1)
+               writemsg(prefix + "\n", noiselevel=-1)
+               msg = "It is best to avoid overridding 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 run " + \
+               "`emerge --regen` after each time that you run `emerge --sync`. " + \
+               "Set PORTAGE_ECLASS_WARNING_ENABLE=\"0\" in /etc/make.conf if " + \
+               "you would like to disable this warning."
+               from textwrap import wrap
+               for line in wrap(msg, 72):
+                       writemsg("%s%s\n" % (prefix, line), noiselevel=-1)
 
        if "moo" in myfiles:
                print """
@@ -6989,6 +7018,13 @@ def emerge_main():
        if ("getbinpkg" in settings.features):
                myopts["--getbinpkg"] = True
 
+       if "--buildpkgonly" in myopts:
+               # --buildpkgonly will not merge anything, so
+               # it cancels all binary package options.
+               for opt in ("--getbinpkg", "--getbinpkgonly",
+                       "--usepkg", "--usepkgonly"):
+                       myopts.pop(opt, None)
+
        if "--skipfirst" in myopts and "--resume" not in myopts:
                myopts["--resume"] = True
 
index eb38773231b558ae74f4168609643af1f72ef54d..8783235af4adf395d160b326fcd5b491f75d948c 100644 (file)
@@ -862,7 +862,43 @@ class config(object):
        Generally if you need data like USE flags, FEATURES, environment variables,
        virtuals ...etc you look in here.
        """
-       
+
+       # Filter selected variables in the config.environ() method so that
+       # they don't needlessly propagate down into the ebuild environment.
+       _environ_filter = []
+
+       # 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",
+               "HOST", "LOGNAME", "MAIL", "REMOTEHOST",
+               "SECURITYSESSIONID",
+               "TERMINFO", "TERM_PROGRAM", "TERM_PROGRAM_VERSION",
+               "VENDOR", "__CF_USER_TEXT_ENCODING",
+       ]
+
+       # portage config variables and variables set directly by portage
+       _environ_filter += [
+               "ACCEPT_KEYWORDS", "AUTOCLEAN",
+               "CLEAN_DELAY", "COLLISION_IGNORE", "CONFIG_PROTECT",
+               "CONFIG_PROTECT_MASK", "EMERGE_DEFAULT_OPTS",
+               "EMERGE_WARNING_DELAY", "FETCHCOMMAND", "FETCHCOMMAND_FTP",
+               "FETCHCOMMAND_HTTP", "FETCHCOMMAND_SFTP",
+               "GENTOO_MIRRORS", "NOCONFMEM", "O",
+               "PORTAGE_BINHOST_CHUNKSIZE", "PORTAGE_CALLER",
+               "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_RSYNC_RETRIES", "PORT_LOGDIR", "QUICKPKG_DEFAULT_OPTS",
+               "RESUMECOMMAND", "RESUMECOMMAND_HTTP", "RESUMECOMMAND_HTTP",
+               "RESUMECOMMAND_SFTP", "SYNC", "USE_EXPAND_HIDDEN", "USE_ORDER",
+       ]
+
+       _environ_filter = frozenset(_environ_filter)
+
        def __init__(self, clone=None, mycpv=None, config_profile_path=None,
                config_incrementals=None, config_root=None, target_root=None,
                local_config=True):
@@ -2451,6 +2487,13 @@ class config(object):
                                return d[k]
                return x
 
+       def pop(self, k, x=None):
+               self.modifying()
+               v = x
+               for d in reversed(self.lookuplist):
+                       v = d.pop(k, v)
+               return v
+
        def has_key(self,mykey):
                return mykey in self
 
@@ -2492,7 +2535,10 @@ class config(object):
        def environ(self):
                "return our locally-maintained environment"
                mydict={}
+               environ_filter = self._environ_filter
                for x in self:
+                       if x in environ_filter:
+                               continue
                        myvalue = self[x]
                        if not isinstance(myvalue, basestring):
                                writemsg("!!! Non-string value in config: %s=%s\n" % \
@@ -3538,8 +3584,18 @@ def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None):
                                return retval
        kwargs = actionmap[mydo]["args"]
        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"] = ""
+       msg = _doebuild_exit_status_check(
+               mydo, mysettings.get("EBUILD_EXIT_STATUS_FILE"))
+       if msg:
+               phase_retval = 1
+               from textwrap import wrap
+               from portage.elog.messages import eerror
+               for l in wrap(msg, 72):
+                       eerror(l, phase=mydo, key=mysettings.mycpv)
 
        if "userpriv" in mysettings.features and \
                not kwargs["droppriv"] and secpass >= 2:
@@ -3751,6 +3807,8 @@ def doebuild_environment(myebuild, mydo, myroot, mysettings, debug, use_cache, m
 
        mysettings["PORTAGE_BASHRC"] = os.path.join(
                mysettings["PORTAGE_CONFIGROOT"], EBUILD_SH_ENV_FILE.lstrip(os.path.sep))
+       mysettings["EBUILD_EXIT_STATUS_FILE"] = os.path.join(
+               mysettings["PORTAGE_BUILDDIR"], ".exit_status")
 
        #set up KV variable -- DEP SPEEDUP :: Don't waste time. Keep var persistent.
        if (mydo!="depend") or not mysettings.has_key("KV"):
@@ -3954,6 +4012,37 @@ def prepare_build_dirs(myroot, mysettings, cleanup):
                        mysettings["PORTAGE_LOG_FILE"] = os.path.join(
                                mysettings["T"], "build.log")
 
+def _doebuild_exit_status_check(mydo, exit_status_file):
+       """
+       Returns an error string if the shell appeared
+       to exit unsuccessfully, None otherwise.
+       """
+       if not exit_status_file or \
+               os.path.exists(exit_status_file):
+               return None
+       msg = ("The ebuild phase '%s' has exited " % mydo) + \
+       "unexpectedly. This type of behavior " + \
+       "is known to be triggered " + \
+       "by things such as failed variable " + \
+       "assignments (bug #190128) or bad substitution " + \
+       "errors (bug #200313)."
+       return msg
+
+def _doebuild_exit_status_unlink(exit_status_file):
+       """
+       Double check to make sure it really doesn't exist
+       and raise an OSError if it still does (it shouldn't).
+       OSError if necessary.
+       """
+       if not exit_status_file:
+               return
+       try:
+               os.unlink(exit_status_file)
+       except OSError:
+               pass
+       if os.path.exists(exit_status_file):
+               os.unlink(exit_status_file)
+
 _doebuild_manifest_exempt_depend = 0
 _doebuild_manifest_checked = None
 
@@ -4096,6 +4185,19 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                                        return 1
                        _doebuild_manifest_checked = manifest_path
 
+       def exit_status_check(retval):
+               if retval != os.EX_OK:
+                       return retval
+               msg = _doebuild_exit_status_check(
+                       mydo, mysettings.get("EBUILD_EXIT_STATUS_FILE"))
+               if msg:
+                       retval = 1
+                       from textwrap import wrap
+                       from portage.elog.messages import eerror
+                       for l in wrap(msg, 72):
+                               eerror(l, phase=mydo, key=mysettings.mycpv)
+               return retval
+
        logfile=None
        builddir_lock = None
        tmpdir = None
@@ -4205,9 +4307,14 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                                "correct your PORTAGE_TMPDIR setting.\n", noiselevel=-1)
                        return 1
 
+               if mydo == "unmerge":
+                       return unmerge(mysettings["CATEGORY"],
+                               mysettings["PF"], myroot, mysettings, vartree=vartree)
+
                # Build directory creation isn't required for any of these.
                have_build_dirs = False
-               if mydo not in ("digest", "fetch", "help", "manifest"):
+               if mydo not in ("clean", "cleanrm", "digest",
+                       "fetch", "help", "manifest"):
                        mystatus = prepare_build_dirs(myroot, mysettings, cleanup)
                        if mystatus:
                                return mystatus
@@ -4216,9 +4323,11 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        logfile = mysettings.get("PORTAGE_LOG_FILE")
                        if logfile and not os.access(os.path.dirname(logfile), os.W_OK):
                                logfile = None
-               if mydo == "unmerge":
-                       return unmerge(mysettings["CATEGORY"],
-                               mysettings["PF"], myroot, mysettings, vartree=vartree)
+               if have_build_dirs:
+                       _doebuild_exit_status_unlink(
+                               mysettings.get("EBUILD_EXIT_STATUS_FILE"))
+               else:
+                       mysettings.pop("EBUILD_EXIT_STATUS_FILE", None)
 
                # if any of these are being called, handle them -- running them out of
                # the sandbox -- and stop now.
@@ -4237,6 +4346,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                                mysettings.load_infodir(infodir)
                        retval = spawn(EBUILD_SH_BINARY + " " + mydo, mysettings,
                                debug=debug, free=1, logfile=logfile)
+                       retval = exit_status_check(retval)
                        if secpass >= 2:
                                """ Privileged phases may have left files that need to be made
                                writable to a less privileged user."""
@@ -4247,6 +4357,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                elif mydo == "preinst":
                        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.
@@ -4264,6 +4375,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        mysettings.load_infodir(mysettings["O"])
                        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.
@@ -4277,8 +4389,10 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        return phase_retval
                elif mydo in ("prerm", "postrm", "config", "info"):
                        mysettings.load_infodir(mysettings["O"])
-                       return 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
 
                mycpv = "/".join((mysettings["CATEGORY"], mysettings["PF"]))
 
@@ -4456,7 +4570,9 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                elif mydo=="merge":
                        retval = spawnebuild("install", actionmap, mysettings, debug,
                                alwaysdep=1, logfile=logfile)
-                       if retval != os.EX_OK:
+                       if retval == os.EX_OK:
+                               retval = exit_status_check(retval)
+                       else:
                                # 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.
index 806505757fecce36be01d3142ff3a0c89ef81bf0..de20d307c27b1c2b34393e5ae6fe746f3d281b9d 100644 (file)
@@ -23,6 +23,7 @@ class cache(object):
                self.porttrees = [self.porttree_root]+overlays
                self.porttrees = tuple(map(normalize_path, self.porttrees))
                self._master_eclass_root = os.path.join(self.porttrees[0],"eclass")
+               self._master_eclasses_overridden = {}
                self.update_eclasses()
 
        def close_caches(self):
@@ -41,6 +42,7 @@ class cache(object):
        def update_eclasses(self):
                self.eclasses = {}
                self._eclass_locations = {}
+               master_eclasses = {}
                eclass_len = len(".eclass")
                ignored_listdir_errnos = (errno.ENOENT, errno.ENOTDIR)
                for x in [normalize_path(os.path.join(y,"eclass")) for y in self.porttrees]:
@@ -63,7 +65,13 @@ class cache(object):
                                ys=y[:-eclass_len]
                                self.eclasses[ys] = (x, long(mtime))
                                self._eclass_locations[ys] = x
-       
+                               if x == self._master_eclass_root:
+                                       master_eclasses[ys] = mtime
+                               else:
+                                       master_mtime = master_eclasses.get(ys)
+                                       if master_mtime and master_mtime != mtime:
+                                               self._master_eclasses_overridden[ys] = x
+
        def is_eclass_data_valid(self, ec_dict):
                if not isinstance(ec_dict, dict):
                        return False