GitInputScheme::lazyFetch(): Return rev/revCount/ref/lastModified

This commit is contained in:
Eelco Dolstra 2022-05-20 15:47:33 +02:00
parent ad4b7669db
commit e6cf987201
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
3 changed files with 62 additions and 31 deletions

View file

@ -303,6 +303,8 @@ struct GitInputScheme : InputScheme
warn("Git tree '%s' is dirty", url); warn("Git tree '%s' is dirty", url);
} }
} }
std::string gitDir = getGitDir();
}; };
RepoInfo getRepoInfo(const Input & input) RepoInfo getRepoInfo(const Input & input)
@ -411,6 +413,34 @@ struct GitInputScheme : InputScheme
return res; return res;
} }
void updateRev(Input & input, const RepoInfo & repoInfo, const std::string & ref)
{
if (!input.getRev())
input.attrs.insert_or_assign("rev",
Hash::parseAny(chomp(runProgram("git", true, { "-C", repoInfo.url, "--git-dir", repoInfo.gitDir, "rev-parse", ref })), htSHA1).gitRev());
}
uint64_t getLastModified(const RepoInfo & repoInfo, const std::string & repoDir, const std::string & ref)
{
return
repoInfo.hasHead
? std::stoull(
runProgram("git", true,
{ "-C", repoDir, "--git-dir", repoInfo.gitDir, "log", "-1", "--format=%ct", "--no-show-signature", ref }))
: 0;
}
uint64_t getRevCount(const RepoInfo & repoInfo, const std::string & repoDir, const Hash & rev)
{
// FIXME: cache this.
return
repoInfo.hasHead
? std::stoull(
runProgram("git", true,
{ "-C", repoDir, "--git-dir", repoInfo.gitDir, "rev-list", "--count", rev.gitRev() }))
: 0;
}
std::string getDefaultRef(const RepoInfo & repoInfo) std::string getDefaultRef(const RepoInfo & repoInfo)
{ {
auto head = repoInfo.isLocal auto head = repoInfo.isLocal
@ -426,7 +456,6 @@ struct GitInputScheme : InputScheme
std::pair<StorePath, Input> fetch(ref<Store> store, const Input & _input) override std::pair<StorePath, Input> fetch(ref<Store> store, const Input & _input) override
{ {
Input input(_input); Input input(_input);
auto gitDir = getGitDir(); // FIXME: move into RepoInfo
auto repoInfo = getRepoInfo(input); auto repoInfo = getRepoInfo(input);
@ -474,13 +503,8 @@ struct GitInputScheme : InputScheme
Path repoDir; Path repoDir;
if (repoInfo.isLocal) { if (repoInfo.isLocal) {
updateRev(input, repoInfo, ref);
if (!input.getRev())
input.attrs.insert_or_assign("rev",
Hash::parseAny(chomp(runProgram("git", true, { "-C", repoInfo.url, "--git-dir", getGitDir(), "rev-parse", ref })), htSHA1).gitRev());
repoDir = repoInfo.url; repoDir = repoInfo.url;
} else { } else {
if (auto res = getCache()->lookup(store, unlockedAttrs)) { if (auto res = getCache()->lookup(store, unlockedAttrs)) {
auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1); auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1);
@ -492,7 +516,7 @@ struct GitInputScheme : InputScheme
Path cacheDir = getCachePath(repoInfo.url); Path cacheDir = getCachePath(repoInfo.url);
repoDir = cacheDir; repoDir = cacheDir;
gitDir = "."; repoInfo.gitDir = ".";
createDirs(dirOf(cacheDir)); createDirs(dirOf(cacheDir));
PathLocks cacheDirLock({cacheDir + ".lock"}); PathLocks cacheDirLock({cacheDir + ".lock"});
@ -513,7 +537,7 @@ struct GitInputScheme : InputScheme
repo. */ repo. */
if (input.getRev()) { if (input.getRev()) {
try { try {
runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "cat-file", "-e", input.getRev()->gitRev() }); runProgram("git", true, { "-C", repoDir, "--git-dir", repoInfo.gitDir, "cat-file", "-e", input.getRev()->gitRev() });
doFetch = false; doFetch = false;
} catch (ExecError & e) { } catch (ExecError & e) {
if (WIFEXITED(e.status)) { if (WIFEXITED(e.status)) {
@ -549,7 +573,7 @@ struct GitInputScheme : InputScheme
: "refs/heads/" + ref; : "refs/heads/" + ref;
runProgram("git", true, runProgram("git", true,
{ "-C", repoDir, { "-C", repoDir,
"--git-dir", gitDir, "--git-dir", repoInfo.gitDir,
"fetch", "fetch",
"--quiet", "--quiet",
"--force", "--force",
@ -574,7 +598,7 @@ struct GitInputScheme : InputScheme
// cache dir lock is removed at scope end; we will only use read-only operations on specific revisions in the remainder // cache dir lock is removed at scope end; we will only use read-only operations on specific revisions in the remainder
} }
bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "rev-parse", "--is-shallow-repository" })) == "true"; bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "--git-dir", repoInfo.gitDir, "rev-parse", "--is-shallow-repository" })) == "true";
if (isShallow && !repoInfo.shallow) if (isShallow && !repoInfo.shallow)
throw Error("'%s' is a shallow Git repository, but a non-shallow repository is needed", repoInfo.url); throw Error("'%s' is a shallow Git repository, but a non-shallow repository is needed", repoInfo.url);
@ -594,7 +618,7 @@ struct GitInputScheme : InputScheme
auto result = runProgram(RunOptions { auto result = runProgram(RunOptions {
.program = "git", .program = "git",
.args = { "-C", repoDir, "--git-dir", gitDir, "cat-file", "commit", input.getRev()->gitRev() }, .args = { "-C", repoDir, "--git-dir", repoInfo.gitDir, "cat-file", "commit", input.getRev()->gitRev() },
.mergeStderrToStdout = true .mergeStderrToStdout = true
}); });
if (WEXITSTATUS(result.first) == 128 if (WEXITSTATUS(result.first) == 128
@ -633,7 +657,7 @@ struct GitInputScheme : InputScheme
auto source = sinkToSource([&](Sink & sink) { auto source = sinkToSource([&](Sink & sink) {
runProgram2({ runProgram2({
.program = "git", .program = "git",
.args = { "-C", repoDir, "--git-dir", gitDir, "archive", input.getRev()->gitRev() }, .args = { "-C", repoDir, "--git-dir", repoInfo.gitDir, "archive", input.getRev()->gitRev() },
.standardOut = &sink .standardOut = &sink
}); });
}); });
@ -643,16 +667,16 @@ struct GitInputScheme : InputScheme
auto storePath = store->addToStore(name, tmpDir, FileIngestionMethod::Recursive, htSHA256, filter); auto storePath = store->addToStore(name, tmpDir, FileIngestionMethod::Recursive, htSHA256, filter);
auto lastModified = std::stoull(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "log", "-1", "--format=%ct", "--no-show-signature", input.getRev()->gitRev() })); auto rev = *input.getRev();
Attrs infoAttrs({ Attrs infoAttrs({
{"rev", input.getRev()->gitRev()}, {"rev", rev.gitRev()},
{"lastModified", lastModified}, {"lastModified", getLastModified(repoInfo, repoDir, rev.gitRev())},
}); });
if (!repoInfo.shallow) if (!repoInfo.shallow)
infoAttrs.insert_or_assign("revCount", infoAttrs.insert_or_assign("revCount",
std::stoull(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "rev-list", "--count", input.getRev()->gitRev() }))); getRevCount(repoInfo, repoDir, rev));
if (!_input.getRev()) if (!_input.getRev())
getCache()->add( getCache()->add(
@ -695,15 +719,15 @@ struct GitInputScheme : InputScheme
// modified dirty file? // modified dirty file?
input.attrs.insert_or_assign( input.attrs.insert_or_assign(
"lastModified", "lastModified",
repoInfo.hasHead getLastModified(repoInfo, repoInfo.url, "HEAD"));
? std::stoull(runProgram("git", true, { "-C", repoInfo.url, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD" }))
: 0);
return {std::move(storePath), input}; return {std::move(storePath), input};
} }
std::pair<ref<InputAccessor>, Input> lazyFetch(ref<Store> store, const Input & input) override std::pair<ref<InputAccessor>, Input> lazyFetch(ref<Store> store, const Input & _input) override
{ {
Input input(_input);
auto repoInfo = getRepoInfo(input); auto repoInfo = getRepoInfo(input);
/* Unless we're using the working tree, copy the tree into the /* Unless we're using the working tree, copy the tree into the
@ -714,7 +738,22 @@ struct GitInputScheme : InputScheme
repoInfo.checkDirty(); repoInfo.checkDirty();
// FIXME: return updated input. auto ref = getDefaultRef(repoInfo);
input.attrs.insert_or_assign("ref", ref);
if (!repoInfo.isDirty) {
updateRev(input, repoInfo, ref);
input.attrs.insert_or_assign(
"revCount",
getRevCount(repoInfo, repoInfo.url, *input.getRev()));
}
// FIXME: maybe we should use the timestamp of the last
// modified dirty file?
input.attrs.insert_or_assign(
"lastModified",
getLastModified(repoInfo, repoInfo.url, ref));
auto makeNotAllowedError = [url{repoInfo.url}](const CanonPath & path) -> RestrictedPathError auto makeNotAllowedError = [url{repoInfo.url}](const CanonPath & path) -> RestrictedPathError
{ {

View file

@ -182,9 +182,6 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
j["revCount"] = *revCount; j["revCount"] = *revCount;
if (auto lastModified = flake.lockedRef.input.getLastModified()) if (auto lastModified = flake.lockedRef.input.getLastModified())
j["lastModified"] = *lastModified; j["lastModified"] = *lastModified;
#if 0
j["path"] = store->printStorePath(flake.sourceInfo->storePath);
#endif
j["locks"] = lockedFlake.lockFile.toJSON(); j["locks"] = lockedFlake.lockFile.toJSON();
logger->cout("%s", j.dump()); logger->cout("%s", j.dump());
} else { } else {
@ -198,11 +195,6 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
logger->cout( logger->cout(
ANSI_BOLD "Description:" ANSI_NORMAL " %s", ANSI_BOLD "Description:" ANSI_NORMAL " %s",
*flake.description); *flake.description);
#if 0
logger->cout(
ANSI_BOLD "Path:" ANSI_NORMAL " %s",
store->printStorePath(flake.sourceInfo->storePath));
#endif
if (auto rev = flake.lockedRef.input.getRev()) if (auto rev = flake.lockedRef.input.getRev())
logger->cout( logger->cout(
ANSI_BOLD "Revision:" ANSI_NORMAL " %s", ANSI_BOLD "Revision:" ANSI_NORMAL " %s",

View file

@ -124,7 +124,7 @@ nix flake metadata $flake1Dir | grep -q 'URL:.*flake1.*'
# Test 'nix flake metadata --json'. # Test 'nix flake metadata --json'.
json=$(nix flake metadata flake1 --json | jq .) json=$(nix flake metadata flake1 --json | jq .)
[[ $(echo "$json" | jq -r .description) = 'Bla bla' ]] [[ $(echo "$json" | jq -r .description) = 'Bla bla' ]]
[[ -d $(echo "$json" | jq -r .path) ]] #[[ -d $(echo "$json" | jq -r .path) ]]
[[ $(echo "$json" | jq -r .lastModified) = $(git -C $flake1Dir log -n1 --format=%ct) ]] [[ $(echo "$json" | jq -r .lastModified) = $(git -C $flake1Dir log -n1 --format=%ct) ]]
hash1=$(echo "$json" | jq -r .revision) hash1=$(echo "$json" | jq -r .revision)