Make the store plugins more introspectable

Directly register the store classes rather than a function to build an
instance of them.
This gives the possibility to introspect static members of the class or
choose different ways of instantiating them.
This commit is contained in:
regnat 2020-09-08 14:50:23 +02:00
parent 609a6d6d9f
commit 7d5bdf8b56
18 changed files with 141 additions and 117 deletions

1
result Symbolic link
View file

@ -0,0 +1 @@
/nix/store/9pqfirjppd91mzhkgh8xnn66iwh53zk2-hello-2.10

View file

@ -6,7 +6,7 @@
namespace nix { namespace nix {
class Store; class Store;
struct StorePath; class StorePath;
} }
namespace nix::flake { namespace nix::flake {

View file

@ -23,7 +23,7 @@ struct InputScheme;
struct Input struct Input
{ {
friend class InputScheme; friend struct InputScheme;
std::shared_ptr<InputScheme> scheme; // note: can be null std::shared_ptr<InputScheme> scheme; // note: can be null
Attrs attrs; Attrs attrs;

View file

@ -2,17 +2,15 @@
namespace nix { namespace nix {
static std::string uriScheme = "dummy://";
struct DummyStore : public Store struct DummyStore : public Store
{ {
DummyStore(const Params & params) DummyStore(const std::string uri, const Params & params)
: Store(params) : Store(params)
{ } { }
string getUri() override string getUri() override
{ {
return uriScheme; return uriPrefixes()[0] + "://";
} }
void queryPathInfoUncached(const StorePath & path, void queryPathInfoUncached(const StorePath & path,
@ -21,6 +19,10 @@ struct DummyStore : public Store
callback(nullptr); callback(nullptr);
} }
static std::vector<std::string> uriPrefixes() {
return {"dummy"};
}
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ unsupported("queryPathFromHashPart"); } { unsupported("queryPathFromHashPart"); }
@ -48,12 +50,6 @@ struct DummyStore : public Store
{ unsupported("buildDerivation"); } { unsupported("buildDerivation"); }
}; };
static RegisterStoreImplementation regStore([]( [[maybe_unused]] static RegisterStoreImplementation<DummyStore> regStore();
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
if (uri != uriScheme) return nullptr;
return std::make_shared<DummyStore>(params);
});
} }

View file

@ -24,7 +24,8 @@ private:
public: public:
HttpBinaryCacheStore( HttpBinaryCacheStore(
const Params & params, const Path & _cacheUri) const Path & _cacheUri,
const Params & params)
: BinaryCacheStore(params) : BinaryCacheStore(params)
, cacheUri(_cacheUri) , cacheUri(_cacheUri)
{ {
@ -55,6 +56,13 @@ public:
} }
} }
static std::vector<std::string> uriPrefixes()
{
static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1";
auto ret = std::vector<std::string>({"http", "https"});
if (forceHttp) ret.push_back("file");
return ret;
}
protected: protected:
void maybeDisable() void maybeDisable()
@ -162,18 +170,6 @@ protected:
}; };
static RegisterStoreImplementation regStore([]( [[maybe_unused]] static RegisterStoreImplementation<HttpBinaryCacheStore> 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;
});
} }

View file

@ -9,8 +9,6 @@
namespace nix { namespace nix {
static std::string uriScheme = "ssh://";
struct LegacySSHStore : public Store struct LegacySSHStore : public Store
{ {
const Setting<int> maxConnections{this, 1, "max-connections", "maximum number of concurrent SSH connections"}; const Setting<int> maxConnections{this, 1, "max-connections", "maximum number of concurrent SSH connections"};
@ -37,6 +35,9 @@ struct LegacySSHStore : public Store
SSHMaster master; SSHMaster master;
static std::vector<std::string> uriPrefixes() { return {"ssh"}; }
LegacySSHStore(const string & host, const Params & params) LegacySSHStore(const string & host, const Params & params)
: Store(params) : Store(params)
, host(host) , host(host)
@ -84,7 +85,7 @@ struct LegacySSHStore : public Store
string getUri() override string getUri() override
{ {
return uriScheme + host; return uriPrefixes()[0] + "://" + host;
} }
void queryPathInfoUncached(const StorePath & path, void queryPathInfoUncached(const StorePath & path,
@ -325,12 +326,6 @@ public:
} }
}; };
static RegisterStoreImplementation regStore([]( [[maybe_unused]] static RegisterStoreImplementation<LegacySSHStore> 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);
});
} }

View file

