From 90948a4e3a64492b7d117d93657221fa7b598e6e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 24 Nov 2017 18:07:29 +0100 Subject: [PATCH] nix-shell/nix-build: Support .drv files again Fixes #1663. Also handle '!' (#1694). --- src/libexpr/get-drvs.cc | 28 ++++++++++++++++++++++++++++ src/libexpr/get-drvs.hh | 1 + src/nix-build/nix-build.cc | 6 ++++-- tests/multiple-outputs.sh | 15 ++++++++++++++- tests/nix-build.sh | 8 +++++++- tests/nix-shell.sh | 7 +++++++ 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index d5bc42352..d38ed2df3 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -1,6 +1,7 @@ #include "get-drvs.hh" #include "util.hh" #include "eval-inline.hh" +#include "derivations.hh" #include #include @@ -15,6 +16,33 @@ DrvInfo::DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs) } +DrvInfo::DrvInfo(EvalState & state, ref store, const std::string & drvPathWithOutputs) + : state(&state), attrs(nullptr), attrPath("") +{ + auto spec = parseDrvPathWithOutputs(drvPathWithOutputs); + + drvPath = spec.first; + + auto drv = store->derivationFromPath(drvPath); + + name = storePathToName(drvPath); + + if (spec.second.size() > 1) + throw Error("building more than one derivation output is not supported, in '%s'", drvPathWithOutputs); + + outputName = + spec.second.empty() + ? get(drv.env, "outputName", "out") + : *spec.second.begin(); + + auto i = drv.outputs.find(outputName); + if (i == drv.outputs.end()) + throw Error("derivation '%s' does not have output '%s'", drvPath, outputName); + + outPath = i->second.path; +} + + string DrvInfo::queryName() const { if (name == "" && attrs) { diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index 32294e458..4d9128e3f 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -37,6 +37,7 @@ public: DrvInfo(EvalState & state) : state(&state) { }; DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs); + DrvInfo(EvalState & state, ref store, const std::string & drvPathWithOutputs); string queryName() const; string querySystem() const; diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 21b0a18dd..58366daa6 100755 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -263,6 +263,8 @@ void mainWrapped(int argc, char * * argv) if (runEnv) setenv("IN_NIX_SHELL", pure ? "pure" : "impure", 1); + DrvInfos drvs; + /* Parse the expressions. */ std::vector exprs; @@ -272,6 +274,8 @@ void mainWrapped(int argc, char * * argv) for (auto i : left) { if (fromArgs) exprs.push_back(state.parseExprFromString(i, absPath("."))); + else if (store->isStorePath(i) && std::regex_match(i, std::regex(".*\\.drv(!.*)?"))) + drvs.push_back(DrvInfo(state, store, i)); else /* If we're in a #! script, interpret filenames relative to the script. */ @@ -280,8 +284,6 @@ void mainWrapped(int argc, char * * argv) } /* Evaluate them into derivations. */ - DrvInfos drvs; - if (attrPaths.empty()) attrPaths = {""}; for (auto e : exprs) { diff --git a/tests/multiple-outputs.sh b/tests/multiple-outputs.sh index ced6d758f..bedbc39a4 100644 --- a/tests/multiple-outputs.sh +++ b/tests/multiple-outputs.sh @@ -2,6 +2,8 @@ source common.sh clearStore +rm -f $TEST_ROOT/result* + # Test whether read-only evaluation works when referring to the # ‘drvPath’ attribute. echo "evaluating c..." @@ -28,7 +30,7 @@ echo "output path is $outPath" [ "$(cat "$outPath"/file)" = "success" ] # Test nix-build on a derivation with multiple outputs. -nix-build multiple-outputs.nix -A a -o $TEST_ROOT/result +outPath1=$(nix-build multiple-outputs.nix -A a -o $TEST_ROOT/result) [ -e $TEST_ROOT/result-first ] (! [ -e $TEST_ROOT/result-second ]) nix-build multiple-outputs.nix -A a.all -o $TEST_ROOT/result @@ -37,6 +39,17 @@ nix-build multiple-outputs.nix -A a.all -o $TEST_ROOT/result [ "$(cat $TEST_ROOT/result-second/link/file)" = "first" ] hash1=$(nix-store -q --hash $TEST_ROOT/result-second) +outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a) --no-out-link) +[[ $outPath1 = $outPath2 ]] + +outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a.first) --no-out-link) +[[ $outPath1 = $outPath2 ]] + +outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a.second) --no-out-link) +[[ $(cat $outPath2/file) = second ]] + +[[ $(nix-build $(nix-instantiate multiple-outputs.nix -A a.all) --no-out-link | wc -l) -eq 2 ]] + # Delete one of the outputs and rebuild it. This will cause a hash # rewrite. nix-store --delete $TEST_ROOT/result-second --ignore-liveness diff --git a/tests/nix-build.sh b/tests/nix-build.sh index dc0e99c73..395264863 100644 --- a/tests/nix-build.sh +++ b/tests/nix-build.sh @@ -2,7 +2,7 @@ source common.sh clearStore -nix-build dependencies.nix -o $TEST_ROOT/result +outPath=$(nix-build dependencies.nix -o $TEST_ROOT/result) test "$(cat $TEST_ROOT/result/foobar)" = FOOBAR # The result should be retained by a GC. @@ -17,3 +17,9 @@ test -e $target/foobar rm $TEST_ROOT/result nix-store --gc if test -e $target/foobar; then false; fi + +outPath2=$(nix-build $(nix-instantiate dependencies.nix) --no-out-link) +[[ $outPath = $outPath2 ]] + +outPath2=$(nix-build $(nix-instantiate dependencies.nix)!out --no-out-link) +[[ $outPath = $outPath2 ]] diff --git a/tests/nix-shell.sh b/tests/nix-shell.sh index f0f34a5f8..f7cac6ecf 100644 --- a/tests/nix-shell.sh +++ b/tests/nix-shell.sh @@ -10,6 +10,13 @@ output=$(nix-shell --pure shell.nix -A shellDrv --run \ [ "$output" = " - foo - bar" ] +# Test nix-shell on a .drv +[[ $(nix-shell --pure $(nix-instantiate shell.nix -A shellDrv) --run \ + 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]] + +[[ $(nix-shell --pure $(nix-instantiate shell.nix -A shellDrv) --run \ + 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]] + # Test nix-shell -p output=$(NIX_PATH=nixpkgs=shell.nix nix-shell --pure -p foo bar --run 'echo "$(foo) $(bar)"') [ "$output" = "foo bar" ]