From b0f2d3419c3340978026272496c306287a8cdbd9 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 25 Jun 2014 15:38:37 +0200 Subject: [PATCH] Allow multiple hooks with the same name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You can now register multiple values per named hook, e.g. addHook preConfigure "echo foo" addHook preConfigure "echo bar" will cause ‘runHook preConfigure’ to run both ‘echo foo’ and ‘echo bar’ (in that order). It will also call the shell function preConfigure() or eval the shell variable $preConfigure, if defined. Thus, if you don't call addHook, it works like the old hook mechanism. Allowing multiple hooks makes stdenv more modular and extensible. For instance, multiple setup hooks can define a preFixup hook, and all of these will be executed. --- pkgs/stdenv/generic/setup.sh | 53 ++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/pkgs/stdenv/generic/setup.sh b/pkgs/stdenv/generic/setup.sh index c3b9033b49a6..de762490715d 100644 --- a/pkgs/stdenv/generic/setup.sh +++ b/pkgs/stdenv/generic/setup.sh @@ -1,8 +1,38 @@ -# Run the named hook, either by calling the function with that name or -# by evaluating the variable with that name. This allows convenient -# setting of hooks both from Nix expressions (as attributes / -# environment variables) and from shell scripts (as functions). +###################################################################### +# Hook handling. + + +# Add the specified shell code to the named hook, e.g. ‘addHook +# preConfigure "rm ./foo; touch ./bar"’. +addHook() { + local hookName="$1" + local hookCode="$2" + eval "_${hookName}_hooks+=(\"\$hookCode\")" +} + + +# Run all hooks with the specified name in the order in which they +# were added, stopping if any fails (returns a non-zero exit +# code). Hooks are added using ‘addHooks ’, or +# implicitly by defining a shell function or variable . Note +# that the latter takes precedence over hooks added via ‘addHooks’. runHook() { + local hookName="$1" + local var="_${hookName}_hooks" + eval "local -a dummy=(\"\${_${hookName}_hooks[@]}\")" + for hook in "runSingleHook $hookName" "${dummy[@]}"; do + if ! _eval "$hook"; then return 1; fi + done + return 0 +} + + +# Run the named hook, either by calling the function with that name or +# by evaluating the variable with that name. This allows convenient +# setting of hooks both from Nix expressions (as attributes / +# environment variables) and from shell scripts (as functions). If you +# want to allow multiple hooks, use runHook instead. +runSingleHook() { local hookName="$1" case "$(type -t $hookName)" in (function|alias|builtin) $hookName;; @@ -13,6 +43,17 @@ runHook() { } +# A function wrapper around ‘eval’ that ensures that ‘return’ inside +# hooks exits the hook, not the caller. +_eval() { + local code="$1" + eval "$code" +} + + +###################################################################### +# Error handling. + exitHandler() { exitCode=$? set +e @@ -467,7 +508,7 @@ unpackFile() { echo "source archive $curSrc has unknown type" exit 1 fi - runHook unpackCmd + runSingleHook unpackCmd fi ;; esac @@ -505,7 +546,7 @@ unpackPhase() { # Find the source directory. if [ -n "$setSourceRoot" ]; then - runHook setSourceRoot + runSingleHook setSourceRoot elif [ -z "$sourceRoot" ]; then sourceRoot= for i in *; do