From d0733a19ea2b08984589c5881b0a99c2ca26e4d6 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sun, 6 Dec 2009 10:22:54 +0000 Subject: [PATCH] Bug #295715 - Implement a register_success_hook function to 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/trunk/; revision=14936 --- bin/ebuild.sh | 11 ++++++++++- bin/isolated-functions.sh | 1 + bin/misc-functions.sh | 16 ++++++++++++++++ man/ebuild.5 | 11 +++++++++++ pym/_emerge/EbuildBuild.py | 28 ++++++++++++++++++++-------- pym/_emerge/EbuildPhase.py | 33 ++++++++++++++++++++++----------- pym/_emerge/Scheduler.py | 12 +++++++++--- pym/portage/__init__.py | 7 +++++++ pym/portage/dbapi/vartree.py | 12 ++++++++++++ 9 files changed, 108 insertions(+), 23 deletions(-) diff --git a/bin/ebuild.sh b/bin/ebuild.sh index 3a203860d..6915296bf 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -267,6 +267,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. @@ -741,7 +749,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}" diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh index 4d3c6960e..9741419b6 100755 --- a/bin/isolated-functions.sh +++ b/bin/isolated-functions.sh @@ -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} ]] \ diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index ef8b0a54a..87aaeff5a 100755 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -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 diff --git a/man/ebuild.5 b/man/ebuild.5 index 18db8e8a2..b9b4ce62f 100644 --- a/man/ebuild.5 +++ b/man/ebuild.5 @@ -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 diff --git a/pym/_emerge/EbuildBuild.py b/pym/_emerge/EbuildBuild.py index 930b5c6df..543fb1b03 100644 --- a/pym/_emerge/EbuildBuild.py +++ b/pym/_emerge/EbuildBuild.py @@ -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: diff --git a/pym/_emerge/EbuildPhase.py b/pym/_emerge/EbuildPhase.py index 01661b2cc..89bdb078f 100644 --- a/pym/_emerge/EbuildPhase.py +++ b/pym/_emerge/EbuildPhase.py @@ -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) diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py index 9a5e931ee..c760c395e 100644 --- a/pym/_emerge/Scheduler.py +++ b/pym/_emerge/Scheduler.py @@ -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() diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 4f32158b0..18cb707e0 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -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 diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 27f2241c7..3244fa4ee 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -4403,6 +4403,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 \ -- 2.26.2