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:
parent
f0f196cef0
commit
934918ba16
48 changed files with 743 additions and 593 deletions
|
@ -33,6 +33,7 @@ let
|
||||||
{
|
{
|
||||||
settings,
|
settings,
|
||||||
doc,
|
doc,
|
||||||
|
uri-schemes,
|
||||||
experimentalFeature,
|
experimentalFeature,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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 (...) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
src/libstore/store-dir-config.cc
Normal file
13
src/libstore/store-dir-config.cc
Normal 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_}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue