diff --git a/src/libexpr/primops/fetchGit.cc b/src/libexpr/primops/fetchGit.cc index 1a8798fccb0e..ff1e24ae48dc 100644 --- a/src/libexpr/primops/fetchGit.cc +++ b/src/libexpr/primops/fetchGit.cc @@ -12,6 +12,8 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va std::string url; std::optional ref; std::optional rev; + std::optional narHash; + std::string name = "source"; bool fetchSubmodules = false; PathSet context; @@ -34,12 +36,18 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va name = state.forceStringNoCtx(*attr.value, *attr.pos); else if (n == "submodules") fetchSubmodules = state.forceBool(*attr.value, *attr.pos); + else if (n == "narHash") + narHash = state.forceStringNoCtx(*attr.value, *attr.pos); else throw EvalError("unsupported argument '%s' to 'fetchGit', at %s", attr.name, *attr.pos); } if (url.empty()) throw EvalError(format("'url' argument required, at %1%") % pos); + if (narHash && !rev) + throw EvalError( + format("'narHash' can only be used for 'fetchGit' if 'rev' is set, at %1%") % pos + ); } else url = state.coerceToString(pos, *args[0], context, false, false); @@ -57,6 +65,7 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va if (ref) attrs.insert_or_assign("ref", *ref); if (rev) attrs.insert_or_assign("rev", rev->gitRev()); if (fetchSubmodules) attrs.insert_or_assign("submodules", true); + if (narHash) attrs.emplace("narHash", *narHash); auto input = fetchers::inputFromAttrs(attrs); // FIXME: use name? diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 94ac30e38004..e6ce036020e4 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -66,7 +66,7 @@ std::pair> Input::fetchTree(ref store) assert(input->narHash == tree.info.narHash); if (narHash && narHash != input->narHash) - throw Error("NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'", + throw Error((unsigned int) 102, "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'", to_string(), tree.actualPath, narHash->to_string(SRI), input->narHash->to_string(SRI)); return {std::move(tree), input}; diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 7c18cf67fd09..6cdc01adb9da 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -115,6 +115,7 @@ struct GitInput : Input { assert(input->rev); assert(!rev || rev == input->rev); + input->narHash = store->queryPathInfo(storePath)->narHash; return { Tree { .actualPath = store->toRealPath(storePath), diff --git a/tests/fetchGit.sh b/tests/fetchGit.sh index d9c9874f568a..6fdf0a18fdf8 100644 --- a/tests/fetchGit.sh +++ b/tests/fetchGit.sh @@ -102,6 +102,14 @@ git -C $repo commit -m 'Bla3' -a path4=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchGit file://$repo).outPath") [[ $path2 = $path4 ]] +nix eval --raw "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$? +[[ "$status" = "102" ]] + +nix eval --raw "(builtins.fetchGit { url = $repo; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" 2>&1 | grep "'narHash' can only be used for 'fetchGit' if 'rev' is set" + +path5=$(nix eval --raw "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath") +[[ $path = $path5 ]] + # tarball-ttl should be ignored if we specify a rev echo delft > $repo/hello git -C $repo add hello