diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml index 89b8aac78..ec96f750e 100644 --- a/doc/manual/command-ref/conf-file.xml +++ b/doc/manual/command-ref/conf-file.xml @@ -562,6 +562,40 @@ flag, e.g. --option gc-keep-outputs false. + pre-build-hook + + + + + If set, the path to a program that can set extra + derivation-specific settings for this system. This is used for settings + that can't be captured by the derivation model itself and are too variable + between different versions of the same system to be hard-coded into nix. + + + The hook is passed the derivation path and, if chroots are enabled, + the chroot directory. It can then modify the chroot and send a series of + commands to modify various settings to stdout. The currently recognized + commands are: + + + extra-chroot-dirs + + + + Pass a list of files and directories to be included in the + chroot for this build. One entry per line, terminated by an empty + line. Entries have the same format as build-chroot-dirs. + + + + + + + + + + diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 1fc5d4181..08b647cd6 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1969,6 +1969,42 @@ void DerivationGoal::startBuilder() } } + if (settings.preBuildHook != "") { + printMsg(lvlChatty, format("executing pre-build hook ‘%1%’") + % settings.preBuildHook); + auto args = useChroot ? Strings({drvPath, chrootRootDir}) : + Strings({ drvPath }); + enum BuildHookState { + stBegin, + stExtraChrootDirs + }; + auto state = stBegin; + auto lines = runProgram(settings.preBuildHook, false, args); + auto lastPos = std::string::size_type{0}; + for (auto nlPos = lines.find('\n'); nlPos != string::npos; + nlPos = lines.find('\n', lastPos)) { + auto line = std::string{lines, lastPos, nlPos}; + lastPos = nlPos + 1; + if (state == stBegin) { + if (line == "extra-chroot-dirs") { + state = stExtraChrootDirs; + } else { + throw Error(format("unknown pre-build hook command ‘%1%’") + % line); + } + } else if (state == stExtraChrootDirs) { + if (line == "") { + state = stBegin; + } else { + auto p = line.find('='); + if (p == string::npos) + dirsInChroot[line] = line; + else + dirsInChroot[string(line, 0, p)] = string(line, p + 1); + } + } + } + } /* Run the builder. */ printMsg(lvlChatty, format("executing builder ‘%1%’") % drv.builder); diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 052ca45cc..d5615d93c 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -182,6 +182,7 @@ void Settings::update() _get(logServers, "log-servers"); _get(enableImportNative, "allow-unsafe-native-code-during-evaluation"); _get(useCaseHack, "use-case-hack"); + _get(preBuildHook, "pre-build-hook"); string subs = getEnv("NIX_SUBSTITUTERS", "default"); if (subs == "default") { diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index 195558dd3..60b11afe6 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -206,6 +206,10 @@ struct Settings { /* Whether the importNative primop should be enabled */ bool enableImportNative; + /* The hook to run just before a build to set derivation-specific + build settings */ + Path preBuildHook; + private: SettingsMap settings, overrides;