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.
This commit is contained in:
Eelco Dolstra 2020-03-16 13:20:32 +01:00
parent 34c7645a58
commit fbcb897e21
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
3 changed files with 21 additions and 6 deletions

View file

@ -67,8 +67,9 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
auto rev2 = input2->getRev().value_or(Hash(htSHA1)); 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("rev")), rev2.gitRev());
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev2.gitShortRev()); mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev2.gitShortRev());
assert(tree.info.revCount); // Backward compatibility: set 'revCount' to 0 for a dirty tree.
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *tree.info.revCount); mkInt(*state.allocAttr(v, state.symbols.create("revCount")),
tree.info.revCount.value_or(0));
v.attrs->sort(); v.attrs->sort();
if (state.allowedPaths) if (state.allowedPaths)

View file

@ -34,6 +34,8 @@ static void cacheGitInfo(
const Tree & tree, const Tree & tree,
const Hash & rev) const Hash & rev)
{ {
if (!tree.info.revCount || !tree.info.lastModified) return;
nlohmann::json json; nlohmann::json json;
json["storePath"] = store.printStorePath(tree.storePath); json["storePath"] = store.printStorePath(tree.storePath);
json["name"] = name; json["name"] = name;
@ -169,6 +171,7 @@ struct GitInput : Input
return url.path; return url.path;
return {}; return {};
} }
void markChangedFile(std::string_view file, std::optional<std::string> commitMsg) const override void markChangedFile(std::string_view file, std::optional<std::string> commitMsg) const override
{ {
auto sourcePath = getSourcePath(); auto sourcePath = getSourcePath();
@ -271,7 +274,6 @@ struct GitInput : Input
.actualPath = store->printStorePath(storePath), .actualPath = store->printStorePath(storePath),
.storePath = std::move(storePath), .storePath = std::move(storePath),
.info = TreeInfo { .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 // FIXME: maybe we should use the timestamp of the last
// modified dirty file? // modified dirty file?
.lastModified = haveCommits ? std::stoull(runProgram("git", true, { "-C", actualUrl, "log", "-1", "--format=%ct", "HEAD" })) : 0, .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); 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)) { if (auto tree = lookupGitInfo(store, name, *input->rev)) {
assert(*input->rev == tree->first); assert(*input->rev == tree->first);
if (isShallow) tree->second.info.revCount.reset();
return {std::move(tree->second), input}; return {std::move(tree->second), input};
} }
@ -380,14 +385,17 @@ struct GitInput : Input
unpackTarfile(*source, tmpDir); unpackTarfile(*source, tmpDir);
auto storePath = store->addToStore(name, 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 lastModified = std::stoull(runProgram("git", true, { "-C", repoDir, "log", "-1", "--format=%ct", input->rev->gitRev() }));
auto tree = Tree { auto tree = Tree {
.actualPath = store->toRealPath(storePath), .actualPath = store->toRealPath(storePath),
.storePath = std::move(storePath), .storePath = std::move(storePath),
.info = TreeInfo { .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 .lastModified = lastModified
} }
}; };

View file

@ -11,7 +11,7 @@ repo=$TEST_ROOT/git
export _NIX_FORCE_HTTP=1 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 init $repo
git -C $repo config user.email "foobar@example.com" 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. # Try again, with 'git' available. This should work.
path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath") path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath")
[[ $path3 = $path5 ]] [[ $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 ]]