Bug #189417 - When ${T}/environment exists, isolate the ebuild
authorZac Medico <zmedico@gentoo.org>
Fri, 30 Nov 2007 00:59:48 +0000 (00:59 -0000)
committerZac Medico <zmedico@gentoo.org>
Fri, 30 Nov 2007 00:59:48 +0000 (00:59 -0000)
environment from the calling environment. This makes it possible
for the build to unset a variable that was inherited from the
calling environment, and the variable will remain unset between
phases. (trunk r8752:8755)

svn path=/main/branches/2.1.2/; revision=8756

bin/ebuild.sh
bin/isolated-functions.sh
pym/portage.py

index a5b89c9d4cb7fb2a844770822c7b07737405264a..f8f7377d7f40bbc1976bd59c6ed2265df806bfca 100755 (executable)
@@ -1547,32 +1547,14 @@ if hasq "depend" "${EBUILD_SH_ARGS}"; then
        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}
index 70cae70975c2a4c1188ebbc07eea7caf9423beb0..62824b2bc11e252d332d01fbb70de203d3144f21 100644 (file)
@@ -423,7 +423,7 @@ save_ebuild_env() {
                        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 \
+                       KV LAST_E_CMD LAST_E_LEN LD_PRELOAD MISC_FUNCTIONS_ARGS MOPREFIX \
                        NORMAL PATH PKGDIR PKGUSE PKG_LOGDIR PKG_TMPDIR \
                        PORTAGE_ACTUAL_DISTDIR PORTAGE_ARCHLIST PORTAGE_BASHRC \
                        PORTAGE_BINPKG_TMPFILE PORTAGE_BUILDDIR \
index c1527a4d42e4d2298bb7a976f5246d4a224fc662..b3d5baf7fb06b574bf9c270d9f32f4bacce416aa 100644 (file)
@@ -996,6 +996,17 @@ class config:
        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 = []
@@ -1055,6 +1066,7 @@ class config:
 
                self.already_in_regenerate = 0
 
+               self._filter_calling_env = False
                self.locked   = 0
                self.mycpv    = None
                self.puse     = []
@@ -1081,6 +1093,7 @@ class config:
                self._env_d_mtime = 0
 
                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)
@@ -2511,6 +2524,9 @@ class config:
                "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
@@ -2519,6 +2535,11 @@ class config:
                                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")
@@ -3561,8 +3582,15 @@ def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None):
        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
@@ -4163,6 +4191,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
        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
@@ -4285,6 +4314,46 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        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:
@@ -4556,6 +4625,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                return retval
 
        finally:
+               mysettings._filter_calling_env = filter_calling_env_state
                if tmpdir:
                        mysettings["PORTAGE_TMPDIR"] = tmpdir_orig
                        shutil.rmtree(tmpdir)
@@ -9563,15 +9633,11 @@ def create_trees(config_root=None, target_root=None, trees=None):
                # 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: