From 26dacc09837cb5226b7d97ed70a0fbade5e40304 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 11 Feb 2020 23:53:46 +0100 Subject: [PATCH] Add fetchTree builtin function This allows all supported fetchers to be used, e.g. builtins.fetchTree { type = "github"; owner = "NixOS"; repo = "nix"; rev = "d4df99a3349cf2228a8ee78dea320afef86eb3ba"; } --- src/libexpr/primops/fetchTree.cc | 61 ++++++++++++++++++++++++++++++++ tests/tarball.sh | 6 ++++ 2 files changed, 67 insertions(+) create mode 100644 src/libexpr/primops/fetchTree.cc diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc new file mode 100644 index 000000000..ccb0cacd5 --- /dev/null +++ b/src/libexpr/primops/fetchTree.cc @@ -0,0 +1,61 @@ +#include "primops.hh" +#include "eval-inline.hh" +#include "store-api.hh" +#include "fetchers/fetchers.hh" +#include "fetchers/registry.hh" + +namespace nix { + +static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, Value & v) +{ + std::shared_ptr input; + PathSet context; + + state.forceValue(*args[0]); + + if (args[0]->type == tAttrs) { + state.forceAttrs(*args[0], pos); + + fetchers::Input::Attrs attrs; + + for (auto & attr : *args[0]->attrs) { + state.forceValue(*attr.value); + if (attr.value->type == tString) + attrs.emplace(attr.name, attr.value->string.s); + else + throw Error("unsupported attribute type"); + } + + if (!attrs.count("type")) + throw Error("attribute 'type' is missing in call to 'fetchTree', at %s", pos); + + input = fetchers::inputFromAttrs(attrs); + } else + input = fetchers::inputFromURL(state.coerceToString(pos, *args[0], context, false, false)); + + if (!evalSettings.pureEval && !input->isDirect()) + input = lookupInRegistries(state.store, input); + + if (evalSettings.pureEval && !input->isImmutable()) + throw Error("in pure evaluation mode, 'fetchTree' requires an immutable input"); + + auto [tree, input2] = input->fetchTree(state.store); + + state.mkAttrs(v, 8); + auto storePath = state.store->printStorePath(tree.storePath); + mkString(*state.allocAttr(v, state.sOutPath), storePath, PathSet({storePath})); + if (input2->getRev()) { + mkString(*state.allocAttr(v, state.symbols.create("rev")), input2->getRev()->gitRev()); + mkString(*state.allocAttr(v, state.symbols.create("shortRev")), input2->getRev()->gitShortRev()); + } + if (tree.info.revCount) + mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *tree.info.revCount); + v.attrs->sort(); + + if (state.allowedPaths) + state.allowedPaths->insert(tree.actualPath); +} + +static RegisterPrimOp r("fetchTree", 1, prim_fetchTree); + +} diff --git a/tests/tarball.sh b/tests/tarball.sh index 8adb8d72f..7c8896b2e 100644 --- a/tests/tarball.sh +++ b/tests/tarball.sh @@ -10,6 +10,8 @@ mkdir -p $tarroot cp dependencies.nix $tarroot/default.nix cp config.nix dependencies.builder*.sh $tarroot/ +hash=$(nix hash-path $tarroot) + test_tarball() { local ext="$1" local compressor="$2" @@ -25,6 +27,10 @@ test_tarball() { nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)" + nix-build -o $TEST_ROOT/result -E "import (fetchTree file://$tarball)" + nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; })" + nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })" + nix-instantiate --eval -E '1 + 2' -I fnord=file://no-such-tarball.tar$ext nix-instantiate --eval -E 'with ; 1 + 2' -I fnord=file://no-such-tarball$ext (! nix-instantiate --eval -E ' 1' -I fnord=file://no-such-tarball$ext)