Merged from trunk -r14926:14936
authorFabian Groffen <grobian@gentoo.org>
Sun, 6 Dec 2009 10:34:05 +0000 (10:34 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sun, 6 Dec 2009 10:34:05 +0000 (10:34 -0000)
   | 14927   | Always append QA Notices resulting from the build log search |
   | zmedico | to the end of the log. Thanks to Diego E. Pettenò for       |
   |         | reporting.                                                   |

   | 14928   | Bug #162404 - Automatically disable logging if sesandbox is  |
   | zmedico | enabled and a pty is not available for some reason           |
   |         | (currently they are never available with python3).           |

   | 14929   | Bug #295805 - Fix ValueError with python3 inside             |
   | zmedico | update_config_files().                                       |

   | 14930   | Move code for handling missing sandbox binary out of the     |
   | zmedico | config constructor.                                          |

   | 14931   | Use portage.StringIO to avoid duplicate import fallback      |
   | zmedico | code.                                                        |

   | 14932   | Make register_die_hook() ensure that each hook is registered |
   | zmedico | only once.                                                   |

   | 14933   | Add a AbstractEbuildProcess class for MiscFunctionsProcess   |
   | zmedico | to inherit the _pipe and _can_log methods that used to be in |
   |         | the EbuildProcess class.                                     |

   | 14934   | Fix _spawn_misc_sh() to properly unset EBUILD_PHASE, and add |
   | zmedico | a 'phase' description parameter for use in messages.         |

   | 14935   | Add 'tla' to the lists of live eclasses.                     |
   | zmedico |                                                              |

   | 14936   | Bug #295715 - Implement a register_success_hook function to  |
   | zmedico | complement register_die_hook, and also add code to ensure    |
   |         | the die hooks are called even when the failure is on the     |
   |         | python side (like for file collisions).                      |

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

19 files changed:
bin/ebuild.sh
bin/isolated-functions.sh
bin/misc-functions.sh
bin/repoman
cnf/sets.conf
man/ebuild.5
pym/_emerge/AbstractEbuildProcess.py [new file with mode: 0644]
pym/_emerge/EbuildBuild.py
pym/_emerge/EbuildExecuter.py
pym/_emerge/EbuildPhase.py
pym/_emerge/EbuildProcess.py
pym/_emerge/JobStatusDisplay.py
pym/_emerge/MiscFunctionsProcess.py
pym/_emerge/Scheduler.py
pym/_emerge/SpawnProcess.py
pym/portage/__init__.py
pym/portage/dbapi/vartree.py
pym/portage/update.py
pym/portage/util.py

index 6062146a983255b7716e4a8a79a61f99ccf4a51e..ee21fed5b6acd937603a2cec189b2034ac8632ff 100755 (executable)
@@ -262,7 +262,19 @@ use_enable() {
 }
 
 register_die_hook() {
-       export EBUILD_DEATH_HOOKS="${EBUILD_DEATH_HOOKS} $*"
+       local x
+       for x in $* ; do
+               hasq $x $EBUILD_DEATH_HOOKS || \
+                       export EBUILD_DEATH_HOOKS="$EBUILD_DEATH_HOOKS $x"
+       done
+}
+
+register_success_hook() {
+       local x
+       for x in $* ; do
+               hasq $x $EBUILD_SUCCESS_HOOKS || \
+                       export EBUILD_SUCCESS_HOOKS="$EBUILD_SUCCESS_HOOKS $x"
+       done
 }
 
 # Ensure that $PWD is sane whenever possible, to protect against
@@ -739,7 +751,8 @@ dyn_clean() {
 
        if [[ $EMERGE_FROM = binary ]] || ! hasq keepwork $FEATURES; then
                rm -f "$PORTAGE_BUILDDIR"/.{ebuild_changed,exit_status,logid,unpacked,prepared} \
-                       "$PORTAGE_BUILDDIR"/.{configured,compiled,tested,packaged}
+                       "$PORTAGE_BUILDDIR"/.{configured,compiled,tested,packaged} \
+                       "$PORTAGE_BUILDDIR"/.die_hooks
 
                rm -rf "${PORTAGE_BUILDDIR}/build-info"
                rm -rf "${WORKDIR}"
index 50c9800e27eb5948637df0659d52ec6e3cf68509..012cd096ef9504346b697afd92f4060c336fb160 100755 (executable)
@@ -156,6 +156,7 @@ die() {
                for x in $EBUILD_DEATH_HOOKS; do
                        ${x} "$@" >&2 1>&2
                done
+               > "$PORTAGE_BUILDDIR/.die_hooks"
        fi
 
        [[ -n ${PORTAGE_LOG_FILE} ]] \
index f252c14be97c8e3ebb34dfb837121b63dc6a7493..c36e01f6d0b70d0c36657525e36d2ae2ef741565 100644 (file)
@@ -1412,6 +1412,22 @@ dyn_rpm() {
                die "Failed to move rpm"
 }
 
+die_hooks() {
+       [[ -f $PORTAGE_BUILDDIR/.die_hooks ]] && return
+       local x
+       for x in $EBUILD_DEATH_HOOKS ; do
+               $x >&2
+       done
+       > "$PORTAGE_BUILDDIR/.die_hooks"
+}
+
+success_hooks() {
+       local x
+       for x in $EBUILD_SUCCESS_HOOKS ; do
+               $x
+       done
+}
+
 if [ -n "${MISC_FUNCTIONS_ARGS}" ]; then
        source_all_bashrcs
        [ "$PORTAGE_DEBUG" == "1" ] && set -x
index 0a858e907830b2311bffb1c35c49ad31139ea02d..d8f2ac8cd821e6fcfd468669bd45f6521458927d 100755 (executable)
@@ -409,7 +409,8 @@ live_eclasses = frozenset([
        "darcs",
        "git",
        "mercurial",
-       "subversion"
+       "subversion",
+       "tla",
 ])
 
 suspect_rdepend = frozenset([
index 311d4a38f83f624f772cb6ae0bd58e917a6233b8..44ff8340c07b8b586bc84c5049f5b87434158478 100644 (file)
@@ -57,7 +57,7 @@ world-candidate = False
 class = portage.sets.dbapi.VariableSet
 world-candidate = False
 variable = INHERITED
-includes = bzr cvs darcs git mercurial subversion
+includes = bzr cvs darcs git mercurial subversion tla
 
 # Installed packages that own files inside /lib/modules.
 [module-rebuild]
index 67f7e39138c6b4aeb6562d03a8cd5c544f74c6c8..a81bcdcc3ceb4a080cf06972c2768a5b4bdaa61e 100644 (file)
@@ -719,6 +719,17 @@ VERINS="$(best_version net\-ftp/glftpd)"
 .br
 (VERINS now has the value "net\-ftp/glftpd\-1.27" if glftpd\-1.27 is installed)
 .RE
+.SH "HELPER FUNCTIONS: HOOKS"
+.TP
+\fBregister_die_hook\fR \fI[list of function names]\fR
+Register one or more functions to call when the ebuild fails for any reason,
+including file collisions with other packages.
+.TP
+\fBregister_success_hook\fR \fI[list of function names]\fR
+Register one or more functions to call when the ebuild builds and/or installs
+successfully.
+.TP
+.RE
 .SH "HELPER FUNCTIONS: OUTPUT"
 .TP
 \fBeinfo\fR \fI"disposable message"\fR
diff --git a/pym/_emerge/AbstractEbuildProcess.py b/pym/_emerge/AbstractEbuildProcess.py
new file mode 100644 (file)
index 0000000..db59901
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+from _emerge.SpawnProcess import SpawnProcess
+import portage
+from portage import os
+
+class AbstractEbuildProcess(SpawnProcess):
+
+       __slots__ = ('phase', 'pkg', 'settings',)
+
+       def _pipe(self, fd_pipes):
+               stdout_pipe = fd_pipes.get(1)
+               got_pty, master_fd, slave_fd = \
+                       portage._create_pty_or_pipe(copy_term_size=stdout_pipe)
+               return (master_fd, slave_fd)
+
+       def _can_log(self, slave_fd):
+               # With sesandbox, logging works through a pty but not through a
+               # normal pipe. So, disable logging if ptys are broken.
+               # See Bug #162404.
+               return not ('sesandbox' in self.settings.features \
+                       and self.settings.selinux_enabled()) or os.isatty(slave_fd)
index 501c74fbe4dbd54bca6cab0bb185b701d378ffcb..add3a00b7c84dc33b12e6c6625bfa44e44d2c3da 100644 (file)
@@ -10,6 +10,7 @@ from _emerge.CompositeTask import CompositeTask
 from _emerge.EbuildMerge import EbuildMerge
 from _emerge.EbuildFetchonly import EbuildFetchonly
 from _emerge.EbuildBuildDir import EbuildBuildDir
+from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
 from portage.util import writemsg
 import portage
 from portage import os
@@ -216,14 +217,13 @@ class EbuildBuild(CompositeTask):
                        return
 
                if self.opts.buildpkgonly:
-                       # Need to call "clean" phase for buildpkgonly mode
-                       portage.elog.elog_process(self.pkg.cpv, self.settings)
-                       phase = "clean"
-                       clean_phase = EbuildPhase(background=self.background,
-                               pkg=self.pkg, phase=phase,
-                               scheduler=self.scheduler, settings=self.settings,
-                               tree=self._tree)
-                       self._start_task(clean_phase, self._clean_exit)
+                       phase = 'success_hooks'
+                       success_hooks = MiscFunctionsProcess(
+                               background=self.background,
+                               commands=[phase], phase=phase, pkg=self.pkg,
+                               scheduler=self.scheduler, settings=self.settings)
+                       self._start_task(success_hooks,
+                               self._buildpkgonly_success_hook_exit)
                        return
 
                # Continue holding the builddir lock until
@@ -232,6 +232,18 @@ class EbuildBuild(CompositeTask):
                self.returncode = packager.returncode
                self.wait()
 
+       def _buildpkgonly_success_hook_exit(self, success_hooks):
+               self._default_exit(success_hooks)
+               self.returncode = None
+               # Need to call "clean" phase for buildpkgonly mode
+               portage.elog.elog_process(self.pkg.cpv, self.settings)
+               phase = 'clean'
+               clean_phase = EbuildPhase(background=self.background,
+                       pkg=self.pkg, phase=phase,
+                       scheduler=self.scheduler, settings=self.settings,
+                       tree=self._tree)
+               self._start_task(clean_phase, self._clean_exit)
+
        def _clean_exit(self, clean_phase):
                if self._final_exit(clean_phase) != os.EX_OK or \
                        self.opts.buildpkgonly:
index 055a8fa4708c8142967796791566b476568c7981..adb7cd6e9c92f352ebd5a5021e9804d1bcb276e8 100644 (file)
@@ -20,7 +20,8 @@ class EbuildExecuter(CompositeTask):
                "darcs",
                "git",
                "mercurial",
-               "subversion"
+               "subversion",
+               "tla",
        ])
 
        def _start(self):
index fcf60d39c8eb128390bc62be9559554e3979fba8..89bdb078f58a76449642d8a2938cd9e81aa2440d 100644 (file)
@@ -5,10 +5,11 @@
 from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
 from _emerge.EbuildProcess import EbuildProcess
 from _emerge.CompositeTask import CompositeTask
-from portage.util import writemsg
+from portage.util import writemsg, writemsg_stdout
 import portage
 from portage import os
 from portage import _encodings
+from portage import _unicode_decode
 from portage import _unicode_encode
 import codecs
 
@@ -30,27 +31,28 @@ class EbuildPhase(CompositeTask):
        def _ebuild_exit(self, ebuild_process):
 
                if self.phase == "install":
-                       out = None
+                       out = portage.StringIO()
                        log_path = self.settings.get("PORTAGE_LOG_FILE")
                        log_file = None
-                       if self.background and log_path is not None:
+                       if log_path is not None:
                                log_file = codecs.open(_unicode_encode(log_path,
                                        encoding=_encodings['fs'], errors='strict'),
                                        mode='a', encoding=_encodings['content'], errors='replace')
-                               out = log_file
                        try:
                                portage._check_build_log(self.settings, out=out)
+                               msg = _unicode_decode(out.getvalue(),
+                                       encoding=_encodings['content'], errors='replace')
+                               if msg:
+                                       if not self.background:
+                                               writemsg_stdout(msg, noiselevel=-1)
+                                       if log_file is not None:
+                                               log_file.write(msg)
                        finally:
                                if log_file is not None:
                                        log_file.close()
 
                if self._default_exit(ebuild_process) != os.EX_OK:
-                       if self.phase != 'clean' and \
-                               'noclean' not in self.settings.features and \
-                               'fail-clean' in self.settings.features:
-                               self._fail_clean()
-                               return
-                       self.wait()
+                       self._die_hooks()
                        return
 
                settings = self.settings
@@ -85,15 +87,31 @@ class EbuildPhase(CompositeTask):
                if self._final_exit(post_phase) != os.EX_OK:
                        writemsg("!!! post %s failed; exiting.\n" % self.phase,
                                noiselevel=-1)
-                       if self.phase != 'clean' and \
-                               'noclean' not in self.settings.features and \
-                               'fail-clean' in self.settings.features:
-                               self._fail_clean()
-                               return
+                       self._die_hooks()
+                       return
                self._current_task = None
                self.wait()
                return
 
+       def _die_hooks(self):
+               self.returncode = None
+               phase = 'die_hooks'
+               die_hooks = MiscFunctionsProcess(background=self.background,
+                       commands=[phase], phase=phase, pkg=self.pkg,
+                       scheduler=self.scheduler, settings=self.settings)
+               self._start_task(die_hooks, self._die_hooks_exit)
+
+       def _die_hooks_exit(self, die_hooks):
+               if self.phase != 'clean' and \
+                       'noclean' not in self.settings.features and \
+                       'fail-clean' in self.settings.features:
+                       self._default_exit(die_hooks)
+                       self._fail_clean()
+                       return
+               self._final_exit(die_hooks)
+               self.returncode = 1
+               self.wait()
+
        def _fail_clean(self):
                self.returncode = None
                portage.elog.elog_process(self.pkg.cpv, self.settings)
index 86a63282ffaa6c21ffbc8666a82f33cafcd81cfc..597caf4dda767da9d6683510f676a0a27ac6127a 100644 (file)
@@ -2,13 +2,13 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id$
 
-from _emerge.SpawnProcess import SpawnProcess
+from _emerge.AbstractEbuildProcess import AbstractEbuildProcess
 import portage
 from portage import os
 
-class EbuildProcess(SpawnProcess):
+class EbuildProcess(AbstractEbuildProcess):
 
-       __slots__ = ("phase", "pkg", "settings", "tree")
+       __slots__ = ('tree',)
 
        def _start(self):
                # Don't open the log file during the clean phase since the
@@ -16,13 +16,7 @@ class EbuildProcess(SpawnProcess):
                # prevents the clean phase from removing $T.
                if self.phase not in ("clean", "cleanrm"):
                        self.logfile = self.settings.get("PORTAGE_LOG_FILE")
-               SpawnProcess._start(self)
-
-       def _pipe(self, fd_pipes):
-               stdout_pipe = fd_pipes.get(1)
-               got_pty, master_fd, slave_fd = \
-                       portage._create_pty_or_pipe(copy_term_size=stdout_pipe)
-               return (master_fd, slave_fd)
+               AbstractEbuildProcess._start(self)
 
        def _spawn(self, args, **kwargs):
 
@@ -40,7 +34,7 @@ class EbuildProcess(SpawnProcess):
                return rval
 
        def _set_returncode(self, wait_retval):
-               SpawnProcess._set_returncode(self, wait_retval)
+               AbstractEbuildProcess._set_returncode(self, wait_retval)
 
                if self.phase not in ("clean", "cleanrm"):
                        self.returncode = portage._doebuild_exit_status_check_and_log(
index bcc682b234308642570732cdb3421c0168eb8a9c..288e355f694bda3b184d06e0694592561f188a0c 100644 (file)
@@ -5,15 +5,9 @@
 import formatter
 import sys
 import time
-try:
-       from io import StringIO
-except ImportError:
-       # Needed for python-2.6 with USE=build since
-       # io imports threading which imports thread
-       # which is unavailable.
-       from StringIO import StringIO
 
 import portage
+from portage import StringIO
 from portage import os
 from portage import _encodings
 from portage import _unicode_decode
index 3e2fff7ccc6df81d6b532759e9d9fcfd75df79b3..63d7873ea85dfeb506e4457e3e4683c1e97d5c7e 100644 (file)
@@ -2,16 +2,16 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id$
 
-from _emerge.SpawnProcess import SpawnProcess
+from _emerge.AbstractEbuildProcess import AbstractEbuildProcess
 import portage
 from portage import os
 
-class MiscFunctionsProcess(SpawnProcess):
+class MiscFunctionsProcess(AbstractEbuildProcess):
        """
        Spawns misc-functions.sh with an existing ebuild environment.
        """
 
-       __slots__ = ("commands", "phase", "pkg", "settings")
+       __slots__ = ('commands',)
 
        def _start(self):
                settings = self.settings
@@ -26,7 +26,7 @@ class MiscFunctionsProcess(SpawnProcess):
                portage._doebuild_exit_status_unlink(
                        settings.get("EBUILD_EXIT_STATUS_FILE"))
 
-               SpawnProcess._start(self)
+               AbstractEbuildProcess._start(self)
 
        def _spawn(self, args, **kwargs):
                settings = self.settings
@@ -35,7 +35,7 @@ class MiscFunctionsProcess(SpawnProcess):
                        debug=debug, **kwargs)
 
        def _set_returncode(self, wait_retval):
-               SpawnProcess._set_returncode(self, wait_retval)
+               AbstractEbuildProcess._set_returncode(self, wait_retval)
                self.returncode = portage._doebuild_exit_status_check_and_log(
                        self.settings, self.phase, self.returncode)
 
index dcd2e47c7ae126d1bf5215d481de4dfbd891c863..c760c395e907565f9b050feb121d571b06382306 100644 (file)
@@ -11,15 +11,8 @@ import textwrap
 import time
 import weakref
 
-try:
-       from io import StringIO
-except ImportError:
-       # Needed for python-2.6 with USE=build since
-       # io imports threading which imports thread
-       # which is unavailable.
-       from StringIO import StringIO
-
 import portage
+from portage import StringIO
 from portage import os
 from portage import _encodings
 from portage import _unicode_decode
@@ -47,6 +40,7 @@ from _emerge._find_deep_system_runtime_deps import _find_deep_system_runtime_dep
 from _emerge._flush_elog_mod_echo import _flush_elog_mod_echo
 from _emerge.JobStatusDisplay import JobStatusDisplay
 from _emerge.MergeListItem import MergeListItem
+from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
 from _emerge.Package import Package
 from _emerge.PackageMerge import PackageMerge
 from _emerge.PollScheduler import PollScheduler
@@ -550,9 +544,14 @@ class Scheduler(PollScheduler):
                background = self._background
                log_path = settings.get("PORTAGE_LOG_FILE")
 
-               ebuild_phase = EbuildPhase(background=background,
-                       pkg=pkg, phase=phase, scheduler=scheduler,
-                       settings=settings, tree=pkg_dblink.treetype)
+               if phase in ('die_hooks', 'success_hooks'):
+                       ebuild_phase = MiscFunctionsProcess(background=background,
+                               commands=[phase], phase=phase, pkg=pkg,
+                               scheduler=scheduler, settings=settings)
+               else:
+                       ebuild_phase = EbuildPhase(background=background,
+                               pkg=pkg, phase=phase, scheduler=scheduler,
+                               settings=settings, tree=pkg_dblink.treetype)
                ebuild_phase.start()
                ebuild_phase.wait()
 
index 1486e6773f8bb4ce1aae1ac9ba4ea8f19c0a0881..67fb17e29693e5caf0f5e7921a0df6abe31f61d5 100644 (file)
@@ -49,7 +49,6 @@ class SpawnProcess(SubProcess):
                        if fd == sys.stderr.fileno():
                                sys.stderr.flush()
 
-               logfile = self.logfile
                self._files = self._files_dict()
                files = self._files
 
@@ -57,6 +56,10 @@ class SpawnProcess(SubProcess):
                fcntl.fcntl(master_fd, fcntl.F_SETFL,
                        fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
 
+               logfile = None
+               if self._can_log(slave_fd):
+                       logfile = self.logfile
+
                null_input = None
                fd_pipes_orig = fd_pipes.copy()
                if self.background:
@@ -125,6 +128,9 @@ class SpawnProcess(SubProcess):
                self.pid = retval[0]
                portage.process.spawned_pids.remove(self.pid)
 
+       def _can_log(self, slave_fd):
+               return True
+
        def _pipe(self, fd_pipes):
                """
                @type fd_pipes: dict
index 16202968bf4e7fc3e5a308fd4e0e05ddc5c4b682..e26b20521b963a10e1db9ffe07f6d36e347aadb4 100644 (file)
@@ -33,6 +33,15 @@ try:
                from subprocess import getstatusoutput as subprocess_getstatusoutput
        except ImportError:
                from commands import getstatusoutput as subprocess_getstatusoutput
+
+       try:
+               from io import StringIO
+       except ImportError:
+               # Needed for python-2.6 with USE=build since
+               # io imports threading which imports thread
+               # which is unavailable.
+               from StringIO import StringIO
+
        from time import sleep
        from random import shuffle
        from itertools import chain
@@ -2209,21 +2218,6 @@ class config(object):
                        # initialize self.features
                        self.regenerate()
 
-                       if not portage.process.sandbox_capable and \
-                               ("sandbox" in self.features or "usersandbox" in self.features):
-                               if self.profile_path is not None and \
-                                       os.path.realpath(self.profile_path) == \
-                                       os.path.realpath(os.path.join(config_root, PROFILE_PATH)):
-                                       """ Don't show this warning when running repoman and the
-                                       sandbox feature came from a profile that doesn't belong to
-                                       the user."""
-                                       writemsg(colorize("BAD", _("!!! Problem with sandbox"
-                                               " binary. Disabling...\n\n")), noiselevel=-1)
-                               if "sandbox" in self.features:
-                                       self.features.remove("sandbox")
-                               if "usersandbox" in self.features:
-                                       self.features.remove("usersandbox")
-
                        if bsd_chflags:
                                self.features.add('chflags')
 
@@ -2360,6 +2354,18 @@ class config(object):
                        writemsg("!!! /etc/portage/profile/virtuals. Please move it to\n")
                        writemsg("!!! this new location.\n\n")
 
+               if not process.sandbox_capable and \
+                       ("sandbox" in self.features or "usersandbox" in self.features):
+                       if self.profile_path is not None and \
+                               os.path.realpath(self.profile_path) == \
+                               os.path.realpath(os.path.join(
+                               self["PORTAGE_CONFIGROOT"], PROFILE_PATH)):
+                               # Don't show this warning when running repoman and the
+                               # sandbox feature came from a profile that doesn't belong
+                               # to the user.
+                               writemsg(colorize("BAD", _("!!! Problem with sandbox"
+                                       " binary. Disabling...\n\n")), noiselevel=-1)
+
                if "fakeroot" in self.features and \
                        not portage.process.fakeroot_capable:
                        writemsg(_("!!! FEATURES=fakeroot is enabled, but the "
@@ -4077,12 +4083,25 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero
                if 1 not in fd_pipes or 2 not in fd_pipes:
                        raise ValueError(fd_pipes)
 
+               got_pty, master_fd, slave_fd = \
+                       _create_pty_or_pipe(copy_term_size=fd_pipes[1])
+
+               if not got_pty and 'sesandbox' in mysettings.features \
+                       and mysettings.selinux_enabled():
+                       # With sesandbox, logging works through a pty but not through a
+                       # normal pipe. So, disable logging if ptys are broken.
+                       # See Bug #162404.
+                       logfile = None
+                       os.close(master_fd)
+                       master_fd = None
+                       os.close(slave_fd)
+                       slave_fd = None
+
+       if logfile:
+
                fd_pipes.setdefault(0, sys.stdin.fileno())
                fd_pipes_orig = fd_pipes.copy()
 
-               got_pty, master_fd, slave_fd = \
-                       _create_pty_or_pipe(copy_term_size=fd_pipes_orig[1])
-
                # We must set non-blocking mode before we close the slave_fd
                # since otherwise the fcntl call can fail on FreeBSD (the child
                # process might have already exited and closed slave_fd so we
@@ -4110,6 +4129,9 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero
                        (not droppriv and "sandbox" not in features and \
                        "usersandbox" not in features and not fakeroot))
 
+       if not free and not (fakeroot or process.sandbox_capable):
+               free = True
+
        if free or "SANDBOX_ACTIVE" in os.environ:
                keywords["opt_name"] += " bash"
                spawn_func = portage.process.spawn_bash
@@ -5649,7 +5671,23 @@ def spawnebuild(mydo, actionmap, mysettings, debug, alwaysdep=0,
 
        _post_phase_userpriv_perms(mysettings)
        if mydo == "install":
-               _check_build_log(mysettings)
+               out = StringIO()
+               _check_build_log(mysettings, out=out)
+               msg = _unicode_decode(out.getvalue(),
+                       encoding=_encodings['content'], errors='replace')
+               if msg:
+                       writemsg_stdout(msg, noiselevel=-1)
+                       if logfile is not None:
+                               try:
+                                       f = codecs.open(_unicode_encode(logfile,
+                                               encoding=_encodings['fs'], errors='strict'),
+                                               mode='a', encoding=_encodings['content'],
+                                               errors='replace')
+                               except EnvironmentError:
+                                       pass
+                               else:
+                                       f.write(msg)
+                                       f.close()
                if phase_retval == os.EX_OK:
                        _post_src_install_chost_fix(mysettings)
                        phase_retval = _post_src_install_checks(mysettings)
@@ -5690,7 +5728,8 @@ def _post_phase_userpriv_perms(mysettings):
 def _post_src_install_checks(mysettings):
        _post_src_install_uid_fix(mysettings)
        global _post_phase_cmds
-       retval = _spawn_misc_sh(mysettings, _post_phase_cmds["install"])
+       retval = _spawn_misc_sh(mysettings, _post_phase_cmds["install"],
+               phase='internal_post_src_install')
        if retval != os.EX_OK:
                writemsg(_("!!! install_qa_check failed; exiting.\n"),
                        noiselevel=-1)
@@ -5995,7 +6034,7 @@ def _post_pkg_postinst_cmd(mysettings):
 
        return myargs
 
-def _spawn_misc_sh(mysettings, commands, **kwargs):
+def _spawn_misc_sh(mysettings, commands, phase=None, **kwargs):
        """
        @param mysettings: the ebuild config
        @type mysettings: config
@@ -6015,14 +6054,14 @@ def _spawn_misc_sh(mysettings, commands, **kwargs):
                mysettings.get("EBUILD_EXIT_STATUS_FILE"))
        debug = mysettings.get("PORTAGE_DEBUG") == "1"
        logfile = mysettings.get("PORTAGE_LOG_FILE")
-       mydo = mysettings["EBUILD_PHASE"]
+       mysettings.pop("EBUILD_PHASE", None)
        try:
                rval = spawn(mycommand, mysettings, debug=debug,
                        logfile=logfile, **kwargs)
        finally:
                pass
 
-       msg = _doebuild_exit_status_check(mydo, mysettings)
+       msg = _doebuild_exit_status_check(phase, mysettings)
        if msg:
                if rval == os.EX_OK:
                        rval = 1
@@ -6346,6 +6385,13 @@ def prepare_build_dirs(myroot, mysettings, cleanup):
                writemsg(_("File Not Found: '%s'\n") % str(e), noiselevel=-1)
                return 1
 
+       # Reset state for things like noauto and keepwork in FEATURES.
+       for x in ('.die_hooks',):
+               try:
+                       os.unlink(os.path.join(mysettings['PORTAGE_BUILDDIR'], x))
+               except OSError:
+                       pass
+
        _prepare_workdir(mysettings)
        if mysettings.get('EBUILD_PHASE') != 'fetch':
                # Avoid spurious permissions adjustments when fetching with
@@ -7254,6 +7300,9 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        nosandbox = ("sandbox" not in features and \
                                "usersandbox" not in features)
 
+               if not process.sandbox_capable:
+                       nosandbox = True
+
                sesandbox = mysettings.selinux_enabled() and \
                        "sesandbox" in mysettings.features
 
index 9120a0cb623d52f5086d68bb67886ebcb5778c1e..c0c07c1c6b119e5f1ffdf5a1a826f5a60f1787ba 100644 (file)
@@ -5405,6 +5405,18 @@ class dblink(object):
                        retval = self.treewalk(mergeroot, myroot, inforoot, myebuild,
                                cleanup=cleanup, mydbapi=mydbapi, prev_mtimes=prev_mtimes)
 
+                       if retval == os.EX_OK:
+                               phase = 'success_hooks'
+                       else:
+                               phase = 'die_hooks'
+
+                       if self._scheduler is None:
+                               portage._spawn_misc_sh(self.settings, [phase],
+                                       phase=phase)
+                       else:
+                               self._scheduler.dblinkEbuildPhase(
+                                       self, mydbapi, myebuild, phase)
+
                        # Process ebuild logfiles
                        elog_process(self.mycpv, self.settings, phasefilter=filter_mergephases)
                        if 'noclean' not in self.settings.features and \
index 04812d5a466788987c28d352264f73e3349f3dc8..af0fd2f42cee4bb5b59a50b7b4d2098a7b2c8fd0 100644 (file)
@@ -201,15 +201,20 @@ def update_config_files(config_root, protect, protect_mask, update_iter):
                config_file = os.path.join(abs_user_config, x)
                if os.path.isdir(config_file):
                        for parent, dirs, files in os.walk(config_file):
-                               for y in dirs:
+                               try:
+                                       parent = _unicode_decode(parent,
+                                               encoding=_encodings['fs'], errors='strict')
+                               except UnicodeDecodeError:
+                                       continue
+                               for y_enc in dirs:
                                        try:
-                                               y = _unicode_decode(y,
+                                               y = _unicode_decode(y_enc,
                                                        encoding=_encodings['fs'], errors='strict')
                                        except UnicodeDecodeError:
-                                               dirs.remove(y)
+                                               dirs.remove(y_enc)
                                                continue
                                        if y.startswith("."):
-                                               dirs.remove(y)
+                                               dirs.remove(y_enc)
                                for y in files:
                                        try:
                                                y = _unicode_decode(y,
index 5a9376666891ef7551167a61f0ca6e31e21e0406..a507edbc83fee3295a379a68197a2824587eab2c 100644 (file)
@@ -24,15 +24,9 @@ import shlex
 import stat
 import string
 import sys
-try:
-       from io import StringIO
-except ImportError:
-       # Needed for python-2.6 with USE=build since
-       # io imports threading which imports thread
-       # which is unavailable.
-       from StringIO import StringIO
 
 import portage
+from portage import StringIO
 from portage import os
 from portage import _encodings
 from portage import _os_merge