aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-03-17 22:32:26 +0100
committerEelco Dolstra <edolstra@gmail.com>2020-03-17 22:35:29 +0100
commit38e360154d8ef6a70e3101a9b0d850e63fbfdfda (patch)
tree24ee0edf6ba989e0a273dc7ca4c7931a22a23fce /src/libstore
parentd1165d8791f559352ff6aa7348e1293b2873db1c (diff)
Git: Use unified caching system
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/fetchers/git.cc166
-rw-r--r--src/libstore/fetchers/mercurial.cc11
2 files changed, 86 insertions, 91 deletions
diff --git a/src/libstore/fetchers/git.cc b/src/libstore/fetchers/git.cc
index c5d4f019c..c1044d5a2 100644
--- a/src/libstore/fetchers/git.cc
+++ b/src/libstore/fetchers/git.cc
@@ -1,5 +1,6 @@
-#include "fetchers.hh"
-#include "parse.hh"
+#include "fetchers/fetchers.hh"
+#include "fetchers/cache.hh"
+#include "fetchers/parse.hh"
#include "globals.hh"
#include "tarfile.hh"
#include "store-api.hh"
@@ -7,77 +8,15 @@
#include <sys/time.h>
-#include <nlohmann/json.hpp>
-
using namespace std::string_literals;
namespace nix::fetchers {
-static Path getCacheInfoPathFor(const std::string & name, const Hash & rev)
-{
- Path cacheDir = getCacheDir() + "/nix/git-revs-v2";
- std::string linkName =
- name == "source"
- ? rev.gitRev()
- : hashString(htSHA512, name + std::string("\0"s) + rev.gitRev()).to_string(Base32, false);
- return cacheDir + "/" + linkName + ".link";
-}
-
static std::string readHead(const Path & path)
{
return chomp(runProgram("git", true, { "-C", path, "rev-parse", "--abbrev-ref", "HEAD" }));
}
-static void cacheGitInfo(
- Store & store,
- const std::string & name,
- const Tree & tree,
- const Hash & rev)
-{
- if (!tree.info.revCount || !tree.info.lastModified) return;
-
- nlohmann::json json;
- json["storePath"] = store.printStorePath(tree.storePath);
- json["name"] = name;
- json["rev"] = rev.gitRev();
- json["revCount"] = *tree.info.revCount;
- json["lastModified"] = *tree.info.lastModified;
-
- auto cacheInfoPath = getCacheInfoPathFor(name, rev);
- createDirs(dirOf(cacheInfoPath));
- writeFile(cacheInfoPath, json.dump());
-}
-
-static std::optional<std::pair<Hash, Tree>> lookupGitInfo(
- ref<Store> store,
- const std::string & name,
- const Hash & rev)
-{
- try {
- auto json = nlohmann::json::parse(readFile(getCacheInfoPathFor(name, rev)));
-
- assert(json["name"] == name && Hash((std::string) json["rev"], htSHA1) == rev);
-
- auto storePath = store->parseStorePath((std::string) json["storePath"]);
-
- if (store->isValidPath(storePath)) {
- return {{rev, Tree{
- .actualPath = store->toRealPath(storePath),
- .storePath = std::move(storePath),
- .info = TreeInfo {
- .revCount = json["revCount"],
- .lastModified = json["lastModified"],
- }
- }}};
- }
-
- } catch (SysError & e) {
- if (e.errNo != ENOENT) throw;
- }
-
- return {};
-}
-
struct GitInput : Input
{
ParsedURL url;
@@ -207,11 +146,38 @@ struct GitInput : Input
assert(!rev || rev->type == htSHA1);
+ auto cacheType = shallow ? "git-shallow" : "git";
+
+ auto getImmutableAttrs = [&]()
+ {
+ return Attrs({
+ {"type", cacheType},
+ {"name", name},
+ {"rev", input->rev->gitRev()},
+ });
+ };
+
+ auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath)
+ -> std::pair<Tree, std::shared_ptr<const Input>>
+ {
+ assert(input->rev);
+ assert(!rev || rev == input->rev);
+ return {
+ Tree{
+ .actualPath = store->toRealPath(storePath),
+ .storePath = std::move(storePath),
+ .info = TreeInfo {
+ .revCount = shallow ? std::nullopt : std::optional(getIntAttr(infoAttrs, "revCount")),
+ .lastModified = getIntAttr(infoAttrs, "lastModified"),
+ },
+ },
+ input
+ };
+ };
+
if (rev) {
- if (auto tree = lookupGitInfo(store, name, *rev)) {
- input->rev = tree->first;
- return {std::move(tree->second), input};
- }
+ if (auto res = getCache()->lookup(store, getImmutableAttrs()))
+ return makeResult(res->first, std::move(res->second));
}
auto [isLocal, actualUrl_] = getActualUrl();
@@ -290,6 +256,13 @@ struct GitInput : Input
if (!input->ref) input->ref = isLocal ? readHead(actualUrl) : "master";
+ Attrs mutableAttrs({
+ {"type", cacheType},
+ {"name", name},
+ {"url", actualUrl},
+ {"ref", *input->ref},
+ });
+
Path repoDir;
if (isLocal) {
@@ -301,6 +274,14 @@ struct GitInput : Input
} else {
+ if (auto res = getCache()->lookup(store, mutableAttrs)) {
+ auto rev2 = Hash(getStrAttr(res->first, "rev"), htSHA1);
+ if (!rev || rev == rev2) {
+ input->rev = rev2;
+ return makeResult(res->first, std::move(res->second));
+ }
+ }
+
Path cacheDir = getCacheDir() + "/nix/gitv3/" + hashString(htSHA256, actualUrl).to_string(Base32, false);
repoDir = cacheDir;
@@ -368,16 +349,15 @@ struct GitInput : Input
if (isShallow && !shallow)
throw Error("'%s' is a shallow Git repository, but a non-shallow repository is needed", actualUrl);
- if (auto tree = lookupGitInfo(store, name, *input->rev)) {
- assert(*input->rev == tree->first);
- if (shallow) tree->second.info.revCount.reset();
- return {std::move(tree->second), input};
- }
-
// FIXME: check whether rev is an ancestor of ref.
printTalkative("using revision %s of repo '%s'", input->rev->gitRev(), actualUrl);
+ /* Now that we know the ref, check again whether we have it in
+ the store. */
+ if (auto res = getCache()->lookup(store, getImmutableAttrs()))
+ return makeResult(res->first, std::move(res->second));
+
// FIXME: should pipe this, or find some better way to extract a
// revision.
auto source = sinkToSource([&](Sink & sink) {
@@ -395,21 +375,31 @@ struct GitInput : Input
auto lastModified = std::stoull(runProgram("git", true, { "-C", repoDir, "log", "-1", "--format=%ct", input->rev->gitRev() }));
- auto tree = Tree {
- .actualPath = store->toRealPath(storePath),
- .storePath = std::move(storePath),
- .info = TreeInfo {
- .revCount =
- !shallow
- ? std::optional(std::stoull(runProgram("git", true, { "-C", repoDir, "rev-list", "--count", input->rev->gitRev() })))
- : std::nullopt,
- .lastModified = lastModified
- }
- };
-
- cacheGitInfo(*store, name, tree, *input->rev);
+ Attrs infoAttrs({
+ {"rev", input->rev->gitRev()},
+ {"lastModified", lastModified},
+ });
- return {std::move(tree), input};
+ if (!shallow)
+ infoAttrs.insert_or_assign("revCount",
+ std::stoull(runProgram("git", true, { "-C", repoDir, "rev-list", "--count", input->rev->gitRev() })));
+
+ if (!this->rev)
+ getCache()->add(
+ store,
+ mutableAttrs,
+ infoAttrs,
+ storePath,
+ false);
+
+ getCache()->add(
+ store,
+ getImmutableAttrs(),
+ infoAttrs,
+ storePath,
+ true);
+
+ return makeResult(infoAttrs, std::move(storePath));
}
};
diff --git a/src/libstore/fetchers/mercurial.cc b/src/libstore/fetchers/mercurial.cc
index 3a767ef17..5cd43a74e 100644
--- a/src/libstore/fetchers/mercurial.cc
+++ b/src/libstore/fetchers/mercurial.cc
@@ -174,7 +174,7 @@ struct MercurialInput : Input
auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath)
-> std::pair<Tree, std::shared_ptr<const Input>>
{
- input->rev = Hash(getStrAttr(infoAttrs, "rev"), htSHA1);
+ assert(input->rev);
assert(!rev || rev == input->rev);
return {
Tree{
@@ -203,8 +203,13 @@ struct MercurialInput : Input
{"ref", *input->ref},
});
- if (auto res = getCache()->lookup(store, mutableAttrs))
- return makeResult(res->first, std::move(res->second));
+ if (auto res = getCache()->lookup(store, mutableAttrs)) {
+ auto rev2 = Hash(getStrAttr(res->first, "rev"), htSHA1);
+ if (!rev || rev == rev2) {
+ input->rev = rev2;
+ return makeResult(res->first, std::move(res->second));
+ }
+ }
Path cacheDir = fmt("%s/nix/hg/%s", getCacheDir(), hashString(htSHA256, actualUrl).to_string(Base32, false));