forked from lix-project/lix
Implement shallow fetching
This commit is contained in:
parent
5dd4ae8687
commit
7ab91e7238
|
@ -364,7 +364,8 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||||
|
|
||||||
void fetch(
|
void fetch(
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const std::string & refspec) override
|
const std::string & refspec,
|
||||||
|
bool shallow) override
|
||||||
{
|
{
|
||||||
Activity act(*logger, lvlTalkative, actFetchTree, fmt("fetching Git repository '%s'", url));
|
Activity act(*logger, lvlTalkative, actFetchTree, fmt("fetching Git repository '%s'", url));
|
||||||
|
|
||||||
|
@ -380,6 +381,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||||
};
|
};
|
||||||
|
|
||||||
git_fetch_options opts = GIT_FETCH_OPTIONS_INIT;
|
git_fetch_options opts = GIT_FETCH_OPTIONS_INIT;
|
||||||
|
opts.depth = shallow ? 1 : GIT_FETCH_DEPTH_FULL;
|
||||||
opts.callbacks.payload = &act;
|
opts.callbacks.payload = &act;
|
||||||
opts.callbacks.sideband_progress = sidebandProgressCallback;
|
opts.callbacks.sideband_progress = sidebandProgressCallback;
|
||||||
opts.callbacks.transfer_progress = transferProgressCallback;
|
opts.callbacks.transfer_progress = transferProgressCallback;
|
||||||
|
|
|
@ -75,7 +75,8 @@ struct GitRepo
|
||||||
|
|
||||||
virtual void fetch(
|
virtual void fetch(
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const std::string & refspec) = 0;
|
const std::string & refspec,
|
||||||
|
bool shallow) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that commit `rev` is signed by one of the keys in
|
* Verify that commit `rev` is signed by one of the keys in
|
||||||
|
|
|
@ -219,9 +219,6 @@ struct GitInputScheme : InputScheme
|
||||||
|| name == "publicKeys")
|
|| name == "publicKeys")
|
||||||
experimentalFeatureSettings.require(Xp::VerifiedFetches);
|
experimentalFeatureSettings.require(Xp::VerifiedFetches);
|
||||||
|
|
||||||
maybeGetBoolAttr(attrs, "shallow");
|
|
||||||
maybeGetBoolAttr(attrs, "submodules");
|
|
||||||
maybeGetBoolAttr(attrs, "allRefs");
|
|
||||||
maybeGetBoolAttr(attrs, "verifyCommit");
|
maybeGetBoolAttr(attrs, "verifyCommit");
|
||||||
|
|
||||||
if (auto ref = maybeGetStrAttr(attrs, "ref")) {
|
if (auto ref = maybeGetStrAttr(attrs, "ref")) {
|
||||||
|
@ -234,6 +231,9 @@ struct GitInputScheme : InputScheme
|
||||||
auto url = fixGitURL(getStrAttr(attrs, "url"));
|
auto url = fixGitURL(getStrAttr(attrs, "url"));
|
||||||
parseURL(url);
|
parseURL(url);
|
||||||
input.attrs["url"] = url;
|
input.attrs["url"] = url;
|
||||||
|
getShallowAttr(input);
|
||||||
|
getSubmodulesAttr(input);
|
||||||
|
getAllRefsAttr(input);
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,8 +243,10 @@ struct GitInputScheme : InputScheme
|
||||||
if (url.scheme != "git") url.scheme = "git+" + url.scheme;
|
if (url.scheme != "git") url.scheme = "git+" + url.scheme;
|
||||||
if (auto rev = input.getRev()) url.query.insert_or_assign("rev", rev->gitRev());
|
if (auto rev = input.getRev()) url.query.insert_or_assign("rev", rev->gitRev());
|
||||||
if (auto ref = input.getRef()) url.query.insert_or_assign("ref", *ref);
|
if (auto ref = input.getRef()) url.query.insert_or_assign("ref", *ref);
|
||||||
if (maybeGetBoolAttr(input.attrs, "shallow").value_or(false))
|
if (getShallowAttr(input))
|
||||||
url.query.insert_or_assign("shallow", "1");
|
url.query.insert_or_assign("shallow", "1");
|
||||||
|
if (getSubmodulesAttr(input))
|
||||||
|
url.query.insert_or_assign("submodules", "1");
|
||||||
if (maybeGetBoolAttr(input.attrs, "verifyCommit").value_or(false))
|
if (maybeGetBoolAttr(input.attrs, "verifyCommit").value_or(false))
|
||||||
url.query.insert_or_assign("verifyCommit", "1");
|
url.query.insert_or_assign("verifyCommit", "1");
|
||||||
auto publicKeys = getPublicKeys(input.attrs);
|
auto publicKeys = getPublicKeys(input.attrs);
|
||||||
|
@ -319,10 +321,6 @@ struct GitInputScheme : InputScheme
|
||||||
|
|
||||||
struct RepoInfo
|
struct RepoInfo
|
||||||
{
|
{
|
||||||
bool shallow = false;
|
|
||||||
bool submodules = false;
|
|
||||||
bool allRefs = false;
|
|
||||||
|
|
||||||
/* Whether this is a local, non-bare repository. */
|
/* Whether this is a local, non-bare repository. */
|
||||||
bool isLocal = false;
|
bool isLocal = false;
|
||||||
|
|
||||||
|
@ -347,11 +345,21 @@ struct GitInputScheme : InputScheme
|
||||||
std::string gitDir = ".git";
|
std::string gitDir = ".git";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool getShallowAttr(const Input & input) const
|
||||||
|
{
|
||||||
|
return maybeGetBoolAttr(input.attrs, "shallow").value_or(false);
|
||||||
|
}
|
||||||
|
|
||||||
bool getSubmodulesAttr(const Input & input) const
|
bool getSubmodulesAttr(const Input & input) const
|
||||||
{
|
{
|
||||||
return maybeGetBoolAttr(input.attrs, "submodules").value_or(false);
|
return maybeGetBoolAttr(input.attrs, "submodules").value_or(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getAllRefsAttr(const Input & input) const
|
||||||
|
{
|
||||||
|
return maybeGetBoolAttr(input.attrs, "allRefs").value_or(false);
|
||||||
|
}
|
||||||
|
|
||||||
RepoInfo getRepoInfo(const Input & input) const
|
RepoInfo getRepoInfo(const Input & input) const
|
||||||
{
|
{
|
||||||
auto checkHashType = [&](const std::optional<Hash> & hash)
|
auto checkHashType = [&](const std::optional<Hash> & hash)
|
||||||
|
@ -363,11 +371,7 @@ struct GitInputScheme : InputScheme
|
||||||
if (auto rev = input.getRev())
|
if (auto rev = input.getRev())
|
||||||
checkHashType(rev);
|
checkHashType(rev);
|
||||||
|
|
||||||
RepoInfo repoInfo {
|
RepoInfo repoInfo;
|
||||||
.shallow = maybeGetBoolAttr(input.attrs, "shallow").value_or(false),
|
|
||||||
.submodules = getSubmodulesAttr(input),
|
|
||||||
.allRefs = maybeGetBoolAttr(input.attrs, "allRefs").value_or(false)
|
|
||||||
};
|
|
||||||
|
|
||||||
// file:// URIs are normally not cloned (but otherwise treated the
|
// file:// URIs are normally not cloned (but otherwise treated the
|
||||||
// same as remote URIs, i.e. we don't use the working tree or
|
// same as remote URIs, i.e. we don't use the working tree or
|
||||||
|
@ -501,7 +505,7 @@ struct GitInputScheme : InputScheme
|
||||||
if (auto rev = input.getRev()) {
|
if (auto rev = input.getRev()) {
|
||||||
doFetch = !repo->hasObject(*rev);
|
doFetch = !repo->hasObject(*rev);
|
||||||
} else {
|
} else {
|
||||||
if (repoInfo.allRefs) {
|
if (getAllRefsAttr(input)) {
|
||||||
doFetch = true;
|
doFetch = true;
|
||||||
} else {
|
} else {
|
||||||
/* If the local ref is older than ‘tarball-ttl’ seconds, do a
|
/* If the local ref is older than ‘tarball-ttl’ seconds, do a
|
||||||
|
@ -514,7 +518,7 @@ struct GitInputScheme : InputScheme
|
||||||
|
|
||||||
if (doFetch) {
|
if (doFetch) {
|
||||||
try {
|
try {
|
||||||
auto fetchRef = repoInfo.allRefs
|
auto fetchRef = getAllRefsAttr(input)
|
||||||
? "refs/*"
|
? "refs/*"
|
||||||
: ref.compare(0, 5, "refs/") == 0
|
: ref.compare(0, 5, "refs/") == 0
|
||||||
? ref
|
? ref
|
||||||
|
@ -522,7 +526,7 @@ struct GitInputScheme : InputScheme
|
||||||
? ref
|
? ref
|
||||||
: "refs/heads/" + ref;
|
: "refs/heads/" + ref;
|
||||||
|
|
||||||
repo->fetch(repoInfo.url, fmt("%s:%s", fetchRef, fetchRef));
|
repo->fetch(repoInfo.url, fmt("%s:%s", fetchRef, fetchRef), getShallowAttr(input));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
if (!pathExists(localRefFile)) throw;
|
if (!pathExists(localRefFile)) throw;
|
||||||
logError(e.info());
|
logError(e.info());
|
||||||
|
@ -556,7 +560,7 @@ struct GitInputScheme : InputScheme
|
||||||
|
|
||||||
auto isShallow = repo->isShallow();
|
auto isShallow = repo->isShallow();
|
||||||
|
|
||||||
if (isShallow && !repoInfo.shallow)
|
if (isShallow && !getShallowAttr(input))
|
||||||
throw Error("'%s' is a shallow Git repository, but shallow repositories are only allowed when `shallow = true;` is specified", repoInfo.url);
|
throw Error("'%s' is a shallow Git repository, but shallow repositories are only allowed when `shallow = true;` is specified", repoInfo.url);
|
||||||
|
|
||||||
// FIXME: check whether rev is an ancestor of ref?
|
// FIXME: check whether rev is an ancestor of ref?
|
||||||
|
@ -568,7 +572,7 @@ struct GitInputScheme : InputScheme
|
||||||
{"lastModified", getLastModified(repoInfo, repoDir, rev)},
|
{"lastModified", getLastModified(repoInfo, repoDir, rev)},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!repoInfo.shallow)
|
if (!getShallowAttr(input))
|
||||||
infoAttrs.insert_or_assign("revCount",
|
infoAttrs.insert_or_assign("revCount",
|
||||||
getRevCount(repoInfo, repoDir, rev));
|
getRevCount(repoInfo, repoDir, rev));
|
||||||
|
|
||||||
|
@ -581,7 +585,7 @@ struct GitInputScheme : InputScheme
|
||||||
/* If the repo has submodules, fetch them and return a mounted
|
/* If the repo has submodules, fetch them and return a mounted
|
||||||
input accessor consisting of the accessor for the top-level
|
input accessor consisting of the accessor for the top-level
|
||||||
repo and the accessors for the submodules. */
|
repo and the accessors for the submodules. */
|
||||||
if (repoInfo.submodules) {
|
if (getSubmodulesAttr(input)) {
|
||||||
std::map<CanonPath, nix::ref<InputAccessor>> mounts;
|
std::map<CanonPath, nix::ref<InputAccessor>> mounts;
|
||||||
|
|
||||||
for (auto & [submodule, submoduleRev] : repo->getSubmodules(rev)) {
|
for (auto & [submodule, submoduleRev] : repo->getSubmodules(rev)) {
|
||||||
|
@ -607,7 +611,7 @@ struct GitInputScheme : InputScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!origRev || origRev == rev);
|
assert(!origRev || origRev == rev);
|
||||||
if (!repoInfo.shallow)
|
if (!getShallowAttr(input))
|
||||||
input.attrs.insert_or_assign("revCount", getIntAttr(infoAttrs, "revCount"));
|
input.attrs.insert_or_assign("revCount", getIntAttr(infoAttrs, "revCount"));
|
||||||
input.attrs.insert_or_assign("lastModified", getIntAttr(infoAttrs, "lastModified"));
|
input.attrs.insert_or_assign("lastModified", getIntAttr(infoAttrs, "lastModified"));
|
||||||
|
|
||||||
|
@ -619,7 +623,7 @@ struct GitInputScheme : InputScheme
|
||||||
RepoInfo & repoInfo,
|
RepoInfo & repoInfo,
|
||||||
Input && input) const
|
Input && input) const
|
||||||
{
|
{
|
||||||
if (repoInfo.submodules)
|
if (getSubmodulesAttr(input))
|
||||||
/* Create mountpoints for the submodules. */
|
/* Create mountpoints for the submodules. */
|
||||||
for (auto & submodule : repoInfo.workdirInfo.submodules)
|
for (auto & submodule : repoInfo.workdirInfo.submodules)
|
||||||
repoInfo.workdirInfo.files.insert(submodule.path);
|
repoInfo.workdirInfo.files.insert(submodule.path);
|
||||||
|
@ -630,7 +634,7 @@ struct GitInputScheme : InputScheme
|
||||||
/* If the repo has submodules, return a mounted input accessor
|
/* If the repo has submodules, return a mounted input accessor
|
||||||
consisting of the accessor for the top-level repo and the
|
consisting of the accessor for the top-level repo and the
|
||||||
accessors for the submodule workdirs. */
|
accessors for the submodule workdirs. */
|
||||||
if (repoInfo.submodules && !repoInfo.workdirInfo.submodules.empty()) {
|
if (getSubmodulesAttr(input) && !repoInfo.workdirInfo.submodules.empty()) {
|
||||||
std::map<CanonPath, nix::ref<InputAccessor>> mounts;
|
std::map<CanonPath, nix::ref<InputAccessor>> mounts;
|
||||||
|
|
||||||
for (auto & submodule : repoInfo.workdirInfo.submodules) {
|
for (auto & submodule : repoInfo.workdirInfo.submodules) {
|
||||||
|
|
Loading…
Reference in a new issue