diff --git a/src/libfetchers/git-accessor.cc b/src/libfetchers/git-accessor.cc index 9e6fcc021..45d387fa9 100644 --- a/src/libfetchers/git-accessor.cc +++ b/src/libfetchers/git-accessor.cc @@ -1,3 +1,4 @@ +#include "git-utils.hh" #include "input-accessor.hh" #include @@ -43,6 +44,14 @@ static Repository openRepo(const CanonPath & path) return Repository(_repo); } +git_oid hashToOID(const Hash & hash) +{ + git_oid oid; + if (git_oid_fromstr(&oid, hash.gitRev().c_str())) + throw Error("cannot convert '%s' to a Git OID", hash.gitRev()); + return oid; +} + struct GitInputAccessor : InputAccessor { Repository repo; @@ -51,9 +60,7 @@ struct GitInputAccessor : InputAccessor GitInputAccessor(Repository && repo_, const Hash & rev) : repo(std::move(repo_)) { - git_oid oid; - if (git_oid_fromstr(&oid, rev.gitRev().c_str())) - throw Error("cannot convert '%s' to a Git OID", rev.gitRev()); + auto oid = hashToOID(rev); git_object * obj = nullptr; if (git_object_lookup(&obj, repo.get(), &oid, GIT_OBJECT_ANY)) { @@ -389,4 +396,20 @@ ref makeTarballCacheAccessor(const Hash & rev) return make_ref(openTarballCache(), rev); } +bool tarballCacheContains(const Hash & treeHash) +{ + auto repo = openTarballCache(); + + auto oid = hashToOID(treeHash); + + git_object * obj = nullptr; + if (auto errCode = git_object_lookup(&obj, repo.get(), &oid, GIT_OBJECT_TREE)) { + if (errCode == GIT_ENOTFOUND) return false; + auto err = git_error_last(); + throw Error("getting Git object '%s': %s", treeHash.gitRev(), err->message); + } + + return true; +} + } diff --git a/src/libfetchers/git-utils.hh b/src/libfetchers/git-utils.hh new file mode 100644 index 000000000..775a0d021 --- /dev/null +++ b/src/libfetchers/git-utils.hh @@ -0,0 +1,15 @@ +#pragma once + +#include "input-accessor.hh" + +namespace nix { + +ref makeGitInputAccessor(const CanonPath & path, const Hash & rev); + +Hash importTarball(Source & source); + +ref makeTarballCacheAccessor(const Hash & rev); + +bool tarballCacheContains(const Hash & treeHash); + +} diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 6985affd6..510595f7e 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -8,6 +8,7 @@ #include "util.hh" #include "git.hh" #include "fs-input-accessor.hh" +#include "git-utils.hh" #include "fetch-settings.hh" diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc index d3db9fed8..b6abb7a4a 100644 --- a/src/libfetchers/github.cc +++ b/src/libfetchers/github.cc @@ -9,6 +9,7 @@ #include "fetch-settings.hh" #include "input-accessor.hh" #include "tarball.hh" +#include "git-utils.hh" #include #include @@ -196,8 +197,10 @@ struct GitArchiveInputScheme : InputScheme if (auto treeHashS = cache->queryFact(treeHashKey)) { auto treeHash = Hash::parseAny(*treeHashS, htSHA1); - // FIXME: verify that treeHash exists in the tarball cache. - return {std::move(input), treeHash}; + if (tarballCacheContains(treeHash)) + return {std::move(input), treeHash}; + else + debug("Git tree with hash '%s' has disappeared from the cache, refetching...", treeHash.gitRev()); } /* Stream the tarball into the tarball cache. */ @@ -272,6 +275,7 @@ struct GitHubInputScheme : GitArchiveInputScheme return getStrAttr(input.attrs, "repo"); } + /* .commit.tree.sha, .commit.committer.date */ Hash getRevFromRef(nix::ref store, const Input & input) const override { auto host = getHost(input); diff --git a/src/libfetchers/input-accessor.hh b/src/libfetchers/input-accessor.hh index 1289d5515..77a9d46c3 100644 --- a/src/libfetchers/input-accessor.hh +++ b/src/libfetchers/input-accessor.hh @@ -117,12 +117,6 @@ ref makePatchingInputAccessor( ref next, const std::vector & patches); -ref makeGitInputAccessor(const CanonPath & path, const Hash & rev); - -Hash importTarball(Source & source); - -ref makeTarballCacheAccessor(const Hash & rev); - struct SourcePath { ref accessor;