@ -13,7 +13,8 @@ private:
public: public:
LocalBinaryCacheStore( LocalBinaryCacheStore(
const Params & params, const Path & binaryCacheDir) const Path & binaryCacheDir,
const Params & params)
: BinaryCacheStore(params) : BinaryCacheStore(params)
, binaryCacheDir(binaryCacheDir) , binaryCacheDir(binaryCacheDir)
{ {
@ -26,6 +27,8 @@ public:
return "file://" + binaryCacheDir; return "file://" + binaryCacheDir;
} }
static std::vector<std::string> uriPrefixes();
protected: protected:
bool fileExists(const std::string & path) override; bool fileExists(const std::string & path) override;
@ -85,16 +88,14 @@ bool LocalBinaryCacheStore::fileExists(const std::string & path)
return pathExists(binaryCacheDir + "/" + path); return pathExists(binaryCacheDir + "/" + path);
} }
static RegisterStoreImplementation regStore([]( std::vector<std::string> LocalBinaryCacheStore::uriPrefixes()
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{ {
if (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") == "1" || if (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") == "1")
std::string(uri, 0, 7) != "file://") return {};
return 0; else
auto store = std::make_shared<LocalBinaryCacheStore>(params, std::string(uri, 7)); return {"file"};
store->init(); }
return store;
}); [[maybe_unused]] static RegisterStoreImplementation<LocalBinaryCacheStore> regStore();
} }

View file

@ -982,14 +982,6 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
return nullptr; return nullptr;
} }
static std::string uriScheme = "unix://"; [[maybe_unused]] static RegisterStoreImplementation<UDSRemoteStore> regStore();
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);
});
} }

View file

@ -150,6 +150,9 @@ public:
std::string getUri() override; std::string getUri() override;
static std::vector<std::string> uriPrefixes()
{ return {"unix"}; }
bool sameMachine() override bool sameMachine() override
{ return true; } { return true; }

View file

@ -193,7 +193,8 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
S3Helper s3Helper; S3Helper s3Helper;
S3BinaryCacheStoreImpl( S3BinaryCacheStoreImpl(
const Params & params, const std::string & bucketName) const std::string & bucketName,
const Params & params)
: S3BinaryCacheStore(params) : S3BinaryCacheStore(params)
, bucketName(bucketName) , bucketName(bucketName)
, s3Helper(profile, region, scheme, endpoint) , s3Helper(profile, region, scheme, endpoint)
@ -426,17 +427,11 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
return paths; return paths;
} }
static std::vector<std::string> uriPrefixes() { return {"s3"}; }
}; };
static RegisterStoreImplementation regStore([]( [[maybe_unused]] static RegisterStoreImplementation<S3BinaryCacheStoreImpl> 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;
});
} }

View file

@ -8,8 +8,6 @@
namespace nix { namespace nix {
static std::string uriScheme = "ssh-ng://";
class SSHStore : public RemoteStore class SSHStore : public RemoteStore
{ {
public: public:
@ -32,9 +30,11 @@ public:
{ {
} }
static std::vector<std::string> uriPrefixes() { return {"ssh-ng"}; }
std::string getUri() override std::string getUri() override
{ {
return uriScheme + host; return uriPrefixes()[0] + "://" + host;
} }
bool sameMachine() override bool sameMachine() override
@ -76,12 +76,6 @@ ref<RemoteStore::Connection> SSHStore::openConnection()
return conn; return conn;
} }
static RegisterStoreImplementation regStore([]( [[maybe_unused]] static RegisterStoreImplementation<SSHStore> 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);
});
} }

View file

