diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index 5994e7cb43eb..93e7d761c90f 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -1523,7 +1523,7 @@ adl_serializer::from_json(const json & _json, const Experiment } } -void adl_serializer::to_json(json & res, const Derivation & d) +void adl_serializer::to_json(json & res, const BasicDerivation & d) { res = nlohmann::json::object(); @@ -1549,24 +1549,6 @@ void adl_serializer::to_json(json & res, const Derivation & d) for (auto & input : d.inputSrcs) inputsList.emplace_back(input); } - - auto doInput = [&](this const auto & doInput, const auto & inputNode) -> nlohmann::json { - auto value = nlohmann::json::object(); - value["outputs"] = inputNode.value; - { - auto next = nlohmann::json::object(); - for (auto & [outputId, childNode] : inputNode.childMap) - next[outputId] = doInput(childNode); - value["dynamicOutputs"] = std::move(next); - } - return value; - }; - - auto & inputDrvsObj = inputsObj["drvs"]; - inputDrvsObj = nlohmann::json::object(); - for (auto & [inputDrv, inputNode] : d.inputDrvs.map) { - inputDrvsObj[inputDrv.to_string()] = doInput(inputNode); - } } res["system"] = d.platform; @@ -1578,6 +1560,28 @@ void adl_serializer::to_json(json & res, const Derivation & d) res["structuredAttrs"] = d.structuredAttrs->structuredAttrs; } +void adl_serializer::to_json(json & res, const Derivation & d) +{ + adl_serializer::to_json(res, static_cast(d)); + + auto doInput = [&](this const auto & doInput, const auto & inputNode) -> nlohmann::json { + auto value = nlohmann::json::object(); + value["outputs"] = inputNode.value; + { + auto next = nlohmann::json::object(); + for (auto & [outputId, childNode] : inputNode.childMap) + next[outputId] = doInput(childNode); + value["dynamicOutputs"] = std::move(next); + } + return value; + }; + + auto & inputDrvsObj = res["inputs"]["drvs"]; + inputDrvsObj = nlohmann::json::object(); + for (auto & [inputDrv, inputNode] : d.inputDrvs.map) + inputDrvsObj[inputDrv.to_string()] = doInput(inputNode); +} + Derivation adl_serializer::from_json(const json & _json, const ExperimentalFeatureSettings & xpSettings) { using nlohmann::detail::value_t; diff --git a/src/libstore/include/nix/store/derivations.hh b/src/libstore/include/nix/store/derivations.hh index 3b07072d99d4..b66094531ec5 100644 --- a/src/libstore/include/nix/store/derivations.hh +++ b/src/libstore/include/nix/store/derivations.hh @@ -614,3 +614,4 @@ constexpr unsigned expectedJsonVersionDerivation = 4; JSON_IMPL_WITH_XP_FEATURES(nix::DerivationOutput) JSON_IMPL_WITH_XP_FEATURES(nix::Derivation) +JSON_IMPL_WITH_XP_FEATURES(nix::BasicDerivation) diff --git a/src/libstore/include/nix/store/globals.hh b/src/libstore/include/nix/store/globals.hh index d0a134b9c4e1..37c14df028b5 100644 --- a/src/libstore/include/nix/store/globals.hh +++ b/src/libstore/include/nix/store/globals.hh @@ -1081,10 +1081,24 @@ public: 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 sandboxes are - enabled, the sandbox directory. It can then modify the sandbox and - send a series of commands to modify various settings to stdout. The - currently recognized commands are: + The hook receives the derivation to be built as JSON in the file + pointed to by the environment variable `NIX_DERIVATION_V4`. See + [@docroot@/protocols/json/derivation/index.md](@docroot@/protocols/json/derivation/index.md) + for the format. For example, to read the `requiredSystemFeatures` + attribute: + + ```sh + jq -r '.env.requiredSystemFeatures' < "$NIX_DERIVATION_V4" + ``` + + > **Deprecated** + > Using the derivation store path passed as `argv[1]` to inspect the + > derivation is deprecated and not recommended. This path may not + > exist when Nix is invoked as a remote builder. + + If sandboxes are enabled, the hook also receives the sandbox + directory as `argv[2]`. It can send a series of commands to modify + various settings to stdout. The currently recognized commands are: - `extra-sandbox-paths`\ Pass a list of files and directories to be included in the diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index c41d3cb4a212..3e7a7a80a194 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -22,6 +22,7 @@ #include "nix/util/terminal.hh" #include "nix/store/provenance.hh" +#include #include #include @@ -932,8 +933,27 @@ PathsInChroot DerivationBuilderImpl::getPathsInSandbox() enum BuildHookState { stBegin, stExtraChrootDirs }; + nlohmann::json drvJson = drv; + + auto [tmpFd, drvJsonPath] = createTempFile("nix-drv-json"); + writeFile(drvJsonPath, drvJson.dump()); + AutoDelete drvJsonFile(drvJsonPath, false); + + auto hookEnv = getEnv(); + static_assert(expectedJsonVersionDerivation == 4); + hookEnv["NIX_DERIVATION_V4"] = drvJsonPath; + + auto [hookStatus, lines] = runProgram( + RunOptions{ + .program = settings.preBuildHook, + .lookupPath = false, + .args = getPreBuildHookArgs(), + .environment = std::move(hookEnv), + }); + if (!statusOk(hookStatus)) + throw ExecError(hookStatus, "pre-build hook '%1%' %2%", settings.preBuildHook, statusToString(hookStatus)); + auto state = stBegin; - auto lines = runProgram(settings.preBuildHook, false, getPreBuildHookArgs()); auto lastPos = std::string::size_type{0}; for (auto nlPos = lines.find('\n'); nlPos != std::string::npos; nlPos = lines.find('\n', lastPos)) { auto line = lines.substr(lastPos, nlPos - lastPos); diff --git a/tests/functional/linux-sandbox.sh b/tests/functional/linux-sandbox.sh index 484ad1d2b688..09101c2bf2e8 100755 --- a/tests/functional/linux-sandbox.sh +++ b/tests/functional/linux-sandbox.sh @@ -102,3 +102,24 @@ nix-sandbox-build symlink-derivation.nix -A test_sandbox_paths \ expectStderr 1 nix-sandbox-build --option extra-sandbox-paths '/does-not-exist' \ -E 'with import '"${config_nix}"'; mkDerivation { name = "trivial"; buildCommand = "echo > $out"; }' | grepQuiet "path '/does-not-exist' is configured as part of the \`sandbox-paths\` option, but is inaccessible" + +# Test pre-build-hook. +DEST="$TEST_ROOT/hook-output" +HOOK="$TEST_ROOT/pre-build-hook" + +echo foo > "$TEST_ROOT"/fnord + +cat > "$HOOK" < "$DEST" +echo "hello from hook!" >&2 +echo "extra-sandbox-paths" +echo "/foo/bar=$TEST_ROOT/fnord" +EOF +chmod +x "$HOOK" + +outPath=$(nix-build --no-out-link --sandbox-paths /nix/store --pre-build-hook "$HOOK" symlink-derivation.nix -A test_sandbox_paths_2) + +[[ $(cat "$TEST_ROOT/store0/nix/store/$(basename "$outPath")/xyzzy") = foo ]] + +[[ "$(cat "$DEST")" == "test-sandbox-paths-2" ]] diff --git a/tests/functional/symlink-derivation.nix b/tests/functional/symlink-derivation.nix index e9a74cdcef27..6f7f5716a4b1 100644 --- a/tests/functional/symlink-derivation.nix +++ b/tests/functional/symlink-derivation.nix @@ -56,4 +56,12 @@ in touch $out ''; }; + + test_sandbox_paths_2 = mkDerivation { + name = "test-sandbox-paths-2"; + buildCommand = '' + mkdir $out + cat /foo/bar > $out/xyzzy + ''; + }; }