Bug #295715 - Implement a register_success_hook function to complement
authorZac Medico <zmedico@gentoo.org>
Sun, 6 Dec 2009 11:03:54 +0000 (11:03 -0000)
committerZac Medico <zmedico@gentoo.org>
Sun, 6 Dec 2009 11:03:54 +0000 (11:03 -0000)
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).
(trunk r14936)

svn path=/main/branches/2.1.7/; revision=14950

bin/ebuild.sh
bin/isolated-functions.sh
bin/misc-functions.sh
man/ebuild.5
pym/_emerge/EbuildBuild.py
pym/_emerge/EbuildPhase.py
pym/_emerge/Scheduler.py
pym/portage/__init__.py
pym/portage/dbapi/vartree.py

index 6a32aa0cefadcac534c92412584f8c7acfe6768f..c4b9c7b0b17efc62c411c23fc48c8f046171f63f 100755 (executable)
@@ -273,6 +273,14 @@ register_die_hook() {
        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
 # exploitation of insecure search path for python -c in ebuilds.
 # See bug #239560.
@@ -747,7 +755,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 4d3c6960e699db4dca3be2a19e88a4ba096f6c6d..9741419b68d2fee814bfa40bc9a95a70b3af8c89 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 ef8b0a54a5699feb50b96e37bddc548f5de15f6b..87aaeff5a9868d39ad87b3926cf61f9ab6174201 100755 (executable)
@@ -781,6 +781,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 4d5cf518ce7f2ba4ee4b2690dd31934db7c98aed..0f4de96f2c3dda7f2ffeba6c1c2637a9bb904ee1 100644 (file)
@@ -703,6 +703,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
index 930b5c6df3be57d6556b14a794b0cf2d7241b15c..543fb1b03def414048cb21c7f5ec9f984503740f 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
@@ -215,14 +216,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
@@ -231,6 +231,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 01661b2cc8da3d21e1d4a300390c5c55a9544ea9..89bdb078f58a76449642d8a2938cd9e81aa2440d 100644 (file)
@@ -52,12 +52,7 @@ class EbuildPhase(CompositeTask):
                                        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
@@ -92,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 6542822f4ee1d131012950e7bde01a1083cf8d45..633539c649aa2fab89ff08b0680d9a3b91305a87 100644 (file)
@@ -40,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
@@ -543,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 2f5d43f85a539ab62f9f89d1da96935289c7fe5f..90d82486e5fa55706657fb3b247c7c28ab428705 100644 (file)
@@ -6351,6 +6351,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
index a6b69e9ff768d874e1ccb09593d0f1cc77f1e9f6..21a2fa90ac84657518997118c3d2437933f89b86 100644 (file)
@@ -3245,6 +3245,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 \