@ -1009,6 +1009,11 @@ Derivation Store::readDerivation(const StorePath & drvPath)
} }
} }
std::shared_ptr<Config> Store::getConfig()
{
return shared_from_this();
}
} }
@ -1019,9 +1024,6 @@ Derivation Store::readDerivation(const StorePath & drvPath)
namespace nix { namespace nix {
RegisterStoreImplementation::Implementations * RegisterStoreImplementation::implementations = 0;
/* Split URI into protocol+hierarchy part and its parameter set. */ /* Split URI into protocol+hierarchy part and its parameter set. */
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_) std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_)
{ {
@ -1035,24 +1037,6 @@ std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_
return {uri, params}; 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) { static bool isNonUriPath(const std::string & spec) {
return return
// is not a URL // is not a URL
@ -1080,10 +1064,7 @@ StoreType getStoreType(const std::string & uri, const std::string & stateDir)
} }
} }
std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Params & params)
static RegisterStoreImplementation regStore([](
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{ {
switch (getStoreType(uri, get(params, "state").value_or(settings.nixStateDir))) { switch (getStoreType(uri, get(params, "state").value_or(settings.nixStateDir))) {
case tDaemon: case tDaemon:
@ -1098,8 +1079,30 @@ static RegisterStoreImplementation regStore([](
default: default:
return nullptr; return nullptr;
} }
}); }
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());
if (auto store = openFromNonUri(uri, params)) {
store->warnUnknownSettings();
return ref<Store>(store);
}
for (auto implem : *implementations) {
auto store = implem.open(uri, params);
if (store) {
store->warnUnknownSettings();
return ref<Store>(store);
}
}
throw Error("don't know how to open Nix store '%s'", uri);
}
std::list<ref<Store>> getDefaultSubstituters() std::list<ref<Store>> getDefaultSubstituters()
{ {

View file

@ -33,6 +33,7 @@ MakeError(SubstituteGone, Error);
MakeError(SubstituterDisabled, Error); MakeError(SubstituterDisabled, Error);
MakeError(BadStorePath, Error); MakeError(BadStorePath, Error);
MakeError(InvalidStoreURI, Error);
class FSAccessor; class FSAccessor;
class NarInfoDiskCache; class NarInfoDiskCache;
@ -199,6 +200,8 @@ protected:
Store(const Params & params); Store(const Params & params);
std::shared_ptr<Config> getConfig();
public: public:
virtual ~Store() { } virtual ~Store() { }
@ -744,25 +747,31 @@ StoreType getStoreType(const std::string & uri = settings.storeUri.get(),
substituters option and various legacy options. */ substituters option and various legacy options. */
std::list<ref<Store>> getDefaultSubstituters(); std::list<ref<Store>> getDefaultSubstituters();
struct StoreFactory
{
std::vector<std::string> uriPrefixes;
std::function<std::shared_ptr<Store> (const std::string & uri, const Store::Params & params)> open;
};
typedef std::vector<StoreFactory> Implementations;
static Implementations * implementations = new Implementations;
/* Store implementation registration. */ template<typename T>
typedef std::function<std::shared_ptr<Store>(
const std::string & uri, const Store::Params & params)> OpenStore;
struct RegisterStoreImplementation struct RegisterStoreImplementation
{ {
typedef std::vector<OpenStore> Implementations; RegisterStoreImplementation()
static Implementations * implementations;
RegisterStoreImplementation(OpenStore fun)
{ {
if (!implementations) implementations = new Implementations; StoreFactory factory{
implementations->push_back(fun); .uriPrefixes = T::uriPrefixes(),
.open =
([](const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{ return std::make_shared<T>(uri, params); })
};
implementations->push_back(factory);
} }
}; };
/* Display a set of paths in human-readable form (i.e., between quotes /* Display a set of paths in human-readable form (i.e., between quotes
and separated by commas). */ and separated by commas). */
string showPaths(const PathSet & paths); string showPaths(const PathSet & paths);

9
src/libstore/store.hh Normal file
View file

@ -0,0 +1,9 @@
#pragma once
namespace nix {
template<typename T> class BasicStore;
class StoreConfig;
typedef BasicStore<StoreConfig> Store;
}

View file

@ -0,0 +1,30 @@
#include "command.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
#include <nlohmann/json.hpp>
using namespace nix;
struct CmdDescribeStores : Command, MixJSON
{
std::string description() override
{
return "show registered store types and their available options";
}
Category category() override { return catUtility; }
void run() override
{
if (json) {
auto availableStores = *implementations;
} else {
throw Error("Only json is available for describe-stores");
}
}
};
static auto r1 = registerCommand<CmdDescribeStores>("describe-stores");

View file

@ -392,7 +392,7 @@ struct CmdDevelop : Common, MixEnvironment
auto bashInstallable = std::make_shared<InstallableFlake>( auto bashInstallable = std::make_shared<InstallableFlake>(
state, state,
std::move(installable->nixpkgsFlakeRef()), installable->nixpkgsFlakeRef(),
Strings{"bashInteractive"}, Strings{"bashInteractive"},
Strings{"legacyPackages." + settings.thisSystem.get() + "."}, Strings{"legacyPackages." + settings.thisSystem.get() + "."},
lockFlags); lockFlags);

View file

@ -81,7 +81,7 @@ void printClosureDiff(
auto beforeSize = totalSize(beforeVersions); auto beforeSize = totalSize(beforeVersions);
auto afterSize = totalSize(afterVersions); auto afterSize = totalSize(afterVersions);
auto sizeDelta = (int64_t) afterSize - (int64_t) beforeSize; auto sizeDelta = (int64_t) afterSize - (int64_t) beforeSize;
auto showDelta = abs(sizeDelta) >= 8 * 1024; auto showDelta = std::abs(sizeDelta) >= 8 * 1024;
std::set<std::string> removed, unchanged; std::set<std::string> removed, unchanged;
for (auto & [version, _] : beforeVersions) for (auto & [version, _] : beforeVersions)

View file

@ -69,7 +69,7 @@ struct Installable
virtual FlakeRef nixpkgsFlakeRef() const virtual FlakeRef nixpkgsFlakeRef() const
{ {
return std::move(FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}})); return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
} }
}; };