1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-24 18:01:16 +02:00

Stores no longer inherit from their configs

Fix #10766

See that ticket for details.

Progress (I hope!) towards #11139.

Co-Authored-By: Sergei Zimmerman <xokdvium@proton.me>
This commit is contained in:
John Ericson 2025-05-07 17:07:23 -04:00
parent f0f196cef0
commit 934918ba16
48 changed files with 743 additions and 593 deletions

View file

@ -33,6 +33,7 @@ let
{ {
settings, settings,
doc, doc,
uri-schemes,
experimentalFeature, experimentalFeature,
}: }:
let let

View file

@ -44,7 +44,7 @@ static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot)
static bool allSupportedLocally(Store & store, const StringSet& requiredFeatures) { static bool allSupportedLocally(Store & store, const StringSet& requiredFeatures) {
for (auto & feature : requiredFeatures) for (auto & feature : requiredFeatures)
if (!store.systemFeatures.get().count(feature)) return false; if (!store.config.systemFeatures.get().count(feature)) return false;
return true; return true;
} }
@ -85,7 +85,7 @@ static int main_build_remote(int argc, char * * argv)
that gets cleared on reboot, but it wouldn't work on macOS. */ that gets cleared on reboot, but it wouldn't work on macOS. */
auto currentLoadName = "/current-load"; auto currentLoadName = "/current-load";
if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>()) if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>())
currentLoad = std::string { localStore->stateDir } + currentLoadName; currentLoad = std::string { localStore->config.stateDir } + currentLoadName;
else else
currentLoad = settings.nixStateDir + currentLoadName; currentLoad = settings.nixStateDir + currentLoadName;

View file

@ -18,7 +18,7 @@ extern char ** savedArgv;
class EvalState; class EvalState;
struct Pos; struct Pos;
class Store; class Store;
class LocalFSStore; struct LocalFSStore;
static constexpr Command::Category catHelp = -1; static constexpr Command::Category catHelp = -1;
static constexpr Command::Category catSecondary = 100; static constexpr Command::Category catSecondary = 100;

View file

