Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 299463 Details for
Bug 272988
New /etc/portage/hooks/{post,pre}-{run,sync,ebuild,configure,compile,install}.d/ functionality
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
portage hooks diff
portage-hooks.diff (text/plain), 25.25 KB, created by
Jacob Godserv
on 2012-01-21 17:39:42 UTC
(
hide
)
Description:
portage hooks diff
Filename:
MIME Type:
Creator:
Jacob Godserv
Created:
2012-01-21 17:39:42 UTC
Size:
25.25 KB
patch
obsolete
>diff --git a/bin/bashrc-functions.sh b/bin/bashrc-functions.sh >index 4da5585..217749b 100644 >--- a/bin/bashrc-functions.sh >+++ b/bin/bashrc-functions.sh >@@ -23,6 +23,51 @@ register_success_hook() { > done > } > >+register_phase_hook() { >+ if [[ -z "$3" ]]; then >+ echo "!!! register_phase_hook() called without enough parameters." >&2 >+ echo "!!! register_phase_hook <before|after> <phase|all> <cmd>" >&2 >+ return 1 >+ fi >+ local x when phase cmd cmdargs phase_hooks >+ when="$(echo $1 | tr 'a-z' 'A-Z')"; shift # uppercase when >+ phase="$(echo $1 | tr 'A-Z' 'a-z')"; shift # lowercase phase name (to match real phase names) >+ >+ case "${when}" in >+ BEFORE|AFTER) >+ : # allowed >+ ;; >+ *) >+ echo "!!! register_phase_hook() called with invalid when parameter: $when" >&2 >+ return 1 >+ ;; >+ esac >+ >+ phase_hooks="$(eval 'echo $EBUILD_PHASE_HOOKS_'"${when}"'_'"${phase}")" >+ >+ if [[ -z "${phase_hooks}" ]]; then >+ phase_hooks="0 " >+ elif ! _is_phase_hook_at_version "${phase_hooks}" 0; then >+ echo "!!! Unsupported ebuild phase hook version" >+ return $? >+ fi >+ >+ for x in $* ; do >+ hasq $x ${phase_hooks} || \ >+ phase_hooks+="${x} " >+ done >+ >+ export EBUILD_PHASE_HOOKS_"${when}"_"${phase}"="${phase_hooks}" >+} >+ >+_is_phase_hook_at_version() { >+ if [[ "${1:0:1}" == "$2" ]]; then >+ return 0 >+ else >+ return 1 >+ fi >+} >+ > strip_duplicate_slashes() { > if [[ -n $1 ]] ; then > local removed=$1 >diff --git a/bin/ebuild.sh b/bin/ebuild.sh >index f8e71f5..d48052d 100755 >--- a/bin/ebuild.sh >+++ b/bin/ebuild.sh >@@ -22,7 +22,7 @@ else > # the "depend" phase. > for x in diropts docompress exeopts get_KV insopts \ > keepdir KV_major KV_micro KV_minor KV_to_int \ >- libopts register_die_hook register_success_hook \ >+ libopts register_die_hook register_phase_hook register_success_hook \ > remove_path_entry set_unless_changed strip_duplicate_slashes \ > unset_unless_changed use_with use_enable ; do > eval "${x}() { >@@ -394,6 +394,17 @@ source_all_bashrcs() { > [ ! -z "${OCXX}" ] && export CXX="${OCXX}" > } > >+# Portage hooks >+portage_hooks_pre_ebuild() { >+ source "${HOOKS_SH_BINARY}" --do-pre-ebuild || return $? >+} >+portage_hooks_post_ebuild() { >+ source "${HOOKS_SH_BINARY}" --do-post-ebuild || return $? >+} >+register_phase_hook before all portage_hooks_pre_ebuild >+register_phase_hook after all portage_hooks_post_ebuild >+ >+ > # === === === === === === === === === === === === === === === === === === > # === === === === === functions end, main part begins === === === === === > # === === === === === === === === === === === === === === === === === === >diff --git a/bin/hooks.sh b/bin/hooks.sh >new file mode 100755 >index 0000000..f420d1d >--- /dev/null >+++ b/bin/hooks.sh >@@ -0,0 +1,96 @@ >+#!/bin/bash >+# Copyright 1999-2010 Gentoo Foundation >+# Distributed under the terms of the GNU General Public License v2 >+ >+# @MAINTAINER: >+# jacobgodserv@gmail.com >+# @BLURB: Executes hooks in the current directory. >+# @DESCRIPTION: >+# Part of the portage hooks system, this script is responsible for executing >+# hooks within a prepared environment >+ >+# Only run hooks if it's requested in $FEATURES >+if ! (source "${PORTAGE_BIN_PATH}/isolated-functions.sh" && hasq hooks $FEATURES) ; then >+ return >+fi >+ >+# TODO: unit testing does not cover this portion of hooks.sh >+# This code is put here so it's easier to do one-liners elsewhere. >+# This section is meant to be run by ebuild.sh >+if [[ "$1" == "--do-pre-ebuild" || "$1" == "--do-post-ebuild" ]]; then >+ if [[ "${EBUILD_PHASE}" == "" ]]; then >+ # an in-between-phases moment; useless to hooks >+ return >+ fi >+ >+ >+ oldwd="$(pwd)" >+ if [[ "$1" == "--do-pre-ebuild" ]]; then >+ hooks_dir="${PORTAGE_CONFIGROOT}/${HOOKS_PATH}/pre-ebuild.d" >+ else >+ hooks_dir="${PORTAGE_CONFIGROOT}/${HOOKS_PATH}/post-ebuild.d" >+ fi >+ >+ [ -d "${hooks_dir}" ] && cd "${hooks_dir}" >+ exit_code="$?" >+ if [[ "${exit_code}" != "0" ]]; then >+ # mimicks behavior in hooks.py >+ # TODO: --verbose detection? >+ : >+ #debug-print "This hook path could not be found; ignored: ${hooks_dir}" >+ else >+ # Execute the hooks >+ source "${HOOKS_SH_BINARY}" --action "${EBUILD_PHASE}" --target "${EBUILD}" >+ exit_code="$?" >+ if [[ "${exit_code}" != "0" ]]; then >+ # mimicks behavior in hooks.py >+ die "Hook directory ${HOOKS_PATH}/pre-ebuild.d failed with exit code ${exit_code}" >+ fi >+ fi >+ cd "${oldwd}" || die "Could not return to the old ebuild directory after pre-ebuild hooks: ${oldwd}" >+ >+ return >+fi >+ >+# Local variables listed here. >+# Using the local keyword makes no difference since this script is being sourced >+# so we'll have to unset them manually later. Be sure to keep the local_vars >+# array up-to-date. >+hook_files=( * ) >+hook_args=( "$@" ) >+hook_verbosity="0" >+hook_rval="0" >+ >+hook_local_vars=( "hook_files" "hook_args" "hook_verbosity" "hook_rval" ) # variables unset for hooks >+ >+for (( i = 0 ; i < ${#hook_args[@]} ; i++ )); do >+ if [[ "${hook_args[$i]}" == "--verbose" ]]; then >+ hook_verbosity="1" >+ fi >+done >+ >+for (( i = 0 ; i < ${#hook_files[@]} ; i++ )); do >+ hook="${hook_files[$i]}" >+ if [[ ! -e "${hook}" ]]; then >+ continue >+ elif [[ ! -f "${hook}" ]]; then >+ [ "${hook_verbosity}" -gt 0 ] && ewarn "Only files are recognized in a hook directory: ${hook}" >+ continue >+ fi >+ >+ [ "${hook_verbosity}" -gt 0 ] && einfo "Executing hook ${hook}..." >+ # We use eval so the hook_args gets expanded before it is unset >+ ( eval unset "${hook_local_vars[@]}" '&&' source "${hook}" "${hook_args[@]}" ) >+ >+ exit_code="$?" >+ if [[ "${exit_code}" == "3" ]]; then >+ hook_rval="3" >+ elif [[ "${exit_code}" != "0" ]]; then >+ eerror "Hook $(pwd)/${hook} returned with exit code ${exit_code}" >+ exit "${exit_code}" >+ fi >+done >+ >+exit_code="${hook_rval}" >+unset "${hook_local_vars[@]}" >+exit "${exit_code}" >diff --git a/bin/phase-functions.sh b/bin/phase-functions.sh >index ce251ce..4351ced 100644 >--- a/bin/phase-functions.sh >+++ b/bin/phase-functions.sh >@@ -198,16 +198,81 @@ preprocess_ebuild_env() { > } > > ebuild_phase() { >- declare -F "$1" >/dev/null && qa_call $1 >+ local x phase_name=${1} pre_phase_hooks post_phase_hooks >+ >+ # only run new-style hooks if this function isn't being used to >+ # execute an old-style phase hook (which causes duplicate new-style >+ # hook calls) >+ if [[ ! "${phase_name}" =~ ^pre_|^post_ ]]; then >+ # Loop through new-style ebuild phase hooks with version check >+ for x in \ >+ EBUILD_PHASE_HOOKS_BEFORE_"${phase_name}" \ >+ EBUILD_PHASE_HOOKS_BEFORE_all \ >+ EBUILD_PHASE_HOOKS_AFTER_"${phase_name}" \ >+ EBUILD_PHASE_HOOKS_AFTER_all >+ do >+ x="$(eval 'echo $'${x})" >+ if [[ "${x}" == "" ]]; then >+ continue >+ fi >+ if ! _is_phase_hook_at_version "${x}" 0; then >+ echo "!!! Unsupported ebuild phase hook version" >+ return 1 >+ fi >+ done >+ pre_phase_hooks="$(eval 'echo $EBUILD_PHASE_HOOKS_BEFORE_'"${phase_name}") $EBUILD_PHASE_HOOKS_BEFORE_all" >+ post_phase_hooks="$(eval 'echo $EBUILD_PHASE_HOOKS_AFTER_'"${phase_name}") $EBUILD_PHASE_HOOKS_AFTER_all" >+ fi >+ >+ for x in \ >+ $pre_phase_hooks \ >+ ${phase_name} \ >+ $post_phase_hooks >+ do >+ exec_ebuild_phase ${x} >+ done > } > >+# TODO: deprecate this function? Should be easy to provide backwards >+# compatibility: >+# register_phase_hook before <phase> pre_<phase> >+# register_phase_hook after <phase> post_<phase> > ebuild_phase_with_hooks() { > local x phase_name=${1} >- for x in {pre_,,post_}${phase_name} ; do >- ebuild_phase ${x} >+ # Loop through new-style ebuild phase hooks with version check >+ for x in \ >+ EBUILD_PHASE_HOOKS_BEFORE_"${phase_name}" \ >+ EBUILD_PHASE_HOOKS_BEFORE_all \ >+ EBUILD_PHASE_HOOKS_AFTER_"${phase_name}" \ >+ EBUILD_PHASE_HOOKS_AFTER_all >+ do >+ x="$(eval 'echo $'${x})" >+ if [[ "${x}" == "" ]]; then >+ continue >+ fi >+ if ! _is_phase_hook_at_version "${x}" 0; then >+ echo "!!! Unsupported ebuild phase hook version" >+ return 1 >+ fi >+ done >+ >+ # Loop through all hooks and the actual phase >+ for x in \ >+ $(eval 'echo $EBUILD_PHASE_HOOKS_BEFORE_'"${phase_name}") \ >+ $EBUILD_PHASE_HOOKS_BEFORE_all \ >+ {pre_,,post_}${phase_name} \ >+ $(eval 'echo $EBUILD_PHASE_HOOKS_AFTER_'"${phase_name}") \ >+ $EBUILD_PHASE_HOOKS_AFTER_all >+ do >+ exec_ebuild_phase ${x} > done > } > >+exec_ebuild_phase() { >+ declare -F "$1" >/dev/null && qa_call $1 >+} >+ >+ > dyn_pretend() { > if [[ -e $PORTAGE_BUILDDIR/.pretended ]] ; then > vecho ">>> It appears that '$PF' is already pretended; skipping." >diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh >index 517a910..10989df 100644 >--- a/bin/phase-helpers.sh >+++ b/bin/phase-helpers.sh >@@ -188,7 +188,7 @@ use() { > # TODO: Add a registration interface for eclasses to register > # any number of phase hooks, so that global scope eclass > # initialization can by migrated to phase hooks in new EAPIs. >- # Example: add_phase_hook before pkg_setup $ECLASS_pre_pkg_setup >+ # Example: register_phase_hook before pkg_setup $ECLASS_pre_pkg_setup > #if [[ -n $EAPI ]] && ! has "$EAPI" 0 1 2 3 ; then > # die "use() called during invalid phase: $EBUILD_PHASE" > #fi >diff --git a/doc/config.docbook b/doc/config.docbook >index 88009df..c2bd0ed 100644 >--- a/doc/config.docbook >+++ b/doc/config.docbook >@@ -2,4 +2,5 @@ > <title>Configuration</title> > &config_bashrc; > &config_set; >+&config_hooks; > </part> >diff --git a/doc/config/hooks.docbook b/doc/config/hooks.docbook >new file mode 100644 >index 0000000..aa37c75 >--- /dev/null >+++ b/doc/config/hooks.docbook >@@ -0,0 +1,108 @@ >+<chapter id='config-hooks'> >+ <title id="config-hooks.title">Hooks Configuration</title> >+ >+ <sect1 id='config-hooks-execution'> >+ <title id="config-hooks-execution.title">Hooks Execution</title> >+ >+ <para>Hooks are only executed if <quote>hooks</quote> is set in >+ FEATURES.</para> >+ >+ <para> >+ If a hook directory exists, the bash scripts within each one >+ wil either be executed before or after that particular phase, in >+ alphabetical order. Each one will receive the environment of an >+ ebuild, so they are capable of inherit, einfo, and other common >+ commands (if you find them useful). For non-ebuild hooks, avoid >+ commands that may trigger changes in the filesystem! >+ </para> >+ >+ <para> >+ Ebuild hooks are executed within ebuild.sh, so they receive the >+ same sandbox limitations as ebuilds. >+ </para> >+ >+ <para> >+ A hook script is expected to understand the following usage: >+ <cmdsynopsis> >+ <command>/bin/bash <replaceable>...</replaceable></command><sbr/> >+ >+ <arg>--opt <replaceable>portage arguments, always translated to long form, given by user at the prompt, such as "--verbose" or "--newuse"</replaceable></arg><sbr/> >+ >+ <arg>--action <replaceable>a single action being performed by portage, such as "depclean", "sync", or an ebuild phase</replaceable></arg><sbr/> >+ >+ <arg>--target <replaceable>the thing to perform the action with or on</replaceable></arg> >+ </cmdsynopsis> >+ </para> >+ >+ <para> >+ Some hook types have slightly different usage. See <quote> >+ <link linkend='config-hooks-locations' endterm="config-hooks-locations.title"/></quote> for more >+ information. >+ </para> >+ >+ </sect1> >+ >+ <sect1 id='config-hooks-locations'> >+ <title id="config-hooks-locations.title">Hooks Locations</title> >+ <para> >+ The following hook directories are supported. Each directory >+ corresponds to a specific type, such as <quote>ebuild</quote> or >+ <quote>run</quote>. The standard hook script usage applies given >+ in <link linkend='config-hooks-execution' endterm="config-hooks-execution.title"/>, >+ except wherever described differently below. >+ </para> >+ >+ <itemizedlist> >+ <listitem><para><filename>/etc/portage/hooks/pre-ebuild.d/</filename> - executed before every ebuild phase execution, within ebuild.sh itself. Never receives --opt, and --target is set to the full path of the ebuild.</para></listitem> >+ <listitem><para><filename>/etc/portage/hooks/post-ebuild.d/</filename> - executed after every ebuild phase execution. Never receives --opt, and --target is set to the full path of the ebuild.</para></listitem> >+ <listitem><para><filename>/etc/portage/hooks/pre-run.d/</filename> - executed before portage considers most things, including proper permissions and validity of parsed arguments.</para></listitem> >+ <listitem><para><filename>/etc/portage/hooks/post-run.d/</filename> - executed after portage is done. It should run regardless of any errors or signals sent, but this cannot be guaranteed for certain scenarios (such as when the KILL signal is received). No information is available concerning the reason portage is exiting. This is a limitation of python itself.</para></listitem> >+ <listitem><para><filename>/etc/portage/hooks/pre-sync.d/</filename> - executed before portage synchronizes the portage tree.</para></listitem> >+ <listitem><para><filename>/etc/portage/hooks/post-sync.d/</filename> - executed after portage has <emphasis>successfully</emphasis> synchronized the portage tree. If you want to catch a sync failure, use post-run.</para></listitem> >+ </itemizedlist> >+ </sect1> >+ >+ <sect1 id='config-hooks-skeleton-hook'> >+ <title id="config-hooks-skeleton-hook.title">Skeleton Hook</title> >+ <para> >+ Most hooks will parse the options at the beginning and look for >+ specific things. This skeleton hook provides that functionality >+ to get you started. >+ </para> >+ <para> >+ It's highly recommended that --verbose, --debug, and --quiet be >+ utilized for suppressing or adding to <quote>regular</quote> >+ output. The following skeleton hook already has example code in >+ place to handle these flags. >+ </para> >+ <programlisting> >+ #!/bin/bash >+ >+ verbose_redirect="/dev/null" >+ debug_redirect="/dev/null" >+ while [[ "$1" != "" ]]; do >+ if [[ "$1" == "--opt" ]]; then >+ if [[ "$2" == "--verbose" ]]; then >+ verbose_redirect="/dev/tty" >+ fi >+ if [[ "$2" == "--debug" ]]; then >+ debug_redirect="/dev/tty" >+ fi >+ if [[ "$2" == "--quiet" ]]; then >+ verbose_redirect="/dev/null" >+ debug_redirect="/dev/null" >+ fi >+ elif [[ "$1" == "--action" ]]; then >+ : # do nothing >+ elif [[ "$1" == "--target" ]]; then >+ : # do nothing >+ else >+ ewarn "Unknown hook option: $1 $2" &> "${verbose_redirect}" >+ fi >+ shift 2 >+ done >+ einfo "This is an example hook." &> "${verbose_redirect}" >+ einfo "This is debug output." &> "${debug_redirect}" >+ </programlisting> >+ </sect1> >+</chapter> >diff --git a/doc/portage.docbook b/doc/portage.docbook >index c0121b8..9b1d774 100644 >--- a/doc/portage.docbook >+++ b/doc/portage.docbook >@@ -25,6 +25,7 @@ > <!ENTITY config SYSTEM "config.docbook"> > <!ENTITY config_bashrc SYSTEM "config/bashrc.docbook"> > <!ENTITY config_set SYSTEM "config/sets.docbook"> >+ <!ENTITY config_hooks SYSTEM "config/hooks.docbook"> > ]> > > <book id="portage" lang="en"> >diff --git a/man/portage.5 b/man/portage.5 >index e2ed754..8805af3 100644 >--- a/man/portage.5 >+++ b/man/portage.5 >@@ -66,6 +66,9 @@ repos.conf > .BR /etc/portage/env/ > package-specific bashrc files > .TP >+.BR /etc/portage/hooks/ >+portage pre/post hooks >+.TP > .BR /etc/portage/profile/ > site-specific overrides of \fB/etc/make.profile/\fR > .TP >@@ -758,6 +761,14 @@ in the following order: > /etc/portage/env/${CATEGORY}/${PF} > .RE > .TP >+.BR /etc/portage/hooks/ >+.RS >+In this directory, portage hooks are executed before each ebuild phase, >+before and after synchronization, and before and after portage runs >+themselves. Please see the DocBook documentation for detailed >+information. >+.RE >+.TP > .BR /usr/portage/metadata/ > .RS > .TP >diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py >index 31d53f9..57105ba 100644 >--- a/pym/_emerge/actions.py >+++ b/pym/_emerge/actions.py >@@ -41,6 +41,7 @@ from portage.output import blue, bold, colorize, create_color_func, darkgreen, \ > red, yellow > good = create_color_func("GOOD") > bad = create_color_func("BAD") >+from portage.hooks import HookDirectory > from portage.package.ebuild._ipc.QueryCommand import QueryCommand > from portage.package.ebuild.doebuild import _check_temp_dir > from portage._sets import load_default_config, SETPREFIX >@@ -1969,6 +1970,11 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): > dosyncuri = syncuri > updatecache_flg = False > git = False >+ >+ rval = HookDirectory(phase='pre-sync', settings=settings, myopts=myopts, myaction=myaction).execute() >+ if rval == 3: >+ return 0 >+ > if myaction == "metadata": > print("skipping sync") > updatecache_flg = True >@@ -2495,6 +2501,8 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): > " %s spawn failed of %s\n" % (bad("*"), postsync,), > level=logging.ERROR, noiselevel=-1) > >+ HookDirectory(phase='post-sync', settings=settings, myopts=myopts, myaction=myaction).execute() >+ > if(mybestpv != mypvs) and not "--quiet" in myopts: > print() > print(red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended") >diff --git a/pym/_emerge/main.py b/pym/_emerge/main.py >index 65df99d..d4d4865 100644 >--- a/pym/_emerge/main.py >+++ b/pym/_emerge/main.py >@@ -25,6 +25,8 @@ bad = create_color_func("BAD") > > from portage.const import _ENABLE_DYN_LINK_MAP > import portage.elog >+import portage.hooks >+import portage.process > import portage.util > import portage.locks > import portage.exception >@@ -1613,7 +1615,18 @@ def emerge_main(args=None): > # Portage needs to ensure a sane umask for the files it creates. > os.umask(0o22) > settings, trees, mtimedb = load_emerge_config() >+ >+ # Portage configured; let's let hooks run before we do anything more >+ rval = portage.hooks.HookDirectory(phase='pre-run', settings=settings, myopts=myopts, myaction=myaction, mytargets=myfiles).execute() >+ if rval == 3: >+ return 0 >+ >+ settings, trees, mtimedb = load_emerge_config() # once more, since pre-run might've done something > portdb = trees[settings['EROOT']]['porttree'].dbapi >+ >+ # Have post-run hooks executed whenever portage quits >+ portage.process.atexit_register(portage.hooks.HookDirectory(phase='post-run', settings=settings, myopts=myopts, myaction=myaction, mytargets=myfiles).execute) >+ > rval = profile_check(trees, myaction) > if rval != os.EX_OK: > return rval >diff --git a/pym/portage/const.py b/pym/portage/const.py >index bebb922..dbe6dcf 100644 >--- a/pym/portage/const.py >+++ b/pym/portage/const.py >@@ -34,6 +34,7 @@ CUSTOM_PROFILE_PATH = USER_CONFIG_PATH + "/profile" > USER_VIRTUALS_FILE = USER_CONFIG_PATH + "/virtuals" > EBUILD_SH_ENV_FILE = USER_CONFIG_PATH + "/bashrc" > EBUILD_SH_ENV_DIR = USER_CONFIG_PATH + "/env" >+HOOKS_PATH = USER_CONFIG_PATH + "/hooks" > CUSTOM_MIRRORS_FILE = USER_CONFIG_PATH + "/mirrors" > COLOR_MAP_FILE = USER_CONFIG_PATH + "/color.map" > PROFILE_PATH = "etc/make.profile" >@@ -62,6 +63,7 @@ PORTAGE_PYM_PATH = PORTAGE_BASE_PATH + "/pym" > LOCALE_DATA_PATH = PORTAGE_BASE_PATH + "/locale" # FIXME: not used > EBUILD_SH_BINARY = PORTAGE_BIN_PATH + "/ebuild.sh" > MISC_SH_BINARY = PORTAGE_BIN_PATH + "/misc-functions.sh" >+HOOKS_SH_BINARY = PORTAGE_BIN_PATH + "/hooks.sh" > SANDBOX_BINARY = "/usr/bin/sandbox" > FAKEROOT_BINARY = "/usr/bin/fakeroot" > BASH_BINARY = "/bin/bash" >@@ -91,7 +93,7 @@ SUPPORTED_FEATURES = frozenset([ > "collision-protect", "compress-build-logs", "compressdebug", > "config-protect-if-modified", > "digest", "distcc", "distcc-pump", "distlocks", "ebuild-locks", "fakeroot", >- "fail-clean", "force-mirror", "force-prefix", "getbinpkg", >+ "fail-clean", "force-mirror", "force-prefix", "getbinpkg", "hooks", > "installsources", "keeptemp", "keepwork", "fixlafiles", "lmirror", > "metadata-transfer", "mirror", "multilib-strict", "news", > "noauto", "noclean", "nodoc", "noinfo", "noman", >diff --git a/pym/portage/hooks.py b/pym/portage/hooks.py >new file mode 100644 >index 0000000..7472856 >--- /dev/null >+++ b/pym/portage/hooks.py >@@ -0,0 +1,74 @@ >+# Copyright 1999-2011 Gentoo Foundation >+# Distributed under the terms of the GNU General Public License v2 >+ >+from portage.const import BASH_BINARY, HOOKS_PATH, HOOKS_SH_BINARY, PORTAGE_BIN_PATH >+from portage import os >+from portage import check_config_instance >+from portage import normalize_path >+from portage.exception import PortageException >+from portage.exception import InvalidLocation >+from portage.output import EOutput >+from process import spawn >+from shutil import rmtree >+from tempfile import mkdtemp >+ >+class HookDirectory(object): >+ >+ def __init__ (self, phase, settings, myopts=None, myaction=None, mytargets=None): >+ self.myopts = myopts >+ self.myaction = myaction >+ self.mytargets = mytargets >+ check_config_instance(settings) >+ self.settings = settings >+ self.path = os.path.join(settings["PORTAGE_CONFIGROOT"], HOOKS_PATH, phase + '.d') >+ self.output = EOutput() >+ >+ >+ def execute (self, path=None): >+ """ >+ Executes all the hooks for the specified phase >+ >+ @param path: the location where the hooks are stored >+ @type msg: StringType >+ >+ Returns 0 on success, or 3 if success but immediate portage exit >+ is requested, or throws an exception on error. >+ """ >+ if "hooks" not in self.settings['FEATURES']: >+ return 0 >+ >+ if not path: >+ path = self.path >+ >+ path = normalize_path(path) >+ >+ if not os.path.exists(path): >+ if self.myopts and "--debug" in self.myopts: >+ # behavior mimicked by hook.sh >+ self.output.ewarn('This hook path could not be found; ignored: ' + path) >+ return 0 >+ >+ if os.path.isdir(path): >+ command=[HOOKS_SH_BINARY] >+ if self.myopts: >+ for myopt in self.myopts: >+ command.extend(['--opt', myopt]) >+ if self.myaction: >+ command.extend(['--action', self.myaction]) >+ if self.mytargets: >+ for mytarget in self.mytargets: >+ command.extend(['--target', mytarget]) >+ >+ command=[BASH_BINARY, '-c', 'cd "'+path+'" && source "' + PORTAGE_BIN_PATH + '/isolated-functions.sh" && source ' + ' '.join(command)] >+ if self.myopts and "--verbose" in self.myopts: >+ self.output.einfo('Executing hooks directory "' + self.path + '"...') >+ code = spawn(mycommand=command, env=self.settings.environ()) >+ if code == 3: # if requesting immediate exit >+ self.output.ewarn("Hook requested immediate successful exit") >+ return 3 >+ if code: # if failure >+ # behavior mimicked by hook.sh >+ raise PortageException('!!! Hook directory %s failed with exit code %s' % (self.path, code)) >+ >+ else: >+ raise InvalidLocation('This hook path ought to be a directory: ' + path) >diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py >index 366f548..184940d 100644 >--- a/pym/portage/package/ebuild/config.py >+++ b/pym/portage/package/ebuild/config.py >@@ -23,7 +23,7 @@ portage.proxy.lazyimport.lazyimport(globals(), > from portage import bsd_chflags, \ > load_mod, os, selinux, _unicode_decode > from portage.const import CACHE_PATH, \ >- DEPCACHE_PATH, INCREMENTALS, MAKE_CONF_FILE, \ >+ DEPCACHE_PATH, HOOKS_PATH, HOOKS_SH_BINARY, INCREMENTALS, MAKE_CONF_FILE, \ > MODULES_FILE_PATH, \ > PRIVATE_PATH, PROFILE_PATH, USER_CONFIG_PATH, \ > USER_VIRTUALS_FILE >@@ -501,6 +501,8 @@ class config(object): > > self["PORTAGE_CONFIGROOT"] = config_root > self.backup_changes("PORTAGE_CONFIGROOT") >+ self["HOOKS_PATH"] = HOOKS_PATH >+ self.backup_changes("HOOKS_PATH") > self["ROOT"] = target_root > self.backup_changes("ROOT") > >diff --git a/pym/portage/tests/hooks/__init__.py b/pym/portage/tests/hooks/__init__.py >new file mode 100644 >index 0000000..95dfcfc >--- /dev/null >+++ b/pym/portage/tests/hooks/__init__.py >@@ -0,0 +1,5 @@ >+# tests/portage/hooks/__init__.py -- Portage Unit Test functionality >+# Copyright 2010 Gentoo Foundation >+# Distributed under the terms of the GNU General Public License v2 >+# $Id$ >+ >diff --git a/pym/portage/tests/hooks/__test__ b/pym/portage/tests/hooks/__test__ >new file mode 100644 >index 0000000..e69de29 >diff --git a/pym/portage/tests/hooks/test_HookDirectory.py b/pym/portage/tests/hooks/test_HookDirectory.py >new file mode 100644 >index 0000000..09949e5 >--- /dev/null >+++ b/pym/portage/tests/hooks/test_HookDirectory.py >@@ -0,0 +1,49 @@ >+# test_HookDirectory.py -- Portage Unit Testing Functionality >+# Copyright 2010 Gentoo Foundation >+# Distributed under the terms of the GNU General Public License v2 >+# $Id$ >+ >+from portage import os >+from portage.hooks import HookDirectory >+from portage.package.ebuild.config import config >+from portage.tests import TestCase >+from tempfile import mkdtemp >+from shutil import rmtree >+ >+class HookDirectoryTestCase(TestCase): >+ >+ def testHookDirectory(self): >+ """ >+ Tests to be sure a hook loads and reads the right settings >+ Based on test_PackageKeywordsFile.py >+ """ >+ >+ self.tmp_dir_path = self.BuildTmp('/etc/portage/hooks/test.d') >+ try: >+ settings = config() >+ settings["PORTAGE_CONFIGROOT"] = self.tmp_dir_path >+ settings["FEATURES"] += " hooks" >+ hooks = HookDirectory(phase='test', settings=settings) >+ hooks.execute() >+ self.assert_(settings["hookonlytest"] == "") >+ finally: >+ rmtree(self.tmp_dir_path) >+ >+ def BuildTmp(self, tmp_subdir): >+ tmp_dir = mkdtemp() >+ hooks_dir = tmp_dir + '/' + tmp_subdir >+ os.makedirs(hooks_dir) >+ >+ f = open(hooks_dir+'/1-testhook', 'w') >+ f.write('#!/bin/bash\n') >+ f.write('export hookonlytest="portage cannot see me!"\n') >+ f.write('exit 0\n') >+ f.close() >+ >+ f = open(hooks_dir+'/2-testhook', 'w') >+ f.write('#!/bin/bash\n') >+ f.write('if [[ "${hookonlytest}" != "" ]]; then echo "Unexpected hookonlytest value: ${hookonlytest}"; exit 1; fi\n'); >+ f.write('exit 0\n') >+ f.close() >+ >+ return tmp_dir
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 272988
:
233213
|
233889
|
233891
|
233991
|
233993
|
238177
|
238181
|
238191
|
238193
|
299457
| 299463