aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2020-09-17 16:33:10 +0000
committerJohn Ericson <John.Ericson@Obsidian.Systems>2020-09-17 16:33:10 +0000
commitb7df353f27b3bd6c1addb98dae19dcc973c1b698 (patch)
tree1f03dab04affc482e7dcac19ff147ea9e68d3228 /src/libstore
parent2741fffa350ec59d29ade24dd93007d535a61bde (diff)
parent649d3aaf2481b928120b6ce77d68b1b7c68f69e6 (diff)
Merge remote-tracking branch 'upstream/master' into ca-floating-upstream
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/binary-cache-store.cc3
-rw-r--r--src/libstore/binary-cache-store.hh24
-rw-r--r--src/libstore/build.cc9
-rw-r--r--src/libstore/dummy-store.cc32
-rw-r--r--src/libstore/gc.cc9
-rw-r--r--src/libstore/globals.cc5
-rw-r--r--src/libstore/globals.hh1
-rw-r--r--src/libstore/http-binary-cache-store.cc39
-rw-r--r--src/libstore/legacy-ssh-store.cc41
-rw-r--r--src/libstore/local-binary-cache-store.cc36
-rw-r--r--src/libstore/local-store.cc3
-rw-r--r--src/libstore/local-store.hh17
-rw-r--r--src/libstore/remote-store.cc38
-rw-r--r--src/libstore/remote-store.hh46
-rw-r--r--src/libstore/s3-binary-cache-store.cc45
-rw-r--r--src/libstore/ssh-store.cc37
-rw-r--r--src/libstore/store-api.cc93
-rw-r--r--src/libstore/store-api.hh137
18 files changed, 378 insertions, 237 deletions
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index 5433fe50d..34f844a18 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -22,7 +22,8 @@
namespace nix {
BinaryCacheStore::BinaryCacheStore(const Params & params)
- : Store(params)
+ : BinaryCacheStoreConfig(params)
+ , Store(params)
{
if (secretKeyFile != "")
secretKey = std::unique_ptr<SecretKey>(new SecretKey(readFile(secretKeyFile)));
diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh
index 9bcdf5901..4b779cdd4 100644
--- a/src/libstore/binary-cache-store.hh
+++ b/src/libstore/binary-cache-store.hh
@@ -11,17 +11,21 @@ namespace nix {
struct NarInfo;
-class BinaryCacheStore : public Store
+struct BinaryCacheStoreConfig : virtual StoreConfig
{
-public:
-
- const Setting<std::string> compression{this, "xz", "compression", "NAR compression method ('xz', 'bzip2', or 'none')"};
- const Setting<bool> writeNARListing{this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"};
- const Setting<bool> writeDebugInfo{this, false, "index-debug-info", "whether to index DWARF debug info files by build ID"};
- const Setting<Path> secretKeyFile{this, "", "secret-key", "path to secret key used to sign the binary cache"};
- const Setting<Path> localNarCache{this, "", "local-nar-cache", "path to a local cache of NARs"};
- const Setting<bool> parallelCompression{this, false, "parallel-compression",
+ using StoreConfig::StoreConfig;
+
+ const Setting<std::string> compression{(StoreConfig*) this, "xz", "compression", "NAR compression method ('xz', 'bzip2', or 'none')"};
+ const Setting<bool> writeNARListing{(StoreConfig*) this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"};
+ const Setting<bool> writeDebugInfo{(StoreConfig*) this, false, "index-debug-info", "whether to index DWARF debug info files by build ID"};
+ const Setting<Path> secretKeyFile{(StoreConfig*) this, "", "secret-key", "path to secret key used to sign the binary cache"};
+ const Setting<Path> localNarCache{(StoreConfig*) this, "", "local-nar-cache", "path to a local cache of NARs"};
+ const Setting<bool> parallelCompression{(StoreConfig*) this, false, "parallel-compression",
"enable multi-threading compression, available for xz only currently"};
+};
+
+class BinaryCacheStore : public Store, public virtual BinaryCacheStoreConfig
+{
private:
@@ -58,7 +62,7 @@ public:
public:
- virtual void init();
+ virtual void init() override;
private:
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 87c50f0e6..bff8a8327 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -2910,18 +2910,23 @@ void DerivationGoal::writeStructuredAttrs()
chownToBuilder(tmpDir + "/.attrs.sh");
}
+struct RestrictedStoreConfig : LocalFSStoreConfig
+{
+ using LocalFSStoreConfig::LocalFSStoreConfig;
+ const std::string name() { return "Restricted Store"; }
+};
/* A wrapper around LocalStore that only allows building/querying of
paths that are in the input closures of the build or were added via
recursive Nix calls. */
-struct RestrictedStore : public LocalFSStore
+struct RestrictedStore : public LocalFSStore, public virtual RestrictedStoreConfig
{
ref<LocalStore> next;
DerivationGoal & goal;
RestrictedStore(const Params & params, ref<LocalStore> next, DerivationGoal & goal)
- : Store(params), LocalFSStore(params), next(next), goal(goal)
+ : StoreConfig(params), Store(params), LocalFSStore(params), next(next), goal(goal)
{ }
Path getRealStoreDir() override
diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc
index 7a5744bc1..128832e60 100644
--- a/src/libstore/dummy-store.cc
+++ b/src/libstore/dummy-store.cc
@@ -2,17 +2,27 @@
namespace nix {
-static std::string uriScheme = "dummy://";
+struct DummyStoreConfig : virtual StoreConfig {
+ using StoreConfig::StoreConfig;
-struct DummyStore : public Store
+ const std::string name() override { return "Dummy Store"; }
+};
+
+struct DummyStore : public Store, public virtual DummyStoreConfig
{
- DummyStore(const Params & params)
- : Store(params)
+ DummyStore(const std::string scheme, const std::string uri, const Params & params)
+ : DummyStore(params)
{ }
+ DummyStore(const Params & params)
+ : StoreConfig(params)
+ , Store(params)
+ {
+ }
+
string getUri() override
{
- return uriScheme;
+ return *uriSchemes().begin();
}
void queryPathInfoUncached(const StorePath & path,
@@ -21,6 +31,10 @@ struct DummyStore : public Store
callback(nullptr);
}
+ static std::set<std::string> uriSchemes() {
+ return {"dummy"};
+ }
+
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ unsupported("queryPathFromHashPart"); }
@@ -48,12 +62,6 @@ struct DummyStore : public Store
{ unsupported("buildDerivation"); }
};
-static RegisterStoreImplementation regStore([](
- const std::string & uri, const Store::Params & params)
- -> std::shared_ptr<Store>
-{
- if (uri != uriScheme) return nullptr;
- return std::make_shared<DummyStore>(params);
-});
+static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regStore;
}
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index e6cbc525d..08b53c702 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -574,9 +574,12 @@ bool LocalStore::canReachRoot(GCState & state, StorePathSet & visited, const Sto
/* If keep-derivations is set and this is a derivation, then
don't delete the derivation if any of the outputs are alive. */
if (state.gcKeepDerivations && path.isDerivation()) {
- for (auto & i : queryDerivationOutputs(path))
- if (isValidPath(i) && queryPathInfo(i)->deriver == path)
- incoming.insert(i);
+ for (auto & [name, maybeOutPath] : queryPartialDerivationOutputMap(path))
+ if (maybeOutPath &&
+ isValidPath(*maybeOutPath) &&
+ queryPathInfo(*maybeOutPath)->deriver == path
+ )
+ incoming.insert(*maybeOutPath);
}
/* If keep-outputs is set, then don't delete this path if there
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 4a5971c3f..491c664db 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -162,11 +162,6 @@ template<> std::string BaseSetting<SandboxMode>::to_string() const
else abort();
}
-template<> nlohmann::json BaseSetting<SandboxMode>::toJSON()
-{
- return AbstractSetting::toJSON();
-}
-
template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::string & category)
{
args.addFlag({
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 8a2d3ff75..02721285a 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -2,6 +2,7 @@
#include "types.hh"
#include "config.hh"
+#include "abstractsettingtojson.hh"
#include "util.hh"
#include <map>
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 1733239fb..f4ab15a10 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -7,7 +7,14 @@ namespace nix {
MakeError(UploadToHTTP, Error);
-class HttpBinaryCacheStore : public BinaryCacheStore
+struct HttpBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
+{
+ using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
+
+ const std::string name() override { return "Http Binary Cache Store"; }
+};
+
+class HttpBinaryCacheStore : public BinaryCacheStore, public HttpBinaryCacheStoreConfig
{
private:
@@ -24,9 +31,12 @@ private:
public:
HttpBinaryCacheStore(
- const Params & params, const Path & _cacheUri)
- : BinaryCacheStore(params)
- , cacheUri(_cacheUri)
+ const std::string & scheme,
+ const Path & _cacheUri,
+ const Params & params)
+ : StoreConfig(params)
+ , BinaryCacheStore(params)
+ , cacheUri(scheme + "://" + _cacheUri)
{
if (cacheUri.back() == '/')
cacheUri.pop_back();
@@ -55,6 +65,13 @@ public:
}
}
+ static std::set<std::string> uriSchemes()
+ {
+ static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1";
+ auto ret = std::set<std::string>({"http", "https"});
+ if (forceHttp) ret.insert("file");
+ return ret;
+ }
protected:
void maybeDisable()
@@ -162,18 +179,6 @@ protected:
};
-static RegisterStoreImplementation regStore([](
- const std::string & uri, const Store::Params & params)
- -> std::shared_ptr<Store>
-{
- static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1";
- if (std::string(uri, 0, 7) != "http://" &&
- std::string(uri, 0, 8) != "https://" &&
- (!forceHttp || std::string(uri, 0, 7) != "file://"))
- return 0;
- auto store = std::make_shared<HttpBinaryCacheStore>(params, uri);
- store->init();
- return store;
-});
+static RegisterStoreImplementation<HttpBinaryCacheStore, HttpBinaryCacheStoreConfig> regStore;
}
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index dc03313f0..e9478c1d5 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -9,18 +9,24 @@
namespace nix {
-static std::string uriScheme = "ssh://";
-
-struct LegacySSHStore : public Store
+struct LegacySSHStoreConfig : virtual StoreConfig
{
- const Setting<int> maxConnections{this, 1, "max-connections", "maximum number of concurrent SSH connections"};
- const Setting<Path> sshKey{this, "", "ssh-key", "path to an SSH private key"};
- const Setting<bool> compress{this, false, "compress", "whether to compress the connection"};
- const Setting<Path> remoteProgram{this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"};
- const Setting<std::string> remoteStore{this, "", "remote-store", "URI of the store on the remote system"};
+ using StoreConfig::StoreConfig;
+ const Setting<int> maxConnections{(StoreConfig*) this, 1, "max-connections", "maximum number of concurrent SSH connections"};
+ const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
+ const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
+ const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"};
+ const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
+
+ const std::string name() override { return "Legacy SSH Store"; }
+};
+struct LegacySSHStore : public Store, public virtual LegacySSHStoreConfig
+{
// Hack for getting remote build log output.
- const Setting<int> logFD{this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"};
+ // Intentionally not in `LegacySSHStoreConfig` so that it doesn't appear in
+ // the documentation
+ const Setting<int> logFD{(StoreConfig*) this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"};
struct Connection
{
@@ -37,8 +43,11 @@ struct LegacySSHStore : public Store
SSHMaster master;
- LegacySSHStore(const string & host, const Params & params)
- : Store(params)
+ static std::set<std::string> uriSchemes() { return {"ssh"}; }
+
+ LegacySSHStore(const string & scheme, const string & host, const Params & params)
+ : StoreConfig(params)
+ , Store(params)
, host(host)
, connections(make_ref<Pool<Connection>>(
std::max(1, (int) maxConnections),
@@ -84,7 +93,7 @@ struct LegacySSHStore : public Store
string getUri() override
{
- return uriScheme + host;
+ return *uriSchemes().begin() + "://" + host;
}
void queryPathInfoUncached(const StorePath & path,
@@ -325,12 +334,6 @@ public:
}
};
-static RegisterStoreImplementation regStore([](
- const std::string & uri, const Store::Params & params)
- -> std::shared_ptr<Store>
-{
- if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
- return std::make_shared<LegacySSHStore>(std::string(uri, uriScheme.size()), params);
-});
+static RegisterStoreImplementation<LegacySSHStore, LegacySSHStoreConfig> regStore;
}
diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc
index 87d8334d7..b5744448e 100644
--- a/src/libstore/local-binary-cache-store.cc
+++ b/src/libstore/local-binary-cache-store.cc
@@ -4,7 +4,14 @@
namespace nix {
-class LocalBinaryCacheStore : public BinaryCacheStore
+struct LocalBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
+{
+ using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
+
+ const std::string name() override { return "Local Binary Cache Store"; }
+};
+
+class LocalBinaryCacheStore : public BinaryCacheStore, public virtual LocalBinaryCacheStoreConfig
{
private:
@@ -13,8 +20,11 @@ private:
public:
LocalBinaryCacheStore(
- const Params & params, const Path & binaryCacheDir)
- : BinaryCacheStore(params)
+ const std::string scheme,
+ const Path & binaryCacheDir,
+ const Params & params)
+ : StoreConfig(params)
+ , BinaryCacheStore(params)
, binaryCacheDir(binaryCacheDir)
{
}
@@ -26,6 +36,8 @@ public:
return "file://" + binaryCacheDir;
}
+ static std::set<std::string> uriSchemes();
+
protected:
bool fileExists(const std::string & path) override;
@@ -85,16 +97,14 @@ bool LocalBinaryCacheStore::fileExists(const std::string & path)
return pathExists(binaryCacheDir + "/" + path);
}
-static RegisterStoreImplementation regStore([](
- const std::string & uri, const Store::Params & params)
- -> std::shared_ptr<Store>
+std::set<std::string> LocalBinaryCacheStore::uriSchemes()
{
- if (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") == "1" ||
- std::string(uri, 0, 7) != "file://")
- return 0;
- auto store = std::make_shared<LocalBinaryCacheStore>(params, std::string(uri, 7));
- store->init();
- return store;
-});
+ if (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") == "1")
+ return {};
+ else
+ return {"file"};
+}
+
+static RegisterStoreImplementation<LocalBinaryCacheStore, LocalBinaryCacheStoreConfig> regStore;
}
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 0755cfa91..8d9a202ce 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -42,7 +42,8 @@ namespace nix {
LocalStore::LocalStore(const Params & params)
- : Store(params)
+ : StoreConfig(params)
+ , Store(params)
, LocalFSStore(params)
, realStoreDir_{this, false, rootDir != "" ? rootDir + "/nix/store" : storeDir, "real",
"physical path to the Nix store"}
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index d5e6d68ef..e7c9d1605 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -30,8 +30,19 @@ struct OptimiseStats
uint64_t blocksFreed = 0;
};
+struct LocalStoreConfig : virtual LocalFSStoreConfig
+{
+ using LocalFSStoreConfig::LocalFSStoreConfig;
+
+ Setting<bool> requireSigs{(StoreConfig*) this,
+ settings.requireSigs,
+ "require-sigs", "whether store paths should have a trusted signature on import"};
+
+ const std::string name() override { return "Local Store"; }
+};
+
-class LocalStore : public LocalFSStore
+class LocalStore : public LocalFSStore, public virtual LocalStoreConfig
{
private:
@@ -95,10 +106,6 @@ public:
private:
- Setting<bool> requireSigs{(Store*) this,
- settings.requireSigs,
- "require-sigs", "whether store paths should have a trusted signature on import"};
-
const PublicKeys & getPublicKeys();
public:
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index dc61951d3..e92b94975 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -94,9 +94,19 @@ void write(const Store & store, Sink & out, const std::optional<StorePath> & sto
/* TODO: Separate these store impls into different files, give them better names */
RemoteStore::RemoteStore(const Params & params)
: Store(params)
+ , RemoteStoreConfig(params)
, connections(make_ref<Pool<Connection>>(
std::max(1, (int) maxConnections),
- [this]() { return openConnectionWrapper(); },
+ [this]() {
+ auto conn = openConnectionWrapper();
+ try {
+ initConnection(*conn);
+ } catch (...) {
+ failed = true;
+ throw;
+ }
+ return conn;
+ },
[this](const ref<Connection> & r) {
return
r->to.good()
@@ -123,19 +133,21 @@ ref<RemoteStore::Connection> RemoteStore::openConnectionWrapper()
UDSRemoteStore::UDSRemoteStore(const Params & params)
- : Store(params)
+ : StoreConfig(params)
+ , Store(params)
, LocalFSStore(params)
, RemoteStore(params)
{
}
-UDSRemoteStore::UDSRemoteStore(std::string socket_path, const Params & params)
- : Store(params)
- , LocalFSStore(params)
- , RemoteStore(params)
- , path(socket_path)
+UDSRemoteStore::UDSRemoteStore(
+ const std::string scheme,
+ std::string socket_path,
+ const Params & params)
+ : UDSRemoteStore(params)
{
+ path.emplace(socket_path);
}
@@ -179,8 +191,6 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
conn->startTime = std::chrono::steady_clock::now();
- initConnection(*conn);
-
return conn;
}
@@ -982,14 +992,6 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
return nullptr;
}
-static std::string uriScheme = "unix://";
-
-static RegisterStoreImplementation regStore([](
- const std::string & uri, const Store::Params & params)
- -> std::shared_ptr<Store>
-{
- if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
- return std::make_shared<UDSRemoteStore>(std::string(uri, uriScheme.size()), params);
-});
+static RegisterStoreImplementation<UDSRemoteStore, UDSRemoteStoreConfig> regStore;
}
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 6f05f2197..91c748006 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -16,18 +16,22 @@ struct FdSource;
template<typename T> class Pool;
struct ConnectionHandle;
-
-/* FIXME: RemoteStore is a misnomer - should be something like
- DaemonStore. */
-class RemoteStore : public virtual Store
+struct RemoteStoreConfig : virtual StoreConfig
{
-public:
+ using StoreConfig::StoreConfig;
- const Setting<int> maxConnections{(Store*) this, 1,
+ const Setting<int> maxConnections{(StoreConfig*) this, 1,
"max-connections", "maximum number of concurrent connections to the Nix daemon"};
- const Setting<unsigned int> maxConnectionAge{(Store*) this, std::numeric_limits<unsigned int>::max(),
+ const Setting<unsigned int> maxConnectionAge{(StoreConfig*) this, std::numeric_limits<unsigned int>::max(),
"max-connection-age", "number of seconds to reuse a connection"};
+};
+
+/* FIXME: RemoteStore is a misnomer - should be something like
+ DaemonStore. */
+class RemoteStore : public virtual Store, public virtual RemoteStoreConfig
+{
+public:
virtual bool sameMachine() = 0;
@@ -102,8 +106,6 @@ public:
void flushBadConnections();
-protected:
-
struct Connection
{
AutoCloseFD fd;
@@ -119,6 +121,8 @@ protected:
ref<Connection> openConnectionWrapper();
+protected:
+
virtual ref<Connection> openConnection() = 0;
void initConnection(Connection & conn);
@@ -141,15 +145,35 @@ private:
};
-class UDSRemoteStore : public LocalFSStore, public RemoteStore
+struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreConfig
+{
+ UDSRemoteStoreConfig(const Store::Params & params)
+ : StoreConfig(params)
+ , LocalFSStoreConfig(params)
+ , RemoteStoreConfig(params)
+ {
+ }
+
+ UDSRemoteStoreConfig()
+ : UDSRemoteStoreConfig(Store::Params({}))
+ {
+ }
+
+ const std::string name() override { return "Local Daemon Store"; }
+};
+
+class UDSRemoteStore : public LocalFSStore, public RemoteStore, public virtual UDSRemoteStoreConfig
{
public:
UDSRemoteStore(const Params & params);
- UDSRemoteStore(std::string path, const Params & params);
+ UDSRemoteStore(const std::string scheme, std::string path, const Params & params);
std::string getUri() override;
+ static std::set<std::string> uriSchemes()
+ { return {"unix"}; }
+
bool sameMachine() override
{ return true; }
diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc
index a0a446bd3..d43f267e0 100644
--- a/src/libstore/s3-binary-cache-store.cc
+++ b/src/libstore/s3-binary-cache-store.cc
@@ -172,20 +172,26 @@ S3Helper::FileTransferResult S3Helper::getObject(
return res;
}
-struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
+struct S3BinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
{
- const Setting<std::string> profile{this, "", "profile", "The name of the AWS configuration profile to use."};
- const Setting<std::string> region{this, Aws::Region::US_EAST_1, "region", {"aws-region"}};
- const Setting<std::string> scheme{this, "", "scheme", "The scheme to use for S3 requests, https by default."};
- const Setting<std::string> endpoint{this, "", "endpoint", "An optional override of the endpoint to use when talking to S3."};
- const Setting<std::string> narinfoCompression{this, "", "narinfo-compression", "compression method for .narinfo files"};
- const Setting<std::string> lsCompression{this, "", "ls-compression", "compression method for .ls files"};
- const Setting<std::string> logCompression{this, "", "log-compression", "compression method for log/* files"};
+ using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
+ const Setting<std::string> profile{(StoreConfig*) this, "", "profile", "The name of the AWS configuration profile to use."};
+ const Setting<std::string> region{(StoreConfig*) this, Aws::Region::US_EAST_1, "region", {"aws-region"}};
+ const Setting<std::string> scheme{(StoreConfig*) this, "", "scheme", "The scheme to use for S3 requests, https by default."};
+ const Setting<std::string> endpoint{(StoreConfig*) this, "", "endpoint", "An optional override of the endpoint to use when talking to S3."};
+ const Setting<std::string> narinfoCompression{(StoreConfig*) this, "", "narinfo-compression", "compression method for .narinfo files"};
+ const Setting<std::string> lsCompression{(StoreConfig*) this, "", "ls-compression", "compression method for .ls files"};
+ const Setting<std::string> logCompression{(StoreConfig*) this, "", "log-compression", "compression method for log/* files"};
const Setting<bool> multipartUpload{
- this, false, "multipart-upload", "whether to use multi-part uploads"};
+ (StoreConfig*) this, false, "multipart-upload", "whether to use multi-part uploads"};
const Setting<uint64_t> bufferSize{
- this, 5 * 1024 * 1024, "buffer-size", "size (in bytes) of each part in multi-part uploads"};
+ (StoreConfig*) this, 5 * 1024 * 1024, "buffer-size", "size (in bytes) of each part in multi-part uploads"};
+ const std::string name() override { return "S3 Binary Cache Store"; }
+};
+
+struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore, virtual S3BinaryCacheStoreConfig
+{
std::string bucketName;
Stats stats;
@@ -193,8 +199,11 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
S3Helper s3Helper;
S3BinaryCacheStoreImpl(
- const Params & params, const std::string & bucketName)
- : S3BinaryCacheStore(params)
+ const std::string & scheme,
+ const std::string & bucketName,
+ const Params & params)
+ : StoreConfig(params)
+ , S3BinaryCacheStore(params)
, bucketName(bucketName)
, s3Helper(profile, region, scheme, endpoint)
{
@@ -426,17 +435,11 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
return paths;
}
+ static std::set<std::string> uriSchemes() { return {"s3"}; }
+
};
-static RegisterStoreImplementation regStore([](
- const std::string & uri, const Store::Params & params)
- -> std::shared_ptr<Store>
-{
- if (std::string(uri, 0, 5) != "s3://") return 0;
- auto store = std::make_shared<S3BinaryCacheStoreImpl>(params, std::string(uri, 5));
- store->init();
- return store;
-});
+static RegisterStoreImplementation<S3BinaryCacheStoreImpl, S3BinaryCacheStoreConfig> regStore;
}
diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc
index 6cb97c1f1..6d6eca98d 100644
--- a/src/libstore/ssh-store.cc
+++ b/src/libstore/ssh-store.cc
@@ -8,19 +8,25 @@
namespace nix {
-static std::string uriScheme = "ssh-ng://";
+struct SSHStoreConfig : virtual RemoteStoreConfig
+{
+ using RemoteStoreConfig::RemoteStoreConfig;
+
+ const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
+ const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
+ const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"};
+ const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
+
+ const std::string name() override { return "SSH Store"; }
+};
-class SSHStore : public RemoteStore
+class SSHStore : public virtual RemoteStore, public virtual SSHStoreConfig
{
public:
- const Setting<Path> sshKey{(Store*) this, "", "ssh-key", "path to an SSH private key"};
- const Setting<bool> compress{(Store*) this, false, "compress", "whether to compress the connection"};
- const Setting<Path> remoteProgram{(Store*) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"};
- const Setting<std::string> remoteStore{(Store*) this, "", "remote-store", "URI of the store on the remote system"};
-
- SSHStore(const std::string & host, const Params & params)
- : Store(params)
+ SSHStore(const std::string & scheme, const std::string & host, const Params & params)
+ : StoreConfig(params)
+ , Store(params)
, RemoteStore(params)
, host(host)
, master(
@@ -32,9 +38,11 @@ public:
{
}
+ static std::set<std::string> uriSchemes() { return {"ssh-ng"}; }
+
std::string getUri() override
{
- return uriScheme + host;
+ return *uriSchemes().begin() + "://" + host;
}
bool sameMachine() override
@@ -72,16 +80,9 @@ ref<RemoteStore::Connection> SSHStore::openConnection()
+ (remoteStore.get() == "" ? "" : " --store " + shellEscape(remoteStore.get())));
conn->to = FdSink(conn->sshConn->in.get());
conn->from = FdSource(conn->sshConn->out.get());
- initConnection(*conn);
return conn;
}
-static RegisterStoreImplementation regStore([](
- const std::string & uri, const Store::Params & params)
- -> std::shared_ptr<Store>
-{
- if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
- return std::make_shared<SSHStore>(std::string(uri, uriScheme.size()), params);
-});
+static RegisterStoreImplementation<SSHStore, SSHStoreConfig> regStore;
}
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index b3877487c..2d5077ed0 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -346,7 +346,7 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
Store::Store(const Params & params)
- : Config(params)
+ : StoreConfig(params)
, state({(size_t) pathInfoCacheSize})
{
}
@@ -1009,7 +1009,6 @@ Derivation Store::readDerivation(const StorePath & drvPath)
}
}
-
}
@@ -1019,9 +1018,6 @@ Derivation Store::readDerivation(const StorePath & drvPath)
namespace nix {
-
-RegisterStoreImplementation::Implementations * RegisterStoreImplementation::implementations = 0;
-
/* Split URI into protocol+hierarchy part and its parameter set. */
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_)
{
@@ -1035,24 +1031,6 @@ std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_
return {uri, params};
}
-ref<Store> openStore(const std::string & uri_,
- const Store::Params & extraParams)
-{
- auto [uri, uriParams] = splitUriAndParams(uri_);
- auto params = extraParams;
- params.insert(uriParams.begin(), uriParams.end());
-
- for (auto fun : *RegisterStoreImplementation::implementations) {
- auto store = fun(uri, params);
- if (store) {
- store->warnUnknownSettings();
- return ref<Store>(store);
- }
- }
-
- throw Error("don't know how to open Nix store '%s'", uri);
-}
-
static bool isNonUriPath(const std::string & spec) {
return
// is not a URL
@@ -1062,44 +1040,62 @@ static bool isNonUriPath(const std::string & spec) {
&& spec.find("/") != std::string::npos;
}
-StoreType getStoreType(const std::string & uri, const std::string & stateDir)
+std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Params & params)
{
- if (uri == "daemon") {
- return tDaemon;
- } else if (uri == "local" || isNonUriPath(uri)) {
- return tLocal;
- } else if (uri == "" || uri == "auto") {
+ if (uri == "" || uri == "auto") {
+ auto stateDir = get(params, "state").value_or(settings.nixStateDir);
if (access(stateDir.c_str(), R_OK | W_OK) == 0)
- return tLocal;
+ return std::make_shared<LocalStore>(params);
else if (pathExists(settings.nixDaemonSocketFile))
- return tDaemon;
+ return std::make_shared<UDSRemoteStore>(params);
else
- return tLocal;
+ return std::make_shared<LocalStore>(params);
+ } else if (uri == "daemon") {
+ return std::make_shared<UDSRemoteStore>(params);
+ } else if (uri == "local") {
+ return std::make_shared<LocalStore>(params);
+ } else if (isNonUriPath(uri)) {
+ Store::Params params2 = params;
+ params2["root"] = absPath(uri);
+ return std::make_shared<LocalStore>(params2);
} else {
- return tOther;
+ return nullptr;
}
}
-
-static RegisterStoreImplementation regStore([](
- const std::string & uri, const Store::Params & params)
- -> std::shared_ptr<Store>
+ref<Store> openStore(const std::string & uri_,
+ const Store::Params & extraParams)
{
- switch (getStoreType(uri, get(params, "state").value_or(settings.nixStateDir))) {
- case tDaemon:
- return std::shared_ptr<Store>(std::make_shared<UDSRemoteStore>(params));
- case tLocal: {
- Store::Params params2 = params;
- if (isNonUriPath(uri)) {
- params2["root"] = absPath(uri);
+ auto params = extraParams;
+ try {
+ auto parsedUri = parseURL(uri_);
+ params.insert(parsedUri.query.begin(), parsedUri.query.end());
+
+ auto baseURI = parsedUri.authority.value_or("") + parsedUri.path;
+
+ for (auto implem : *Implementations::registered) {
+ if (implem.uriSchemes.count(parsedUri.scheme)) {
+ auto store = implem.create(parsedUri.scheme, baseURI, params);
+ if (store) {
+ store->init();
+ store->warnUnknownSettings();
+ return ref<Store>(store);
+ }
}
- return std::shared_ptr<Store>(std::make_shared<LocalStore>(params2));
}
- default:
- return nullptr;
}
-});
+ catch (BadURL &) {
+ auto [uri, uriParams] = splitUriAndParams(uri_);
+ params.insert(uriParams.begin(), uriParams.end());
+ if (auto store = openFromNonUri(uri, params)) {
+ store->warnUnknownSettings();
+ return ref<Store>(store);
+ }
+ }
+
+ throw Error("don't know how to open Nix store '%s'", uri_);
+}
std::list<ref<Store>> getDefaultSubstituters()
{
@@ -1133,5 +1129,6 @@ std::list<ref<Store>> getDefaultSubstituters()
return stores;
}
+std::vector<StoreFactory> * Implementations::registered = 0;
}
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 8b42aa6d2..4d3f07dfc 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -24,6 +24,31 @@
namespace nix {
+/**
+ * About the class hierarchy of the store implementations:
+ *
+ * Each store type `Foo` consists of two classes:
+ *
+ * 1. A class `FooConfig : virtual StoreConfig` that contains the configuration
+ * for the store
+ *
+ * It should only contain members of type `const Setting<T>` (or subclasses
+ * of it) and inherit the constructors of `StoreConfig`
+ * (`using StoreConfig::StoreConfig`).
+ *
+ * 2. A class `Foo : virtual Store, virtual FooConfig` that contains the
+ * implementation of the store.
+ *
+ * This class is expected to have a constructor `Foo(const Params & params)`
+ * that calls `StoreConfig(params)` (otherwise you're gonna encounter an
+ * `assertion failure` when trying to instantiate it).
+ *
+ * You can then register the new store using:
+ *
+ * ```
+ * cpp static RegisterStoreImplementation<Foo, FooConfig> regStore;
+ * ```
+ */
MakeError(SubstError, Error);
MakeError(BuildError, Error); // denotes a permanent build failure
@@ -33,6 +58,7 @@ MakeError(SubstituteGone, Error);
MakeError(SubstituterDisabled, Error);
MakeError(BadStorePath, Error);
+MakeError(InvalidStoreURI, Error);
class FSAccessor;
class NarInfoDiskCache;
@@ -144,12 +170,31 @@ struct BuildResult
}
};
-
-class Store : public std::enable_shared_from_this<Store>, public Config
+struct StoreConfig : public Config
{
-public:
-
- typedef std::map<std::string, std::string> Params;
+ using Config::Config;
+
+ /**
+ * When constructing a store implementation, we pass in a map `params` of
+ * parameters that's supposed to initialize the associated config.
+ * To do that, we must use the `StoreConfig(StringMap & params)`
+ * constructor, so we'd like to `delete` its default constructor to enforce
+ * it.
+ *
+ * However, actually deleting it means that all the subclasses of
+ * `StoreConfig` will have their default constructor deleted (because it's
+ * supposed to call the deleted default constructor of `StoreConfig`). But
+ * because we're always using virtual inheritance, the constructors of
+ * child classes will never implicitely call this one, so deleting it will
+ * be more painful than anything else.
+ *
+ * So we `assert(false)` here to ensure at runtime that the right
+ * constructor is always called without having to redefine a custom
+ * constructor for each `*Config` class.
+ */
+ StoreConfig() { assert(false); }
+
+ virtual const std::string name() = 0;
const PathSetting storeDir_{this, false, settings.nixStore,
"store", "path to the Nix store"};
@@ -167,6 +212,14 @@ public:
"system-features",
"Optional features that the system this store builds on implements (like \"kvm\")."};
+};
+
+class Store : public std::enable_shared_from_this<Store>, public virtual StoreConfig
+{
+public:
+
+ typedef std::map<std::string, std::string> Params;
+
protected:
struct PathInfoCacheValue {
@@ -200,6 +253,11 @@ protected:
Store(const Params & params);
public:
+ /**
+ * Perform any necessary effectful operation to make the store up and
+ * running
+ */
+ virtual void init() {};
virtual ~Store() { }
@@ -626,22 +684,25 @@ protected:
};
-
-class LocalFSStore : public virtual Store
+struct LocalFSStoreConfig : virtual StoreConfig
{
-public:
-
- // FIXME: the (Store*) cast works around a bug in gcc that causes
+ using StoreConfig::StoreConfig;
+ // FIXME: the (StoreConfig*) cast works around a bug in gcc that causes
// it to omit the call to the Setting constructor. Clang works fine
// either way.
- const PathSetting rootDir{(Store*) this, true, "",
+ const PathSetting rootDir{(StoreConfig*) this, true, "",
"root", "directory prefixed to all other paths"};
- const PathSetting stateDir{(Store*) this, false,
+ const PathSetting stateDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir,
"state", "directory where Nix will store state"};
- const PathSetting logDir{(Store*) this, false,
+ const PathSetting logDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir,
"log", "directory where Nix will store state"};
+};
+
+class LocalFSStore : public virtual Store, public virtual LocalFSStoreConfig
+{
+public:
const static string drvsLogDir;
@@ -730,39 +791,49 @@ ref<Store> openStore(const std::string & uri = settings.storeUri.get(),
const Store::Params & extraParams = Store::Params());
-enum StoreType {
- tDaemon,
- tLocal,
- tOther
-};
-
-
-StoreType getStoreType(const std::string & uri = settings.storeUri.get(),
- const std::string & stateDir = settings.nixStateDir);
-
/* Return the default substituter stores, defined by the
‘substituters’ option and various legacy options. */
std::list<ref<Store>> getDefaultSubstituters();
+struct StoreFactory
+{
+ std::set<std::string> uriSchemes;
+ std::function<std::shared_ptr<Store> (const std::string & scheme, const std::string & uri, const Store::Params & params)> create;
+ std::function<std::shared_ptr<StoreConfig> ()> getConfig;
+};
+struct Implementations
+{
+ static std::vector<StoreFactory> * registered;
-/* Store implementation registration. */
-typedef std::function<std::shared_ptr<Store>(
- const std::string & uri, const Store::Params & params)> OpenStore;
+ template<typename T, typename TConfig>
+ static void add()
+ {
+ if (!registered) registered = new std::vector<StoreFactory>();
+ StoreFactory factory{
+ .uriSchemes = T::uriSchemes(),
+ .create =
+ ([](const std::string & scheme, const std::string & uri, const Store::Params & params)
+ -> std::shared_ptr<Store>
+ { return std::make_shared<T>(scheme, uri, params); }),
+ .getConfig =
+ ([]()
+ -> std::shared_ptr<StoreConfig>
+ { return std::make_shared<TConfig>(StringMap({})); })
+ };
+ registered->push_back(factory);
+ }
+};
+template<typename T, typename TConfig>
struct RegisterStoreImplementation
{
- typedef std::vector<OpenStore> Implementations;
- static Implementations * implementations;
-
- RegisterStoreImplementation(OpenStore fun)
+ RegisterStoreImplementation()
{
- if (!implementations) implementations = new Implementations;
- implementations->push_back(fun);
+ Implementations::add<T, TConfig>();
}
};
-
/* Display a set of paths in human-readable form (i.e., between quotes
and separated by commas). */
string showPaths(const PathSet & paths);