about summary refs log tree commit diff
path: root/src/libstore/binary-cache-store.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2016-02-25T16·43+0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2016-02-25T16·43+0100
commit1042c10fd0417fe33dd879317f5d7a73aa6f7fe3 (patch)
tree32497b429bf45d6338638ec5f20fdcfc48a56c39 /src/libstore/binary-cache-store.cc
parent152b1d6bf9c89b4db9848475e3000821e159d479 (diff)
Add NAR / Store accessor abstraction
This is primary to allow hydra-queue-runner to extract files like
"nix-support/hydra-build-products" from NARs in binary caches.
Diffstat (limited to 'src/libstore/binary-cache-store.cc')
-rw-r--r--src/libstore/binary-cache-store.cc80
1 files changed, 76 insertions, 4 deletions
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index dc086fe9cf..6a4e3a5605 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -1,12 +1,13 @@
-#include "binary-cache-store.hh"
-#include "sync.hh"
-
 #include "archive.hh"
+#include "binary-cache-store.hh"
 #include "compression.hh"
 #include "derivations.hh"
+#include "fs-accessor.hh"
 #include "globals.hh"
 #include "nar-info.hh"
+#include "sync.hh"
 #include "worker-protocol.hh"
+#include "nar-accessor.hh"
 
 #include <chrono>
 
@@ -122,7 +123,8 @@ NarInfo BinaryCacheStore::readNarInfo(const Path & storePath)
 
     auto narInfoFile = narInfoFileFor(storePath);
     auto narInfo = make_ref<NarInfo>(getFile(narInfoFile), narInfoFile);
-    assert(narInfo->path == storePath);
+    if (narInfo->path != storePath)
+        throw Error(format("NAR info file for store path ‘%1%’ does not match ‘%2%’") % narInfo->path % storePath);
 
     stats.narInfoRead++;
 
@@ -142,6 +144,9 @@ NarInfo BinaryCacheStore::readNarInfo(const Path & storePath)
 
 bool BinaryCacheStore::isValidPath(const Path & storePath)
 {
+    // FIXME: this only checks whether a .narinfo with a matching hash
+    // part exists. So ‘f4kb...-foo’ matches ‘f4kb...-bar’, even
+    // though they shouldn't. Not easily fixed.
     return fileExists(narInfoFileFor(storePath));
 }
 
@@ -344,4 +349,71 @@ void BinaryCacheStore::ensurePath(const Path & path)
     buildPaths({path});
 }
 
+/* Given requests for a path /nix/store/<x>/<y>, this accessor will
+   first download the NAR for /nix/store/<x> from the binary cache,
+   build a NAR accessor for that NAR, and use that to access <y>. */
+struct BinaryCacheStoreAccessor : public FSAccessor
+{
+    ref<BinaryCacheStore> store;
+
+    std::map<Path, ref<FSAccessor>> nars;
+
+    BinaryCacheStoreAccessor(ref<BinaryCacheStore> store)
+        : store(store)
+    {
+    }
+
+    std::pair<ref<FSAccessor>, Path> fetch(const Path & path_)
+    {
+        auto path = canonPath(path_);
+
+        auto storePath = toStorePath(path);
+        std::string restPath = std::string(path, storePath.size());
+
+        if (!store->isValidPath(storePath))
+            throw Error(format("path ‘%1%’ is not a valid store path") % storePath);
+
+        auto i = nars.find(storePath);
+        if (i != nars.end()) return {i->second, restPath};
+
+        StringSink sink;
+        store->exportPath(storePath, false, sink);
+
+        // FIXME: gratuitous string copying.
+        auto accessor = makeNarAccessor(make_ref<std::string>(sink.s));
+        nars.emplace(storePath, accessor);
+        return {accessor, restPath};
+    }
+
+    Stat stat(const Path & path) override
+    {
+        auto res = fetch(path);
+        return res.first->stat(res.second);
+    }
+
+    StringSet readDirectory(const Path & path) override
+    {
+        auto res = fetch(path);
+        return res.first->readDirectory(res.second);
+    }
+
+    std::string readFile(const Path & path) override
+    {
+        auto res = fetch(path);
+        return res.first->readFile(res.second);
+    }
+
+    std::string readLink(const Path & path) override
+    {
+        auto res = fetch(path);
+        return res.first->readLink(res.second);
+    }
+};
+
+ref<FSAccessor> BinaryCacheStore::getFSAccessor()
+{
+    return make_ref<BinaryCacheStoreAccessor>(ref<BinaryCacheStore>(
+            std::dynamic_pointer_cast<BinaryCacheStore>(shared_from_this())));
+}
+
 }