From fbcb897e21e6c7b866a7aed97129141c0e7caa22 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 16 Mar 2020 13:20:32 +0100 Subject: [PATCH] Add a test for shallow Git clones Also, don't return a revCount anymore for shallow or dirty Git trees, since it's incorrect. Closes #2988. --- src/libexpr/primops/fetchGit.cc | 5 +++-- src/libstore/fetchers/git.cc | 14 +++++++++++--- tests/fetchGit.sh | 8 +++++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/libexpr/primops/fetchGit.cc b/src/libexpr/primops/fetchGit.cc index 18774371b..638c14970 100644 --- a/src/libexpr/primops/fetchGit.cc +++ b/src/libexpr/primops/fetchGit.cc @@ -67,8 +67,9 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va auto rev2 = input2->getRev().value_or(Hash(htSHA1)); mkString(*state.allocAttr(v, state.symbols.create("rev")), rev2.gitRev()); mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev2.gitShortRev()); - assert(tree.info.revCount); - mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *tree.info.revCount); + // Backward compatibility: set 'revCount' to 0 for a dirty tree. + mkInt(*state.allocAttr(v, state.symbols.create("revCount")), + tree.info.revCount.value_or(0)); v.attrs->sort(); if (state.allowedPaths) diff --git a/src/libstore/fetchers/git.cc b/src/libstore/fetchers/git.cc index 9276b0993..46ca187fe 100644 --- a/src/libstore/fetchers/git.cc +++ b/src/libstore/fetchers/git.cc @@ -34,6 +34,8 @@ static void cacheGitInfo( const Tree & tree, const Hash & rev) { + if (!tree.info.revCount || !tree.info.lastModified) return; + nlohmann::json json; json["storePath"] = store.printStorePath(tree.storePath); json["name"] = name; @@ -169,6 +171,7 @@ struct GitInput : Input return url.path; return {}; } + void markChangedFile(std::string_view file, std::optional commitMsg) const override { auto sourcePath = getSourcePath(); @@ -271,7 +274,6 @@ struct GitInput : Input .actualPath = store->printStorePath(storePath), .storePath = std::move(storePath), .info = TreeInfo { - .revCount = haveCommits ? std::stoull(runProgram("git", true, { "-C", actualUrl, "rev-list", "--count", "HEAD" })) : 0, // FIXME: maybe we should use the timestamp of the last // modified dirty file? .lastModified = haveCommits ? std::stoull(runProgram("git", true, { "-C", actualUrl, "log", "-1", "--format=%ct", "HEAD" })) : 0, @@ -357,8 +359,11 @@ struct GitInput : Input input->rev = Hash(chomp(readFile(localRefFile)), htSHA1); } + bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "rev-parse", "--is-shallow-repository" })) == "true"; + if (auto tree = lookupGitInfo(store, name, *input->rev)) { assert(*input->rev == tree->first); + if (isShallow) tree->second.info.revCount.reset(); return {std::move(tree->second), input}; } @@ -380,14 +385,17 @@ struct GitInput : Input unpackTarfile(*source, tmpDir); auto storePath = store->addToStore(name, tmpDir); - auto revCount = std::stoull(runProgram("git", true, { "-C", repoDir, "rev-list", "--count", input->rev->gitRev() })); + auto lastModified = std::stoull(runProgram("git", true, { "-C", repoDir, "log", "-1", "--format=%ct", input->rev->gitRev() })); auto tree = Tree { .actualPath = store->toRealPath(storePath), .storePath = std::move(storePath), .info = TreeInfo { - .revCount = revCount, + .revCount = + !isShallow + ? std::optional(std::stoull(runProgram("git", true, { "-C", repoDir, "rev-list", "--count", input->rev->gitRev() }))) + : std::nullopt, .lastModified = lastModified } }; diff --git a/tests/fetchGit.sh b/tests/fetchGit.sh index b64f444a5..6e5a4750e 100644 --- a/tests/fetchGit.sh +++ b/tests/fetchGit.sh @@ -11,7 +11,7 @@ repo=$TEST_ROOT/git export _NIX_FORCE_HTTP=1 -rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix/gitv* $TEST_ROOT/worktree +rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix/git* $TEST_ROOT/worktree $TEST_ROOT/shallow git init $repo git -C $repo config user.email "foobar@example.com" @@ -147,3 +147,9 @@ NIX=$(command -v nix) # Try again, with 'git' available. This should work. path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath") [[ $path3 = $path5 ]] + +# Check that shallow clones work and don't return a revcount. +git clone --depth 1 file://$repo $TEST_ROOT/shallow +path6=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $TEST_ROOT/shallow; ref = \"dev\"; }).outPath") +[[ $path3 = $path6 ]] +[[ $(nix eval --impure --expr "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow\"; ref = \"dev\"; }).revCount or 123") == 123 ]]