aboutsummaryrefslogtreecommitdiff
path: root/src/libfetchers/git.cc
diff options
context:
space:
mode:
authorGuillaume Maudoux <guillaume.maudoux@tweag.io>2022-04-29 00:12:25 +0200
committerGuillaume Maudoux <guillaume.maudoux@tweag.io>2022-04-29 00:12:25 +0200
commite93b59fbc5ada40e77d6f2b2a8bbd8e482418d6a (patch)
treef9436753bba299d648a6721845a9465b34a50062 /src/libfetchers/git.cc
parentf6baa4d18845297f3f7fc2434b7ade93a45718e7 (diff)
parent35393dc2c65765acb6cc99d6a976eab62c28a51d (diff)
Merge remote-tracking branch 'origin/master' into coerce-string
Diffstat (limited to 'src/libfetchers/git.cc')
-rw-r--r--src/libfetchers/git.cc50
1 files changed, 35 insertions, 15 deletions
diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc
index d75c5d3ae..af40990e5 100644
--- a/src/libfetchers/git.cc
+++ b/src/libfetchers/git.cc
@@ -21,16 +21,23 @@ namespace nix::fetchers {
// old version of git, which will ignore unrecognized `-c` options.
const std::string gitInitialBranch = "__nix_dummy_branch";
+static std::string getGitDir()
+{
+ auto gitDir = getEnv("GIT_DIR");
+ if (!gitDir) {
+ return ".git";
+ }
+ return *gitDir;
+}
+
static std::string readHead(const Path & path)
{
- return chomp(runProgram("git", true, { "-C", path, "rev-parse", "--abbrev-ref", "HEAD" }));
+ return chomp(runProgram("git", true, { "-C", path, "--git-dir", ".git", "rev-parse", "--abbrev-ref", "HEAD" }));
}
static bool isNotDotGitDirectory(const Path & path)
{
- static const std::regex gitDirRegex("^(?:.*/)?\\.git$");
-
- return not std::regex_match(path, gitDirRegex);
+ return baseNameOf(path) != ".git";
}
struct GitInputScheme : InputScheme
@@ -152,13 +159,14 @@ struct GitInputScheme : InputScheme
{
auto sourcePath = getSourcePath(input);
assert(sourcePath);
+ auto gitDir = getGitDir();
runProgram("git", true,
- { "-C", *sourcePath, "add", "--force", "--intent-to-add", "--", std::string(file) });
+ { "-C", *sourcePath, "--git-dir", gitDir, "add", "--force", "--intent-to-add", "--", std::string(file) });
if (commitMsg)
runProgram("git", true,
- { "-C", *sourcePath, "commit", std::string(file), "-m", *commitMsg });
+ { "-C", *sourcePath, "--git-dir", gitDir, "commit", std::string(file), "-m", *commitMsg });
}
std::pair<bool, std::string> getActualUrl(const Input & input) const
@@ -177,6 +185,7 @@ struct GitInputScheme : InputScheme
std::pair<StorePath, Input> fetch(ref<Store> store, const Input & _input) override
{
Input input(_input);
+ auto gitDir = getGitDir();
std::string name = input.getName();
@@ -189,8 +198,16 @@ struct GitInputScheme : InputScheme
if (submodules) cacheType += "-submodules";
if (allRefs) cacheType += "-all-refs";
+ auto checkHashType = [&](const std::optional<Hash> & hash)
+ {
+ if (hash.has_value() && !(hash->type == htSHA1 || hash->type == htSHA256))
+ throw Error("Hash '%s' is not supported by Git. Supported types are sha1 and sha256.", hash->to_string(Base16, true));
+ };
+
auto getLockedAttrs = [&]()
{
+ checkHashType(input.getRev());
+
return Attrs({
{"type", cacheType},
{"name", name},
@@ -231,7 +248,7 @@ struct GitInputScheme : InputScheme
since that is the refrence we want to use later on. */
auto result = runProgram(RunOptions {
.program = "git",
- .args = { "-C", actualUrl, "--git-dir=.git", "rev-parse", "--verify", "--no-revs", "HEAD^{commit}" },
+ .args = { "-C", actualUrl, "--git-dir", gitDir, "rev-parse", "--verify", "--no-revs", "HEAD^{commit}" },
.environment = env,
.mergeStderrToStdout = true
});
@@ -253,7 +270,7 @@ struct GitInputScheme : InputScheme
if (hasHead) {
// Using git diff is preferrable over lower-level operations here,
// because its conceptually simpler and we only need the exit code anyways.
- auto gitDiffOpts = Strings({ "-C", actualUrl, "diff", "HEAD", "--quiet"});
+ auto gitDiffOpts = Strings({ "-C", actualUrl, "--git-dir", gitDir, "diff", "HEAD", "--quiet"});
if (!submodules) {
// Changes in submodules should only make the tree dirty
// when those submodules will be copied as well.
@@ -278,16 +295,18 @@ struct GitInputScheme : InputScheme
if (fetchSettings.warnDirty)
warn("Git tree '%s' is dirty", actualUrl);
- auto gitOpts = Strings({ "-C", actualUrl, "ls-files", "-z" });
+ auto gitOpts = Strings({ "-C", actualUrl, "--git-dir", gitDir, "ls-files", "-z" });
if (submodules)
gitOpts.emplace_back("--recurse-submodules");
auto files = tokenizeString<std::set<std::string>>(
runProgram("git", true, gitOpts), "\0"s);
+ Path actualPath(absPath(actualUrl));
+
PathFilter filter = [&](const Path & p) -> bool {
- assert(hasPrefix(p, actualUrl));
- std::string file(p, actualUrl.size() + 1);
+ assert(hasPrefix(p, actualPath));
+ std::string file(p, actualPath.size() + 1);
auto st = lstat(p);
@@ -300,13 +319,13 @@ struct GitInputScheme : InputScheme
return files.count(file);
};
- auto storePath = store->addToStore(input.getName(), actualUrl, FileIngestionMethod::Recursive, htSHA256, filter);
+ auto storePath = store->addToStore(input.getName(), actualPath, FileIngestionMethod::Recursive, htSHA256, filter);
// FIXME: maybe we should use the timestamp of the last
// modified dirty file?
input.attrs.insert_or_assign(
"lastModified",
- hasHead ? std::stoull(runProgram("git", true, { "-C", actualUrl, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD" })) : 0);
+ hasHead ? std::stoull(runProgram("git", true, { "-C", actualPath, "--git-dir", gitDir, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD" })) : 0);
return {std::move(storePath), input};
}
@@ -327,7 +346,7 @@ struct GitInputScheme : InputScheme
if (!input.getRev())
input.attrs.insert_or_assign("rev",
- Hash::parseAny(chomp(runProgram("git", true, { "-C", actualUrl, "rev-parse", *input.getRef() })), htSHA1).gitRev());
+ Hash::parseAny(chomp(runProgram("git", true, { "-C", actualUrl, "--git-dir", gitDir, "rev-parse", *input.getRef() })), htSHA1).gitRev());
repoDir = actualUrl;
@@ -343,6 +362,7 @@ struct GitInputScheme : InputScheme
Path cacheDir = getCacheDir() + "/nix/gitv3/" + hashString(htSHA256, actualUrl).to_string(Base32, false);
repoDir = cacheDir;
+ gitDir = ".";
createDirs(dirOf(cacheDir));
PathLocks cacheDirLock({cacheDir + ".lock"});
@@ -419,7 +439,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
}
- bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "rev-parse", "--is-shallow-repository" })) == "true";
+ bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "rev-parse", "--is-shallow-repository" })) == "true";
if (isShallow && !shallow)
throw Error("'%s' is a shallow Git repository, but a non-shallow repository is needed", actualUrl);