Allow multiple hooks with the same name

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.
This commit is contained in:
Eelco Dolstra 2014-06-25 15:38:37 +02:00
parent 18e422d047
commit b0f2d3419c

View File

@ -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 <hookName> <code>, or
# implicitly by defining a shell function or variable <hookName>. 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