@ -42,7 +42,7 @@ Store * nix_store_open(nix_c_context * context, const char * uri, const char ***
if (!params) if (!params)
return new Store{nix::openStore(uri_str)}; return new Store{nix::openStore(uri_str)};
nix::Store::Params params_map; nix::Store::Config::Params params_map;
for (size_t i = 0; params[i] != nullptr; i++) { for (size_t i = 0; params[i] != nullptr; i++) {
params_map[params[i][0]] = params[i][1]; params_map[params[i][0]] = params[i][1];
} }

View file

@ -24,16 +24,15 @@
namespace nix { namespace nix {
BinaryCacheStore::BinaryCacheStore(const Params & params) BinaryCacheStore::BinaryCacheStore(Config & config)
: BinaryCacheStoreConfig(params) : config{config}
, Store(params)
{ {
if (secretKeyFile != "") if (config.secretKeyFile != "")
signers.push_back(std::make_unique<LocalSigner>( signers.push_back(std::make_unique<LocalSigner>(
SecretKey { readFile(secretKeyFile) })); SecretKey { readFile(config.secretKeyFile) }));
if (secretKeyFiles != "") { if (config.secretKeyFiles != "") {
std::stringstream ss(secretKeyFiles); std::stringstream ss(config.secretKeyFiles);
Path keyPath; Path keyPath;
while (std::getline(ss, keyPath, ',')) { while (std::getline(ss, keyPath, ',')) {
signers.push_back(std::make_unique<LocalSigner>( signers.push_back(std::make_unique<LocalSigner>(
@ -62,9 +61,9 @@ void BinaryCacheStore::init()
throw Error("binary cache '%s' is for Nix stores with prefix '%s', not '%s'", throw Error("binary cache '%s' is for Nix stores with prefix '%s', not '%s'",
getUri(), value, storeDir); getUri(), value, storeDir);
} else if (name == "WantMassQuery") { } else if (name == "WantMassQuery") {
wantMassQuery.setDefault(value == "1"); config.wantMassQuery.setDefault(value == "1");
} else if (name == "Priority") { } else if (name == "Priority") {
priority.setDefault(std::stoi(value)); config.priority.setDefault(std::stoi(value));
} }
} }
} }
@ -156,7 +155,11 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
{ {
FdSink fileSink(fdTemp.get()); FdSink fileSink(fdTemp.get());
TeeSink teeSinkCompressed { fileSink, fileHashSink }; TeeSink teeSinkCompressed { fileSink, fileHashSink };
auto compressionSink = makeCompressionSink(compression, teeSinkCompressed, parallelCompression, compressionLevel); auto compressionSink = makeCompressionSink(
config.compression,
teeSinkCompressed,
config.parallelCompression,
config.compressionLevel);
TeeSink teeSinkUncompressed { *compressionSink, narHashSink }; TeeSink teeSinkUncompressed { *compressionSink, narHashSink };
TeeSource teeSource { narSource, teeSinkUncompressed }; TeeSource teeSource { narSource, teeSinkUncompressed };
narAccessor = makeNarAccessor(teeSource); narAccessor = makeNarAccessor(teeSource);
@ -168,17 +171,17 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
auto info = mkInfo(narHashSink.finish()); auto info = mkInfo(narHashSink.finish());
auto narInfo = make_ref<NarInfo>(info); auto narInfo = make_ref<NarInfo>(info);
narInfo->compression = compression; narInfo->compression = config.compression;
auto [fileHash, fileSize] = fileHashSink.finish(); auto [fileHash, fileSize] = fileHashSink.finish();
narInfo->fileHash = fileHash; narInfo->fileHash = fileHash;
narInfo->fileSize = fileSize; narInfo->fileSize = fileSize;
narInfo->url = "nar/" + narInfo->fileHash->to_string(HashFormat::Nix32, false) + ".nar" narInfo->url = "nar/" + narInfo->fileHash->to_string(HashFormat::Nix32, false) + ".nar"
+ (compression == "xz" ? ".xz" : + (config.compression == "xz" ? ".xz" :
compression == "bzip2" ? ".bz2" : config.compression == "bzip2" ? ".bz2" :
compression == "zstd" ? ".zst" : config.compression == "zstd" ? ".zst" :
compression == "lzip" ? ".lzip" : config.compression == "lzip" ? ".lzip" :
compression == "lz4" ? ".lz4" : config.compression == "lz4" ? ".lz4" :
compression == "br" ? ".br" : config.compression == "br" ? ".br" :
""); "");
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count();
@ -200,7 +203,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
/* Optionally write a JSON file containing a listing of the /* Optionally write a JSON file containing a listing of the
contents of the NAR. */ contents of the NAR. */
if (writeNARListing) { if (config.writeNARListing) {
nlohmann::json j = { nlohmann::json j = {
{"version", 1}, {"version", 1},
{"root", listNar(ref<SourceAccessor>(narAccessor), CanonPath::root, true)}, {"root", listNar(ref<SourceAccessor>(narAccessor), CanonPath::root, true)},
@ -212,7 +215,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
/* Optionally maintain an index of DWARF debug info files /* Optionally maintain an index of DWARF debug info files
consisting of JSON files named 'debuginfo/<build-id>' that consisting of JSON files named 'debuginfo/<build-id>' that
specify the NAR file and member containing the debug info. */ specify the NAR file and member containing the debug info. */
if (writeDebugInfo) { if (config.writeDebugInfo) {
CanonPath buildIdDir("lib/debug/.build-id"); CanonPath buildIdDir("lib/debug/.build-id");
@ -524,7 +527,7 @@ void BinaryCacheStore::registerDrvOutput(const Realisation& info) {
ref<SourceAccessor> BinaryCacheStore::getFSAccessor(bool requireValidPath) ref<SourceAccessor> BinaryCacheStore::getFSAccessor(bool requireValidPath)
{ {
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()), requireValidPath, localNarCache); return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()), requireValidPath, config.localNarCache);
} }
void BinaryCacheStore::addSignatures(const StorePath & storePath, const StringSet & sigs) void BinaryCacheStore::addSignatures(const StorePath & storePath, const StringSet & sigs)

View file

@ -1284,7 +1284,7 @@ Path DerivationGoal::openLogFile()
/* Create a log file. */ /* Create a log file. */
Path logDir; Path logDir;
if (auto localStore = dynamic_cast<LocalStore *>(&worker.store)) if (auto localStore = dynamic_cast<LocalStore *>(&worker.store))
logDir = localStore->logDir; logDir = localStore->config->logDir;
else else
logDir = settings.nixLogDir; logDir = settings.nixLogDir;
Path dir = fmt("%s/%s/%s/", logDir, LocalFSStore::drvsLogDir, baseName.substr(0, 2)); Path dir = fmt("%s/%s/%s/", logDir, LocalFSStore::drvsLogDir, baseName.substr(0, 2));

View file

@ -121,7 +121,7 @@ Goal::Co PathSubstitutionGoal::init()
/* Bail out early if this substituter lacks a valid /* Bail out early if this substituter lacks a valid
signature. LocalStore::addToStore() also checks for this, but signature. LocalStore::addToStore() also checks for this, but
only after we've downloaded the path. */ only after we've downloaded the path. */
if (!sub->isTrusted && worker.store.pathInfoIsUntrusted(*info)) if (!sub->config.isTrusted && worker.store.pathInfoIsUntrusted(*info))
{ {
warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'", warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'",
worker.store.printStorePath(storePath), sub->getUri()); worker.store.printStorePath(storePath), sub->getUri());
@ -215,7 +215,7 @@ Goal::Co PathSubstitutionGoal::tryToRun(StorePath subPath, nix::ref<Store> sub,
PushActivity pact(act.id); PushActivity pact(act.id);
copyStorePath(*sub, worker.store, copyStorePath(*sub, worker.store,
subPath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs); subPath, repair, sub->config.isTrusted ? NoCheckSigs : CheckSigs);
promise.set_value(); promise.set_value();
} catch (...) { } catch (...) {

View file

@ -28,7 +28,7 @@ CommonSSHStoreConfig::CommonSSHStoreConfig(std::string_view scheme, std::string_
{ {
} }
SSHMaster CommonSSHStoreConfig::createSSHMaster(bool useMaster, Descriptor logFD) SSHMaster CommonSSHStoreConfig::createSSHMaster(bool useMaster, Descriptor logFD) const
{ {
return { return {
host, host,

View file

@ -265,7 +265,7 @@ bool DerivationOptions::canBuildLocally(Store & localStore, const BasicDerivatio
return false; return false;
for (auto & feature : getRequiredSystemFeatures(drv)) for (auto & feature : getRequiredSystemFeatures(drv))
if (!localStore.systemFeatures.get().count(feature)) if (!localStore.config.systemFeatures.get().count(feature))
return false; return false;
return true; return true;

View file

@ -3,7 +3,7 @@
namespace nix { namespace nix {
struct DummyStoreConfig : virtual StoreConfig { struct DummyStoreConfig : public std::enable_shared_from_this<DummyStoreConfig>, virtual StoreConfig {
using StoreConfig::StoreConfig; using StoreConfig::StoreConfig;
DummyStoreConfig(std::string_view scheme, std::string_view authority, const Params & params) DummyStoreConfig(std::string_view scheme, std::string_view authority, const Params & params)
@ -13,9 +13,9 @@ struct DummyStoreConfig : virtual StoreConfig {
throw UsageError("`%s` store URIs must not contain an authority part %s", scheme, authority); throw UsageError("`%s` store URIs must not contain an authority part %s", scheme, authority);
} }
const std::string name() override { return "Dummy Store"; } static const std::string name() { return "Dummy Store"; }
std::string doc() override static std::string doc()
{ {
return return
#include "dummy-store.md" #include "dummy-store.md"
@ -25,23 +25,24 @@ struct DummyStoreConfig : virtual StoreConfig {
static StringSet uriSchemes() { static StringSet uriSchemes() {
return {"dummy"}; return {"dummy"};
} }
ref<Store> openStore() const override;
}; };
struct DummyStore : public virtual DummyStoreConfig, public virtual Store struct DummyStore : virtual Store
{ {
DummyStore(std::string_view scheme, std::string_view authority, const Params & params) using Config = DummyStoreConfig;
: StoreConfig(params)
, DummyStoreConfig(scheme, authority, params)
, Store(params)
{ }
DummyStore(const Params & params) ref<const Config> config;
: DummyStore("dummy", "", params)
DummyStore(ref<const Config> config)
: Store{*config}
, config(config)
{ } { }
std::string getUri() override std::string getUri() override
{ {
return *uriSchemes().begin(); return *Config::uriSchemes().begin();
} }
void queryPathInfoUncached(const StorePath & path, void queryPathInfoUncached(const StorePath & path,
@ -88,6 +89,11 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store
} }
}; };
static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regDummyStore; ref<Store> DummyStore::Config::openStore() const
{
return make_ref<DummyStore>(ref{shared_from_this()});
}
static RegisterStoreImplementation<DummyStore::Config> regDummyStore;
} }

View file

@ -771,7 +771,7 @@ struct curlFileTransfer : public FileTransfer
} }
#if NIX_WITH_S3_SUPPORT #if NIX_WITH_S3_SUPPORT
std::tuple<std::string, std::string, Store::Params> parseS3Uri(std::string uri) std::tuple<std::string, std::string, Store::Config::Params> parseS3Uri(std::string uri)
{ {
auto [path, params] = splitUriAndParams(uri); auto [path, params] = splitUriAndParams(uri);

View file

@ -43,7 +43,7 @@ static std::string gcRootsDir = "gcroots";
void LocalStore::addIndirectRoot(const Path & path) void LocalStore::addIndirectRoot(const Path & path)
{ {
std::string hash = hashString(HashAlgorithm::SHA1, path).to_string(HashFormat::Nix32, false); std::string hash = hashString(HashAlgorithm::SHA1, path).to_string(HashFormat::Nix32, false);
Path realRoot = canonPath(fmt("%1%/%2%/auto/%3%", stateDir, gcRootsDir, hash)); Path realRoot = canonPath(fmt("%1%/%2%/auto/%3%", config->stateDir, gcRootsDir, hash));
makeSymlink(realRoot, path); makeSymlink(realRoot, path);
} }
@ -82,7 +82,7 @@ void LocalStore::createTempRootsFile()
void LocalStore::addTempRoot(const StorePath & path) void LocalStore::addTempRoot(const StorePath & path)
{ {
if (readOnly) { if (config->readOnly) {
debug("Read-only store doesn't support creating lock files for temp roots, but nothing can be deleted anyways."); debug("Read-only store doesn't support creating lock files for temp roots, but nothing can be deleted anyways.");
return; return;
} }
@ -109,7 +109,7 @@ void LocalStore::addTempRoot(const StorePath & path)
auto fdRootsSocket(_fdRootsSocket.lock()); auto fdRootsSocket(_fdRootsSocket.lock());
if (!*fdRootsSocket) { if (!*fdRootsSocket) {
auto socketPath = stateDir.get() + gcSocketPath; auto socketPath = config->stateDir.get() + gcSocketPath;
debug("connecting to '%s'", socketPath); debug("connecting to '%s'", socketPath);
*fdRootsSocket = createUnixDomainSocket(); *fdRootsSocket = createUnixDomainSocket();
try { try {
@ -247,7 +247,7 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R
else { else {
target = absPath(target, dirOf(path)); target = absPath(target, dirOf(path));
if (!pathExists(target)) { if (!pathExists(target)) {
if (isInDir(path, std::filesystem::path{stateDir.get()} / gcRootsDir / "auto")) { if (isInDir(path, std::filesystem::path{config->stateDir.get()} / gcRootsDir / "auto")) {
printInfo("removing stale link from '%1%' to '%2%'", path, target); printInfo("removing stale link from '%1%' to '%2%'", path, target);
unlink(path.c_str()); unlink(path.c_str());
} }
@ -288,8 +288,8 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R
void LocalStore::findRootsNoTemp(Roots & roots, bool censor) void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
{ {
/* Process direct roots in {gcroots,profiles}. */ /* Process direct roots in {gcroots,profiles}. */
findRoots(stateDir + "/" + gcRootsDir, std::filesystem::file_type::unknown, roots); findRoots(config->stateDir + "/" + gcRootsDir, std::filesystem::file_type::unknown, roots);
findRoots(stateDir + "/profiles", std::filesystem::file_type::unknown, roots); findRoots(config->stateDir + "/profiles", std::filesystem::file_type::unknown, roots);
/* Add additional roots returned by different platforms-specific /* Add additional roots returned by different platforms-specific
heuristics. This is typically used to add running programs to heuristics. This is typically used to add running programs to
@ -498,7 +498,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
readFile(*p); readFile(*p);
/* Start the server for receiving new roots. */ /* Start the server for receiving new roots. */
auto socketPath = stateDir.get() + gcSocketPath; auto socketPath = config->stateDir.get() + gcSocketPath;
createDirs(dirOf(socketPath)); createDirs(dirOf(socketPath));
auto fdServer = createUnixDomainSocket(socketPath, 0666); auto fdServer = createUnixDomainSocket(socketPath, 0666);
@ -635,7 +635,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
auto deleteFromStore = [&](std::string_view baseName) auto deleteFromStore = [&](std::string_view baseName)
{ {
Path path = storeDir + "/" + std::string(baseName); Path path = storeDir + "/" + std::string(baseName);
Path realPath = realStoreDir + "/" + std::string(baseName); Path realPath = config->realStoreDir + "/" + std::string(baseName);
/* There may be temp directories in the store that are still in use /* There may be temp directories in the store that are still in use
by another process. We need to be sure that we can acquire an by another process. We need to be sure that we can acquire an
@ -804,8 +804,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
printInfo("determining live/dead paths..."); printInfo("determining live/dead paths...");
try { try {
AutoCloseDir dir(opendir(realStoreDir.get().c_str())); AutoCloseDir dir(opendir(config->realStoreDir.get().c_str()));
if (!dir) throw SysError("opening directory '%1%'", realStoreDir); if (!dir) throw SysError("opening directory '%1%'", config->realStoreDir);
/* Read the store and delete all paths that are invalid or /* Read the store and delete all paths that are invalid or
unreachable. We don't use readDirectory() here so that unreachable. We don't use readDirectory() here so that
@ -907,8 +907,8 @@ void LocalStore::autoGC(bool sync)
return std::stoll(readFile(*fakeFreeSpaceFile)); return std::stoll(readFile(*fakeFreeSpaceFile));
struct statvfs st; struct statvfs st;
if (statvfs(realStoreDir.get().c_str(), &st)) if (statvfs(config->realStoreDir.get().c_str(), &st))
throw SysError("getting filesystem info about '%s'", realStoreDir); throw SysError("getting filesystem info about '%s'", config->realStoreDir);
return (uint64_t) st.f_bavail * st.f_frsize; return (uint64_t) st.f_bavail * st.f_frsize;
}; };

View file

@ -9,6 +9,15 @@ namespace nix {
MakeError(UploadToHTTP, Error); MakeError(UploadToHTTP, Error);
StringSet HttpBinaryCacheStoreConfig::uriSchemes()
{
static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1";
auto ret = StringSet{"http", "https"};
if (forceHttp)
ret.insert("file");
return ret;
}
HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig( HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig(
std::string_view scheme, std::string_view scheme,
std::string_view _cacheUri, std::string_view _cacheUri,
@ -35,10 +44,9 @@ std::string HttpBinaryCacheStoreConfig::doc()
} }
class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public virtual BinaryCacheStore class HttpBinaryCacheStore :
public virtual BinaryCacheStore
{ {
private:
struct State struct State
{ {
bool enabled = true; bool enabled = true;
@ -49,37 +57,37 @@ private:
public: public:
HttpBinaryCacheStore( using Config = HttpBinaryCacheStoreConfig;
std::string_view scheme,
PathView cacheUri, ref<Config> config;
const Params & params)
: StoreConfig(params) HttpBinaryCacheStore(ref<Config> config)
, BinaryCacheStoreConfig(params) : Store{*config}
, HttpBinaryCacheStoreConfig(scheme, cacheUri, params) // TODO it will actually mutate the configuration
, Store(params) , BinaryCacheStore{*config}
, BinaryCacheStore(params) , config{config}
{ {
diskCache = getNarInfoDiskCache(); diskCache = getNarInfoDiskCache();
} }
std::string getUri() override std::string getUri() override
{ {
return cacheUri; return config->cacheUri;
} }
void init() override void init() override
{ {
// FIXME: do this lazily? // FIXME: do this lazily?
if (auto cacheInfo = diskCache->upToDateCacheExists(cacheUri)) { if (auto cacheInfo = diskCache->upToDateCacheExists(config->cacheUri)) {
wantMassQuery.setDefault(cacheInfo->wantMassQuery); config->wantMassQuery.setDefault(cacheInfo->wantMassQuery);
priority.setDefault(cacheInfo->priority); config->priority.setDefault(cacheInfo->priority);
} else { } else {
try { try {
BinaryCacheStore::init(); BinaryCacheStore::init();
} catch (UploadToHTTP &) { } catch (UploadToHTTP &) {
throw Error("'%s' does not appear to be a binary cache", cacheUri); throw Error("'%s' does not appear to be a binary cache", config->cacheUri);
} }
diskCache->createCache(cacheUri, storeDir, wantMassQuery, priority); diskCache->createCache(config->cacheUri, config->storeDir, config->wantMassQuery, config->priority);
} }
} }
@ -137,7 +145,7 @@ protected:
try { try {
getFileTransfer()->upload(req); getFileTransfer()->upload(req);
} catch (FileTransferError & e) { } catch (FileTransferError & e) {
throw UploadToHTTP("while uploading to HTTP binary cache at '%s': %s", cacheUri, e.msg()); throw UploadToHTTP("while uploading to HTTP binary cache at '%s': %s", config->cacheUri, e.msg());
} }
} }
@ -146,7 +154,7 @@ protected:
return FileTransferRequest( return FileTransferRequest(
hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://") hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://")
? path ? path
: cacheUri + "/" + path); : config->cacheUri + "/" + path);
} }
@ -221,6 +229,14 @@ protected:
} }
}; };
static RegisterStoreImplementation<HttpBinaryCacheStore, HttpBinaryCacheStoreConfig> regHttpBinaryCacheStore; ref<Store> HttpBinaryCacheStore::Config::openStore() const
{
return make_ref<HttpBinaryCacheStore>(ref{
// FIXME we shouldn't actually need a mutable config
std::const_pointer_cast<HttpBinaryCacheStore::Config>(shared_from_this())
});
}
static RegisterStoreImplementation<HttpBinaryCacheStore::Config> regHttpBinaryCacheStore;
} }

View file

@ -54,10 +54,17 @@ struct BinaryCacheStoreConfig : virtual StoreConfig
* @note subclasses must implement at least one of the two * @note subclasses must implement at least one of the two
* virtual getFile() methods. * virtual getFile() methods.
*/ */
class BinaryCacheStore : public virtual BinaryCacheStoreConfig, struct BinaryCacheStore :
public virtual Store, virtual Store,
public virtual LogStore virtual LogStore
{ {
using Config = BinaryCacheStoreConfig;
/**
* Intentionally mutable because some things we update due to the
* cache's own (remote side) settings.
*/
Config & config;
private: private:
std::vector<std::unique_ptr<Signer>> signers; std::vector<std::unique_ptr<Signer>> signers;
@ -69,7 +76,7 @@ protected:
const std::string cacheInfoFile = "nix-cache-info"; const std::string cacheInfoFile = "nix-cache-info";
BinaryCacheStore(const Params & params); BinaryCacheStore(Config &);
public: public:

View file

@ -56,7 +56,7 @@ struct CommonSSHStoreConfig : virtual StoreConfig
*/ */
SSHMaster createSSHMaster( SSHMaster createSSHMaster(
bool useMaster, bool useMaster,
Descriptor logFD = INVALID_DESCRIPTOR); Descriptor logFD = INVALID_DESCRIPTOR) const;
}; };
} }

View file

@ -2,29 +2,27 @@
namespace nix { namespace nix {
struct HttpBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig struct HttpBinaryCacheStoreConfig : std::enable_shared_from_this<HttpBinaryCacheStoreConfig>,
virtual Store::Config,
BinaryCacheStoreConfig
{ {
using BinaryCacheStoreConfig::BinaryCacheStoreConfig; using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
HttpBinaryCacheStoreConfig(std::string_view scheme, std::string_view _cacheUri, const Params & params); HttpBinaryCacheStoreConfig(
std::string_view scheme, std::string_view cacheUri, const Store::Config::Params & params);
Path cacheUri; Path cacheUri;
const std::string name() override static const std::string name()
{ {
return "HTTP Binary Cache Store"; return "HTTP Binary Cache Store";
} }
static StringSet uriSchemes() static StringSet uriSchemes();
{
static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1";
auto ret = StringSet({"http", "https"});
if (forceHttp)
ret.insert("file");
return ret;
}
std::string doc() override; static std::string doc();
ref<Store> openStore() const override;
}; };
} }

View file

@ -10,7 +10,7 @@
namespace nix { namespace nix {
struct LegacySSHStoreConfig : virtual CommonSSHStoreConfig struct LegacySSHStoreConfig : std::enable_shared_from_this<LegacySSHStoreConfig>, virtual CommonSSHStoreConfig
{ {
using CommonSSHStoreConfig::CommonSSHStoreConfig; using CommonSSHStoreConfig::CommonSSHStoreConfig;
@ -19,6 +19,15 @@ struct LegacySSHStoreConfig : virtual CommonSSHStoreConfig
std::string_view authority, std::string_view authority,
const Params & params); const Params & params);
#ifndef _WIN32
// Hack for getting remote build log output.
// Intentionally not in `LegacySSHStoreConfig` so that it doesn't appear in
// the documentation
const Setting<int> logFD{this, INVALID_DESCRIPTOR, "log-fd", "file descriptor to which SSH's stderr is connected"};
#else
Descriptor logFD = INVALID_DESCRIPTOR;
#endif
const Setting<Strings> remoteProgram{this, {"nix-store"}, "remote-program", const Setting<Strings> remoteProgram{this, {"nix-store"}, "remote-program",
"Path to the `nix-store` executable on the remote machine."}; "Path to the `nix-store` executable on the remote machine."};
@ -35,23 +44,20 @@ struct LegacySSHStoreConfig : virtual CommonSSHStoreConfig
*/ */
std::optional<size_t> connPipeSize; std::optional<size_t> connPipeSize;
const std::string name() override { return "SSH Store"; } static const std::string name() { return "SSH Store"; }
static StringSet uriSchemes() { return {"ssh"}; } static StringSet uriSchemes() { return {"ssh"}; }
std::string doc() override; static std::string doc();
ref<Store> openStore() const override;
}; };
struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Store struct LegacySSHStore : public virtual Store
{ {
#ifndef _WIN32 using Config = LegacySSHStoreConfig;
// Hack for getting remote build log output.
// Intentionally not in `LegacySSHStoreConfig` so that it doesn't appear in ref<const Config> config;
// the documentation
const Setting<int> logFD{this, INVALID_DESCRIPTOR, "log-fd", "file descriptor to which SSH's stderr is connected"};
#else
Descriptor logFD = INVALID_DESCRIPTOR;
#endif
struct Connection; struct Connection;
@ -59,10 +65,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
SSHMaster master; SSHMaster master;
LegacySSHStore( LegacySSHStore(ref<const Config>);
std::string_view scheme,
std::string_view host,
const Params & params);
ref<Connection> openConnection(); ref<Connection> openConnection();
@ -187,10 +190,7 @@ public:
* The legacy ssh protocol doesn't support checking for trusted-user. * The legacy ssh protocol doesn't support checking for trusted-user.
* Try using ssh-ng:// instead if you want to know. * Try using ssh-ng:// instead if you want to know.
*/ */
std::optional<TrustedFlag> isTrustedClient() override std::optional<TrustedFlag> isTrustedClient() override;
{
return std::nullopt;
}
void queryRealisationUncached(const DrvOutput &, void queryRealisationUncached(const DrvOutput &,
Callback<std::shared_ptr<const Realisation>> callback) noexcept override Callback<std::shared_ptr<const Realisation>> callback) noexcept override

View file

@ -2,22 +2,30 @@
namespace nix { namespace nix {
struct LocalBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig struct LocalBinaryCacheStoreConfig : std::enable_shared_from_this<LocalBinaryCacheStoreConfig>,
virtual Store::Config,
BinaryCacheStoreConfig
{ {
using BinaryCacheStoreConfig::BinaryCacheStoreConfig; using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
/**
* @param binaryCacheDir `file://` is a short-hand for `file:///`
* for now.
*/
LocalBinaryCacheStoreConfig(std::string_view scheme, PathView binaryCacheDir, const Params & params); LocalBinaryCacheStoreConfig(std::string_view scheme, PathView binaryCacheDir, const Params & params);
Path binaryCacheDir; Path binaryCacheDir;
const std::string name() override static const std::string name()
{ {
return "Local Binary Cache Store"; return "Local Binary Cache Store";
} }
static StringSet uriSchemes(); static StringSet uriSchemes();
std::string doc() override; static std::string doc();
ref<Store> openStore() const override;
}; };
} }

View file

@ -20,36 +20,39 @@ struct LocalFSStoreConfig : virtual StoreConfig
*/ */
LocalFSStoreConfig(PathView path, const Params & params); LocalFSStoreConfig(PathView path, const Params & params);
const OptionalPathSetting rootDir{this, std::nullopt, OptionalPathSetting rootDir{this, std::nullopt,
"root", "root",
"Directory prefixed to all other paths."}; "Directory prefixed to all other paths."};
const PathSetting stateDir{this, PathSetting stateDir{this,
rootDir.get() ? *rootDir.get() + "/nix/var/nix" : settings.nixStateDir, rootDir.get() ? *rootDir.get() + "/nix/var/nix" : settings.nixStateDir,
"state", "state",
"Directory where Nix will store state."}; "Directory where Nix will store state."};
const PathSetting logDir{this, PathSetting logDir{this,
rootDir.get() ? *rootDir.get() + "/nix/var/log/nix" : settings.nixLogDir, rootDir.get() ? *rootDir.get() + "/nix/var/log/nix" : settings.nixLogDir,
"log", "log",
"directory where Nix will store log files."}; "directory where Nix will store log files."};
const PathSetting realStoreDir{this, PathSetting realStoreDir{this,
rootDir.get() ? *rootDir.get() + "/nix/store" : storeDir, "real", rootDir.get() ? *rootDir.get() + "/nix/store" : storeDir, "real",
"Physical path of the Nix store."}; "Physical path of the Nix store."};
}; };
class LocalFSStore : public virtual LocalFSStoreConfig, struct LocalFSStore :
public virtual Store, virtual Store,
public virtual GcStore, virtual GcStore,
public virtual LogStore virtual LogStore
{ {
public: using Config = LocalFSStoreConfig;
const Config & config;
inline static std::string operationName = "Local Filesystem Store"; inline static std::string operationName = "Local Filesystem Store";
const static std::string drvsLogDir; const static std::string drvsLogDir;
LocalFSStore(const Params & params); LocalFSStore(const Config & params);
void narFromPath(const StorePath & path, Sink & sink) override; void narFromPath(const StorePath & path, Sink & sink) override;
ref<SourceAccessor> getFSAccessor(bool requireValidPath = true) override; ref<SourceAccessor> getFSAccessor(bool requireValidPath = true) override;
@ -70,7 +73,7 @@ public:
*/ */
virtual Path addPermRoot(const StorePath & storePath, const Path & gcRoot) = 0; virtual Path addPermRoot(const StorePath & storePath, const Path & gcRoot) = 0;
virtual Path getRealStoreDir() { return realStoreDir; } virtual Path getRealStoreDir() { return config.realStoreDir; }
Path toRealPath(const Path & storePath) override Path toRealPath(const Path & storePath) override
{ {

View file

@ -56,9 +56,9 @@ struct LocalOverlayStoreConfig : virtual LocalStoreConfig
The store directory is passed as an argument to the invoked executable. The store directory is passed as an argument to the invoked executable.
)"}; )"};
const std::string name() override { return "Experimental Local Overlay Store"; } static const std::string name() { return "Experimental Local Overlay Store"; }
std::optional<ExperimentalFeature> experimentalFeature() const override static std::optional<ExperimentalFeature> experimentalFeature()
{ {
return ExperimentalFeature::LocalOverlayStore; return ExperimentalFeature::LocalOverlayStore;
} }
@ -68,7 +68,9 @@ struct LocalOverlayStoreConfig : virtual LocalStoreConfig
return { "local-overlay" }; return { "local-overlay" };
} }
std::string doc() override; static std::string doc();
ref<Store> openStore() const override;
protected: protected:
/** /**
@ -79,7 +81,9 @@ protected:
* at that file path. It might be stored in the lower layer instead, * at that file path. It might be stored in the lower layer instead,
* or it might not be part of this store at all. * or it might not be part of this store at all.
*/ */
Path toUpperPath(const StorePath & path); Path toUpperPath(const StorePath & path) const;
friend struct LocalOverlayStore;
}; };
/** /**
@ -88,8 +92,20 @@ protected:
* Documentation on overridden methods states how they differ from their * Documentation on overridden methods states how they differ from their
* `LocalStore` counterparts. * `LocalStore` counterparts.
*/ */
class LocalOverlayStore : public virtual LocalOverlayStoreConfig, public virtual LocalStore struct LocalOverlayStore : virtual LocalStore
{ {
using Config = LocalOverlayStoreConfig;
ref<const Config> config;
LocalOverlayStore(ref<const Config>);
std::string getUri() override
{
return "local-overlay://";
}
private:
/** /**
* The store beneath us. * The store beneath us.
* *
@ -99,20 +115,6 @@ class LocalOverlayStore : public virtual LocalOverlayStoreConfig, public virtual
*/ */
ref<LocalFSStore> lowerStore; ref<LocalFSStore> lowerStore;
public:
LocalOverlayStore(const Params & params)
: LocalOverlayStore("local-overlay", "", params)
{
}
LocalOverlayStore(std::string_view scheme, PathView path, const Params & params);
std::string getUri() override
{
return "local-overlay://";
}
private:
/** /**
* First copy up any lower store realisation with the same key, so we * First copy up any lower store realisation with the same key, so we
* merge rather than mask it. * merge rather than mask it.

View file

@ -34,7 +34,7 @@ struct OptimiseStats
uint64_t bytesFreed = 0; uint64_t bytesFreed = 0;
}; };
struct LocalStoreConfig : virtual LocalFSStoreConfig struct LocalStoreConfig : std::enable_shared_from_this<LocalStoreConfig>, virtual LocalFSStoreConfig
{ {
using LocalFSStoreConfig::LocalFSStoreConfig; using LocalFSStoreConfig::LocalFSStoreConfig;
@ -65,18 +65,26 @@ struct LocalStoreConfig : virtual LocalFSStoreConfig
> While the filesystem the database resides on might appear to be read-only, consider whether another user or system might have write access to it. > While the filesystem the database resides on might appear to be read-only, consider whether another user or system might have write access to it.
)"}; )"};
const std::string name() override { return "Local Store"; } static const std::string name() { return "Local Store"; }
static StringSet uriSchemes() static StringSet uriSchemes()
{ return {"local"}; } { return {"local"}; }
std::string doc() override; static std::string doc();
ref<Store> openStore() const override;
}; };
class LocalStore : public virtual LocalStoreConfig class LocalStore :
, public virtual IndirectRootStore public virtual IndirectRootStore,
, public virtual GcStore public virtual GcStore
{ {
public:
using Config = LocalStoreConfig;
ref<const LocalStoreConfig> config;
private: private:
/** /**
@ -144,11 +152,7 @@ public:
* Initialise the local store, upgrading the schema if * Initialise the local store, upgrading the schema if
* necessary. * necessary.
*/ */
LocalStore(const Params & params); LocalStore(ref<const Config> params);
LocalStore(
std::string_view scheme,
PathView path,
const Params & params);
~LocalStore(); ~LocalStore();

View file

@ -86,7 +86,7 @@ typedef std::list<Generation> Generations;
*/ */
std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path profile); std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path profile);
class LocalFSStore; struct LocalFSStore;
/** /**
* Create a new generation of the given profile * Create a new generation of the given profile

View file

@ -19,7 +19,7 @@ class RemoteFSAccessor : public SourceAccessor
std::pair<ref<SourceAccessor>, CanonPath> fetch(const CanonPath & path); std::pair<ref<SourceAccessor>, CanonPath> fetch(const CanonPath & path);
friend class BinaryCacheStore; friend struct BinaryCacheStore;
Path makeCacheFile(std::string_view hashPart, const std::string & ext); Path makeCacheFile(std::string_view hashPart, const std::string & ext);

View file

@ -35,14 +35,16 @@ struct RemoteStoreConfig : virtual StoreConfig
* \todo RemoteStore is a misnomer - should be something like * \todo RemoteStore is a misnomer - should be something like
* DaemonStore. * DaemonStore.
*/ */
class RemoteStore : public virtual RemoteStoreConfig, struct RemoteStore :
public virtual Store, public virtual Store,
public virtual GcStore, public virtual GcStore,
public virtual LogStore public virtual LogStore
{ {
public: using Config = RemoteStoreConfig;
RemoteStore(const Params & params); const Config & config;
RemoteStore(const Config & config);
/* Implementations of abstract store API methods. */ /* Implementations of abstract store API methods. */

View file

@ -55,6 +55,6 @@ struct RestrictionContext
/** /**
* Create a shared pointer to a restricted store. * Create a shared pointer to a restricted store.
*/ */
ref<Store> makeRestrictedStore(const Store::Params & params, ref<LocalStore> next, RestrictionContext & context); ref<Store> makeRestrictedStore(ref<LocalStore::Config> config, ref<LocalStore> next, RestrictionContext & context);
} }

View file

@ -11,7 +11,7 @@
namespace nix { namespace nix {
struct S3BinaryCacheStoreConfig : virtual BinaryCacheStoreConfig struct S3BinaryCacheStoreConfig : std::enable_shared_from_this<S3BinaryCacheStoreConfig>, virtual BinaryCacheStoreConfig
{ {
std::string bucketName; std::string bucketName;
@ -93,7 +93,7 @@ public:
const Setting<uint64_t> bufferSize{ const Setting<uint64_t> bufferSize{
this, 5 * 1024 * 1024, "buffer-size", "Size (in bytes) of each part in multi-part uploads."}; this, 5 * 1024 * 1024, "buffer-size", "Size (in bytes) of each part in multi-part uploads."};
const std::string name() override static const std::string name()
{ {
return "S3 Binary Cache Store"; return "S3 Binary Cache Store";
} }
@ -103,16 +103,18 @@ public:
return {"s3"}; return {"s3"};
} }
std::string doc() override; static std::string doc();
ref<Store> openStore() const override;
}; };
class S3BinaryCacheStore : public virtual BinaryCacheStore struct S3BinaryCacheStore : virtual BinaryCacheStore
{ {
protected: using Config = S3BinaryCacheStoreConfig;
S3BinaryCacheStore(const Params & params); ref<Config> config;
public: S3BinaryCacheStore(ref<Config>);
struct Stats struct Stats
{ {

View file

@ -8,7 +8,9 @@
namespace nix { namespace nix {
struct SSHStoreConfig : virtual RemoteStoreConfig, virtual CommonSSHStoreConfig struct SSHStoreConfig : std::enable_shared_from_this<SSHStoreConfig>,
virtual RemoteStoreConfig,
virtual CommonSSHStoreConfig
{ {
using CommonSSHStoreConfig::CommonSSHStoreConfig; using CommonSSHStoreConfig::CommonSSHStoreConfig;
using RemoteStoreConfig::RemoteStoreConfig; using RemoteStoreConfig::RemoteStoreConfig;
@ -18,7 +20,7 @@ struct SSHStoreConfig : virtual RemoteStoreConfig, virtual CommonSSHStoreConfig
const Setting<Strings> remoteProgram{ const Setting<Strings> remoteProgram{
this, {"nix-daemon"}, "remote-program", "Path to the `nix-daemon` executable on the remote machine."}; this, {"nix-daemon"}, "remote-program", "Path to the `nix-daemon` executable on the remote machine."};
const std::string name() override static const std::string name()
{ {
return "Experimental SSH Store"; return "Experimental SSH Store";
} }
@ -28,19 +30,17 @@ struct SSHStoreConfig : virtual RemoteStoreConfig, virtual CommonSSHStoreConfig
return {"ssh-ng"}; return {"ssh-ng"};
} }
std::string doc() override; static std::string doc();
ref<Store> openStore() const override;
}; };
struct MountedSSHStoreConfig : virtual SSHStoreConfig, virtual LocalFSStoreConfig struct MountedSSHStoreConfig : virtual SSHStoreConfig, virtual LocalFSStoreConfig
{ {
using LocalFSStoreConfig::LocalFSStoreConfig;
using SSHStoreConfig::SSHStoreConfig;
MountedSSHStoreConfig(StringMap params); MountedSSHStoreConfig(StringMap params);
MountedSSHStoreConfig(std::string_view scheme, std::string_view host, StringMap params); MountedSSHStoreConfig(std::string_view scheme, std::string_view host, StringMap params);
const std::string name() override static const std::string name()
{ {
return "Experimental SSH Store with filesystem mounted"; return "Experimental SSH Store with filesystem mounted";
} }
@ -50,12 +50,14 @@ struct MountedSSHStoreConfig : virtual SSHStoreConfig, virtual LocalFSStoreConfi
return {"mounted-ssh-ng"}; return {"mounted-ssh-ng"};
} }
std::string doc() override; static std::string doc();
std::optional<ExperimentalFeature> experimentalFeature() const override static std::optional<ExperimentalFeature> experimentalFeature()
{ {
return ExperimentalFeature::MountedSSHStore; return ExperimentalFeature::MountedSSHStore;
} }
ref<Store> openStore() const override;
}; };
} }

View file

@ -26,32 +26,6 @@
namespace nix { namespace nix {
/**
* About the class hierarchy of the store types:
*
* 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(SubstError, Error);
/** /**
* denotes a permanent build failure * denotes a permanent build failure
@ -97,27 +71,48 @@ struct KeyedBuildResult;
typedef std::map<StorePath, std::optional<ContentAddress>> StorePathCAMap; typedef std::map<StorePath, std::optional<ContentAddress>> StorePathCAMap;
/**
* About the class hierarchy of the store types:
*
* 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 `Setting<T>` (or subclasses
* of it) and inherit the constructors of `StoreConfig`
* (`using StoreConfig::StoreConfig`).
*
* 2. A class `Foo : virtual Store` that contains the
* implementation of the store.
*
* This class is expected to have:
*
* 1. an alias `using Config = FooConfig;`
*
* 2. a constructor `Foo(ref<const Config> params)`.
*
* You can then register the new store using:
*
* ```
* cpp static RegisterStoreImplementation<FooConfig> regStore;
* ```
*/
struct StoreConfig : public StoreDirConfig struct StoreConfig : public StoreDirConfig
{ {
using Params = StoreReference::Params;
using StoreDirConfig::StoreDirConfig; using StoreDirConfig::StoreDirConfig;
StoreConfig() = delete; StoreConfig() = delete;
static StringSet getDefaultSystemFeatures();
virtual ~StoreConfig() { } virtual ~StoreConfig() { }
/** static StringSet getDefaultSystemFeatures();
* The name of this type of store.
*/
virtual const std::string name() = 0;
/** /**
* Documentation for this type of store. * Documentation for this type of store.
*/ */
virtual std::string doc() static std::string doc()
{ {
return ""; return "";
} }
@ -126,15 +121,15 @@ struct StoreConfig : public StoreDirConfig
* An experimental feature this type store is gated, if it is to be * An experimental feature this type store is gated, if it is to be
* experimental. * experimental.
*/ */
virtual std::optional<ExperimentalFeature> experimentalFeature() const static std::optional<ExperimentalFeature> experimentalFeature()
{ {
return std::nullopt; return std::nullopt;
} }
const Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size", Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size",
"Size of the in-memory store path metadata cache."}; "Size of the in-memory store path metadata cache."};
const Setting<bool> isTrusted{this, false, "trusted", Setting<bool> isTrusted{this, false, "trusted",
R"( R"(
Whether paths from this store can be used as substitutes Whether paths from this store can be used as substitutes
even if they are not signed by a key listed in the even if they are not signed by a key listed in the
@ -163,10 +158,38 @@ struct StoreConfig : public StoreDirConfig
{}, {},
// Don't document the machine-specific default value // Don't document the machine-specific default value
false}; false};
/**
* Open a store of the type corresponding to this configuration
* type.
*/
virtual ref<Store> openStore() const = 0;
}; };
class Store : public std::enable_shared_from_this<Store>, public virtual StoreConfig /**
* A Store (client)
*
* This is an interface type allowing for create and read operations on
* a collection of store objects, and also building new store objects
* from `Derivation`s. See the manual for further details.
*
* "client" used is because this is just one view/actor onto an
* underlying resource, which could be an external process (daemon
* server), file system state, etc.
*/
class Store : public std::enable_shared_from_this<Store>, public MixStoreDirMethods
{ {
public:
using Config = StoreConfig;
const Config & config;
/**
* @note Avoid churn, since we used to inherit from `Config`.
*/
operator const Config &() const { return config; }
protected: protected:
struct PathInfoCacheValue { struct PathInfoCacheValue {
@ -205,7 +228,7 @@ protected:
std::shared_ptr<NarInfoDiskCache> diskCache; std::shared_ptr<NarInfoDiskCache> diskCache;
Store(const Params & params); Store(const Store::Config & config);
public: public:
/** /**
@ -877,7 +900,7 @@ ref<Store> openStore(StoreReference && storeURI);
*/ */
ref<Store> openStore(const std::string & uri = settings.storeUri.get(), ref<Store> openStore(const std::string & uri = settings.storeUri.get(),
const Store::Params & extraParams = Store::Params()); const Store::Config::Params & extraParams = Store::Config::Params());
/** /**
@ -888,46 +911,72 @@ std::list<ref<Store>> getDefaultSubstituters();
struct StoreFactory struct StoreFactory
{ {
/**
* Documentation for this type of store.
*/
std::string doc;
/**
* URIs with these schemes should be handled by this factory
*/
StringSet uriSchemes; StringSet uriSchemes;
/**
* An experimental feature this type store is gated, if it is to be
* experimental.
*/
std::optional<ExperimentalFeature> experimentalFeature;
/** /**
* The `authorityPath` parameter is `<authority>/<path>`, or really * The `authorityPath` parameter is `<authority>/<path>`, or really
* whatever comes after `<scheme>://` and before `?<query-params>`. * whatever comes after `<scheme>://` and before `?<query-params>`.
*/ */
std::function<std::shared_ptr<Store> ( std::function<ref<StoreConfig>(
std::string_view scheme, std::string_view scheme, std::string_view authorityPath, const Store::Config::Params & params)>
std::string_view authorityPath, parseConfig;
const Store::Params & params)> create;
std::function<std::shared_ptr<StoreConfig> ()> getConfig; /**
* Just for dumping the defaults. Kind of awkward this exists,
* because it means we cannot require fields to be manually
* specified so easily.
*/
std::function<ref<StoreConfig>()> getConfig;
}; };
struct Implementations struct Implementations
{ {
static std::vector<StoreFactory> & registered(); using Map = std::map<std::string, StoreFactory>;
template<typename T, typename TConfig> static Map & registered();
template<typename TConfig>
static void add() static void add()
{ {
StoreFactory factory{ StoreFactory factory{
.doc = TConfig::doc(),
.uriSchemes = TConfig::uriSchemes(), .uriSchemes = TConfig::uriSchemes(),
.create = .experimentalFeature = TConfig::experimentalFeature(),
.parseConfig =
([](auto scheme, auto uri, auto & params) ([](auto scheme, auto uri, auto & params)
-> std::shared_ptr<Store> -> ref<StoreConfig>
{ return std::make_shared<T>(scheme, uri, params); }), { return make_ref<TConfig>(scheme, uri, params); }),
.getConfig = .getConfig =
([]() ([]() -> ref<StoreConfig>
-> std::shared_ptr<StoreConfig> { return make_ref<TConfig>(Store::Config::Params{}); }),
{ return std::make_shared<TConfig>(StringMap({})); })
}; };
registered().push_back(factory); auto [it, didInsert] = registered().insert({TConfig::name(), std::move(factory)});
if (!didInsert) {
throw Error("Already registred store with name '%s'", it->first);
}
} }
}; };
template<typename T, typename TConfig> template<typename TConfig>
struct RegisterStoreImplementation struct RegisterStoreImplementation
{ {
RegisterStoreImplementation() RegisterStoreImplementation()
{ {
Implementations::add<T, TConfig>(); Implementations::add<TConfig>();
} }
}; };

View file

@ -18,22 +18,18 @@ struct SourcePath;
MakeError(BadStorePath, Error); MakeError(BadStorePath, Error);
MakeError(BadStorePathName, BadStorePath); MakeError(BadStorePathName, BadStorePath);
struct StoreDirConfig : public Config /**
* @todo This should just be part of `StoreDirConfig`. However, it would
* be a huge amount of churn if `Store` didn't have these methods
* anymore, forcing a bunch of code to go from `store.method(...)` to
* `store.config.method(...)`.
*
* So we instead pull out the methods into their own mix-in, so can put
* them directly on the Store too.
*/
struct MixStoreDirMethods
{ {
using Config::Config; const Path & storeDir;
StoreDirConfig() = delete;
virtual ~StoreDirConfig() = default;
const PathSetting storeDir_{this, settings.nixStore,
"store",
R"(
Logical location of the Nix store, usually
`/nix/store`. Note that you can only copy store paths
between stores if they have the same `store` setting.
)"};
const Path storeDir = storeDir_;
// pure methods // pure methods
@ -56,7 +52,7 @@ struct StoreDirConfig : public Config
* 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).
*/ */
std::string showPaths(const StorePathSet & paths); std::string showPaths(const StorePathSet & paths) const;
/** /**
* @return true if *path* is in the Nix store (but not the Nix * @return true if *path* is in the Nix store (but not the Nix
@ -104,4 +100,38 @@ struct StoreDirConfig : public Config
PathFilter & filter = defaultPathFilter) const; PathFilter & filter = defaultPathFilter) const;
}; };
/**
* Need to make this a separate class so I can get the right
* initialization order in the constructor for `StoreDirConfig`.
*/
struct StoreDirConfigItself : Config
{
using Config::Config;
const PathSetting storeDir_{this, settings.nixStore,
"store",
R"(
Logical location of the Nix store, usually
`/nix/store`. Note that you can only copy store paths
between stores if they have the same `store` setting.
)"};
};
/**
* The order of `StoreDirConfigItself` and then `MixStoreDirMethods` is
* very important. This ensures that `StoreDirConfigItself::storeDir_`
* is initialized before we have our one chance (because references are
* immutable) to initialize `MixStoreDirMethods::storeDir`.
*/
struct StoreDirConfig : StoreDirConfigItself, MixStoreDirMethods
{
using Params = std::map<std::string, std::string>;
StoreDirConfig(const Params & params);
StoreDirConfig() = delete;
virtual ~StoreDirConfig() = default;
};
} }

View file

@ -7,7 +7,10 @@
namespace nix { namespace nix {
struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreConfig struct UDSRemoteStoreConfig :
std::enable_shared_from_this<UDSRemoteStoreConfig>,
virtual LocalFSStoreConfig,
virtual RemoteStoreConfig
{ {
// TODO(fzakaria): Delete this constructor once moved over to the factory pattern // TODO(fzakaria): Delete this constructor once moved over to the factory pattern
// outlined in https://github.com/NixOS/nix/issues/10766 // outlined in https://github.com/NixOS/nix/issues/10766
@ -22,9 +25,11 @@ struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreCon
std::string_view authority, std::string_view authority,
const Params & params); const Params & params);
const std::string name() override { return "Local Daemon Store"; } UDSRemoteStoreConfig(const Params & params);
std::string doc() override; static const std::string name() { return "Local Daemon Store"; }
static std::string doc();
/** /**
* The path to the unix domain socket. * The path to the unix domain socket.
@ -34,32 +39,21 @@ struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreCon
*/ */
Path path; Path path;
protected:
static constexpr char const * scheme = "unix";
public:
static StringSet uriSchemes() static StringSet uriSchemes()
{ return {scheme}; } { return {"unix"}; }
ref<Store> openStore() const override;
}; };
class UDSRemoteStore : public virtual UDSRemoteStoreConfig struct UDSRemoteStore :
, public virtual IndirectRootStore virtual IndirectRootStore,
, public virtual RemoteStore virtual RemoteStore
{ {
public: using Config = UDSRemoteStoreConfig;
/** ref<const Config> config;
* @deprecated This is the old API to construct the store.
*/
UDSRemoteStore(const Params & params);
/** UDSRemoteStore(ref<const Config>);
* @param authority is the socket path.
*/
UDSRemoteStore(
std::string_view scheme,
std::string_view authority,
const Params & params);
std::string getUri() override; std::string getUri() override;

View file

@ -38,23 +38,19 @@ struct LegacySSHStore::Connection : public ServeProto::BasicClientConnection
bool good = true; bool good = true;
}; };
LegacySSHStore::LegacySSHStore(
std::string_view scheme, LegacySSHStore::LegacySSHStore(ref<const Config> config)
std::string_view host, : Store{*config}
const Params & params) , config{config}
: StoreConfig(params)
, CommonSSHStoreConfig(scheme, host, params)
, LegacySSHStoreConfig(scheme, host, params)
, Store(params)
, connections(make_ref<Pool<Connection>>( , connections(make_ref<Pool<Connection>>(
std::max(1, (int) maxConnections), std::max(1, (int) config->maxConnections),
[this]() { return openConnection(); }, [this]() { return openConnection(); },
[](const ref<Connection> & r) { return r->good; } [](const ref<Connection> & r) { return r->good; }
)) ))
, master(createSSHMaster( , master(config->createSSHMaster(
// Use SSH master only if using more than 1 connection. // Use SSH master only if using more than 1 connection.
connections->capacity() > 1, connections->capacity() > 1,
logFD)) config->logFD))
{ {
} }
@ -62,16 +58,16 @@ LegacySSHStore::LegacySSHStore(
ref<LegacySSHStore::Connection> LegacySSHStore::openConnection() ref<LegacySSHStore::Connection> LegacySSHStore::openConnection()
{ {
auto conn = make_ref<Connection>(); auto conn = make_ref<Connection>();
Strings command = remoteProgram.get(); Strings command = config->remoteProgram.get();
command.push_back("--serve"); command.push_back("--serve");
command.push_back("--write"); command.push_back("--write");
if (remoteStore.get() != "") { if (config->remoteStore.get() != "") {
command.push_back("--store"); command.push_back("--store");
command.push_back(remoteStore.get()); command.push_back(config->remoteStore.get());
} }
conn->sshConn = master.startCommand(std::move(command), std::list{extraSshArgs}); conn->sshConn = master.startCommand(std::move(command), std::list{config->extraSshArgs});
if (connPipeSize) { if (config->connPipeSize) {
conn->sshConn->trySetBufferSize(*connPipeSize); conn->sshConn->trySetBufferSize(*config->connPipeSize);
} }
conn->to = FdSink(conn->sshConn->in.get()); conn->to = FdSink(conn->sshConn->in.get());
conn->from = FdSource(conn->sshConn->out.get()); conn->from = FdSource(conn->sshConn->out.get());
@ -80,7 +76,7 @@ ref<LegacySSHStore::Connection> LegacySSHStore::openConnection()
TeeSource tee(conn->from, saved); TeeSource tee(conn->from, saved);
try { try {
conn->remoteVersion = ServeProto::BasicClientConnection::handshake( conn->remoteVersion = ServeProto::BasicClientConnection::handshake(
conn->to, tee, SERVE_PROTOCOL_VERSION, host); conn->to, tee, SERVE_PROTOCOL_VERSION, config->host);
} catch (SerialisationError & e) { } catch (SerialisationError & e) {
// in.close(): Don't let the remote block on us not writing. // in.close(): Don't let the remote block on us not writing.
conn->sshConn->in.close(); conn->sshConn->in.close();
@ -89,9 +85,9 @@ ref<LegacySSHStore::Connection> LegacySSHStore::openConnection()
tee.drainInto(nullSink); tee.drainInto(nullSink);
} }
throw Error("'nix-store --serve' protocol mismatch from '%s', got '%s'", throw Error("'nix-store --serve' protocol mismatch from '%s', got '%s'",
host, chomp(saved.s)); config->host, chomp(saved.s));
} catch (EndOfFile & e) { } catch (EndOfFile & e) {
throw Error("cannot connect to '%1%'", host); throw Error("cannot connect to '%1%'", config->host);
} }
return conn; return conn;
@ -100,7 +96,7 @@ ref<LegacySSHStore::Connection> LegacySSHStore::openConnection()
std::string LegacySSHStore::getUri() std::string LegacySSHStore::getUri()
{ {
return *uriSchemes().begin() + "://" + host; return *Config::uriSchemes().begin() + "://" + config->host;
} }
std::map<StorePath, UnkeyedValidPathInfo> LegacySSHStore::queryPathInfosUncached( std::map<StorePath, UnkeyedValidPathInfo> LegacySSHStore::queryPathInfosUncached(
@ -111,7 +107,7 @@ std::map<StorePath, UnkeyedValidPathInfo> LegacySSHStore::queryPathInfosUncached
/* No longer support missing NAR hash */ /* No longer support missing NAR hash */
assert(GET_PROTOCOL_MINOR(conn->remoteVersion) >= 4); assert(GET_PROTOCOL_MINOR(conn->remoteVersion) >= 4);
debug("querying remote host '%s' for info on '%s'", host, concatStringsSep(", ", printStorePathSet(paths))); debug("querying remote host '%s' for info on '%s'", config->host, concatStringsSep(", ", printStorePathSet(paths)));
auto infos = conn->queryPathInfos(*this, paths); auto infos = conn->queryPathInfos(*this, paths);
@ -151,7 +147,7 @@ void LegacySSHStore::queryPathInfoUncached(const StorePath & path,
void LegacySSHStore::addToStore(const ValidPathInfo & info, Source & source, void LegacySSHStore::addToStore(const ValidPathInfo & info, Source & source,
RepairFlag repair, CheckSigsFlag checkSigs) RepairFlag repair, CheckSigsFlag checkSigs)
{ {
debug("adding path '%s' to remote host '%s'", printStorePath(info.path), host); debug("adding path '%s' to remote host '%s'", printStorePath(info.path), config->host);
auto conn(connections->get()); auto conn(connections->get());
@ -178,7 +174,7 @@ void LegacySSHStore::addToStore(const ValidPathInfo & info, Source & source,
conn->to.flush(); conn->to.flush();
if (readInt(conn->from) != 1) if (readInt(conn->from) != 1)
throw Error("failed to add path '%s' to remote host '%s'", printStorePath(info.path), host); throw Error("failed to add path '%s' to remote host '%s'", printStorePath(info.path), config->host);
} else { } else {
@ -390,12 +386,17 @@ LegacySSHStore::ConnectionStats LegacySSHStore::getConnectionStats()
* The legacy ssh protocol doesn't support checking for trusted-user. * The legacy ssh protocol doesn't support checking for trusted-user.
* Try using ssh-ng:// instead if you want to know. * Try using ssh-ng:// instead if you want to know.
*/ */
std::optional<TrustedFlag> isTrustedClient() std::optional<TrustedFlag> LegacySSHStore::isTrustedClient()
{ {
return std::nullopt; return std::nullopt;
} }
static RegisterStoreImplementation<LegacySSHStore, LegacySSHStoreConfig> regLegacySSHStore; ref<Store> LegacySSHStore::Config::openStore() const {
return make_ref<LegacySSHStore>(ref{shared_from_this()});
}
static RegisterStoreImplementation<LegacySSHStore::Config> regLegacySSHStore;
} }

View file

@ -10,9 +10,9 @@ namespace nix {
LocalBinaryCacheStoreConfig::LocalBinaryCacheStoreConfig( LocalBinaryCacheStoreConfig::LocalBinaryCacheStoreConfig(
std::string_view scheme, std::string_view scheme,
PathView binaryCacheDir, PathView binaryCacheDir,
const Params & params) const StoreReference::Params & params)
: StoreConfig(params) : Store::Config{params}
, BinaryCacheStoreConfig(params) , BinaryCacheStoreConfig{params}
, binaryCacheDir(binaryCacheDir) , binaryCacheDir(binaryCacheDir)
{ {
} }
@ -26,29 +26,26 @@ std::string LocalBinaryCacheStoreConfig::doc()
} }
struct LocalBinaryCacheStore : virtual LocalBinaryCacheStoreConfig, virtual BinaryCacheStore struct LocalBinaryCacheStore :
virtual BinaryCacheStore
{ {
/** using Config = LocalBinaryCacheStoreConfig;
* @param binaryCacheDir `file://` is a short-hand for `file:///`
* for now. ref<Config> config;
*/
LocalBinaryCacheStore( LocalBinaryCacheStore(ref<Config> config)
std::string_view scheme, : Store{*config}
PathView binaryCacheDir, , BinaryCacheStore{*config}
const Params & params) , config{config}
: StoreConfig(params)
, BinaryCacheStoreConfig(params)
, LocalBinaryCacheStoreConfig(scheme, binaryCacheDir, params)
, Store(params)
, BinaryCacheStore(params)
{ {
init();
} }
void init() override; void init() override;
std::string getUri() override std::string getUri() override
{ {
return "file://" + binaryCacheDir; return "file://" + config->binaryCacheDir;
} }
protected: protected:
@ -59,7 +56,7 @@ protected:
std::shared_ptr<std::basic_iostream<char>> istream, std::shared_ptr<std::basic_iostream<char>> istream,
const std::string & mimeType) override const std::string & mimeType) override
{ {
auto path2 = binaryCacheDir + "/" + path; auto path2 = config->binaryCacheDir + "/" + path;
static std::atomic<int> counter{0}; static std::atomic<int> counter{0};
Path tmp = fmt("%s.tmp.%d.%d", path2, getpid(), ++counter); Path tmp = fmt("%s.tmp.%d.%d", path2, getpid(), ++counter);
AutoDelete del(tmp, false); AutoDelete del(tmp, false);
@ -72,7 +69,7 @@ protected:
void getFile(const std::string & path, Sink & sink) override void getFile(const std::string & path, Sink & sink) override
{ {
try { try {
readFile(binaryCacheDir + "/" + path, sink); readFile(config->binaryCacheDir + "/" + path, sink);
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo == ENOENT) if (e.errNo == ENOENT)
throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache", path); throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache", path);
@ -84,7 +81,7 @@ protected:
{ {
StorePathSet paths; StorePathSet paths;
for (auto & entry : DirectoryIterator{binaryCacheDir}) { for (auto & entry : DirectoryIterator{config->binaryCacheDir}) {
checkInterrupt(); checkInterrupt();
auto name = entry.path().filename().string(); auto name = entry.path().filename().string();
if (name.size() != 40 || if (name.size() != 40 ||
@ -106,17 +103,17 @@ protected:
void LocalBinaryCacheStore::init() void LocalBinaryCacheStore::init()
{ {
createDirs(binaryCacheDir + "/nar"); createDirs(config->binaryCacheDir + "/nar");
createDirs(binaryCacheDir + "/" + realisationsPrefix); createDirs(config->binaryCacheDir + "/" + realisationsPrefix);
if (writeDebugInfo) if (config->writeDebugInfo)
createDirs(binaryCacheDir + "/debuginfo"); createDirs(config->binaryCacheDir + "/debuginfo");
createDirs(binaryCacheDir + "/log"); createDirs(config->binaryCacheDir + "/log");
BinaryCacheStore::init(); BinaryCacheStore::init();
} }
bool LocalBinaryCacheStore::fileExists(const std::string & path) bool LocalBinaryCacheStore::fileExists(const std::string & path)
{ {
return pathExists(binaryCacheDir + "/" + path); return pathExists(config->binaryCacheDir + "/" + path);
} }
StringSet LocalBinaryCacheStoreConfig::uriSchemes() StringSet LocalBinaryCacheStoreConfig::uriSchemes()
@ -127,6 +124,13 @@ StringSet LocalBinaryCacheStoreConfig::uriSchemes()
return {"file"}; return {"file"};
} }
static RegisterStoreImplementation<LocalBinaryCacheStore, LocalBinaryCacheStoreConfig> regLocalBinaryCacheStore; ref<Store> LocalBinaryCacheStoreConfig::openStore() const {
return make_ref<LocalBinaryCacheStore>(ref{
// FIXME we shouldn't actually need a mutable config
std::const_pointer_cast<LocalBinaryCacheStore::Config>(shared_from_this())
});
}
static RegisterStoreImplementation<LocalBinaryCacheStore::Config> regLocalBinaryCacheStore;
} }

View file

@ -22,8 +22,9 @@ LocalFSStoreConfig::LocalFSStoreConfig(PathView rootDir, const Params & params)
{ {
} }
LocalFSStore::LocalFSStore(const Params & params) LocalFSStore::LocalFSStore(const Config & config)
: Store(params) : Store{static_cast<const Store::Config &>(*this)}
, config{config}
{ {
} }
@ -33,7 +34,7 @@ struct LocalStoreAccessor : PosixSourceAccessor
bool requireValidPath; bool requireValidPath;
LocalStoreAccessor(ref<LocalFSStore> store, bool requireValidPath) LocalStoreAccessor(ref<LocalFSStore> store, bool requireValidPath)
: PosixSourceAccessor(std::filesystem::path{store->realStoreDir.get()}) : PosixSourceAccessor(std::filesystem::path{store->config.realStoreDir.get()})
, store(store) , store(store)
, requireValidPath(requireValidPath) , requireValidPath(requireValidPath)
{ {
@ -104,8 +105,8 @@ std::optional<std::string> LocalFSStore::getBuildLogExact(const StorePath & path
Path logPath = Path logPath =
j == 0 j == 0
? fmt("%s/%s/%s/%s", logDir, drvsLogDir, baseName.substr(0, 2), baseName.substr(2)) ? fmt("%s/%s/%s/%s", config.logDir.get(), drvsLogDir, baseName.substr(0, 2), baseName.substr(2))
: fmt("%s/%s/%s", logDir, drvsLogDir, baseName); : fmt("%s/%s/%s", config.logDir.get(), drvsLogDir, baseName);
Path logBz2Path = logPath + ".bz2"; Path logBz2Path = logPath + ".bz2";
if (pathExists(logPath)) if (pathExists(logPath))

View file

@ -14,25 +14,32 @@ std::string LocalOverlayStoreConfig::doc()
; ;
} }
Path LocalOverlayStoreConfig::toUpperPath(const StorePath & path) { ref<Store> LocalOverlayStoreConfig::openStore() const
{
return make_ref<LocalOverlayStore>(ref{
std::dynamic_pointer_cast<const LocalOverlayStoreConfig>(shared_from_this())
});
}
Path LocalOverlayStoreConfig::toUpperPath(const StorePath & path) const
{
return upperLayer + "/" + path.to_string(); return upperLayer + "/" + path.to_string();
} }
LocalOverlayStore::LocalOverlayStore(std::string_view scheme, PathView path, const Params & params)
: StoreConfig(params) LocalOverlayStore::LocalOverlayStore(ref<const Config> config)
, LocalFSStoreConfig(path, params) : Store{*config}
, LocalStoreConfig(params) , LocalFSStore{*config}
, LocalOverlayStoreConfig(scheme, path, params) , LocalStore{static_cast<ref<const LocalStore::Config>>(config)}
, Store(params) , config{config}
, LocalFSStore(params) , lowerStore(openStore(percentDecode(config->lowerStoreUri.get())).dynamic_pointer_cast<LocalFSStore>())
, LocalStore(params)
, lowerStore(openStore(percentDecode(lowerStoreUri.get())).dynamic_pointer_cast<LocalFSStore>())
{ {
if (checkMount.get()) { if (config->checkMount.get()) {
std::smatch match; std::smatch match;
std::string mountInfo; std::string mountInfo;
auto mounts = readFile(std::filesystem::path{"/proc/self/mounts"}); auto mounts = readFile(std::filesystem::path{"/proc/self/mounts"});
auto regex = std::regex(R"((^|\n)overlay )" + realStoreDir.get() + R"( .*(\n|$))"); auto regex = std::regex(R"((^|\n)overlay )" + config->realStoreDir.get() + R"( .*(\n|$))");
// Mount points can be stacked, so there might be multiple matching entries. // Mount points can be stacked, so there might be multiple matching entries.
// Loop until the last match, which will be the current state of the mount point. // Loop until the last match, which will be the current state of the mount point.
@ -45,13 +52,13 @@ LocalOverlayStore::LocalOverlayStore(std::string_view scheme, PathView path, con
return std::regex_search(mountInfo, std::regex("\\b" + option + "=" + value + "( |,)")); return std::regex_search(mountInfo, std::regex("\\b" + option + "=" + value + "( |,)"));
}; };
auto expectedLowerDir = lowerStore->realStoreDir.get(); auto expectedLowerDir = lowerStore->config.realStoreDir.get();
if (!checkOption("lowerdir", expectedLowerDir) || !checkOption("upperdir", upperLayer)) { if (!checkOption("lowerdir", expectedLowerDir) || !checkOption("upperdir", config->upperLayer)) {
debug("expected lowerdir: %s", expectedLowerDir); debug("expected lowerdir: %s", expectedLowerDir);
debug("expected upperdir: %s", upperLayer); debug("expected upperdir: %s", config->upperLayer);
debug("actual mount: %s", mountInfo); debug("actual mount: %s", mountInfo);
throw Error("overlay filesystem '%s' mounted incorrectly", throw Error("overlay filesystem '%s' mounted incorrectly",
realStoreDir.get()); config->realStoreDir.get());
} }
} }
} }
@ -201,14 +208,14 @@ void LocalOverlayStore::collectGarbage(const GCOptions & options, GCResults & re
void LocalOverlayStore::deleteStorePath(const Path & path, uint64_t & bytesFreed) void LocalOverlayStore::deleteStorePath(const Path & path, uint64_t & bytesFreed)
{ {
auto mergedDir = realStoreDir.get() + "/"; auto mergedDir = config->realStoreDir.get() + "/";
if (path.substr(0, mergedDir.length()) != mergedDir) { if (path.substr(0, mergedDir.length()) != mergedDir) {
warn("local-overlay: unexpected gc path '%s' ", path); warn("local-overlay: unexpected gc path '%s' ", path);
return; return;
} }
StorePath storePath = {path.substr(mergedDir.length())}; StorePath storePath = {path.substr(mergedDir.length())};
auto upperPath = toUpperPath(storePath); auto upperPath = config->toUpperPath(storePath);
if (pathExists(upperPath)) { if (pathExists(upperPath)) {
debug("upper exists: %s", path); debug("upper exists: %s", path);
@ -257,7 +264,7 @@ LocalStore::VerificationResult LocalOverlayStore::verifyAllValidPaths(RepairFlag
StorePathSet done; StorePathSet done;
auto existsInStoreDir = [&](const StorePath & storePath) { auto existsInStoreDir = [&](const StorePath & storePath) {
return pathExists(realStoreDir.get() + "/" + storePath.to_string()); return pathExists(config->realStoreDir.get() + "/" + storePath.to_string());
}; };
bool errors = false; bool errors = false;
@ -277,16 +284,16 @@ void LocalOverlayStore::remountIfNecessary()
{ {
if (!_remountRequired) return; if (!_remountRequired) return;
if (remountHook.get().empty()) { if (config->remountHook.get().empty()) {
warn("'%s' needs remounting, set remount-hook to do this automatically", realStoreDir.get()); warn("'%s' needs remounting, set remount-hook to do this automatically", config->realStoreDir.get());
} else { } else {
runProgram(remountHook, false, {realStoreDir}); runProgram(config->remountHook, false, {config->realStoreDir});
} }
_remountRequired = false; _remountRequired = false;
} }
static RegisterStoreImplementation<LocalOverlayStore, LocalOverlayStoreConfig> regLocalOverlayStore; static RegisterStoreImplementation<LocalOverlayStore::Config> regLocalOverlayStore;
} }

View file

@ -75,6 +75,11 @@ std::string LocalStoreConfig::doc()
; ;
} }
ref<Store> LocalStore::Config::openStore() const
{
return make_ref<LocalStore>(ref{shared_from_this()});
}
struct LocalStore::State::Stmts { struct LocalStore::State::Stmts {
/* Some precompiled SQLite statements. */ /* Some precompiled SQLite statements. */
SQLiteStmt RegisterValidPath; SQLiteStmt RegisterValidPath;
@ -97,38 +102,33 @@ struct LocalStore::State::Stmts {
SQLiteStmt AddRealisationReference; SQLiteStmt AddRealisationReference;
}; };
LocalStore::LocalStore( LocalStore::LocalStore(ref<const Config> config)
std::string_view scheme, : Store{*config}
PathView path, , LocalFSStore{*config}
const Params & params) , config{config}
: StoreConfig(params) , dbDir(config->stateDir + "/db")
, LocalFSStoreConfig(path, params) , linksDir(config->realStoreDir + "/.links")
, LocalStoreConfig(scheme, path, params)
, Store(params)
, LocalFSStore(params)
, dbDir(stateDir + "/db")
, linksDir(realStoreDir + "/.links")
, reservedPath(dbDir + "/reserved") , reservedPath(dbDir + "/reserved")
, schemaPath(dbDir + "/schema") , schemaPath(dbDir + "/schema")
, tempRootsDir(stateDir + "/temproots") , tempRootsDir(config->stateDir + "/temproots")
, fnTempRoots(fmt("%s/%d", tempRootsDir, getpid())) , fnTempRoots(fmt("%s/%d", tempRootsDir, getpid()))
{ {
auto state(_state.lock()); auto state(_state.lock());
state->stmts = std::make_unique<State::Stmts>(); state->stmts = std::make_unique<State::Stmts>();
/* Create missing state directories if they don't already exist. */ /* Create missing state directories if they don't already exist. */
createDirs(realStoreDir.get()); createDirs(config->realStoreDir.get());
if (readOnly) { if (config->readOnly) {
experimentalFeatureSettings.require(Xp::ReadOnlyLocalStore); experimentalFeatureSettings.require(Xp::ReadOnlyLocalStore);
} else { } else {
makeStoreWritable(); makeStoreWritable();
} }
createDirs(linksDir); createDirs(linksDir);
Path profilesDir = stateDir + "/profiles"; Path profilesDir = config->stateDir + "/profiles";
createDirs(profilesDir); createDirs(profilesDir);
createDirs(tempRootsDir); createDirs(tempRootsDir);
createDirs(dbDir); createDirs(dbDir);
Path gcRootsDir = stateDir + "/gcroots"; Path gcRootsDir = config->stateDir + "/gcroots";
if (!pathExists(gcRootsDir)) { if (!pathExists(gcRootsDir)) {
createDirs(gcRootsDir); createDirs(gcRootsDir);
createSymlink(profilesDir, gcRootsDir + "/profiles"); createSymlink(profilesDir, gcRootsDir + "/profiles");
@ -136,7 +136,7 @@ LocalStore::LocalStore(
for (auto & perUserDir : {profilesDir + "/per-user", gcRootsDir + "/per-user"}) { for (auto & perUserDir : {profilesDir + "/per-user", gcRootsDir + "/per-user"}) {
createDirs(perUserDir); createDirs(perUserDir);
if (!readOnly) { if (!config->readOnly) {
// Skip chmod call if the directory already has the correct permissions (0755). // Skip chmod call if the directory already has the correct permissions (0755).
// This is to avoid failing when the executing user lacks permissions to change the directory's permissions // This is to avoid failing when the executing user lacks permissions to change the directory's permissions
// even if it would be no-op. // even if it would be no-op.
@ -153,16 +153,16 @@ LocalStore::LocalStore(
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
if (!gr) if (!gr)
printError("warning: the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup); printError("warning: the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup);
else if (!readOnly) { else if (!config->readOnly) {
struct stat st; struct stat st;
if (stat(realStoreDir.get().c_str(), &st)) if (stat(config->realStoreDir.get().c_str(), &st))
throw SysError("getting attributes of path '%1%'", realStoreDir); throw SysError("getting attributes of path '%1%'", config->realStoreDir);
if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) { if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) {
if (chown(realStoreDir.get().c_str(), 0, gr->gr_gid) == -1) if (chown(config->realStoreDir.get().c_str(), 0, gr->gr_gid) == -1)
throw SysError("changing ownership of path '%1%'", realStoreDir); throw SysError("changing ownership of path '%1%'", config->realStoreDir);
if (chmod(realStoreDir.get().c_str(), perm) == -1) if (chmod(config->realStoreDir.get().c_str(), perm) == -1)
throw SysError("changing permissions on path '%1%'", realStoreDir); throw SysError("changing permissions on path '%1%'", config->realStoreDir);
} }
} }
} }
@ -170,7 +170,7 @@ LocalStore::LocalStore(
/* Ensure that the store and its parents are not symlinks. */ /* Ensure that the store and its parents are not symlinks. */
if (!settings.allowSymlinkedStore) { if (!settings.allowSymlinkedStore) {
std::filesystem::path path = realStoreDir.get(); std::filesystem::path path = config->realStoreDir.get();
std::filesystem::path root = path.root_path(); std::filesystem::path root = path.root_path();
while (path != root) { while (path != root) {
if (std::filesystem::is_symlink(path)) if (std::filesystem::is_symlink(path))
@ -217,12 +217,12 @@ LocalStore::LocalStore(
/* Acquire the big fat lock in shared mode to make sure that no /* Acquire the big fat lock in shared mode to make sure that no
schema upgrade is in progress. */ schema upgrade is in progress. */
if (!readOnly) { if (!config->readOnly) {
Path globalLockPath = dbDir + "/big-lock"; Path globalLockPath = dbDir + "/big-lock";
globalLock = openLockFile(globalLockPath.c_str(), true); globalLock = openLockFile(globalLockPath.c_str(), true);
} }
if (!readOnly && !lockFile(globalLock.get(), ltRead, false)) { if (!config->readOnly && !lockFile(globalLock.get(), ltRead, false)) {
printInfo("waiting for the big Nix store lock..."); printInfo("waiting for the big Nix store lock...");
lockFile(globalLock.get(), ltRead, true); lockFile(globalLock.get(), ltRead, true);
} }
@ -230,7 +230,7 @@ LocalStore::LocalStore(
/* Check the current database schema and if necessary do an /* Check the current database schema and if necessary do an
upgrade. */ upgrade. */
int curSchema = getSchema(); int curSchema = getSchema();
if (readOnly && curSchema < nixSchemaVersion) { if (config->readOnly && curSchema < nixSchemaVersion) {
debug("current schema version: %d", curSchema); debug("current schema version: %d", curSchema);
debug("supported schema version: %d", nixSchemaVersion); debug("supported schema version: %d", nixSchemaVersion);
throw Error(curSchema == 0 ? throw Error(curSchema == 0 ?
@ -378,15 +378,9 @@ LocalStore::LocalStore(
} }
LocalStore::LocalStore(const Params & params)
: LocalStore("local", "", params)
{
}
AutoCloseFD LocalStore::openGCLock() AutoCloseFD LocalStore::openGCLock()
{ {
Path fnGCLock = stateDir + "/gc.lock"; Path fnGCLock = config->stateDir + "/gc.lock";
auto fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT auto fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT
#ifndef _WIN32 #ifndef _WIN32
| O_CLOEXEC | O_CLOEXEC
@ -452,17 +446,17 @@ int LocalStore::getSchema()
void LocalStore::openDB(State & state, bool create) void LocalStore::openDB(State & state, bool create)
{ {
if (create && readOnly) { if (create && config->readOnly) {
throw Error("cannot create database while in read-only mode"); throw Error("cannot create database while in read-only mode");
} }
if (access(dbDir.c_str(), R_OK | (readOnly ? 0 : W_OK))) if (access(dbDir.c_str(), R_OK | (config->readOnly ? 0 : W_OK)))
throw SysError("Nix database directory '%1%' is not writable", dbDir); throw SysError("Nix database directory '%1%' is not writable", dbDir);
/* Open the Nix database. */ /* Open the Nix database. */
std::string dbPath = dbDir + "/db.sqlite"; std::string dbPath = dbDir + "/db.sqlite";
auto & db(state.db); auto & db(state.db);
auto openMode = readOnly ? SQLiteOpenMode::Immutable auto openMode = config->readOnly ? SQLiteOpenMode::Immutable
: create ? SQLiteOpenMode::Normal : create ? SQLiteOpenMode::Normal
: SQLiteOpenMode::NoCreate; : SQLiteOpenMode::NoCreate;
state.db = SQLite(dbPath, openMode); state.db = SQLite(dbPath, openMode);
@ -575,12 +569,12 @@ void LocalStore::makeStoreWritable()
if (!isRootUser()) return; if (!isRootUser()) return;
/* Check if /nix/store is on a read-only mount. */ /* Check if /nix/store is on a read-only mount. */
struct statvfs stat; struct statvfs stat;
if (statvfs(realStoreDir.get().c_str(), &stat) != 0) if (statvfs(config->realStoreDir.get().c_str(), &stat) != 0)
throw SysError("getting info about the Nix store mount point"); throw SysError("getting info about the Nix store mount point");
if (stat.f_flag & ST_RDONLY) { if (stat.f_flag & ST_RDONLY) {
if (mount(0, realStoreDir.get().c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1) if (mount(0, config->realStoreDir.get().c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
throw SysError("remounting %1% writable", realStoreDir); throw SysError("remounting %1% writable", config->realStoreDir);
} }
#endif #endif
} }
@ -920,7 +914,7 @@ StorePathSet LocalStore::querySubstitutablePaths(const StorePathSet & paths)
for (auto & sub : getDefaultSubstituters()) { for (auto & sub : getDefaultSubstituters()) {
if (remaining.empty()) break; if (remaining.empty()) break;
if (sub->storeDir != storeDir) continue; if (sub->storeDir != storeDir) continue;
if (!sub->wantMassQuery) continue; if (!sub->config.wantMassQuery) continue;
auto valid = sub->queryValidPaths(remaining); auto valid = sub->queryValidPaths(remaining);
@ -1032,12 +1026,12 @@ const PublicKeys & LocalStore::getPublicKeys()
bool LocalStore::pathInfoIsUntrusted(const ValidPathInfo & info) bool LocalStore::pathInfoIsUntrusted(const ValidPathInfo & info)
{ {
return requireSigs && !info.checkSignatures(*this, getPublicKeys()); return config->requireSigs && !info.checkSignatures(*this, getPublicKeys());
} }
bool LocalStore::realisationIsUntrusted(const Realisation & realisation) bool LocalStore::realisationIsUntrusted(const Realisation & realisation)
{ {
return requireSigs && !realisation.checkSignatures(getPublicKeys()); return config->requireSigs && !realisation.checkSignatures(getPublicKeys());
} }
void LocalStore::addToStore(const ValidPathInfo & info, Source & source, void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
@ -1334,7 +1328,7 @@ std::pair<std::filesystem::path, AutoCloseFD> LocalStore::createTempDirInStore()
/* There is a slight possibility that `tmpDir' gets deleted by /* There is a slight possibility that `tmpDir' gets deleted by
the GC between createTempDir() and when we acquire a lock on it. the GC between createTempDir() and when we acquire a lock on it.
We'll repeat until 'tmpDir' exists and we've locked it. */ We'll repeat until 'tmpDir' exists and we've locked it. */
tmpDirFn = createTempDir(realStoreDir, "tmp"); tmpDirFn = createTempDir(config->realStoreDir, "tmp");
tmpDirFd = openDirectory(tmpDirFn); tmpDirFd = openDirectory(tmpDirFn);
if (!tmpDirFd) { if (!tmpDirFd) {
continue; continue;
@ -1475,7 +1469,7 @@ LocalStore::VerificationResult LocalStore::verifyAllValidPaths(RepairFlag repair
database and the filesystem) in the loop below, in order to catch database and the filesystem) in the loop below, in order to catch
invalid states. invalid states.
*/ */
for (auto & i : DirectoryIterator{realStoreDir.to_string()}) { for (auto & i : DirectoryIterator{config->realStoreDir.get()}) {
checkInterrupt(); checkInterrupt();
try { try {
storePathsInStoreDir.insert({i.path().filename().string()}); storePathsInStoreDir.insert({i.path().filename().string()});
@ -1664,7 +1658,7 @@ void LocalStore::addBuildLog(const StorePath & drvPath, std::string_view log)
auto baseName = drvPath.to_string(); auto baseName = drvPath.to_string();
auto logPath = fmt("%s/%s/%s/%s.bz2", logDir, drvsLogDir, baseName.substr(0, 2), baseName.substr(2)); auto logPath = fmt("%s/%s/%s/%s.bz2", config->logDir, drvsLogDir, baseName.substr(0, 2), baseName.substr(2));
if (pathExists(logPath)) return; if (pathExists(logPath)) return;
@ -1682,6 +1676,6 @@ std::optional<std::string> LocalStore::getVersion()
return nixVersion; return nixVersion;
} }
static RegisterStoreImplementation<LocalStore, LocalStoreConfig> regLocalStore; static RegisterStoreImplementation<LocalStore::Config> regLocalStore;
} // namespace nix } // namespace nix

View file

@ -313,6 +313,7 @@ sources = files(
'ssh-store.cc', 'ssh-store.cc',
'ssh.cc', 'ssh.cc',
'store-api.cc', 'store-api.cc',
'store-dir-config.cc',
'store-reference.cc', 'store-reference.cc',
'uds-remote-store.cc', 'uds-remote-store.cc',
'worker-protocol-connection.cc', 'worker-protocol-connection.cc',

View file

@ -101,7 +101,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
/* HFS/macOS has some undocumented security feature disabling hardlinking for /* HFS/macOS has some undocumented security feature disabling hardlinking for
special files within .app dirs. Known affected paths include special files within .app dirs. Known affected paths include
*.app/Contents/{PkgInfo,Resources/\*.lproj,_CodeSignature} and .DS_Store. *.app/Contents/{PkgInfo,Resources/\*.lproj,_CodeSignature} and .DS_Store.
See https://github.com/NixOS/nix/issues/1443 and See https://github.com/NixOS/nix/issues/1443 and
https://github.com/NixOS/nix/pull/2230 for more discussion. */ https://github.com/NixOS/nix/pull/2230 for more discussion. */
if (std::regex_search(path, std::regex("\\.app/Contents/.+$"))) if (std::regex_search(path, std::regex("\\.app/Contents/.+$")))
@ -216,14 +216,14 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
the store itself (we don't want or need to mess with its the store itself (we don't want or need to mess with its
permissions). */ permissions). */
const Path dirOfPath(dirOf(path)); const Path dirOfPath(dirOf(path));
bool mustToggle = dirOfPath != realStoreDir.get(); bool mustToggle = dirOfPath != config->realStoreDir.get();
if (mustToggle) makeWritable(dirOfPath); if (mustToggle) makeWritable(dirOfPath);
/* When we're done, make the directory read-only again and reset /* When we're done, make the directory read-only again and reset
its timestamp back to 0. */ its timestamp back to 0. */
MakeReadOnly makeReadOnly(mustToggle ? dirOfPath : ""); MakeReadOnly makeReadOnly(mustToggle ? dirOfPath : "");
std::filesystem::path tempLink = fmt("%1%/.tmp-link-%2%-%3%", realStoreDir, getpid(), rand()); std::filesystem::path tempLink = fmt("%1%/.tmp-link-%2%-%3%", config->realStoreDir, getpid(), rand());
try { try {
std::filesystem::create_hard_link(linkPath, tempLink); std::filesystem::create_hard_link(linkPath, tempLink);
@ -285,7 +285,7 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
if (!isValidPath(i)) continue; /* path was GC'ed, probably */ if (!isValidPath(i)) continue; /* path was GC'ed, probably */
{ {
Activity act(*logger, lvlTalkative, actUnknown, fmt("optimising path '%s'", printStorePath(i))); Activity act(*logger, lvlTalkative, actUnknown, fmt("optimising path '%s'", printStorePath(i)));
optimisePath_(&act, stats, realStoreDir + "/" + std::string(i.to_string()), inodeHash, NoRepair); optimisePath_(&act, stats, config->realStoreDir + "/" + std::string(i.to_string()), inodeHash, NoRepair);
} }
done++; done++;
act.progress(done, paths.size()); act.progress(done, paths.size());

View file

@ -75,7 +75,7 @@ StorePath StorePath::random(std::string_view name)
return StorePath(Hash::random(HashAlgorithm::SHA1), name); return StorePath(Hash::random(HashAlgorithm::SHA1), name);
} }
StorePath StoreDirConfig::parseStorePath(std::string_view path) const StorePath MixStoreDirMethods::parseStorePath(std::string_view path) const
{ {
// On Windows, `/nix/store` is not a canonical path. More broadly it // On Windows, `/nix/store` is not a canonical path. More broadly it
// is unclear whether this function should be using the native // is unclear whether this function should be using the native
@ -94,7 +94,7 @@ StorePath StoreDirConfig::parseStorePath(std::string_view path) const
return StorePath(baseNameOf(p)); return StorePath(baseNameOf(p));
} }
std::optional<StorePath> StoreDirConfig::maybeParseStorePath(std::string_view path) const std::optional<StorePath> MixStoreDirMethods::maybeParseStorePath(std::string_view path) const
{ {
try { try {
return parseStorePath(path); return parseStorePath(path);
@ -103,24 +103,24 @@ std::optional<StorePath> StoreDirConfig::maybeParseStorePath(std::string_view pa
} }
} }
bool StoreDirConfig::isStorePath(std::string_view path) const bool MixStoreDirMethods::isStorePath(std::string_view path) const
{ {
return (bool) maybeParseStorePath(path); return (bool) maybeParseStorePath(path);
} }
StorePathSet StoreDirConfig::parseStorePathSet(const PathSet & paths) const StorePathSet MixStoreDirMethods::parseStorePathSet(const PathSet & paths) const
{ {
StorePathSet res; StorePathSet res;
for (auto & i : paths) res.insert(parseStorePath(i)); for (auto & i : paths) res.insert(parseStorePath(i));
return res; return res;
} }
std::string StoreDirConfig::printStorePath(const StorePath & path) const std::string MixStoreDirMethods::printStorePath(const StorePath & path) const
{ {
return (storeDir + "/").append(path.to_string()); return (storeDir + "/").append(path.to_string());
} }
PathSet StoreDirConfig::printStorePathSet(const StorePathSet & paths) const PathSet MixStoreDirMethods::printStorePathSet(const StorePathSet & paths) const
{ {
PathSet res; PathSet res;
for (auto & i : paths) res.insert(printStorePath(i)); for (auto & i : paths) res.insert(printStorePath(i));

View file

@ -24,11 +24,11 @@
namespace nix { namespace nix {
/* TODO: Separate these store types into different files, give them better names */ /* TODO: Separate these store types into different files, give them better names */
RemoteStore::RemoteStore(const Params & params) RemoteStore::RemoteStore(const Config & config)
: RemoteStoreConfig(params) : Store{config}
, Store(params) , config{config}
, connections(make_ref<Pool<Connection>>( , connections(make_ref<Pool<Connection>>(
std::max(1, maxConnections.get()), std::max(1, config.maxConnections.get()),
[this]() { [this]() {
auto conn = openConnectionWrapper(); auto conn = openConnectionWrapper();
try { try {
@ -44,7 +44,7 @@ RemoteStore::RemoteStore(const Params & params)
r->to.good() r->to.good()
&& r->from.good() && r->from.good()
&& std::chrono::duration_cast<std::chrono::seconds>( && std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::steady_clock::now() - r->startTime).count() < maxConnectionAge; std::chrono::steady_clock::now() - r->startTime).count() < this->config.maxConnectionAge;
} }
)) ))
{ {
@ -122,7 +122,7 @@ void RemoteStore::setOptions(Connection & conn)
<< settings.useSubstitutes; << settings.useSubstitutes;
if (GET_PROTOCOL_MINOR(conn.protoVersion) >= 12) { if (GET_PROTOCOL_MINOR(conn.protoVersion) >= 12) {
std::map<std::string, Config::SettingInfo> overrides; std::map<std::string, nix::Config::SettingInfo> overrides;
settings.getSettings(overrides, true); // libstore settings settings.getSettings(overrides, true); // libstore settings
fileTransferSettings.getSettings(overrides, true); fileTransferSettings.getSettings(overrides, true);
overrides.erase(settings.keepFailed.name); overrides.erase(settings.keepFailed.name);

View file

@ -30,32 +30,23 @@ bool RestrictionContext::isAllowed(const DerivedPath & req)
return isAllowed(pathPartOfReq(req)); return isAllowed(pathPartOfReq(req));
} }
struct RestrictedStoreConfig : virtual LocalFSStoreConfig
{
using LocalFSStoreConfig::LocalFSStoreConfig;
const std::string name() override
{
return "Restricted Store";
}
};
/** /**
* A wrapper around LocalStore that only allows building/querying of * A wrapper around LocalStore that only allows building/querying of
* paths that are in the input closures of the build or were added via * paths that are in the input closures of the build or were added via
* recursive Nix calls. * recursive Nix calls.
*/ */
struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual IndirectRootStore, public virtual GcStore struct RestrictedStore : public virtual IndirectRootStore, public virtual GcStore
{ {
ref<const LocalStore::Config> config;
ref<LocalStore> next; ref<LocalStore> next;
RestrictionContext & goal; RestrictionContext & goal;
RestrictedStore(const Params & params, ref<LocalStore> next, RestrictionContext & goal) RestrictedStore(ref<LocalStore::Config> config, ref<LocalStore> next, RestrictionContext & goal)
: StoreConfig(params) : Store{*config}
, LocalFSStoreConfig(params) , LocalFSStore{*config}
, RestrictedStoreConfig(params) , config{config}
, Store(params)
, LocalFSStore(params)
, next(next) , next(next)
, goal(goal) , goal(goal)
{ {
@ -63,7 +54,7 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual In
Path getRealStoreDir() override Path getRealStoreDir() override
{ {
return next->realStoreDir; return next->config->realStoreDir;
} }
std::string getUri() override std::string getUri() override
@ -176,9 +167,9 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual In
} }
}; };
ref<Store> makeRestrictedStore(const Store::Params & params, ref<LocalStore> next, RestrictionContext & context) ref<Store> makeRestrictedStore(ref<LocalStore::Config> config, ref<LocalStore> next, RestrictionContext & context)
{ {
return make_ref<RestrictedStore>(params, next, context); return make_ref<RestrictedStore>(config, next, context);
} }
StorePathSet RestrictedStore::queryAllValidPaths() StorePathSet RestrictedStore::queryAllValidPaths()

View file

@ -235,11 +235,6 @@ S3Helper::FileTransferResult S3Helper::getObject(
return res; return res;
} }
S3BinaryCacheStore::S3BinaryCacheStore(const Params & params)
: BinaryCacheStoreConfig(params)
, BinaryCacheStore(params)
{ }
S3BinaryCacheStoreConfig::S3BinaryCacheStoreConfig( S3BinaryCacheStoreConfig::S3BinaryCacheStoreConfig(
std::string_view uriScheme, std::string_view uriScheme,
@ -258,6 +253,12 @@ S3BinaryCacheStoreConfig::S3BinaryCacheStoreConfig(
throw UsageError("`%s` store requires a bucket name in its Store URI", uriScheme); throw UsageError("`%s` store requires a bucket name in its Store URI", uriScheme);
} }
S3BinaryCacheStore::S3BinaryCacheStore(ref<Config> config)
: BinaryCacheStore(*config)
, config{config}
{ }
std::string S3BinaryCacheStoreConfig::doc() std::string S3BinaryCacheStoreConfig::doc()
{ {
return return
@ -266,40 +267,37 @@ std::string S3BinaryCacheStoreConfig::doc()
} }
struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual S3BinaryCacheStore struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStore
{ {
Stats stats; Stats stats;
S3Helper s3Helper; S3Helper s3Helper;
S3BinaryCacheStoreImpl( S3BinaryCacheStoreImpl(ref<Config> config)
std::string_view uriScheme, : Store{*config}
std::string_view bucketName, , BinaryCacheStore{*config}
const Params & params) , S3BinaryCacheStore{config}
: StoreConfig(params) , s3Helper(config->profile, config->region, config->scheme, config->endpoint)
, BinaryCacheStoreConfig(params)
, S3BinaryCacheStoreConfig(uriScheme, bucketName, params)
, Store(params)
, BinaryCacheStore(params)
, S3BinaryCacheStore(params)
, s3Helper(profile, region, scheme, endpoint)
{ {
diskCache = getNarInfoDiskCache(); diskCache = getNarInfoDiskCache();
init();
} }
std::string getUri() override std::string getUri() override
{ {
return "s3://" + bucketName; return "s3://" + config->bucketName;
} }
void init() override void init() override
{ {
if (auto cacheInfo = diskCache->upToDateCacheExists(getUri())) { if (auto cacheInfo = diskCache->upToDateCacheExists(getUri())) {
wantMassQuery.setDefault(cacheInfo->wantMassQuery); config->wantMassQuery.setDefault(cacheInfo->wantMassQuery);
priority.setDefault(cacheInfo->priority); config->priority.setDefault(cacheInfo->priority);
} else { } else {
BinaryCacheStore::init(); BinaryCacheStore::init();
diskCache->createCache(getUri(), storeDir, wantMassQuery, priority); diskCache->createCache(
getUri(), config->storeDir, config->wantMassQuery, config->priority);
} }
} }
@ -328,7 +326,7 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
auto res = s3Helper.client->HeadObject( auto res = s3Helper.client->HeadObject(
Aws::S3::Model::HeadObjectRequest() Aws::S3::Model::HeadObjectRequest()
.WithBucket(bucketName) .WithBucket(config->bucketName)
.WithKey(path)); .WithKey(path));
if (!res.IsSuccess()) { if (!res.IsSuccess()) {
@ -372,7 +370,7 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
const std::string & mimeType, const std::string & mimeType,
const std::string & contentEncoding) const std::string & contentEncoding)
{ {
std::string uri = "s3://" + bucketName + "/" + path; std::string uri = "s3://" + config->bucketName + "/" + path;
Activity act(*logger, lvlTalkative, actFileTransfer, Activity act(*logger, lvlTalkative, actFileTransfer,
fmt("uploading '%s'", uri), fmt("uploading '%s'", uri),
Logger::Fields{uri}, getCurActivity()); Logger::Fields{uri}, getCurActivity());
@ -387,11 +385,11 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
std::call_once(transferManagerCreated, [&]() std::call_once(transferManagerCreated, [&]()
{ {
if (multipartUpload) { if (config->multipartUpload) {
TransferManagerConfiguration transferConfig(executor.get()); TransferManagerConfiguration transferConfig(executor.get());
transferConfig.s3Client = s3Helper.client; transferConfig.s3Client = s3Helper.client;
transferConfig.bufferSize = bufferSize; transferConfig.bufferSize = config->bufferSize;
transferConfig.uploadProgressCallback = transferConfig.uploadProgressCallback =
[](const TransferManager * transferManager, [](const TransferManager * transferManager,
@ -421,6 +419,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
auto now1 = std::chrono::steady_clock::now(); auto now1 = std::chrono::steady_clock::now();
auto & bucketName = config->bucketName;
if (transferManager) { if (transferManager) {
if (contentEncoding != "") if (contentEncoding != "")
@ -508,12 +508,12 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
return std::make_shared<std::stringstream>(std::move(compressed)); return std::make_shared<std::stringstream>(std::move(compressed));
}; };
if (narinfoCompression != "" && hasSuffix(path, ".narinfo")) if (config->narinfoCompression != "" && hasSuffix(path, ".narinfo"))
uploadFile(path, compress(narinfoCompression), mimeType, narinfoCompression); uploadFile(path, compress(config->narinfoCompression), mimeType, config->narinfoCompression);
else if (lsCompression != "" && hasSuffix(path, ".ls")) else if (config->lsCompression != "" && hasSuffix(path, ".ls"))
uploadFile(path, compress(lsCompression), mimeType, lsCompression); uploadFile(path, compress(config->lsCompression), mimeType, config->lsCompression);
else if (logCompression != "" && hasPrefix(path, "log/")) else if (config->logCompression != "" && hasPrefix(path, "log/"))
uploadFile(path, compress(logCompression), mimeType, logCompression); uploadFile(path, compress(config->logCompression), mimeType, config->logCompression);
else else
uploadFile(path, istream, mimeType, ""); uploadFile(path, istream, mimeType, "");
} }
@ -523,14 +523,14 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
stats.get++; stats.get++;
// FIXME: stream output to sink. // FIXME: stream output to sink.
auto res = s3Helper.getObject(bucketName, path); auto res = s3Helper.getObject(config->bucketName, path);
stats.getBytes += res.data ? res.data->size() : 0; stats.getBytes += res.data ? res.data->size() : 0;
stats.getTimeMs += res.durationMs; stats.getTimeMs += res.durationMs;
if (res.data) { if (res.data) {
printTalkative("downloaded 's3://%s/%s' (%d bytes) in %d ms", printTalkative("downloaded 's3://%s/%s' (%d bytes) in %d ms",
bucketName, path, res.data->size(), res.durationMs); config->bucketName, path, res.data->size(), res.durationMs);
sink(*res.data); sink(*res.data);
} else } else
@ -542,6 +542,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
StorePathSet paths; StorePathSet paths;
std::string marker; std::string marker;
auto & bucketName = config->bucketName;
do { do {
debug("listing bucket 's3://%s' from key '%s'...", bucketName, marker); debug("listing bucket 's3://%s' from key '%s'...", bucketName, marker);
@ -580,7 +582,15 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
} }
}; };
static RegisterStoreImplementation<S3BinaryCacheStoreImpl, S3BinaryCacheStoreConfig> regS3BinaryCacheStore; ref<Store> S3BinaryCacheStoreImpl::Config::openStore() const
{
return make_ref<S3BinaryCacheStoreImpl>(ref{
// FIXME we shouldn't actually need a mutable config
std::const_pointer_cast<S3BinaryCacheStore::Config>(shared_from_this())
});
}
static RegisterStoreImplementation<S3BinaryCacheStoreImpl::Config> regS3BinaryCacheStore;
} }

View file

@ -14,12 +14,13 @@ SSHStoreConfig::SSHStoreConfig(
std::string_view scheme, std::string_view scheme,
std::string_view authority, std::string_view authority,
const Params & params) const Params & params)
: StoreConfig(params) : Store::Config{params}
, RemoteStoreConfig(params) , RemoteStore::Config{params}
, CommonSSHStoreConfig(scheme, authority, params) , CommonSSHStoreConfig{scheme, authority, params}
{ {
} }
std::string SSHStoreConfig::doc() std::string SSHStoreConfig::doc()
{ {
return return
@ -27,21 +28,18 @@ std::string SSHStoreConfig::doc()
; ;
} }
class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore
{
public:
SSHStore( struct SSHStore : virtual RemoteStore
std::string_view scheme, {
std::string_view host, using Config = SSHStoreConfig;
const Params & params)
: StoreConfig(params) ref<const Config> config;
, RemoteStoreConfig(params)
, CommonSSHStoreConfig(scheme, host, params) SSHStore(ref<const Config> config)
, SSHStoreConfig(scheme, host, params) : Store{*config}
, Store(params) , RemoteStore{*config}
, RemoteStore(params) , config{config}
, master(createSSHMaster( , master(config->createSSHMaster(
// Use SSH master only if using more than 1 connection. // Use SSH master only if using more than 1 connection.
connections->capacity() > 1)) connections->capacity() > 1))
{ {
@ -49,7 +47,7 @@ public:
std::string getUri() override std::string getUri() override
{ {
return *uriSchemes().begin() + "://" + host; return *Config::uriSchemes().begin() + "://" + host;
} }
// FIXME extend daemon protocol, move implementation to RemoteStore // FIXME extend daemon protocol, move implementation to RemoteStore
@ -101,7 +99,7 @@ MountedSSHStoreConfig::MountedSSHStoreConfig(std::string_view scheme, std::strin
: StoreConfig(params) : StoreConfig(params)
, RemoteStoreConfig(params) , RemoteStoreConfig(params)
, CommonSSHStoreConfig(scheme, host, params) , CommonSSHStoreConfig(scheme, host, params)
, SSHStoreConfig(params) , SSHStoreConfig(scheme, host, params)
, LocalFSStoreConfig(params) , LocalFSStoreConfig(params)
{ {
} }
@ -128,35 +126,21 @@ std::string MountedSSHStoreConfig::doc()
* The difference lies in how they manage GC roots. See addPermRoot * The difference lies in how they manage GC roots. See addPermRoot
* below for details. * below for details.
*/ */
class MountedSSHStore : public virtual MountedSSHStoreConfig, public virtual SSHStore, public virtual LocalFSStore struct MountedSSHStore : virtual SSHStore, virtual LocalFSStore
{ {
public: using Config = MountedSSHStoreConfig;
MountedSSHStore( MountedSSHStore(ref<const Config> config)
std::string_view scheme, : Store{*config}
std::string_view host, , RemoteStore{*config}
const Params & params) , SSHStore{config}
: StoreConfig(params) , LocalFSStore{*config}
, RemoteStoreConfig(params)
, CommonSSHStoreConfig(scheme, host, params)
, SSHStoreConfig(params)
, LocalFSStoreConfig(params)
, MountedSSHStoreConfig(params)
, Store(params)
, RemoteStore(params)
, SSHStore(scheme, host, params)
, LocalFSStore(params)
{ {
extraRemoteProgramArgs = { extraRemoteProgramArgs = {
"--process-ops", "--process-ops",
}; };
} }
std::string getUri() override
{
return *uriSchemes().begin() + "://" + host;
}
void narFromPath(const StorePath & path, Sink & sink) override void narFromPath(const StorePath & path, Sink & sink) override
{ {
return LocalFSStore::narFromPath(path, sink); return LocalFSStore::narFromPath(path, sink);
@ -198,14 +182,26 @@ public:
} }
}; };
ref<Store> SSHStore::Config::openStore() const {
return make_ref<SSHStore>(ref{shared_from_this()});
}
ref<Store> MountedSSHStore::Config::openStore() const {
return make_ref<MountedSSHStore>(ref{
std::dynamic_pointer_cast<const MountedSSHStore::Config>(shared_from_this())
});
}
ref<RemoteStore::Connection> SSHStore::openConnection() ref<RemoteStore::Connection> SSHStore::openConnection()
{ {
auto conn = make_ref<Connection>(); auto conn = make_ref<Connection>();
Strings command = remoteProgram.get(); Strings command = config->remoteProgram.get();
command.push_back("--stdio"); command.push_back("--stdio");
if (remoteStore.get() != "") { if (config->remoteStore.get() != "") {
command.push_back("--store"); command.push_back("--store");
command.push_back(remoteStore.get()); command.push_back(config->remoteStore.get());
} }
command.insert(command.end(), command.insert(command.end(),
extraRemoteProgramArgs.begin(), extraRemoteProgramArgs.end()); extraRemoteProgramArgs.begin(), extraRemoteProgramArgs.end());
@ -215,7 +211,7 @@ ref<RemoteStore::Connection> SSHStore::openConnection()
return conn; return conn;
} }
static RegisterStoreImplementation<SSHStore, SSHStoreConfig> regSSHStore; static RegisterStoreImplementation<SSHStore::Config> regSSHStore;
static RegisterStoreImplementation<MountedSSHStore, MountedSSHStoreConfig> regMountedSSHStore; static RegisterStoreImplementation<MountedSSHStore::Config> regMountedSSHStore;
} }

View file

@ -29,13 +29,13 @@ using json = nlohmann::json;
namespace nix { namespace nix {
bool StoreDirConfig::isInStore(PathView path) const bool MixStoreDirMethods::isInStore(PathView path) const
{ {
return isInDir(path, storeDir); return isInDir(path, storeDir);
} }
std::pair<StorePath, Path> StoreDirConfig::toStorePath(PathView path) const std::pair<StorePath, Path> MixStoreDirMethods::toStorePath(PathView path) const
{ {
if (!isInStore(path)) if (!isInStore(path))
throw Error("path '%1%' is not in the Nix store", path); throw Error("path '%1%' is not in the Nix store", path);
@ -77,7 +77,7 @@ to match.
*/ */
StorePath StoreDirConfig::makeStorePath(std::string_view type, StorePath MixStoreDirMethods::makeStorePath(std::string_view type,
std::string_view hash, std::string_view name) const std::string_view hash, std::string_view name) const
{ {
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
@ -88,14 +88,14 @@ StorePath StoreDirConfig::makeStorePath(std::string_view type,
} }
StorePath StoreDirConfig::makeStorePath(std::string_view type, StorePath MixStoreDirMethods::makeStorePath(std::string_view type,
const Hash & hash, std::string_view name) const const Hash & hash, std::string_view name) const
{ {
return makeStorePath(type, hash.to_string(HashFormat::Base16, true), name); return makeStorePath(type, hash.to_string(HashFormat::Base16, true), name);
} }
StorePath StoreDirConfig::makeOutputPath(std::string_view id, StorePath MixStoreDirMethods::makeOutputPath(std::string_view id,
const Hash & hash, std::string_view name) const const Hash & hash, std::string_view name) const
{ {
return makeStorePath("output:" + std::string { id }, hash, outputPathName(name, id)); return makeStorePath("output:" + std::string { id }, hash, outputPathName(name, id));
@ -106,7 +106,7 @@ StorePath StoreDirConfig::makeOutputPath(std::string_view id,
hacky, but we can't put them in, say, <s2> (per the grammar above) hacky, but we can't put them in, say, <s2> (per the grammar above)
since that would be ambiguous. */ since that would be ambiguous. */
static std::string makeType( static std::string makeType(
const StoreDirConfig & store, const MixStoreDirMethods & store,
std::string && type, std::string && type,
const StoreReferences & references) const StoreReferences & references)
{ {
@ -119,7 +119,7 @@ static std::string makeType(
} }
StorePath StoreDirConfig::makeFixedOutputPath(std::string_view name, const FixedOutputInfo & info) const StorePath MixStoreDirMethods::makeFixedOutputPath(std::string_view name, const FixedOutputInfo & info) const
{ {
if (info.method == FileIngestionMethod::Git && info.hash.algo != HashAlgorithm::SHA1) if (info.method == FileIngestionMethod::Git && info.hash.algo != HashAlgorithm::SHA1)
throw Error("Git file ingestion must use SHA-1 hash"); throw Error("Git file ingestion must use SHA-1 hash");
@ -141,7 +141,7 @@ StorePath StoreDirConfig::makeFixedOutputPath(std::string_view name, const Fixed
} }
StorePath StoreDirConfig::makeFixedOutputPathFromCA(std::string_view name, const ContentAddressWithReferences & ca) const StorePath MixStoreDirMethods::makeFixedOutputPathFromCA(std::string_view name, const ContentAddressWithReferences & ca) const
{ {
// New template // New template
return std::visit(overloaded { return std::visit(overloaded {
@ -162,7 +162,7 @@ StorePath StoreDirConfig::makeFixedOutputPathFromCA(std::string_view name, const
} }
std::pair<StorePath, Hash> StoreDirConfig::computeStorePath( std::pair<StorePath, Hash> MixStoreDirMethods::computeStorePath(
std::string_view name, std::string_view name,
const SourcePath & path, const SourcePath & path,
ContentAddressMethod method, ContentAddressMethod method,
@ -420,7 +420,7 @@ ValidPathInfo Store::addToStoreSlow(
return info; return info;
} }
StringSet StoreConfig::getDefaultSystemFeatures() StringSet Store::Config::getDefaultSystemFeatures()
{ {
auto res = settings.systemFeatures.get(); auto res = settings.systemFeatures.get();
@ -433,9 +433,10 @@ StringSet StoreConfig::getDefaultSystemFeatures()
return res; return res;
} }
Store::Store(const Params & params) Store::Store(const Store::Config & config)
: StoreConfig(params) : MixStoreDirMethods{config}
, state({(size_t) pathInfoCacheSize}) , config{config}
, state({(size_t) config.pathInfoCacheSize})
{ {
assertLibStoreInitialized(); assertLibStoreInitialized();
} }
@ -1205,7 +1206,7 @@ std::optional<ValidPathInfo> decodeValidPathInfo(const Store & store, std::istre
} }
std::string StoreDirConfig::showPaths(const StorePathSet & paths) std::string MixStoreDirMethods::showPaths(const StorePathSet & paths) const
{ {
std::string s; std::string s;
for (auto & i : paths) { for (auto & i : paths) {
@ -1312,7 +1313,7 @@ void Store::signRealisation(Realisation & realisation)
namespace nix { namespace nix {
ref<Store> openStore(const std::string & uri, ref<Store> openStore(const std::string & uri,
const Store::Params & extraParams) const Store::Config::Params & extraParams)
{ {
return openStore(StoreReference::parse(uri, extraParams)); return openStore(StoreReference::parse(uri, extraParams));
} }
@ -1321,13 +1322,13 @@ ref<Store> openStore(StoreReference && storeURI)
{ {
auto & params = storeURI.params; auto & params = storeURI.params;
auto store = std::visit(overloaded { auto storeConfig = std::visit(overloaded {
[&](const StoreReference::Auto &) -> std::shared_ptr<Store> { [&](const StoreReference::Auto &) -> ref<StoreConfig> {
auto stateDir = getOr(params, "state", settings.nixStateDir); auto stateDir = getOr(params, "state", settings.nixStateDir);
if (access(stateDir.c_str(), R_OK | W_OK) == 0) if (access(stateDir.c_str(), R_OK | W_OK) == 0)
return std::make_shared<LocalStore>(params); return make_ref<LocalStore::Config>(params);
else if (pathExists(settings.nixDaemonSocketFile)) else if (pathExists(settings.nixDaemonSocketFile))
return std::make_shared<UDSRemoteStore>(params); return make_ref<UDSRemoteStore::Config>(params);
#ifdef __linux__ #ifdef __linux__
else if (!pathExists(stateDir) else if (!pathExists(stateDir)
&& params.empty() && params.empty()
@ -1343,31 +1344,33 @@ ref<Store> openStore(StoreReference && storeURI)
try { try {
createDirs(chrootStore); createDirs(chrootStore);
} catch (SystemError & e) { } catch (SystemError & e) {
return std::make_shared<LocalStore>(params); return make_ref<LocalStore::Config>(params);
} }
warn("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore); warn("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
} else } else
debug("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore); debug("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
return std::make_shared<LocalStore>("local", chrootStore, params); return make_ref<LocalStore::Config>("local", chrootStore, params);
} }
#endif #endif
else else
return std::make_shared<LocalStore>(params); return make_ref<LocalStore::Config>(params);
}, },
[&](const StoreReference::Specified & g) { [&](const StoreReference::Specified & g) {
for (const auto & implem : Implementations::registered()) for (const auto & [storeName, implem] : Implementations::registered())
if (implem.uriSchemes.count(g.scheme)) if (implem.uriSchemes.count(g.scheme))
return implem.create(g.scheme, g.authority, params); return implem.parseConfig(g.scheme, g.authority, params);
throw Error("don't know how to open Nix store with scheme '%s'", g.scheme); throw Error("don't know how to open Nix store with scheme '%s'", g.scheme);
}, },
}, storeURI.variant); }, storeURI.variant);
experimentalFeatureSettings.require(store->experimentalFeature()); experimentalFeatureSettings.require(storeConfig->experimentalFeature());
store->warnUnknownSettings(); storeConfig->warnUnknownSettings();
auto store = storeConfig->openStore();
store->init(); store->init();
return ref<Store> { store }; return store;
} }
std::list<ref<Store>> getDefaultSubstituters() std::list<ref<Store>> getDefaultSubstituters()
@ -1390,7 +1393,7 @@ std::list<ref<Store>> getDefaultSubstituters()
addStore(uri); addStore(uri);
stores.sort([](ref<Store> & a, ref<Store> & b) { stores.sort([](ref<Store> & a, ref<Store> & b) {
return a->priority < b->priority; return a->config.priority < b->config.priority;
}); });
return stores; return stores;
@ -1399,9 +1402,9 @@ std::list<ref<Store>> getDefaultSubstituters()
return stores; return stores;
} }
std::vector<StoreFactory> & Implementations::registered() Implementations::Map & Implementations::registered()
{ {
static std::vector<StoreFactory> registered; static Map registered;
return registered; return registered;
} }

View file

@ -0,0 +1,13 @@
#include "nix/store/store-dir-config.hh"
#include "nix/util/util.hh"
#include "nix/store/globals.hh"
namespace nix {
StoreDirConfig::StoreDirConfig(const Params & params)
: StoreDirConfigItself(params)
, MixStoreDirMethods{storeDir_}
{
}
}

View file

@ -20,13 +20,13 @@ namespace nix {
UDSRemoteStoreConfig::UDSRemoteStoreConfig( UDSRemoteStoreConfig::UDSRemoteStoreConfig(
std::string_view scheme, std::string_view scheme,
std::string_view authority, std::string_view authority,
const Params & params) const StoreReference::Params & params)
: StoreConfig(params) : Store::Config{params}
, LocalFSStoreConfig(params) , LocalFSStore::Config{params}
, RemoteStoreConfig(params) , RemoteStore::Config{params}
, path{authority.empty() ? settings.nixDaemonSocketFile : authority} , path{authority.empty() ? settings.nixDaemonSocketFile : authority}
{ {
if (scheme != UDSRemoteStoreConfig::scheme) { if (uriSchemes().count(scheme) == 0) {
throw UsageError("Scheme must be 'unix'"); throw UsageError("Scheme must be 'unix'");
} }
} }
@ -44,32 +44,30 @@ std::string UDSRemoteStoreConfig::doc()
// empty string will later default to the same nixDaemonSocketFile. Why // empty string will later default to the same nixDaemonSocketFile. Why
// don't we just wire it all through? I believe there are cases where it // don't we just wire it all through? I believe there are cases where it
// will live reload so we want to continue to account for that. // will live reload so we want to continue to account for that.
UDSRemoteStore::UDSRemoteStore(const Params & params) UDSRemoteStoreConfig::UDSRemoteStoreConfig(const Params & params)
: UDSRemoteStore(scheme, "", params) : UDSRemoteStoreConfig(*uriSchemes().begin(), "", params)
{} {
}
UDSRemoteStore::UDSRemoteStore(std::string_view scheme, std::string_view authority, const Params & params) UDSRemoteStore::UDSRemoteStore(ref<const Config> config)
: StoreConfig(params) : Store{*config}
, LocalFSStoreConfig(params) , LocalFSStore{*config}
, RemoteStoreConfig(params) , RemoteStore{*config}
, UDSRemoteStoreConfig(scheme, authority, params) , config{config}
, Store(params)
, LocalFSStore(params)
, RemoteStore(params)
{ {
} }
std::string UDSRemoteStore::getUri() std::string UDSRemoteStore::getUri()
{ {
return path == settings.nixDaemonSocketFile return config->path == settings.nixDaemonSocketFile
? // FIXME: Not clear why we return daemon here and not default ? // FIXME: Not clear why we return daemon here and not default
// to settings.nixDaemonSocketFile // to settings.nixDaemonSocketFile
// //
// unix:// with no path also works. Change what we return? // unix:// with no path also works. Change what we return?
"daemon" "daemon"
: std::string(scheme) + "://" + path; : std::string(*Config::uriSchemes().begin()) + "://" + config->path;
} }
@ -86,7 +84,7 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
/* Connect to a daemon that does the privileged work for us. */ /* Connect to a daemon that does the privileged work for us. */
conn->fd = createUnixDomainSocket(); conn->fd = createUnixDomainSocket();
nix::connect(toSocket(conn->fd.get()), path); nix::connect(toSocket(conn->fd.get()), config->path);
conn->from.fd = conn->fd.get(); conn->from.fd = conn->fd.get();
conn->to.fd = conn->fd.get(); conn->to.fd = conn->fd.get();
@ -106,6 +104,11 @@ void UDSRemoteStore::addIndirectRoot(const Path & path)
} }
static RegisterStoreImplementation<UDSRemoteStore, UDSRemoteStoreConfig> regUDSRemoteStore; ref<Store> UDSRemoteStore::Config::openStore() const {
return make_ref<UDSRemoteStore>(ref{shared_from_this()});
}
static RegisterStoreImplementation<UDSRemoteStore::Config> regUDSRemoteStore;
} }

View file

@ -36,7 +36,7 @@
#include "store-config-private.hh" #include "store-config-private.hh"
#if HAVE_STATVFS #if HAVE_STATVFS
#include <sys/statvfs.h> # include <sys/statvfs.h>
#endif #endif
/* Includes required for chroot support. */ /* Includes required for chroot support. */
@ -60,9 +60,9 @@
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
#include <spawn.h> # include <spawn.h>
#include <sys/sysctl.h> # include <sys/sysctl.h>
#include <sandbox.h> # include <sandbox.h>
/* This definition is undocumented but depended upon by all major browsers. */ /* This definition is undocumented but depended upon by all major browsers. */
extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf);
@ -494,7 +494,7 @@ bool DerivationBuilderImpl::prepareBuild()
} }
auto & localStore = getLocalStore(); auto & localStore = getLocalStore();
if (localStore.storeDir != localStore.realStoreDir.get()) { if (localStore.storeDir != localStore.config->realStoreDir.get()) {
#ifdef __linux__ #ifdef __linux__
useChroot = true; useChroot = true;
#else #else
@ -707,7 +707,7 @@ bool DerivationBuilderImpl::cleanupDecideWhetherDiskFull()
auto & localStore = getLocalStore(); auto & localStore = getLocalStore();
uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable
struct statvfs st; struct statvfs st;
if (statvfs(localStore.realStoreDir.get().c_str(), &st) == 0 && if (statvfs(localStore.config->realStoreDir.get().c_str(), &st) == 0 &&
(uint64_t) st.f_bavail * st.f_bsize < required) (uint64_t) st.f_bavail * st.f_bsize < required)
diskFull = true; diskFull = true;
if (statvfs(tmpDir.c_str(), &st) == 0 && if (statvfs(tmpDir.c_str(), &st) == 0 &&
@ -871,7 +871,7 @@ void DerivationBuilderImpl::startBuilder()
concatStringsSep(", ", drvOptions.getRequiredSystemFeatures(drv)), concatStringsSep(", ", drvOptions.getRequiredSystemFeatures(drv)),
store.printStorePath(drvPath), store.printStorePath(drvPath),
settings.thisSystem, settings.thisSystem,
concatStringsSep<StringSet>(", ", store.systemFeatures)); concatStringsSep<StringSet>(", ", store.config.systemFeatures));
} }
} }
@ -1594,14 +1594,14 @@ void DerivationBuilderImpl::startDaemon()
{ {
experimentalFeatureSettings.require(Xp::RecursiveNix); experimentalFeatureSettings.require(Xp::RecursiveNix);
Store::Params params; auto store = makeRestrictedStore(
params["path-info-cache-size"] = "0"; [&]{
params["store"] = store.storeDir; auto config = make_ref<LocalStore::Config>(*getLocalStore().config);
if (auto & optRoot = getLocalStore().rootDir.get()) config->pathInfoCacheSize = 0;
params["root"] = *optRoot; config->stateDir = "/no-such-path";
params["state"] = "/no-such-path"; config->logDir = "/no-such-path";
params["log"] = "/no-such-path"; return config;
auto store = makeRestrictedStore(params, }(),
ref<LocalStore>(std::dynamic_pointer_cast<LocalStore>(this->store.shared_from_this())), ref<LocalStore>(std::dynamic_pointer_cast<LocalStore>(this->store.shared_from_this())),
*this); *this);
@ -1946,7 +1946,7 @@ void DerivationBuilderImpl::runChild()
createDirs(chrootRootDir + "/dev/shm"); createDirs(chrootRootDir + "/dev/shm");
createDirs(chrootRootDir + "/dev/pts"); createDirs(chrootRootDir + "/dev/pts");
ss.push_back("/dev/full"); ss.push_back("/dev/full");
if (store.systemFeatures.get().count("kvm") && pathExists("/dev/kvm")) if (store.config.systemFeatures.get().count("kvm") && pathExists("/dev/kvm"))
ss.push_back("/dev/kvm"); ss.push_back("/dev/kvm");
ss.push_back("/dev/null"); ss.push_back("/dev/null");
ss.push_back("/dev/random"); ss.push_back("/dev/random");

View file

@ -193,13 +193,12 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs
res["args"] = toJSON(); res["args"] = toJSON();
auto stores = nlohmann::json::object(); auto stores = nlohmann::json::object();
for (auto & implem : Implementations::registered()) { for (auto & [storeName, implem] : Implementations::registered()) {
auto storeConfig = implem.getConfig();
auto storeName = storeConfig->name();
auto & j = stores[storeName]; auto & j = stores[storeName];
j["doc"] = storeConfig->doc(); j["doc"] = implem.doc;
j["settings"] = storeConfig->toJSON(); j["uri-schemes"] = implem.uriSchemes;
j["experimentalFeature"] = storeConfig->experimentalFeature(); j["settings"] = implem.getConfig()->toJSON();
j["experimentalFeature"] = implem.experimentalFeature;
} }
res["stores"] = std::move(stores); res["stores"] = std::move(stores);
res["fetchers"] = fetchers::dumpRegisterInputSchemeInfo(); res["fetchers"] = fetchers::dumpRegisterInputSchemeInfo();

View file

@ -244,7 +244,7 @@ static PeerInfo getPeerInfo(int remote)
*/ */
static ref<Store> openUncachedStore() static ref<Store> openUncachedStore()
{ {
Store::Params params; // FIXME: get params from somewhere Store::Config::Params params; // FIXME: get params from somewhere
// Disable caching since the client already does that. // Disable caching since the client already does that.
params["path-info-cache-size"] = "0"; params["path-info-cache-size"] = "0";
return openStore(settings.storeUri, params); return openStore(settings.storeUri, params);