aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2023-03-30 16:28:53 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2023-03-30 16:28:53 -0400
commitaa99005004bccc9be506a2a2f162f78bad4bcb41 (patch)
treeeeda5852bad75701d48776cd141bbc8f857480e0 /src/libstore
parentd381248ec0847cacd918480e83a99287f814456a (diff)
parent06d87b95bc751480d5961def9c0a21f557103625 (diff)
Merge remote-tracking branch 'upstream/master' into path-info
Also improve content-address.hh API docs.
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/binary-cache-store.hh34
-rw-r--r--src/libstore/build/derivation-goal.cc14
-rw-r--r--src/libstore/build/drv-output-substitution-goal.cc23
-rw-r--r--src/libstore/build/drv-output-substitution-goal.hh12
-rw-r--r--src/libstore/build/goal.cc4
-rw-r--r--src/libstore/build/goal.hh2
-rw-r--r--src/libstore/build/hook-instance.cc5
-rw-r--r--src/libstore/build/local-derivation-goal.cc104
-rw-r--r--src/libstore/build/local-derivation-goal.hh5
-rw-r--r--src/libstore/builtins/buildenv.cc12
-rw-r--r--src/libstore/builtins/buildenv.hh26
-rw-r--r--src/libstore/content-address.cc7
-rw-r--r--src/libstore/content-address.hh127
-rw-r--r--src/libstore/daemon.cc8
-rw-r--r--src/libstore/derivations.cc4
-rw-r--r--src/libstore/derivations.hh348
-rw-r--r--src/libstore/derived-path.cc2
-rw-r--r--src/libstore/derived-path.hh2
-rw-r--r--src/libstore/dummy-store.cc7
-rw-r--r--src/libstore/dummy-store.md13
-rw-r--r--src/libstore/export-import.cc4
-rw-r--r--src/libstore/filetransfer.cc12
-rw-r--r--src/libstore/gc.cc53
-rw-r--r--src/libstore/globals.cc44
-rw-r--r--src/libstore/globals.hh43
-rw-r--r--src/libstore/http-binary-cache-store.cc9
-rw-r--r--src/libstore/http-binary-cache-store.md8
-rw-r--r--src/libstore/legacy-ssh-store.cc29
-rw-r--r--src/libstore/legacy-ssh-store.md8
-rw-r--r--src/libstore/local-binary-cache-store.cc7
-rw-r--r--src/libstore/local-binary-cache-store.md16
-rw-r--r--src/libstore/local-fs-store.hh16
-rw-r--r--src/libstore/local-store.cc31
-rw-r--r--src/libstore/local-store.hh10
-rw-r--r--src/libstore/local-store.md39
-rw-r--r--src/libstore/lock.cc2
-rw-r--r--src/libstore/misc.cc2
-rw-r--r--src/libstore/optimise-store.cc17
-rw-r--r--src/libstore/outputs-spec.hh33
-rw-r--r--src/libstore/path.hh21
-rw-r--r--src/libstore/pathlocks.cc8
-rw-r--r--src/libstore/profiles.cc34
-rw-r--r--src/libstore/profiles.hh29
-rw-r--r--src/libstore/references.cc3
-rw-r--r--src/libstore/remote-store.cc4
-rw-r--r--src/libstore/remote-store.hh12
-rw-r--r--src/libstore/s3-binary-cache-store.cc83
-rw-r--r--src/libstore/s3-binary-cache-store.md8
-rw-r--r--src/libstore/ssh-store-config.hh26
-rw-r--r--src/libstore/ssh-store.cc24
-rw-r--r--src/libstore/ssh-store.md8
-rw-r--r--src/libstore/store-api.cc23
-rw-r--r--src/libstore/store-api.hh710
-rw-r--r--src/libstore/uds-remote-store.cc6
-rw-r--r--src/libstore/uds-remote-store.hh10
-rw-r--r--src/libstore/uds-remote-store.md9
56 files changed, 1472 insertions, 688 deletions
diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh
index abd92a83c..c1d08926d 100644
--- a/src/libstore/binary-cache-store.hh
+++ b/src/libstore/binary-cache-store.hh
@@ -16,17 +16,33 @@ struct BinaryCacheStoreConfig : virtual StoreConfig
{
using StoreConfig::StoreConfig;
- const Setting<std::string> compression{(StoreConfig*) this, "xz", "compression", "NAR compression method ('xz', 'bzip2', 'gzip', 'zstd', or 'none')"};
- const Setting<bool> writeNARListing{(StoreConfig*) this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"};
- const Setting<bool> writeDebugInfo{(StoreConfig*) this, false, "index-debug-info", "whether to index DWARF debug info files by build ID"};
- const Setting<Path> secretKeyFile{(StoreConfig*) this, "", "secret-key", "path to secret key used to sign the binary cache"};
- const Setting<Path> localNarCache{(StoreConfig*) this, "", "local-nar-cache", "path to a local cache of NARs"};
+ const Setting<std::string> compression{(StoreConfig*) this, "xz", "compression",
+ "NAR compression method (`xz`, `bzip2`, `gzip`, `zstd`, or `none`)."};
+
+ const Setting<bool> writeNARListing{(StoreConfig*) this, false, "write-nar-listing",
+ "Whether to write a JSON file that lists the files in each NAR."};
+
+ const Setting<bool> writeDebugInfo{(StoreConfig*) this, false, "index-debug-info",
+ R"(
+ Whether to index DWARF debug info files by build ID. This allows [`dwarffs`](https://github.com/edolstra/dwarffs) to
+ fetch debug info on demand
+ )"};
+
+ const Setting<Path> secretKeyFile{(StoreConfig*) this, "", "secret-key",
+ "Path to the secret key used to sign the binary cache."};
+
+ const Setting<Path> localNarCache{(StoreConfig*) this, "", "local-nar-cache",
+ "Path to a local cache of NARs fetched from this binary cache, used by commands such as `nix store cat`."};
+
const Setting<bool> parallelCompression{(StoreConfig*) this, false, "parallel-compression",
- "enable multi-threading compression for NARs, available for xz and zstd only currently"};
+ "Enable multi-threaded compression of NARs. This is currently only available for `xz` and `zstd`."};
+
const Setting<int> compressionLevel{(StoreConfig*) this, -1, "compression-level",
- "specify 'preset level' of compression to be used with NARs: "
- "meaning and accepted range of values depends on compression method selected, "
- "other than -1 which we reserve to indicate Nix defaults should be used"};
+ R"(
+ The *preset level* to be used when compressing NARs.
+ The meaning and accepted values depend on the compression method selected.
+ `-1` specifies that the default compression level should be used.
+ )"};
};
class BinaryCacheStore : public virtual BinaryCacheStoreConfig,
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 2021d0023..596034c0f 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -199,10 +199,10 @@ void DerivationGoal::haveDerivation()
parsedDrv = std::make_unique<ParsedDerivation>(drvPath, *drv);
if (!drv->type().hasKnownOutputPaths())
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
if (!drv->type().isPure()) {
- settings.requireExperimentalFeature(Xp::ImpureDerivations);
+ experimentalFeatureSettings.require(Xp::ImpureDerivations);
for (auto & [outputName, output] : drv->outputs) {
auto randomPath = StorePath::random(outputPathName(drv->name, outputName));
@@ -336,7 +336,7 @@ void DerivationGoal::gaveUpOnSubstitution()
for (auto & i : dynamic_cast<Derivation *>(drv.get())->inputDrvs) {
/* Ensure that pure, non-fixed-output derivations don't
depend on impure derivations. */
- if (settings.isExperimentalFeatureEnabled(Xp::ImpureDerivations) && drv->type().isPure() && !drv->type().isFixed()) {
+ if (experimentalFeatureSettings.isEnabled(Xp::ImpureDerivations) && drv->type().isPure() && !drv->type().isFixed()) {
auto inputDrv = worker.evalStore.readDerivation(i.first);
if (!inputDrv.type().isPure())
throw Error("pure derivation '%s' depends on impure derivation '%s'",
@@ -477,7 +477,7 @@ void DerivationGoal::inputsRealised()
ca.fixed
/* Can optionally resolve if fixed, which is good
for avoiding unnecessary rebuilds. */
- ? settings.isExperimentalFeatureEnabled(Xp::CaDerivations)
+ ? experimentalFeatureSettings.isEnabled(Xp::CaDerivations)
/* Must resolve if floating and there are any inputs
drvs. */
: true);
@@ -488,7 +488,7 @@ void DerivationGoal::inputsRealised()
}, drvType.raw());
if (resolveDrv && !fullDrv.inputDrvs.empty()) {
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
/* We are be able to resolve this derivation based on the
now-known results of dependencies. If so, we become a
@@ -732,7 +732,7 @@ void replaceValidPath(const Path & storePath, const Path & tmpPath)
tmpPath (the replacement), so we have to move it out of the
way first. We'd better not be interrupted here, because if
we're repairing (say) Glibc, we end up with a broken system. */
- Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % random()).str();
+ Path oldPath = fmt("%1%.old-%2%-%3%", storePath, getpid(), random());
if (pathExists(storePath))
movePath(storePath, oldPath);
@@ -1352,7 +1352,7 @@ std::pair<bool, DrvOutputs> DerivationGoal::checkPathValidity()
};
}
auto drvOutput = DrvOutput{info.outputHash, i.first};
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
if (auto real = worker.store.queryRealisation(drvOutput)) {
info.known = {
.path = real->outPath,
diff --git a/src/libstore/build/drv-output-substitution-goal.cc b/src/libstore/build/drv-output-substitution-goal.cc
index b7f7b5ab1..b30957c84 100644
--- a/src/libstore/build/drv-output-substitution-goal.cc
+++ b/src/libstore/build/drv-output-substitution-goal.cc
@@ -61,20 +61,25 @@ void DrvOutputSubstitutionGoal::tryNext()
// FIXME: Make async
// outputInfo = sub->queryRealisation(id);
- outPipe.create();
- promise = decltype(promise)();
+
+ /* The callback of the curl download below can outlive `this` (if
+ some other error occurs), so it must not touch `this`. So put
+ the shared state in a separate refcounted object. */
+ downloadState = std::make_shared<DownloadState>();
+ downloadState->outPipe.create();
sub->queryRealisation(
- id, { [&](std::future<std::shared_ptr<const Realisation>> res) {
+ id,
+ { [downloadState(downloadState)](std::future<std::shared_ptr<const Realisation>> res) {
try {
- Finally updateStats([this]() { outPipe.writeSide.close(); });
- promise.set_value(res.get());
+ Finally updateStats([&]() { downloadState->outPipe.writeSide.close(); });
+ downloadState->promise.set_value(res.get());
} catch (...) {
- promise.set_exception(std::current_exception());
+ downloadState->promise.set_exception(std::current_exception());
}
} });
- worker.childStarted(shared_from_this(), {outPipe.readSide.get()}, true, false);
+ worker.childStarted(shared_from_this(), {downloadState->outPipe.readSide.get()}, true, false);
state = &DrvOutputSubstitutionGoal::realisationFetched;
}
@@ -84,7 +89,7 @@ void DrvOutputSubstitutionGoal::realisationFetched()
worker.childTerminated(this);
try {
- outputInfo = promise.get_future().get();
+ outputInfo = downloadState->promise.get_future().get();
} catch (std::exception & e) {
printError(e.what());
substituterFailed = true;
@@ -155,7 +160,7 @@ void DrvOutputSubstitutionGoal::work()
void DrvOutputSubstitutionGoal::handleEOF(int fd)
{
- if (fd == outPipe.readSide.get()) worker.wakeUp(shared_from_this());
+ if (fd == downloadState->outPipe.readSide.get()) worker.wakeUp(shared_from_this());
}
diff --git a/src/libstore/build/drv-output-substitution-goal.hh b/src/libstore/build/drv-output-substitution-goal.hh
index 948dbda8f..e4b044790 100644
--- a/src/libstore/build/drv-output-substitution-goal.hh
+++ b/src/libstore/build/drv-output-substitution-goal.hh
@@ -16,7 +16,7 @@ class Worker;
// 2. Substitute the corresponding output path
// 3. Register the output info
class DrvOutputSubstitutionGoal : public Goal {
-private:
+
// The drv output we're trying to substitue
DrvOutput id;
@@ -30,9 +30,13 @@ private:
/* The current substituter. */
std::shared_ptr<Store> sub;
- Pipe outPipe;
- std::thread thr;
- std::promise<std::shared_ptr<const Realisation>> promise;
+ struct DownloadState
+ {
+ Pipe outPipe;
+ std::promise<std::shared_ptr<const Realisation>> promise;
+ };
+
+ std::shared_ptr<DownloadState> downloadState;
/* Whether a substituter failed. */
bool substituterFailed = false;
diff --git a/src/libstore/build/goal.cc b/src/libstore/build/goal.cc
index 58e805f55..d59b94797 100644
--- a/src/libstore/build/goal.cc
+++ b/src/libstore/build/goal.cc
@@ -78,9 +78,9 @@ void Goal::amDone(ExitCode result, std::optional<Error> ex)
}
-void Goal::trace(const FormatOrString & fs)
+void Goal::trace(std::string_view s)
{
- debug("%1%: %2%", name, fs.s);
+ debug("%1%: %2%", name, s);
}
}
diff --git a/src/libstore/build/goal.hh b/src/libstore/build/goal.hh
index 35121c5d9..776eb86bc 100644
--- a/src/libstore/build/goal.hh
+++ b/src/libstore/build/goal.hh
@@ -88,7 +88,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
abort();
}
- void trace(const FormatOrString & fs);
+ void trace(std::string_view s);
std::string getName()
{
diff --git a/src/libstore/build/hook-instance.cc b/src/libstore/build/hook-instance.cc
index cb58a1f02..075ad554f 100644
--- a/src/libstore/build/hook-instance.cc
+++ b/src/libstore/build/hook-instance.cc
@@ -35,7 +35,10 @@ HookInstance::HookInstance()
/* Fork the hook. */
pid = startProcess([&]() {
- commonChildInit(fromHook);
+ if (dup2(fromHook.writeSide.get(), STDERR_FILENO) == -1)
+ throw SysError("cannot pipe standard error into log file");
+
+ commonChildInit();
if (chdir("/") == -1) throw SysError("changing into /");
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 87eac6e19..caa15ab04 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -292,7 +292,7 @@ void LocalDerivationGoal::closeReadPipes()
if (hook) {
DerivationGoal::closeReadPipes();
} else
- builderOut.readSide = -1;
+ builderOut.close();
}
@@ -413,7 +413,7 @@ void LocalDerivationGoal::startBuilder()
)
{
#if __linux__
- settings.requireExperimentalFeature(Xp::Cgroups);
+ experimentalFeatureSettings.require(Xp::Cgroups);
auto cgroupFS = getCgroupFS();
if (!cgroupFS)
@@ -650,7 +650,7 @@ void LocalDerivationGoal::startBuilder()
/* Clean up the chroot directory automatically. */
autoDelChroot = std::make_shared<AutoDelete>(chrootRootDir);
- printMsg(lvlChatty, format("setting up chroot environment in '%1%'") % chrootRootDir);
+ printMsg(lvlChatty, "setting up chroot environment in '%1%'", chrootRootDir);
// FIXME: make this 0700
if (mkdir(chrootRootDir.c_str(), buildUser && buildUser->getUIDCount() != 1 ? 0755 : 0750) == -1)
@@ -753,8 +753,7 @@ void LocalDerivationGoal::startBuilder()
throw Error("home directory '%1%' exists; please remove it to assure purity of builds without sandboxing", homeDir);
if (useChroot && settings.preBuildHook != "" && dynamic_cast<Derivation *>(drv.get())) {
- printMsg(lvlChatty, format("executing pre-build hook '%1%'")
- % settings.preBuildHook);
+ printMsg(lvlChatty, "executing pre-build hook '%1%'", settings.preBuildHook);
auto args = useChroot ? Strings({worker.store.printStorePath(drvPath), chrootRootDir}) :
Strings({ worker.store.printStorePath(drvPath) });
enum BuildHookState {
@@ -803,15 +802,13 @@ void LocalDerivationGoal::startBuilder()
/* Create the log file. */
Path logFile = openLogFile();
- /* Create a pipe to get the output of the builder. */
- //builderOut.create();
-
- builderOut.readSide = posix_openpt(O_RDWR | O_NOCTTY);
- if (!builderOut.readSide)
+ /* Create a pseudoterminal to get the output of the builder. */
+ builderOut = posix_openpt(O_RDWR | O_NOCTTY);
+ if (!builderOut)
throw SysError("opening pseudoterminal master");
// FIXME: not thread-safe, use ptsname_r
- std::string slaveName(ptsname(builderOut.readSide.get()));
+ std::string slaveName = ptsname(builderOut.get());
if (buildUser) {
if (chmod(slaveName.c_str(), 0600))
@@ -822,34 +819,34 @@ void LocalDerivationGoal::startBuilder()
}
#if __APPLE__
else {
- if (grantpt(builderOut.readSide.get()))
+ if (grantpt(builderOut.get()))
throw SysError("granting access to pseudoterminal slave");
}
#endif
- #if 0
- // Mount the pt in the sandbox so that the "tty" command works.
- // FIXME: this doesn't work with the new devpts in the sandbox.
- if (useChroot)
- dirsInChroot[slaveName] = {slaveName, false};
- #endif
-
- if (unlockpt(builderOut.readSide.get()))
+ if (unlockpt(builderOut.get()))
throw SysError("unlocking pseudoterminal");
- builderOut.writeSide = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
- if (!builderOut.writeSide)
- throw SysError("opening pseudoterminal slave");
+ /* Open the slave side of the pseudoterminal and use it as stderr. */
+ auto openSlave = [&]()
+ {
+ AutoCloseFD builderOut = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
+ if (!builderOut)
+ throw SysError("opening pseudoterminal slave");
- // Put the pt into raw mode to prevent \n -> \r\n translation.
- struct termios term;
- if (tcgetattr(builderOut.writeSide.get(), &term))
- throw SysError("getting pseudoterminal attributes");
+ // Put the pt into raw mode to prevent \n -> \r\n translation.
+ struct termios term;
+ if (tcgetattr(builderOut.get(), &term))
+ throw SysError("getting pseudoterminal attributes");
- cfmakeraw(&term);
+ cfmakeraw(&term);
- if (tcsetattr(builderOut.writeSide.get(), TCSANOW, &term))
- throw SysError("putting pseudoterminal into raw mode");
+ if (tcsetattr(builderOut.get(), TCSANOW, &term))
+ throw SysError("putting pseudoterminal into raw mode");
+
+ if (dup2(builderOut.get(), STDERR_FILENO) == -1)
+ throw SysError("cannot pipe standard error into log file");
+ };
buildResult.startTime = time(0);
@@ -898,7 +895,16 @@ void LocalDerivationGoal::startBuilder()
usingUserNamespace = userNamespacesSupported();
+ Pipe sendPid;
+ sendPid.create();
+
Pid helper = startProcess([&]() {
+ sendPid.readSide.close();
+
+ /* We need to open the slave early, before
+ CLONE_NEWUSER. Otherwise we get EPERM when running as
+ root. */
+ openSlave();
/* Drop additional groups here because we can't do it
after we've created the new user namespace. FIXME:
@@ -920,11 +926,12 @@ void LocalDerivationGoal::startBuilder()
pid_t child = startProcess([&]() { runChild(); }, options);
- writeFull(builderOut.writeSide.get(),
- fmt("%d %d\n", usingUserNamespace, child));
+ writeFull(sendPid.writeSide.get(), fmt("%d\n", child));
_exit(0);
});
+ sendPid.writeSide.close();
+
if (helper.wait() != 0)
throw Error("unable to start build process");
@@ -936,10 +943,9 @@ void LocalDerivationGoal::startBuilder()
userNamespaceSync.writeSide = -1;
});
- auto ss = tokenizeString<std::vector<std::string>>(readLine(builderOut.readSide.get()));
- assert(ss.size() == 2);
- usingUserNamespace = ss[0] == "1";
- pid = string2Int<pid_t>(ss[1]).value();
+ auto ss = tokenizeString<std::vector<std::string>>(readLine(sendPid.readSide.get()));
+ assert(ss.size() == 1);
+ pid = string2Int<pid_t>(ss[0]).value();
if (usingUserNamespace) {
/* Set the UID/GID mapping of the builder's user namespace
@@ -994,21 +1000,21 @@ void LocalDerivationGoal::startBuilder()
#endif
{
pid = startProcess([&]() {
+ openSlave();
runChild();
});
}
/* parent */
pid.setSeparatePG(true);
- builderOut.writeSide = -1;
- worker.childStarted(shared_from_this(), {builderOut.readSide.get()}, true, true);
+ worker.childStarted(shared_from_this(), {builderOut.get()}, true, true);
/* Check if setting up the build environment failed. */
std::vector<std::string> msgs;
while (true) {
std::string msg = [&]() {
try {
- return readLine(builderOut.readSide.get());
+ return readLine(builderOut.get());
} catch (Error & e) {
auto status = pid.wait();
e.addTrace({}, "while waiting for the build environment for '%s' to initialize (%s, previous messages: %s)",
@@ -1020,7 +1026,7 @@ void LocalDerivationGoal::startBuilder()
}();
if (msg.substr(0, 1) == "\2") break;
if (msg.substr(0, 1) == "\1") {
- FdSource source(builderOut.readSide.get());
+ FdSource source(builderOut.get());
auto ex = readError(source);
ex.addTrace({}, "while setting up the build environment");
throw ex;
@@ -1104,7 +1110,7 @@ void LocalDerivationGoal::initEnv()
env["NIX_STORE"] = worker.store.storeDir;
/* The maximum number of cores to utilize for parallel building. */
- env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
+ env["NIX_BUILD_CORES"] = fmt("%d", settings.buildCores);
initTmpDir();
@@ -1155,10 +1161,10 @@ void LocalDerivationGoal::writeStructuredAttrs()
writeFile(tmpDir + "/.attrs.sh", rewriteStrings(jsonSh, inputRewrites));
chownToBuilder(tmpDir + "/.attrs.sh");
- env["NIX_ATTRS_SH_FILE"] = tmpDir + "/.attrs.sh";
+ env["NIX_ATTRS_SH_FILE"] = tmpDirInSandbox + "/.attrs.sh";
writeFile(tmpDir + "/.attrs.json", rewriteStrings(json.dump(), inputRewrites));
chownToBuilder(tmpDir + "/.attrs.json");
- env["NIX_ATTRS_JSON_FILE"] = tmpDir + "/.attrs.json";
+ env["NIX_ATTRS_JSON_FILE"] = tmpDirInSandbox + "/.attrs.json";
}
}
@@ -1414,7 +1420,7 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
void LocalDerivationGoal::startDaemon()
{
- settings.requireExperimentalFeature(Xp::RecursiveNix);
+ experimentalFeatureSettings.require(Xp::RecursiveNix);
Store::Params params;
params["path-info-cache-size"] = "0";
@@ -1650,7 +1656,7 @@ void LocalDerivationGoal::runChild()
try { /* child */
- commonChildInit(builderOut);
+ commonChildInit();
try {
setupSeccomp();
@@ -2063,7 +2069,7 @@ void LocalDerivationGoal::runChild()
/* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms
to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */
- Path globalTmpDir = canonPath(getEnv("TMPDIR").value_or("/tmp"), true);
+ Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true);
/* They don't like trailing slashes on subpath directives */
if (globalTmpDir.back() == '/') globalTmpDir.pop_back();
@@ -2274,7 +2280,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
bool discardReferences = false;
if (auto structuredAttrs = parsedDrv->getStructuredAttrs()) {
if (auto udr = get(*structuredAttrs, "unsafeDiscardReferences")) {
- settings.requireExperimentalFeature(Xp::DiscardReferences);
+ experimentalFeatureSettings.require(Xp::DiscardReferences);
if (auto output = get(*udr, outputName)) {
if (!output->is_boolean())
throw Error("attribute 'unsafeDiscardReferences.\"%s\"' of derivation '%s' must be a Boolean", outputName, drvPath.to_string());
@@ -2686,7 +2692,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
},
.outPath = newInfo.path
};
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)
&& drv->type().isPure())
{
signRealisation(thisRealisation);
@@ -2884,7 +2890,7 @@ void LocalDerivationGoal::deleteTmpDir(bool force)
bool LocalDerivationGoal::isReadDesc(int fd)
{
return (hook && DerivationGoal::isReadDesc(fd)) ||
- (!hook && fd == builderOut.readSide.get());
+ (!hook && fd == builderOut.get());
}
diff --git a/src/libstore/build/local-derivation-goal.hh b/src/libstore/build/local-derivation-goal.hh
index 34c4e9187..c9ecc8828 100644
--- a/src/libstore/build/local-derivation-goal.hh
+++ b/src/libstore/build/local-derivation-goal.hh
@@ -24,8 +24,9 @@ struct LocalDerivationGoal : public DerivationGoal
/* The path of the temporary directory in the sandbox. */
Path tmpDirInSandbox;
- /* Pipe for the builder's standard output/error. */
- Pipe builderOut;
+ /* Master side of the pseudoterminal used for the builder's
+ standard output/error. */
+ AutoCloseFD builderOut;
/* Pipe for synchronising updates to the builder namespaces. */
Pipe userNamespaceSync;
diff --git a/src/libstore/builtins/buildenv.cc b/src/libstore/builtins/buildenv.cc
index b1fbda13d..7bba33fb9 100644
--- a/src/libstore/builtins/buildenv.cc
+++ b/src/libstore/builtins/buildenv.cc
@@ -92,13 +92,11 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
if (S_ISLNK(dstSt.st_mode)) {
auto prevPriority = state.priorities[dstFile];
if (prevPriority == priority)
- throw Error(
- "files '%1%' and '%2%' have the same priority %3%; "
- "use 'nix-env --set-flag priority NUMBER INSTALLED_PKGNAME' "
- "or type 'nix profile install --help' if using 'nix profile' to find out how "
- "to change the priority of one of the conflicting packages"
- " (0 being the highest priority)",
- srcFile, readLink(dstFile), priority);
+ throw BuildEnvFileConflictError(
+ readLink(dstFile),
+ srcFile,
+ priority
+ );
if (prevPriority < priority)
continue;
if (unlink(dstFile.c_str()) == -1)
diff --git a/src/libstore/builtins/buildenv.hh b/src/libstore/builtins/buildenv.hh
index 73c0f5f7f..a018de3af 100644
--- a/src/libstore/builtins/buildenv.hh
+++ b/src/libstore/builtins/buildenv.hh
@@ -12,6 +12,32 @@ struct Package {
Package(const Path & path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
};
+class BuildEnvFileConflictError : public Error
+{
+public:
+ const Path fileA;
+ const Path fileB;
+ int priority;
+
+ BuildEnvFileConflictError(
+ const Path fileA,
+ const Path fileB,
+ int priority
+ )
+ : Error(
+ "Unable to build profile. There is a conflict for the following files:\n"
+ "\n"
+ " %1%\n"
+ " %2%",
+ fileA,
+ fileB
+ )
+ , fileA(fileA)
+ , fileB(fileB)
+ , priority(priority)
+ {}
+};
+
typedef std::vector<Package> Packages;
void buildProfile(const Path & out, Packages && pkgs);
diff --git a/src/libstore/content-address.cc b/src/libstore/content-address.cc
index d9a8a4535..64daea0d4 100644
--- a/src/libstore/content-address.cc
+++ b/src/libstore/content-address.cc
@@ -22,13 +22,6 @@ std::string makeFileIngestionPrefix(FileIngestionMethod m)
}
}
-std::string makeFixedOutputCA(FileIngestionMethod method, const Hash & hash)
-{
- return "fixed:"
- + makeFileIngestionPrefix(method)
- + hash.to_string(Base32, true);
-}
-
std::string renderContentAddress(ContentAddress ca)
{
return std::visit(overloaded {
diff --git a/src/libstore/content-address.hh b/src/libstore/content-address.hh
index 9fae288d8..d74d1ff4b 100644
--- a/src/libstore/content-address.hh
+++ b/src/libstore/content-address.hh
@@ -14,10 +14,28 @@ namespace nix {
/* We only have one way to hash text with references, so this is a single-value
type, mainly useful with std::variant.
*/
+
+/**
+ * The single way we can serialize "text" file system objects.
+ *
+ * Somewhat obscure, used by \ref Derivation derivations and
+ * `builtins.toFile` currently.
+ */
struct TextHashMethod : std::monostate { };
+/**
+ * An enumeration of the main ways we can serialize file system
+ * objects.
+ */
enum struct FileIngestionMethod : uint8_t {
+ /**
+ * Flat-file hashing. Directly ingest the contents of a single file
+ */
Flat = false,
+ /**
+ * Recursive (or NAR) hashing. Serializes the file-system object in Nix
+ * Archive format and ingest that
+ */
Recursive = true
};
@@ -26,15 +44,21 @@ struct FixedOutputHashMethod {
HashType hashType;
};
-/* Compute the prefix to the hash algorithm which indicates how the files were
- ingested. */
+/**
+ * Compute the prefix to the hash algorithm which indicates how the
+ * files were ingested.
+ */
std::string makeFileIngestionPrefix(FileIngestionMethod m);
-/* Just the type of a content address. Combine with the hash itself, and we
- have a `ContentAddress` as defined below. Combine that, in turn, with info
- on references, and we have `ContentAddressWithReferences`, as defined
- further below. */
+/**
+ * An enumeration of all the ways we can serialize file system objects.
+ *
+ * Just the type of a content address. Combine with the hash itself, and
+ * we have a `ContentAddress` as defined below. Combine that, in turn,
+ * with info on references, and we have `ContentAddressWithReferences`,
+ * as defined further below.
+ */
typedef std::variant<
TextHashMethod,
FixedOutputHashMethod
@@ -48,37 +72,58 @@ std::string renderContentAddressMethod(ContentAddressMethod caMethod);
* Mini content address
*/
+/**
+ * Somewhat obscure, used by \ref Derivation derivations and
+ * `builtins.toFile` currently.
+ */
struct TextHash {
+ /**
+ * Hash of the contents of the text/file.
+ */
Hash hash;
GENERATE_CMP(TextHash, me->hash);
};
-/// Pair of a hash, and how the file system was ingested
+/**
+ * Used by most store objects that are content-addressed.
+ */
struct FixedOutputHash {
+ /**
+ * How the file system objects are serialized
+ */
FileIngestionMethod method;
+ /**
+ * Hash of that serialization
+ */
Hash hash;
+
std::string printMethodAlgo() const;
GENERATE_CMP(FixedOutputHash, me->method, me->hash);
};
-/*
- We've accumulated several types of content-addressed paths over the years;
- fixed-output derivations support multiple hash algorithms and serialisation
- methods (flat file vs NAR). Thus, ‘ca’ has one of the following forms:
-
- * ‘text:sha256:<sha256 hash of file contents>’: For paths
- computed by makeTextPath() / addTextToStore().
-
- * ‘fixed:<r?>:<ht>:<h>’: For paths computed by
- makeFixedOutputPath() / addToStore().
-*/
+/**
+ * We've accumulated several types of content-addressed paths over the
+ * years; fixed-output derivations support multiple hash algorithms and
+ * serialisation methods (flat file vs NAR). Thus, ‘ca’ has one of the
+ * following forms:
+ *
+ * - ‘text:sha256:<sha256 hash of file contents>’: For paths
+ * computed by Store::makeTextPath() / Store::addTextToStore().
+ *
+ * - ‘fixed:<r?>:<ht>:<h>’: For paths computed by
+ * Store::makeFixedOutputPath() / Store::addToStore().
+ */
typedef std::variant<
- TextHash, // for paths computed by makeTextPath() / addTextToStore
- FixedOutputHash // for path computed by makeFixedOutputPath
+ TextHash,
+ FixedOutputHash
> ContentAddress;
+/**
+ * Compute the content-addressability assertion (ValidPathInfo::ca) for
+ * paths created by Store::makeFixedOutputPath() / Store::addToStore().
+ */
std::string renderContentAddress(ContentAddress ca);
std::string renderContentAddress(std::optional<ContentAddress> ca);
@@ -90,15 +135,33 @@ std::optional<ContentAddress> parseContentAddressOpt(std::string_view rawCaOpt);
Hash getContentAddressHash(const ContentAddress & ca);
-/*
- * References set
+/**
+ * A set of references to other store objects.
+ *
+ * References to other store objects are tracked with store paths, self
+ * references however are tracked with a boolean.
*/
-
struct StoreReferences {
+ /**
+ * References to other store objects
+ */
StorePathSet others;
+
+ /**
+ * Reference to this store object
+ */
bool self = false;
+ /**
+ * @return true iff no references, i.e. others is empty and self is
+ * false.
+ */
bool empty() const;
+
+ /**
+ * Returns the numbers of references, i.e. the size of others + 1
+ * iff self is true.
+ */
size_t size() const;
GENERATE_CMP(StoreReferences, me->self, me->others);
@@ -113,7 +176,10 @@ struct StoreReferences {
// This matches the additional info that we need for makeTextPath
struct TextInfo {
TextHash hash;
- // References for the paths, self references disallowed
+ /**
+ * References to other store objects only; self references
+ * disallowed
+ */
StorePathSet references;
GENERATE_CMP(TextInfo, me->hash, me->references);
@@ -121,17 +187,28 @@ struct TextInfo {
struct FixedOutputInfo {
FixedOutputHash hash;
- // References for the paths
+ /**
+ * References to other store objects or this one.
+ */
StoreReferences references;
GENERATE_CMP(FixedOutputInfo, me->hash, me->references);
};
+/**
+ * Ways of content addressing but not a complete ContentAddress.
+ *
+ * A ContentAddress without a Hash.
+ */
typedef std::variant<
TextInfo,
FixedOutputInfo
> ContentAddressWithReferences;
+/**
+ * Create a ContentAddressWithReferences from a mere ContentAddress, by
+ * assuming no references in all cases.
+ */
ContentAddressWithReferences caWithoutRefs(const ContentAddress &);
}
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index 5e6fd011f..656ad4587 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -67,12 +67,12 @@ struct TunnelLogger : public Logger
state->pendingMsgs.push_back(s);
}
- void log(Verbosity lvl, const FormatOrString & fs) override
+ void log(Verbosity lvl, std::string_view s) override
{
if (lvl > verbosity) return;
StringSink buf;
- buf << STDERR_NEXT << (fs.s + "\n");
+ buf << STDERR_NEXT << (s + "\n");
enqueueMsg(buf.s);
}
@@ -231,10 +231,10 @@ struct ClientSettings
try {
if (name == "ssh-auth-sock") // obsolete
;
- else if (name == settings.experimentalFeatures.name) {
+ else if (name == experimentalFeatureSettings.experimentalFeatures.name) {
// We don’t want to forward the experimental features to
// the daemon, as that could cause some pretty weird stuff
- if (parseFeatures(tokenizeString<StringSet>(value)) != settings.experimentalFeatures.get())
+ if (parseFeatures(tokenizeString<StringSet>(value)) != experimentalFeatureSettings.experimentalFeatures.get())
debug("Ignoring the client-specified experimental features");
} else if (name == settings.pluginFiles.name) {
if (tokenizeString<Paths>(value) != settings.pluginFiles.get())
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index 31be7040e..fdb5f999a 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -221,7 +221,7 @@ static DerivationOutput parseDerivationOutput(const Store & store,
}
const auto hashType = parseHashType(hashAlgo);
if (hash == "impure") {
- settings.requireExperimentalFeature(Xp::ImpureDerivations);
+ experimentalFeatureSettings.require(Xp::ImpureDerivations);
assert(pathS == "");
return DerivationOutput::Impure {
.method = std::move(method),
@@ -236,7 +236,7 @@ static DerivationOutput parseDerivationOutput(const Store & store,
},
};
} else {
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
assert(pathS == "");
return DerivationOutput::CAFloating {
.method = std::move(method),
diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh
index 8456b29e7..a5731f18d 100644
--- a/src/libstore/derivations.hh
+++ b/src/libstore/derivations.hh
@@ -17,42 +17,72 @@ class Store;
/* Abstract syntax of derivations. */
-/* The traditional non-fixed-output derivation type. */
+/**
+ * The traditional non-fixed-output derivation type.
+ */
struct DerivationOutputInputAddressed
{
StorePath path;
};
-/* Fixed-output derivations, whose output paths are content addressed
- according to that fixed output. */
+/**
+ * Fixed-output derivations, whose output paths are content
+ * addressed according to that fixed output.
+ */
struct DerivationOutputCAFixed
{
- FixedOutputHash hash; /* hash used for expected hash computation */
+ /**
+ * hash used for expected hash computation
+ */
+ FixedOutputHash hash;
+
+ /**
+ * Return the \ref StorePath "store path" corresponding to this output
+ *
+ * @param drvName The name of the derivation this is an output of, without the `.drv`.
+ * @param outputName The name of this output.
+ */
StorePath path(const Store & store, std::string_view drvName, std::string_view outputName) const;
};
-/* Floating-output derivations, whose output paths are content addressed, but
- not fixed, and so are dynamically calculated from whatever the output ends
- up being. */
+/**
+ * Floating-output derivations, whose output paths are content
+ * addressed, but not fixed, and so are dynamically calculated from
+ * whatever the output ends up being.
+ * */
struct DerivationOutputCAFloating
{
- /* information used for expected hash computation */
+ /**
+ * How the file system objects will be serialized for hashing
+ */
FileIngestionMethod method;
+
+ /**
+ * How the serialization will be hashed
+ */
HashType hashType;
};
-/* Input-addressed output which depends on a (CA) derivation whose hash isn't
- * known yet.
+/**
+ * Input-addressed output which depends on a (CA) derivation whose hash
+ * isn't known yet.
*/
struct DerivationOutputDeferred {};
-/* Impure output which is moved to a content-addressed location (like
- CAFloating) but isn't registered as a realization.
+/**
+ * Impure output which is moved to a content-addressed location (like
+ * CAFloating) but isn't registered as a realization.
*/
struct DerivationOutputImpure
{
- /* information used for expected hash computation */
+ /**
+ * How the file system objects will be serialized for hashing
+ */
FileIngestionMethod method;
+
+ /**
+ * How the serialization will be hashed
+ */
HashType hashType;
};
@@ -64,6 +94,9 @@ typedef std::variant<
DerivationOutputImpure
> _DerivationOutputRaw;
+/**
+ * A single output of a BasicDerivation (and Derivation).
+ */
struct DerivationOutput : _DerivationOutputRaw
{
using Raw = _DerivationOutputRaw;
@@ -75,9 +108,12 @@ struct DerivationOutput : _DerivationOutputRaw
using Deferred = DerivationOutputDeferred;
using Impure = DerivationOutputImpure;
- /* Note, when you use this function you should make sure that you're passing
- the right derivation name. When in doubt, you should use the safer
- interface provided by BasicDerivation::outputsAndOptPaths */
+ /**
+ * \note when you use this function you should make sure that you're
+ * passing the right derivation name. When in doubt, you should use
+ * the safer interface provided by
+ * BasicDerivation::outputsAndOptPaths
+ */
std::optional<StorePath> path(const Store & store, std::string_view drvName, std::string_view outputName) const;
inline const Raw & raw() const {
@@ -92,26 +128,61 @@ struct DerivationOutput : _DerivationOutputRaw
typedef std::map<std::string, DerivationOutput> DerivationOutputs;
-/* These are analogues to the previous DerivationOutputs data type, but they
- also contains, for each output, the (optional) store path in which it would
- be written. To calculate values of these types, see the corresponding
- functions in BasicDerivation */
+/**
+ * These are analogues to the previous DerivationOutputs data type,
+ * but they also contains, for each output, the (optional) store
+ * path in which it would be written. To calculate values of these
+ * types, see the corresponding functions in BasicDerivation.
+ */
typedef std::map<std::string, std::pair<DerivationOutput, std::optional<StorePath>>>
DerivationOutputsAndOptPaths;
-/* For inputs that are sub-derivations, we specify exactly which
- output IDs we are interested in. */
+/**
+ * For inputs that are sub-derivations, we specify exactly which
+ * output IDs we are interested in.
+ */
typedef std::map<StorePath, StringSet> DerivationInputs;
+/**
+ * Input-addressed derivation types
+ */
struct DerivationType_InputAddressed {
+ /**
+ * True iff the derivation type can't be determined statically,
+ * for instance because it (transitively) depends on a content-addressed
+ * derivation.
+ */
bool deferred;
};
+/**
+ * Content-addressed derivation types
+ */
struct DerivationType_ContentAddressed {
+ /**
+ * Whether the derivation should be built safely inside a sandbox.
+ */
bool sandboxed;
+ /**
+ * Whether the derivation's outputs' content-addresses are "fixed"
+ * or "floating.
+ *
+ * - Fixed: content-addresses are written down as part of the
+ * derivation itself. If the outputs don't end up matching the
+ * build fails.
+ *
+ * - Floating: content-addresses are not written down, we do not
+ * know them until we perform the build.
+ */
bool fixed;
};
+/**
+ * Impure derivation type
+ *
+ * This is similar at buil-time to the content addressed, not standboxed, not fixed
+ * type, but has some restrictions on its usage.
+ */
struct DerivationType_Impure {
};
@@ -128,30 +199,38 @@ struct DerivationType : _DerivationTypeRaw {
using ContentAddressed = DerivationType_ContentAddressed;
using Impure = DerivationType_Impure;
- /* Do the outputs of the derivation have paths calculated from their content,
- or from the derivation itself? */
+ /**
+ * Do the outputs of the derivation have paths calculated from their
+ * content, or from the derivation itself?
+ */
bool isCA() const;
- /* Is the content of the outputs fixed a-priori via a hash? Never true for
- non-CA derivations. */
+ /**
+ * Is the content of the outputs fixed <em>a priori</em> via a hash?
+ * Never true for non-CA derivations.
+ */
bool isFixed() const;
- /* Whether the derivation is fully sandboxed. If false, the
- sandbox is opened up, e.g. the derivation has access to the
- network. Note that whether or not we actually sandbox the
- derivation is controlled separately. Always true for non-CA
- derivations. */
+ /**
+ * Whether the derivation is fully sandboxed. If false, the sandbox
+ * is opened up, e.g. the derivation has access to the network. Note
+ * that whether or not we actually sandbox the derivation is
+ * controlled separately. Always true for non-CA derivations.
+ */
bool isSandboxed() const;
- /* Whether the derivation is expected to produce the same result
- every time, and therefore it only needs to be built once. This
- is only false for derivations that have the attribute '__impure
- = true'. */
+ /**
+ * Whether the derivation is expected to produce the same result
+ * every time, and therefore it only needs to be built once. This is
+ * only false for derivations that have the attribute '__impure =
+ * true'.
+ */
bool isPure() const;
- /* Does the derivation knows its own output paths?
- Only true when there's no floating-ca derivation involved in the
- closure, or if fixed output.
+ /**
+ * Does the derivation knows its own output paths?
+ * Only true when there's no floating-ca derivation involved in the
+ * closure, or if fixed output.
*/
bool hasKnownOutputPaths() const;
@@ -175,15 +254,21 @@ struct BasicDerivation
bool isBuiltin() const;
- /* Return true iff this is a fixed-output derivation. */
+ /**
+ * Return true iff this is a fixed-output derivation.
+ */
DerivationType type() const;
- /* Return the output names of a derivation. */
+ /**
+ * Return the output names of a derivation.
+ */
StringSet outputNames() const;
- /* Calculates the maps that contains all the DerivationOutputs, but
- augmented with knowledge of the Store paths they would be written
- into. */
+ /**
+ * Calculates the maps that contains all the DerivationOutputs, but
+ * augmented with knowledge of the Store paths they would be written
+ * into.
+ */
DerivationOutputsAndOptPaths outputsAndOptPaths(const Store & store) const;
static std::string_view nameFromPath(const StorePath & storePath);
@@ -191,23 +276,33 @@ struct BasicDerivation
struct Derivation : BasicDerivation
{
- DerivationInputs inputDrvs; /* inputs that are sub-derivations */
+ /**
+ * inputs that are sub-derivations
+ */
+ DerivationInputs inputDrvs;
- /* Print a derivation. */
+ /**
+ * Print a derivation.
+ */
std::string unparse(const Store & store, bool maskOutputs,
std::map<std::string, StringSet> * actualInputs = nullptr) const;
- /* Return the underlying basic derivation but with these changes:
-
- 1. Input drvs are emptied, but the outputs of them that were used are
- added directly to input sources.
-
- 2. Input placeholders are replaced with realized input store paths. */
+ /**
+ * Return the underlying basic derivation but with these changes:
+ *
+ * 1. Input drvs are emptied, but the outputs of them that were used
+ * are added directly to input sources.
+ *
+ * 2. Input placeholders are replaced with realized input store
+ * paths.
+ */
std::optional<BasicDerivation> tryResolve(Store & store) const;
- /* Like the above, but instead of querying the Nix database for
- realisations, uses a given mapping from input derivation paths
- + output names to actual output store paths. */
+ /**
+ * Like the above, but instead of querying the Nix database for
+ * realisations, uses a given mapping from input derivation paths +
+ * output names to actual output store paths.
+ */
std::optional<BasicDerivation> tryResolve(
Store & store,
const std::map<std::pair<StorePath, std::string>, StorePath> & inputDrvOutputs) const;
@@ -222,81 +317,108 @@ struct Derivation : BasicDerivation
class Store;
-/* Write a derivation to the Nix store, and return its path. */
+/**
+ * Write a derivation to the Nix store, and return its path.
+ */
StorePath writeDerivation(Store & store,
const Derivation & drv,
RepairFlag repair = NoRepair,
bool readOnly = false);
-/* Read a derivation from a file. */
+/**
+ * Read a derivation from a file.
+ */
Derivation parseDerivation(const Store & store, std::string && s, std::string_view name);
-// FIXME: remove
+/**
+ * \todo Remove.
+ *
+ * Use Path::isDerivation instead.
+ */
bool isDerivation(std::string_view fileName);
-/* Calculate the name that will be used for the store path for this
- output.
-
- This is usually <drv-name>-<output-name>, but is just <drv-name> when
- the output name is "out". */
+/**
+ * Calculate the name that will be used for the store path for this
+ * output.
+ *
+ * This is usually <drv-name>-<output-name>, but is just <drv-name> when
+ * the output name is "out".
+ */
std::string outputPathName(std::string_view drvName, std::string_view outputName);
-// The hashes modulo of a derivation.
-//
-// Each output is given a hash, although in practice only the content-addressed
-// derivations (fixed-output or not) will have a different hash for each
-// output.
+/**
+ * The hashes modulo of a derivation.
+ *
+ * Each output is given a hash, although in practice only the content-addressed
+ * derivations (fixed-output or not) will have a different hash for each
+ * output.
+ */
struct DrvHash {
+ /**
+ * Map from output names to hashes
+ */
std::map<std::string, Hash> hashes;
enum struct Kind : bool {
- // Statically determined derivations.
- // This hash will be directly used to compute the output paths
+ /**
+ * Statically determined derivations.
+ * This hash will be directly used to compute the output paths
+ */
Regular,
- // Floating-output derivations (and their reverse dependencies).
+
+ /**
+ * Floating-output derivations (and their reverse dependencies).
+ */
Deferred,
};
+ /**
+ * The kind of derivation this is, simplified for just "derivation hash
+ * modulo" purposes.
+ */
Kind kind;
};
void operator |= (DrvHash::Kind & self, const DrvHash::Kind & other) noexcept;
-/* Returns hashes with the details of fixed-output subderivations
- expunged.
-
- A fixed-output derivation is a derivation whose outputs have a
- specified content hash and hash algorithm. (Currently they must have
- exactly one output (`out'), which is specified using the `outputHash'
- and `outputHashAlgo' attributes, but the algorithm doesn't assume
- this.) We don't want changes to such derivations to propagate upwards
- through the dependency graph, changing output paths everywhere.
-
- For instance, if we change the url in a call to the `fetchurl'
- function, we do not want to rebuild everything depending on it---after
- all, (the hash of) the file being downloaded is unchanged. So the
- *output paths* should not change. On the other hand, the *derivation
- paths* should change to reflect the new dependency graph.
-
- For fixed-output derivations, this returns a map from the name of
- each output to its hash, unique up to the output's contents.
-
- For regular derivations, it returns a single hash of the derivation
- ATerm, after subderivations have been likewise expunged from that
- derivation.
+/**
+ * Returns hashes with the details of fixed-output subderivations
+ * expunged.
+ *
+ * A fixed-output derivation is a derivation whose outputs have a
+ * specified content hash and hash algorithm. (Currently they must have
+ * exactly one output (`out'), which is specified using the `outputHash'
+ * and `outputHashAlgo' attributes, but the algorithm doesn't assume
+ * this.) We don't want changes to such derivations to propagate upwards
+ * through the dependency graph, changing output paths everywhere.
+ *
+ * For instance, if we change the url in a call to the `fetchurl'
+ * function, we do not want to rebuild everything depending on it---after
+ * all, (the hash of) the file being downloaded is unchanged. So the
+ * *output paths* should not change. On the other hand, the *derivation
+ * paths* should change to reflect the new dependency graph.
+ *
+ * For fixed-output derivations, this returns a map from the name of
+ * each output to its hash, unique up to the output's contents.
+ *
+ * For regular derivations, it returns a single hash of the derivation
+ * ATerm, after subderivations have been likewise expunged from that
+ * derivation.
*/
DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOutputs);
-/*
- Return a map associating each output to a hash that uniquely identifies its
- derivation (modulo the self-references).
-
- FIXME: what is the Hash in this map?
+/**
+ * Return a map associating each output to a hash that uniquely identifies its
+ * derivation (modulo the self-references).
+ *
+ * \todo What is the Hash in this map?
*/
std::map<std::string, Hash> staticOutputHashes(Store & store, const Derivation & drv);
-/* Memoisation of hashDerivationModulo(). */
+/**
+ * Memoisation of hashDerivationModulo().
+ */
typedef std::map<StorePath, DrvHash> DrvHashes;
// FIXME: global, though at least thread-safe.
@@ -308,21 +430,25 @@ struct Sink;
Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv, std::string_view name);
void writeDerivation(Sink & out, const Store & store, const BasicDerivation & drv);
-/* This creates an opaque and almost certainly unique string
- deterministically from the output name.
-
- It is used as a placeholder to allow derivations to refer to their
- own outputs without needing to use the hash of a derivation in
- itself, making the hash near-impossible to calculate. */
+/**
+ * This creates an opaque and almost certainly unique string
+ * deterministically from the output name.
+ *
+ * It is used as a placeholder to allow derivations to refer to their
+ * own outputs without needing to use the hash of a derivation in
+ * itself, making the hash near-impossible to calculate.
+ */
std::string hashPlaceholder(const std::string_view outputName);
-/* This creates an opaque and almost certainly unique string
- deterministically from a derivation path and output name.
-
- It is used as a placeholder to allow derivations to refer to
- content-addressed paths whose content --- and thus the path
- themselves --- isn't yet known. This occurs when a derivation has a
- dependency which is a CA derivation. */
+/**
+ * This creates an opaque and almost certainly unique string
+ * deterministically from a derivation path and output name.
+ *
+ * It is used as a placeholder to allow derivations to refer to
+ * content-addressed paths whose content --- and thus the path
+ * themselves --- isn't yet known. This occurs when a derivation has a
+ * dependency which is a CA derivation.
+ */
std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath, std::string_view outputName);
extern const Hash impureOutputHash;
diff --git a/src/libstore/derived-path.cc b/src/libstore/derived-path.cc
index e0d86a42f..e5f0f1b33 100644
--- a/src/libstore/derived-path.cc
+++ b/src/libstore/derived-path.cc
@@ -105,7 +105,7 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
auto drvHashes =
staticOutputHashes(store, store.readDerivation(p.drvPath));
for (auto& [outputName, outputPath] : p.outputs) {
- if (settings.isExperimentalFeatureEnabled(
+ if (experimentalFeatureSettings.isEnabled(
Xp::CaDerivations)) {
auto drvOutput = get(drvHashes, outputName);
if (!drvOutput)
diff --git a/src/libstore/derived-path.hh b/src/libstore/derived-path.hh
index 9e0cce377..72dbcc128 100644
--- a/src/libstore/derived-path.hh
+++ b/src/libstore/derived-path.hh
@@ -105,7 +105,7 @@ using _BuiltPathRaw = std::variant<
>;
/**
- * A built path. Similar to a `DerivedPath`, but enriched with the corresponding
+ * A built path. Similar to a DerivedPath, but enriched with the corresponding
* output path(s).
*/
struct BuiltPath : _BuiltPathRaw {
diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc
index b4fbe0b70..16e5fafd7 100644
--- a/src/libstore/dummy-store.cc
+++ b/src/libstore/dummy-store.cc
@@ -7,6 +7,13 @@ struct DummyStoreConfig : virtual StoreConfig {
using StoreConfig::StoreConfig;
const std::string name() override { return "Dummy Store"; }
+
+ std::string doc() override
+ {
+ return
+ #include "dummy-store.md"
+ ;
+ }
};
struct DummyStore : public virtual DummyStoreConfig, public virtual Store
diff --git a/src/libstore/dummy-store.md b/src/libstore/dummy-store.md
new file mode 100644
index 000000000..eb7b4ba0d
--- /dev/null
+++ b/src/libstore/dummy-store.md
@@ -0,0 +1,13 @@
+R"(
+
+**Store URL format**: `dummy://`
+
+This store type represents a store that contains no store paths and
+cannot be written to. It's useful when you want to use the Nix
+evaluator when no actual Nix store exists, e.g.
+
+```console
+# nix eval --store dummy:// --expr '1 + 2'
+```
+
+)"
diff --git a/src/libstore/export-import.cc b/src/libstore/export-import.cc
index 9875da909..4eb838b68 100644
--- a/src/libstore/export-import.cc
+++ b/src/libstore/export-import.cc
@@ -16,7 +16,7 @@ void Store::exportPaths(const StorePathSet & paths, Sink & sink)
//logger->incExpected(doneLabel, sorted.size());
for (auto & path : sorted) {
- //Activity act(*logger, lvlInfo, format("exporting path '%s'") % path);
+ //Activity act(*logger, lvlInfo, "exporting path '%s'", path);
sink << 1;
exportPath(path, sink);
//logger->incProgress(doneLabel);
@@ -71,7 +71,7 @@ StorePaths Store::importPaths(Source & source, CheckSigsFlag checkSigs)
auto path = parseStorePath(readString(source));
- //Activity act(*logger, lvlInfo, format("importing path '%s'") % info.path);
+ //Activity act(*logger, lvlInfo, "importing path '%s'", info.path);
auto references = worker_proto::read(*this, source, Phantom<StorePathSet> {});
auto deriver = readString(source);
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 1c8676a59..1ba399a29 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -88,6 +88,10 @@ struct curlFileTransfer : public FileTransfer
{request.uri}, request.parentAct)
, callback(std::move(callback))
, finalSink([this](std::string_view data) {
+ if (errorSink) {
+ (*errorSink)(data);
+ }
+
if (this->request.dataCallback) {
auto httpStatus = getHTTPStatus();
@@ -163,8 +167,6 @@ struct curlFileTransfer : public FileTransfer
}
}
- if (errorSink)
- (*errorSink)({(char *) contents, realSize});
(*decompressionSink)({(char *) contents, realSize});
return realSize;
@@ -183,7 +185,7 @@ struct curlFileTransfer : public FileTransfer
{
size_t realSize = size * nmemb;
std::string line((char *) contents, realSize);
- printMsg(lvlVomit, format("got header for '%s': %s") % request.uri % trim(line));
+ printMsg(lvlVomit, "got header for '%s': %s", request.uri, trim(line));
static std::regex statusLine("HTTP/[^ ]+ +[0-9]+(.*)", std::regex::extended | std::regex::icase);
std::smatch match;
if (std::regex_match(line, match, statusLine)) {
@@ -207,7 +209,7 @@ struct curlFileTransfer : public FileTransfer
long httpStatus = 0;
curl_easy_getinfo(req, CURLINFO_RESPONSE_CODE, &httpStatus);
if (result.etag == request.expectedETag && httpStatus == 200) {
- debug(format("shutting down on 200 HTTP response with expected ETag"));
+ debug("shutting down on 200 HTTP response with expected ETag");
return 0;
}
} else if (name == "content-encoding")
@@ -316,7 +318,7 @@ struct curlFileTransfer : public FileTransfer
if (request.verifyTLS) {
if (settings.caFile != "")
- curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str());
+ curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.get().c_str());
} else {
curl_easy_setopt(req, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(req, CURLOPT_SSL_VERIFYHOST, 0);
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 996f26a95..0038ec802 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -34,8 +34,7 @@ static void makeSymlink(const Path & link, const Path & target)
createDirs(dirOf(link));
/* Create the new symlink. */
- Path tempLink = (format("%1%.tmp-%2%-%3%")
- % link % getpid() % random()).str();
+ Path tempLink = fmt("%1%.tmp-%2%-%3%", link, getpid(), random());
createSymlink(target, tempLink);
/* Atomically replace the old one. */
@@ -197,7 +196,7 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
pid_t pid = std::stoi(i.name);
- debug(format("reading temporary root file '%1%'") % path);
+ debug("reading temporary root file '%1%'", path);
AutoCloseFD fd(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666));
if (!fd) {
/* It's okay if the file has disappeared. */
@@ -263,7 +262,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
target = absPath(target, dirOf(path));
if (!pathExists(target)) {
if (isInDir(path, stateDir + "/" + gcRootsDir + "/auto")) {
- printInfo(format("removing stale link from '%1%' to '%2%'") % path % target);
+ printInfo("removing stale link from '%1%' to '%2%'", path, target);
unlink(path.c_str());
}
} else {
@@ -372,29 +371,29 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
while (errno = 0, ent = readdir(procDir.get())) {
checkInterrupt();
if (std::regex_match(ent->d_name, digitsRegex)) {
- readProcLink(fmt("/proc/%s/exe" ,ent->d_name), unchecked);
- readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked);
-
- auto fdStr = fmt("/proc/%s/fd", ent->d_name);
- auto fdDir = AutoCloseDir(opendir(fdStr.c_str()));
- if (!fdDir) {
- if (errno == ENOENT || errno == EACCES)
- continue;
- throw SysError("opening %1%", fdStr);
- }
- struct dirent * fd_ent;
- while (errno = 0, fd_ent = readdir(fdDir.get())) {
- if (fd_ent->d_name[0] != '.')
- readProcLink(fmt("%s/%s", fdStr, fd_ent->d_name), unchecked);
- }
- if (errno) {
- if (errno == ESRCH)
- continue;
- throw SysError("iterating /proc/%1%/fd", ent->d_name);
- }
- fdDir.reset();
-
try {
+ readProcLink(fmt("/proc/%s/exe" ,ent->d_name), unchecked);
+ readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked);
+
+ auto fdStr = fmt("/proc/%s/fd", ent->d_name);
+ auto fdDir = AutoCloseDir(opendir(fdStr.c_str()));
+ if (!fdDir) {
+ if (errno == ENOENT || errno == EACCES)
+ continue;
+ throw SysError("opening %1%", fdStr);
+ }
+ struct dirent * fd_ent;
+ while (errno = 0, fd_ent = readdir(fdDir.get())) {
+ if (fd_ent->d_name[0] != '.')
+ readProcLink(fmt("%s/%s", fdStr, fd_ent->d_name), unchecked);
+ }
+ if (errno) {
+ if (errno == ESRCH)
+ continue;
+ throw SysError("iterating /proc/%1%/fd", ent->d_name);
+ }
+ fdDir.reset();
+
auto mapFile = fmt("/proc/%s/maps", ent->d_name);
auto mapLines = tokenizeString<std::vector<std::string>>(readFile(mapFile), "\n");
for (const auto & line : mapLines) {
@@ -863,7 +862,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
continue;
}
- printMsg(lvlTalkative, format("deleting unused link '%1%'") % path);
+ printMsg(lvlTalkative, "deleting unused link '%1%'", path);
if (unlink(path.c_str()) == -1)
throw SysError("deleting '%1%'", path);
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 8e33a3dec..823b4af74 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -30,28 +30,23 @@ static GlobalConfig::Register rSettings(&settings);
Settings::Settings()
: nixPrefix(NIX_PREFIX)
- , nixStore(canonPath(getEnv("NIX_STORE_DIR").value_or(getEnv("NIX_STORE").value_or(NIX_STORE_DIR))))
- , nixDataDir(canonPath(getEnv("NIX_DATA_DIR").value_or(NIX_DATA_DIR)))
- , nixLogDir(canonPath(getEnv("NIX_LOG_DIR").value_or(NIX_LOG_DIR)))
- , nixStateDir(canonPath(getEnv("NIX_STATE_DIR").value_or(NIX_STATE_DIR)))
- , nixConfDir(canonPath(getEnv("NIX_CONF_DIR").value_or(NIX_CONF_DIR)))
+ , nixStore(canonPath(getEnvNonEmpty("NIX_STORE_DIR").value_or(getEnvNonEmpty("NIX_STORE").value_or(NIX_STORE_DIR))))
+ , nixDataDir(canonPath(getEnvNonEmpty("NIX_DATA_DIR").value_or(NIX_DATA_DIR)))
+ , nixLogDir(canonPath(getEnvNonEmpty("NIX_LOG_DIR").value_or(NIX_LOG_DIR)))
+ , nixStateDir(canonPath(getEnvNonEmpty("NIX_STATE_DIR").value_or(NIX_STATE_DIR)))
+ , nixConfDir(canonPath(getEnvNonEmpty("NIX_CONF_DIR").value_or(NIX_CONF_DIR)))
, nixUserConfFiles(getUserConfigFiles())
- , nixBinDir(canonPath(getEnv("NIX_BIN_DIR").value_or(NIX_BIN_DIR)))
+ , nixBinDir(canonPath(getEnvNonEmpty("NIX_BIN_DIR").value_or(NIX_BIN_DIR)))
, nixManDir(canonPath(NIX_MAN_DIR))
- , nixDaemonSocketFile(canonPath(getEnv("NIX_DAEMON_SOCKET_PATH").value_or(nixStateDir + DEFAULT_SOCKET_PATH)))
+ , nixDaemonSocketFile(canonPath(getEnvNonEmpty("NIX_DAEMON_SOCKET_PATH").value_or(nixStateDir + DEFAULT_SOCKET_PATH)))
{
buildUsersGroup = getuid() == 0 ? "nixbld" : "";
lockCPU = getEnv("NIX_AFFINITY_HACK") == "1";
allowSymlinkedStore = getEnv("NIX_IGNORE_SYMLINK_STORE") == "1";
- caFile = getEnv("NIX_SSL_CERT_FILE").value_or(getEnv("SSL_CERT_FILE").value_or(""));
- if (caFile == "") {
- for (auto & fn : {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"})
- if (pathExists(fn)) {
- caFile = fn;
- break;
- }
- }
+ auto sslOverride = getEnv("NIX_SSL_CERT_FILE").value_or(getEnv("SSL_CERT_FILE").value_or(""));
+ if (sslOverride != "")
+ caFile = sslOverride;
/* Backwards compatibility. */
auto s = getEnv("NIX_REMOTE_SYSTEMS");
@@ -166,18 +161,6 @@ StringSet Settings::getDefaultExtraPlatforms()
return extraPlatforms;
}
-bool Settings::isExperimentalFeatureEnabled(const ExperimentalFeature & feature)
-{
- auto & f = experimentalFeatures.get();
- return std::find(f.begin(), f.end(), feature) != f.end();
-}
-
-void Settings::requireExperimentalFeature(const ExperimentalFeature & feature)
-{
- if (!isExperimentalFeatureEnabled(feature))
- throw MissingExperimentalFeature(feature);
-}
-
bool Settings::isWSL1()
{
struct utsname utsbuf;
@@ -187,6 +170,13 @@ bool Settings::isWSL1()
return hasSuffix(utsbuf.release, "-Microsoft");
}
+Path Settings::getDefaultSSLCertFile()
+{
+ for (auto & fn : {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"})
+ if (pathExists(fn)) return fn;
+ return "";
+}
+
const std::string nixVersion = PACKAGE_VERSION;
NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, {
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 93086eaf8..299584f99 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -3,7 +3,6 @@
#include "types.hh"
#include "config.hh"
#include "util.hh"
-#include "experimental-features.hh"
#include <map>
#include <limits>
@@ -64,6 +63,8 @@ class Settings : public Config {
bool isWSL1();
+ Path getDefaultSSLCertFile();
+
public:
Settings();
@@ -97,7 +98,12 @@ public:
Path nixDaemonSocketFile;
Setting<std::string> storeUri{this, getEnv("NIX_REMOTE").value_or("auto"), "store",
- "The default Nix store to use."};
+ R"(
+ The [URL of the Nix store](@docroot@/command-ref/new-cli/nix3-help-stores.md#store-url-format)
+ to use for most operations.
+ See [`nix help-stores`](@docroot@/command-ref/new-cli/nix3-help-stores.md)
+ for supported store types and settings.
+ )"};
Setting<bool> keepFailed{this, false, "keep-failed",
"Whether to keep temporary directories of failed builds."};
@@ -678,8 +684,9 @@ public:
Strings{"https://cache.nixos.org/"},
"substituters",
R"(
- A list of URLs of substituters, separated by whitespace. Substituters
- are tried based on their Priority value, which each substituter can set
+ A list of [URLs of Nix stores](@docroot@/command-ref/new-cli/nix3-help-stores.md#store-url-format)
+ to be used as substituters, separated by whitespace.
+ Substituters are tried based on their Priority value, which each substituter can set
independently. Lower value means higher priority.
The default is `https://cache.nixos.org`, with a Priority of 40.
@@ -697,7 +704,8 @@ public:
Setting<StringSet> trustedSubstituters{
this, {}, "trusted-substituters",
R"(
- A list of URLs of substituters, separated by whitespace. These are
+ A list of [URLs of Nix stores](@docroot@/command-ref/new-cli/nix3-help-stores.md#store-url-format),
+ separated by whitespace. These are
not used by default, but can be enabled by users of the Nix daemon
by specifying `--option substituters urls` on the command
line. Unprivileged users are only allowed to pass a subset of the
@@ -826,8 +834,22 @@ public:
> `.netrc`.
)"};
- /* Path to the SSL CA file used */
- Path caFile;
+ Setting<Path> caFile{
+ this, getDefaultSSLCertFile(), "ssl-cert-file",
+ R"(
+ The path of a file containing CA certificates used to
+ authenticate `https://` downloads. Nix by default will use
+ the first of the following files that exists:
+
+ 1. `/etc/ssl/certs/ca-certificates.crt`
+ 2. `/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt`
+
+ The path can be overridden by the following environment
+ variables, in order of precedence:
+
+ 1. `NIX_SSL_CERT_FILE`
+ 2. `SSL_CERT_FILE`
+ )"};
#if __linux__
Setting<bool> filterSyscalls{
@@ -932,13 +954,6 @@ public:
are loaded as plugins (non-recursively).
)"};
- Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features",
- "Experimental Nix features to enable."};
-
- bool isExperimentalFeatureEnabled(const ExperimentalFeature &);
-
- void requireExperimentalFeature(const ExperimentalFeature &);
-
Setting<size_t> narBufferSize{this, 32 * 1024 * 1024, "nar-buffer-size",
"Maximum size of NARs before spilling them to disk."};
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 1479822a9..238fd1d98 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -12,7 +12,14 @@ struct HttpBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
{
using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
- const std::string name() override { return "Http Binary Cache Store"; }
+ const std::string name() override { return "HTTP Binary Cache Store"; }
+
+ std::string doc() override
+ {
+ return
+ #include "http-binary-cache-store.md"
+ ;
+ }
};
class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public virtual BinaryCacheStore
diff --git a/src/libstore/http-binary-cache-store.md b/src/libstore/http-binary-cache-store.md
new file mode 100644
index 000000000..20c26d0c2
--- /dev/null
+++ b/src/libstore/http-binary-cache-store.md
@@ -0,0 +1,8 @@
+R"(
+
+**Store URL format**: `http://...`, `https://...`
+
+This store allows a binary cache to be accessed via the HTTP
+protocol.
+
+)"
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index 2c9dd2680..98322b045 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -1,3 +1,4 @@
+#include "ssh-store-config.hh"
#include "archive.hh"
#include "pool.hh"
#include "remote-store.hh"
@@ -12,17 +13,24 @@
namespace nix {
-struct LegacySSHStoreConfig : virtual StoreConfig
+struct LegacySSHStoreConfig : virtual CommonSSHStoreConfig
{
- using StoreConfig::StoreConfig;
- const Setting<int> maxConnections{(StoreConfig*) this, 1, "max-connections", "maximum number of concurrent SSH connections"};
- const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
- const Setting<std::string> sshPublicHostKey{(StoreConfig*) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"};
- const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
- const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"};
- const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
-
- const std::string name() override { return "Legacy SSH Store"; }
+ using CommonSSHStoreConfig::CommonSSHStoreConfig;
+
+ const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-store", "remote-program",
+ "Path to the `nix-store` executable on the remote machine."};
+
+ const Setting<int> maxConnections{(StoreConfig*) this, 1, "max-connections",
+ "Maximum number of concurrent SSH connections."};
+
+ const std::string name() override { return "SSH Store"; }
+
+ std::string doc() override
+ {
+ return
+ #include "legacy-ssh-store.md"
+ ;
+ }
};
struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Store
@@ -51,6 +59,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
LegacySSHStore(const std::string & scheme, const std::string & host, const Params & params)
: StoreConfig(params)
+ , CommonSSHStoreConfig(params)
, LegacySSHStoreConfig(params)
, Store(params)
, host(host)
diff --git a/src/libstore/legacy-ssh-store.md b/src/libstore/legacy-ssh-store.md
new file mode 100644
index 000000000..043acebd6
--- /dev/null
+++ b/src/libstore/legacy-ssh-store.md
@@ -0,0 +1,8 @@
+R"(
+
+**Store URL format**: `ssh://[username@]hostname`
+
+This store type allows limited access to a remote store on another
+machine via SSH.
+
+)"
diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc
index f20b1fa02..e5ee6fc15 100644
--- a/src/libstore/local-binary-cache-store.cc
+++ b/src/libstore/local-binary-cache-store.cc
@@ -11,6 +11,13 @@ struct LocalBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
const std::string name() override { return "Local Binary Cache Store"; }
+
+ std::string doc() override
+ {
+ return
+ #include "local-binary-cache-store.md"
+ ;
+ }
};
class LocalBinaryCacheStore : public virtual LocalBinaryCacheStoreConfig, public virtual BinaryCacheStore
diff --git a/src/libstore/local-binary-cache-store.md b/src/libstore/local-binary-cache-store.md
new file mode 100644
index 000000000..93fddc840
--- /dev/null
+++ b/src/libstore/local-binary-cache-store.md
@@ -0,0 +1,16 @@
+R"(
+
+**Store URL format**: `file://`*path*
+
+This store allows reading and writing a binary cache stored in *path*
+in the local filesystem. If *path* does not exist, it will be created.
+
+For example, the following builds or downloads `nixpkgs#hello` into
+the local store and then copies it to the binary cache in
+`/tmp/binary-cache`:
+
+```
+# nix copy --to file:///tmp/binary-cache nixpkgs#hello
+```
+
+)"
diff --git a/src/libstore/local-fs-store.hh b/src/libstore/local-fs-store.hh
index 947707341..796e72045 100644
--- a/src/libstore/local-fs-store.hh
+++ b/src/libstore/local-fs-store.hh
@@ -9,20 +9,28 @@ namespace nix {
struct LocalFSStoreConfig : virtual StoreConfig
{
using StoreConfig::StoreConfig;
+
// FIXME: the (StoreConfig*) cast works around a bug in gcc that causes
// it to omit the call to the Setting constructor. Clang works fine
// either way.
+
const PathSetting rootDir{(StoreConfig*) this, true, "",
- "root", "directory prefixed to all other paths"};
+ "root",
+ "Directory prefixed to all other paths."};
+
const PathSetting stateDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir,
- "state", "directory where Nix will store state"};
+ "state",
+ "Directory where Nix will store state."};
+
const PathSetting logDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir,
- "log", "directory where Nix will store state"};
+ "log",
+ "directory where Nix will store log files."};
+
const PathSetting realStoreDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/store" : storeDir, "real",
- "physical path to the Nix store"};
+ "Physical path of the Nix store."};
};
class LocalFSStore : public virtual LocalFSStoreConfig,
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 8b33b2da5..e1c7e387a 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -44,6 +44,13 @@
namespace nix {
+std::string LocalStoreConfig::doc()
+{
+ return
+ #include "local-store.md"
+ ;
+}
+
struct LocalStore::State::Stmts {
/* Some precompiled SQLite statements. */
SQLiteStmt RegisterValidPath;
@@ -280,7 +287,7 @@ LocalStore::LocalStore(const Params & params)
else if (curSchema == 0) { /* new store */
curSchema = nixSchemaVersion;
openDB(*state, true);
- writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
+ writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, true);
}
else if (curSchema < nixSchemaVersion) {
@@ -329,14 +336,14 @@ LocalStore::LocalStore(const Params & params)
txn.commit();
}
- writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
+ writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, true);
lockFile(globalLock.get(), ltRead, true);
}
else openDB(*state, false);
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
migrateCASchema(state->db, dbDir + "/ca-schema", globalLock);
}
@@ -366,7 +373,7 @@ LocalStore::LocalStore(const Params & params)
state->stmts->QueryPathFromHashPart.create(state->db,
"select path from ValidPaths where path >= ? limit 1;");
state->stmts->QueryValidPaths.create(state->db, "select path from ValidPaths");
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
state->stmts->RegisterRealisedOutput.create(state->db,
R"(
insert into Realisations (drvPath, outputName, outputPath, signatures)
@@ -413,6 +420,13 @@ LocalStore::LocalStore(const Params & params)
}
+LocalStore::LocalStore(std::string scheme, std::string path, const Params & params)
+ : LocalStore(params)
+{
+ throw UnimplementedError("LocalStore");
+}
+
+
AutoCloseFD LocalStore::openGCLock()
{
Path fnGCLock = stateDir + "/gc.lock";
@@ -754,7 +768,7 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
{
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info))
registerDrvOutput(info);
else
@@ -763,7 +777,7 @@ void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag check
void LocalStore::registerDrvOutput(const Realisation & info)
{
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
retrySQLite<void>([&]() {
auto state(_state.lock());
if (auto oldR = queryRealisation_(*state, info.id)) {
@@ -1052,7 +1066,7 @@ LocalStore::queryPartialDerivationOutputMap(const StorePath & path_)
return outputs;
});
- if (!settings.isExperimentalFeatureEnabled(Xp::CaDerivations))
+ if (!experimentalFeatureSettings.isEnabled(Xp::CaDerivations))
return outputs;
auto drv = readInvalidDerivation(path);
@@ -1580,7 +1594,7 @@ void LocalStore::invalidatePathChecked(const StorePath & path)
bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
{
- printInfo(format("reading the Nix store..."));
+ printInfo("reading the Nix store...");
bool errors = false;
@@ -1970,5 +1984,6 @@ std::optional<std::string> LocalStore::getVersion()
return nixVersion;
}
+static RegisterStoreImplementation<LocalStore, LocalStoreConfig> regLocalStore;
} // namespace nix
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index a84eb7c26..639772b36 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -38,11 +38,13 @@ struct LocalStoreConfig : virtual LocalFSStoreConfig
Setting<bool> requireSigs{(StoreConfig*) this,
settings.requireSigs,
- "require-sigs", "whether store paths should have a trusted signature on import"};
+ "require-sigs",
+ "Whether store paths copied into this store should have a trusted signature."};
const std::string name() override { return "Local Store"; }
-};
+ std::string doc() override;
+};
class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore, public virtual GcStore
{
@@ -100,9 +102,13 @@ public:
/* Initialise the local store, upgrading the schema if
necessary. */
LocalStore(const Params & params);
+ LocalStore(std::string scheme, std::string path, const Params & params);
~LocalStore();
+ static std::set<std::string> uriSchemes()
+ { return {}; }
+
/* Implementations of abstract store API methods. */
std::string getUri() override;
diff --git a/src/libstore/local-store.md b/src/libstore/local-store.md
new file mode 100644
index 000000000..8174df839
--- /dev/null
+++ b/src/libstore/local-store.md
@@ -0,0 +1,39 @@
+R"(
+
+**Store URL format**: `local`, *root*
+
+This store type accesses a Nix store in the local filesystem directly
+(i.e. not via the Nix daemon). *root* is an absolute path that is
+prefixed to other directories such as the Nix store directory. The
+store pseudo-URL `local` denotes a store that uses `/` as its root
+directory.
+
+A store that uses a *root* other than `/` is called a *chroot
+store*. With such stores, the store directory is "logically" still
+`/nix/store`, so programs stored in them can only be built and
+executed by `chroot`-ing into *root*. Chroot stores only support
+building and running on Linux when [`mount namespaces`](https://man7.org/linux/man-pages/man7/mount_namespaces.7.html) and [`user namespaces`](https://man7.org/linux/man-pages/man7/user_namespaces.7.html) are
+enabled.
+
+For example, the following uses `/tmp/root` as the chroot environment
+to build or download `nixpkgs#hello` and then execute it:
+
+```console
+# nix run --store /tmp/root nixpkgs#hello
+Hello, world!
+```
+
+Here, the "physical" store location is `/tmp/root/nix/store`, and
+Nix's store metadata is in `/tmp/root/nix/var/nix/db`.
+
+It is also possible, but not recommended, to change the "logical"
+location of the Nix store from its default of `/nix/store`. This makes
+it impossible to use default substituters such as
+`https://cache.nixos.org/`, and thus you may have to build everything
+locally. Here is an example:
+
+```console
+# nix build --store 'local?store=/tmp/my-nix/store&state=/tmp/my-nix/state&log=/tmp/my-nix/log' nixpkgs#hello
+```
+
+)"
diff --git a/src/libstore/lock.cc b/src/libstore/lock.cc
index 4fe1fcf56..7202a64b3 100644
--- a/src/libstore/lock.cc
+++ b/src/libstore/lock.cc
@@ -129,7 +129,7 @@ struct AutoUserLock : UserLock
useUserNamespace = false;
#endif
- settings.requireExperimentalFeature(Xp::AutoAllocateUids);
+ experimentalFeatureSettings.require(Xp::AutoAllocateUids);
assert(settings.startId > 0);
assert(settings.uidCount % maxIdsPerBuild == 0);
assert((uint64_t) settings.startId + (uint64_t) settings.uidCount <= std::numeric_limits<uid_t>::max());
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index b28768459..89148d415 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -326,7 +326,7 @@ OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd,
throw Error(
"the derivation '%s' doesn't have an output named '%s'",
store.printStorePath(bfd.drvPath), output);
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
DrvOutput outputId { *outputHash, output };
auto realisation = store.queryRealisation(outputId);
if (!realisation)
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index 4d2781180..4a79cf4a1 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -55,7 +55,7 @@ LocalStore::InodeHash LocalStore::loadInodeHash()
}
if (errno) throw SysError("reading directory '%1%'", linksDir);
- printMsg(lvlTalkative, format("loaded %1% hash inodes") % inodeHash.size());
+ printMsg(lvlTalkative, "loaded %1% hash inodes", inodeHash.size());
return inodeHash;
}
@@ -73,7 +73,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa
checkInterrupt();
if (inodeHash.count(dirent->d_ino)) {
- debug(format("'%1%' is already linked") % dirent->d_name);
+ debug("'%1%' is already linked", dirent->d_name);
continue;
}
@@ -102,7 +102,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
if (std::regex_search(path, std::regex("\\.app/Contents/.+$")))
{
- debug(format("'%1%' is not allowed to be linked in macOS") % path);
+ debug("'%1%' is not allowed to be linked in macOS", path);
return;
}
#endif
@@ -146,7 +146,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
contents of the symlink (i.e. the result of readlink()), not
the contents of the target (which may not even exist). */
Hash hash = hashPath(htSHA256, path).first;
- debug(format("'%1%' has hash '%2%'") % path % hash.to_string(Base32, true));
+ debug("'%1%' has hash '%2%'", path, hash.to_string(Base32, true));
/* Check if this is a known hash. */
Path linkPath = linksDir + "/" + hash.to_string(Base32, false);
@@ -196,11 +196,11 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
auto stLink = lstat(linkPath);
if (st.st_ino == stLink.st_ino) {
- debug(format("'%1%' is already linked to '%2%'") % path % linkPath);
+ debug("'%1%' is already linked to '%2%'", path, linkPath);
return;
}
- printMsg(lvlTalkative, format("linking '%1%' to '%2%'") % path % linkPath);
+ printMsg(lvlTalkative, "linking '%1%' to '%2%'", path, linkPath);
/* Make the containing directory writable, but only if it's not
the store itself (we don't want or need to mess with its
@@ -213,8 +213,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
its timestamp back to 0. */
MakeReadOnly makeReadOnly(mustToggle ? dirOfPath : "");
- Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
- % realStoreDir % getpid() % random()).str();
+ Path tempLink = fmt("%1%/.tmp-link-%2%-%3%", realStoreDir, getpid(), random());
if (link(linkPath.c_str(), tempLink.c_str()) == -1) {
if (errno == EMLINK) {
@@ -222,7 +221,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
systems). This is likely to happen with empty files.
Just shrug and ignore. */
if (st.st_size)
- printInfo(format("'%1%' has maximum number of links") % linkPath);
+ printInfo("'%1%' has maximum number of links", linkPath);
return;
}
throw SysError("cannot link '%1%' to '%2%'", tempLink, linkPath);
diff --git a/src/libstore/outputs-spec.hh b/src/libstore/outputs-spec.hh
index 46bc35ebc..0b7c98ac9 100644
--- a/src/libstore/outputs-spec.hh
+++ b/src/libstore/outputs-spec.hh
@@ -9,6 +9,9 @@
namespace nix {
+/**
+ * A non-empty set of outputs, specified by name
+ */
struct OutputNames : std::set<std::string> {
using std::set<std::string>::set;
@@ -18,6 +21,9 @@ struct OutputNames : std::set<std::string> {
: std::set<std::string>(s)
{ assert(!empty()); }
+ /**
+ * Needs to be "inherited manually"
+ */
OutputNames(std::set<std::string> && s)
: std::set<std::string>(s)
{ assert(!empty()); }
@@ -28,6 +34,9 @@ struct OutputNames : std::set<std::string> {
OutputNames() = delete;
};
+/**
+ * The set of all outputs, without needing to name them explicitly
+ */
struct AllOutputs : std::monostate { };
typedef std::variant<AllOutputs, OutputNames> _OutputsSpecRaw;
@@ -36,7 +45,9 @@ struct OutputsSpec : _OutputsSpecRaw {
using Raw = _OutputsSpecRaw;
using Raw::Raw;
- /* Force choosing a variant */
+ /**
+ * Force choosing a variant
+ */
OutputsSpec() = delete;
using Names = OutputNames;
@@ -52,14 +63,20 @@ struct OutputsSpec : _OutputsSpecRaw {
bool contains(const std::string & output) const;
- /* Create a new OutputsSpec which is the union of this and that. */
+ /**
+ * Create a new OutputsSpec which is the union of this and that.
+ */
OutputsSpec union_(const OutputsSpec & that) const;
- /* Whether this OutputsSpec is a subset of that. */
+ /**
+ * Whether this OutputsSpec is a subset of that.
+ */
bool isSubsetOf(const OutputsSpec & outputs) const;
- /* Parse a string of the form 'output1,...outputN' or
- '*', returning the outputs spec. */
+ /**
+ * Parse a string of the form 'output1,...outputN' or '*', returning
+ * the outputs spec.
+ */
static OutputsSpec parse(std::string_view s);
static std::optional<OutputsSpec> parseOpt(std::string_view s);
@@ -81,8 +98,10 @@ struct ExtendedOutputsSpec : _ExtendedOutputsSpecRaw {
return static_cast<const Raw &>(*this);
}
- /* Parse a string of the form 'prefix^output1,...outputN' or
- 'prefix^*', returning the prefix and the extended outputs spec. */
+ /**
+ * Parse a string of the form 'prefix^output1,...outputN' or
+ * 'prefix^*', returning the prefix and the extended outputs spec.
+ */
static std::pair<std::string_view, ExtendedOutputsSpec> parse(std::string_view s);
static std::optional<std::pair<std::string_view, ExtendedOutputsSpec>> parseOpt(std::string_view s);
diff --git a/src/libstore/path.hh b/src/libstore/path.hh
index 1e5579b90..2730541c6 100644
--- a/src/libstore/path.hh
+++ b/src/libstore/path.hh
@@ -8,13 +8,22 @@ namespace nix {
struct Hash;
+/**
+ * \ref StorePath "Store path" is the fundamental reference type of Nix.
+ * A store paths refers to a Store object.
+ *
+ * See glossary.html#gloss-store-path for more information on a
+ * conceptual level.
+ */
class StorePath
{
std::string baseName;
public:
- /* Size of the hash part of store paths, in base-32 characters. */
+ /**
+ * Size of the hash part of store paths, in base-32 characters.
+ */
constexpr static size_t HashLen = 32; // i.e. 160 bits
constexpr static size_t MaxPathLen = 211;
@@ -45,8 +54,9 @@ public:
return baseName != other.baseName;
}
- /* Check whether a file name ends with the extension for
- derivations. */
+ /**
+ * Check whether a file name ends with the extension for derivations.
+ */
bool isDerivation() const;
std::string_view name() const
@@ -67,7 +77,10 @@ public:
typedef std::set<StorePath> StorePathSet;
typedef std::vector<StorePath> StorePaths;
-/* Extension of derivations in the Nix store. */
+/**
+ * The file extension of \ref Derivation derivations when serialized
+ * into store objects.
+ */
const std::string drvExtension = ".drv";
}
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index 42023cd0a..adc763e6a 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -96,7 +96,7 @@ bool PathLocks::lockPaths(const PathSet & paths,
checkInterrupt();
Path lockPath = path + ".lock";
- debug(format("locking path '%1%'") % path);
+ debug("locking path '%1%'", path);
AutoCloseFD fd;
@@ -118,7 +118,7 @@ bool PathLocks::lockPaths(const PathSet & paths,
}
}
- debug(format("lock acquired on '%1%'") % lockPath);
+ debug("lock acquired on '%1%'", lockPath);
/* Check that the lock file hasn't become stale (i.e.,
hasn't been unlinked). */
@@ -130,7 +130,7 @@ bool PathLocks::lockPaths(const PathSet & paths,
a lock on a deleted file. This means that other
processes may create and acquire a lock on
`lockPath', and proceed. So we must retry. */
- debug(format("open lock file '%1%' has become stale") % lockPath);
+ debug("open lock file '%1%' has become stale", lockPath);
else
break;
}
@@ -163,7 +163,7 @@ void PathLocks::unlock()
"error (ignored): cannot close lock file on '%1%'",
i.second);
- debug(format("lock released on '%1%'") % i.second);
+ debug("lock released on '%1%'", i.second);
}
fds.clear();
diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc
index c551c5f3e..ba5c8583f 100644
--- a/src/libstore/profiles.cc
+++ b/src/libstore/profiles.cc
@@ -64,7 +64,7 @@ std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path pro
static void makeName(const Path & profile, GenerationNumber num,
Path & outLink)
{
- Path prefix = (format("%1%-%2%") % profile % num).str();
+ Path prefix = fmt("%1%-%2%", profile, num);
outLink = prefix + "-link";
}
@@ -269,7 +269,7 @@ void switchGeneration(
void lockProfile(PathLocks & lock, const Path & profile)
{
- lock.lockPaths({profile}, (format("waiting for lock on profile '%1%'") % profile).str());
+ lock.lockPaths({profile}, fmt("waiting for lock on profile '%1%'", profile));
lock.setDeletion(true);
}
@@ -282,28 +282,48 @@ std::string optimisticLockProfile(const Path & profile)
Path profilesDir()
{
- auto profileRoot = createNixStateDir() + "/profiles";
+ auto profileRoot =
+ (getuid() == 0)
+ ? rootProfilesDir()
+ : createNixStateDir() + "/profiles";
createDirs(profileRoot);
return profileRoot;
}
+Path rootProfilesDir()
+{
+ return settings.nixStateDir + "/profiles/per-user/root";
+}
+
Path getDefaultProfile()
{
Path profileLink = settings.useXDGBaseDirectories ? createNixStateDir() + "/profile" : getHome() + "/.nix-profile";
try {
- auto profile =
- getuid() == 0
- ? settings.nixStateDir + "/profiles/default"
- : profilesDir() + "/profile";
+ auto profile = profilesDir() + "/profile";
if (!pathExists(profileLink)) {
replaceSymlink(profile, profileLink);
}
+ // Backwards compatibiliy measure: Make root's profile available as
+ // `.../default` as it's what NixOS and most of the init scripts expect
+ Path globalProfileLink = settings.nixStateDir + "/profiles/default";
+ if (getuid() == 0 && !pathExists(globalProfileLink)) {
+ replaceSymlink(profile, globalProfileLink);
+ }
return absPath(readLink(profileLink), dirOf(profileLink));
} catch (Error &) {
return profileLink;
}
}
+Path defaultChannelsDir()
+{
+ return profilesDir() + "/channels";
+}
+
+Path rootChannelsDir()
+{
+ return rootProfilesDir() + "/channels";
+}
}
diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh
index fbf95b850..3cadd5c2a 100644
--- a/src/libstore/profiles.hh
+++ b/src/libstore/profiles.hh
@@ -68,13 +68,32 @@ void lockProfile(PathLocks & lock, const Path & profile);
rebuilt. */
std::string optimisticLockProfile(const Path & profile);
-/* Creates and returns the path to a directory suitable for storing the user’s
- profiles. */
+/**
+ * Create and return the path to a directory suitable for storing the user’s
+ * profiles.
+ */
Path profilesDir();
-/* Resolve the default profile (~/.nix-profile by default, $XDG_STATE_HOME/
- nix/profile if XDG Base Directory Support is enabled), and create if doesn't
- exist */
+/**
+ * Return the path to the profile directory for root (but don't try creating it)
+ */
+Path rootProfilesDir();
+
+/**
+ * Create and return the path to the file used for storing the users's channels
+ */
+Path defaultChannelsDir();
+
+/**
+ * Return the path to the channel directory for root (but don't try creating it)
+ */
+Path rootChannelsDir();
+
+/**
+ * Resolve the default profile (~/.nix-profile by default,
+ * $XDG_STATE_HOME/nix/profile if XDG Base Directory Support is enabled),
+ * and create if doesn't exist
+ */
Path getDefaultProfile();
}
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index 3bb297fc8..345f4528b 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -39,8 +39,7 @@ static void search(
if (!match) continue;
std::string ref(s.substr(i, refLength));
if (hashes.erase(ref)) {
- debug(format("found reference to '%1%' at offset '%2%'")
- % ref % i);
+ debug("found reference to '%1%' at offset '%2%'", ref, i);
seen.insert(ref);
}
++i;
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index d1296627a..d24d83117 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -265,7 +265,7 @@ void RemoteStore::setOptions(Connection & conn)
overrides.erase(settings.buildCores.name);
overrides.erase(settings.useSubstitutes.name);
overrides.erase(loggerSettings.showTrace.name);
- overrides.erase(settings.experimentalFeatures.name);
+ overrides.erase(experimentalFeatureSettings.experimentalFeatures.name);
overrides.erase(settings.pluginFiles.name);
conn.to << overrides.size();
for (auto & i : overrides)
@@ -876,7 +876,7 @@ std::vector<BuildResult> RemoteStore::buildPathsWithResults(
"the derivation '%s' doesn't have an output named '%s'",
printStorePath(bfd.drvPath), output);
auto outputId = DrvOutput{ *outputHash, output };
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
auto realisation =
queryRealisation(outputId);
if (!realisation)
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 11d089cd2..999151239 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -22,11 +22,13 @@ struct RemoteStoreConfig : virtual StoreConfig
{
using StoreConfig::StoreConfig;
- const Setting<int> maxConnections{(StoreConfig*) this, 1,
- "max-connections", "maximum number of concurrent connections to the Nix daemon"};
+ const Setting<int> maxConnections{(StoreConfig*) this, 1, "max-connections",
+ "Maximum number of concurrent connections to the Nix daemon."};
- const Setting<unsigned int> maxConnectionAge{(StoreConfig*) this, std::numeric_limits<unsigned int>::max(),
- "max-connection-age", "number of seconds to reuse a connection"};
+ const Setting<unsigned int> maxConnectionAge{(StoreConfig*) this,
+ std::numeric_limits<unsigned int>::max(),
+ "max-connection-age",
+ "Maximum age of a connection before it is closed."};
};
/* FIXME: RemoteStore is a misnomer - should be something like
@@ -38,8 +40,6 @@ class RemoteStore : public virtual RemoteStoreConfig,
{
public:
- virtual bool sameMachine() = 0;
-
RemoteStore(const Params & params);
/* Implementations of abstract store API methods. */
diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc
index 8d76eee99..ac82147ee 100644
--- a/src/libstore/s3-binary-cache-store.cc
+++ b/src/libstore/s3-binary-cache-store.cc
@@ -40,12 +40,12 @@ struct S3Error : public Error
/* Helper: given an Outcome<R, E>, return R in case of success, or
throw an exception in case of an error. */
template<typename R, typename E>
-R && checkAws(const FormatOrString & fs, Aws::Utils::Outcome<R, E> && outcome)
+R && checkAws(std::string_view s, Aws::Utils::Outcome<R, E> && outcome)
{
if (!outcome.IsSuccess())
throw S3Error(
outcome.GetError().GetErrorType(),
- fs.s + ": " + outcome.GetError().GetMessage());
+ s + ": " + outcome.GetError().GetMessage());
return outcome.GetResultWithOwnership();
}
@@ -192,19 +192,72 @@ S3BinaryCacheStore::S3BinaryCacheStore(const Params & params)
struct S3BinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
{
using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
- const Setting<std::string> profile{(StoreConfig*) this, "", "profile", "The name of the AWS configuration profile to use."};
- const Setting<std::string> region{(StoreConfig*) this, Aws::Region::US_EAST_1, "region", {"aws-region"}};
- const Setting<std::string> scheme{(StoreConfig*) this, "", "scheme", "The scheme to use for S3 requests, https by default."};
- const Setting<std::string> endpoint{(StoreConfig*) this, "", "endpoint", "An optional override of the endpoint to use when talking to S3."};
- const Setting<std::string> narinfoCompression{(StoreConfig*) this, "", "narinfo-compression", "compression method for .narinfo files"};
- const Setting<std::string> lsCompression{(StoreConfig*) this, "", "ls-compression", "compression method for .ls files"};
- const Setting<std::string> logCompression{(StoreConfig*) this, "", "log-compression", "compression method for log/* files"};
+
+ const Setting<std::string> profile{(StoreConfig*) this, "", "profile",
+ R"(
+ The name of the AWS configuration profile to use. By default
+ Nix will use the `default` profile.
+ )"};
+
+ const Setting<std::string> region{(StoreConfig*) this, Aws::Region::US_EAST_1, "region",
+ R"(
+ The region of the S3 bucket. If your bucket is not in
+ `us–east-1`, you should always explicitly specify the region
+ parameter.
+ )"};
+
+ const Setting<std::string> scheme{(StoreConfig*) this, "", "scheme",
+ R"(
+ The scheme used for S3 requests, `https` (default) or `http`. This
+ option allows you to disable HTTPS for binary caches which don't
+ support it.
+
+ > **Note**
+ >
+ > HTTPS should be used if the cache might contain sensitive
+ > information.
+ )"};
+
+ const Setting<std::string> endpoint{(StoreConfig*) this, "", "endpoint",
+ R"(
+ The URL of the endpoint of an S3-compatible service such as MinIO.
+ Do not specify this setting if you're using Amazon S3.
+
+ > **Note**
+ >
+ > This endpoint must support HTTPS and will use path-based
+ > addressing instead of virtual host based addressing.
+ )"};
+
+ const Setting<std::string> narinfoCompression{(StoreConfig*) this, "", "narinfo-compression",
+ "Compression method for `.narinfo` files."};
+
+ const Setting<std::string> lsCompression{(StoreConfig*) this, "", "ls-compression",
+ "Compression method for `.ls` files."};
+
+ const Setting<std::string> logCompression{(StoreConfig*) this, "", "log-compression",
+ R"(
+ Compression method for `log/*` files. It is recommended to
+ use a compression method supported by most web browsers
+ (e.g. `brotli`).
+ )"};
+
const Setting<bool> multipartUpload{
- (StoreConfig*) this, false, "multipart-upload", "whether to use multi-part uploads"};
+ (StoreConfig*) this, false, "multipart-upload",
+ "Whether to use multi-part uploads."};
+
const Setting<uint64_t> bufferSize{
- (StoreConfig*) this, 5 * 1024 * 1024, "buffer-size", "size (in bytes) of each part in multi-part uploads"};
+ (StoreConfig*) this, 5 * 1024 * 1024, "buffer-size",
+ "Size (in bytes) of each part in multi-part uploads."};
const std::string name() override { return "S3 Binary Cache Store"; }
+
+ std::string doc() override
+ {
+ return
+ #include "s3-binary-cache-store.md"
+ ;
+ }
};
struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual S3BinaryCacheStore
@@ -430,9 +483,9 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
std::string marker;
do {
- debug(format("listing bucket 's3://%s' from key '%s'...") % bucketName % marker);
+ debug("listing bucket 's3://%s' from key '%s'...", bucketName, marker);
- auto res = checkAws(format("AWS error listing bucket '%s'") % bucketName,
+ auto res = checkAws(fmt("AWS error listing bucket '%s'", bucketName),
s3Helper.client->ListObjects(
Aws::S3::Model::ListObjectsRequest()
.WithBucket(bucketName)
@@ -441,8 +494,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
auto & contents = res.GetContents();
- debug(format("got %d keys, next marker '%s'")
- % contents.size() % res.GetNextMarker());
+ debug("got %d keys, next marker '%s'",
+ contents.size(), res.GetNextMarker());
for (auto object : contents) {
auto & key = object.GetKey();
diff --git a/src/libstore/s3-binary-cache-store.md b/src/libstore/s3-binary-cache-store.md
new file mode 100644
index 000000000..70fe0eb09
--- /dev/null
+++ b/src/libstore/s3-binary-cache-store.md
@@ -0,0 +1,8 @@
+R"(
+
+**Store URL format**: `s3://`*bucket-name*
+
+This store allows reading and writing a binary cache stored in an AWS
+S3 bucket.
+
+)"
diff --git a/src/libstore/ssh-store-config.hh b/src/libstore/ssh-store-config.hh
new file mode 100644
index 000000000..c4232df34
--- /dev/null
+++ b/src/libstore/ssh-store-config.hh
@@ -0,0 +1,26 @@
+#include "store-api.hh"
+
+namespace nix {
+
+struct CommonSSHStoreConfig : virtual StoreConfig
+{
+ using StoreConfig::StoreConfig;
+
+ const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key",
+ "Path to the SSH private key used to authenticate to the remote machine."};
+
+ const Setting<std::string> sshPublicHostKey{(StoreConfig*) this, "", "base64-ssh-public-host-key",
+ "The public host key of the remote machine."};
+
+ const Setting<bool> compress{(StoreConfig*) this, false, "compress",
+ "Whether to enable SSH compression."};
+
+ const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store",
+ R"(
+ [Store URL](@docroot@/command-ref/new-cli/nix3-help-stores.md#store-url-format)
+ to be used on the remote machine. The default is `auto`
+ (i.e. use the Nix daemon or `/nix/store` directly).
+ )"};
+};
+
+}
diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc
index a1d4daafd..962221ad2 100644
--- a/src/libstore/ssh-store.cc
+++ b/src/libstore/ssh-store.cc
@@ -1,3 +1,4 @@
+#include "ssh-store-config.hh"
#include "store-api.hh"
#include "remote-store.hh"
#include "remote-fs-accessor.hh"
@@ -8,17 +9,22 @@
namespace nix {
-struct SSHStoreConfig : virtual RemoteStoreConfig
+struct SSHStoreConfig : virtual RemoteStoreConfig, virtual CommonSSHStoreConfig
{
using RemoteStoreConfig::RemoteStoreConfig;
+ using CommonSSHStoreConfig::CommonSSHStoreConfig;
- const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
- const Setting<std::string> sshPublicHostKey{(StoreConfig*) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"};
- const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
- const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"};
- const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
+ const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-daemon", "remote-program",
+ "Path to the `nix-daemon` executable on the remote machine."};
- const std::string name() override { return "SSH Store"; }
+ const std::string name() override { return "Experimental SSH Store"; }
+
+ std::string doc() override
+ {
+ return
+ #include "ssh-store.md"
+ ;
+ }
};
class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore
@@ -28,6 +34,7 @@ public:
SSHStore(const std::string & scheme, const std::string & host, const Params & params)
: StoreConfig(params)
, RemoteStoreConfig(params)
+ , CommonSSHStoreConfig(params)
, SSHStoreConfig(params)
, Store(params)
, RemoteStore(params)
@@ -49,9 +56,6 @@ public:
return *uriSchemes().begin() + "://" + host;
}
- bool sameMachine() override
- { return false; }
-
// FIXME extend daemon protocol, move implementation to RemoteStore
std::optional<std::string> getBuildLogExact(const StorePath & path) override
{ unsupported("getBuildLogExact"); }
diff --git a/src/libstore/ssh-store.md b/src/libstore/ssh-store.md
new file mode 100644
index 000000000..881537e71
--- /dev/null
+++ b/src/libstore/ssh-store.md
@@ -0,0 +1,8 @@
+R"(
+
+**Store URL format**: `ssh-ng://[username@]hostname`
+
+Experimental store type that allows full access to a Nix store on a
+remote machine.
+
+)"
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index b8a77b324..fed38e2dd 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -465,10 +465,10 @@ StringSet StoreConfig::getDefaultSystemFeatures()
{
auto res = settings.systemFeatures.get();
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations))
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations))
res.insert("ca-derivations");
- if (settings.isExperimentalFeatureEnabled(Xp::RecursiveNix))
+ if (experimentalFeatureSettings.isEnabled(Xp::RecursiveNix))
res.insert("recursive-nix");
return res;
@@ -810,13 +810,13 @@ std::string Store::makeValidityRegistration(const StorePathSet & paths,
if (showHash) {
s += info->narHash.to_string(Base16, false) + "\n";
- s += (format("%1%\n") % info->narSize).str();
+ s += fmt("%1%\n", info->narSize);
}
auto deriver = showDerivers && info->deriver ? printStorePath(*info->deriver) : "";
s += deriver + "\n";
- s += (format("%1%\n") % info->references.size()).str();
+ s += fmt("%1%\n", info->references.size());
for (auto & j : info->references)
s += printStorePath(j) + "\n";
@@ -875,6 +875,7 @@ json Store::pathInfoToJSON(const StorePathSet & storePaths,
auto info = queryPathInfo(storePath);
jsonPath["path"] = printStorePath(info->path);
+ jsonPath["valid"] = true;
jsonPath["narHash"] = info->narHash.to_string(hashBase, true);
jsonPath["narSize"] = info->narSize;
@@ -1038,7 +1039,7 @@ std::map<StorePath, StorePath> copyPaths(
for (auto & path : paths) {
storePaths.insert(path.path());
if (auto realisation = std::get_if<Realisation>(&path.raw)) {
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
toplevelRealisations.insert(*realisation);
}
}
@@ -1124,6 +1125,8 @@ std::map<StorePath, StorePath> copyPaths(
return storePathForDst;
};
+ uint64_t total = 0;
+
for (auto & missingPath : sortedMissing) {
auto info = srcStore.queryPathInfo(missingPath);
@@ -1144,7 +1147,13 @@ std::map<StorePath, StorePath> copyPaths(
{storePathS, srcUri, dstUri});
PushActivity pact(act.id);
- srcStore.narFromPath(missingPath, sink);
+ LambdaSink progressSink([&](std::string_view data) {
+ total += data.size();
+ act.progress(total, info->narSize);
+ });
+ TeeSink tee { sink, progressSink };
+
+ srcStore.narFromPath(missingPath, tee);
});
pathsToCopy.push_back(std::pair{infoForDst, std::move(source)});
}
@@ -1265,7 +1274,7 @@ std::optional<StorePath> Store::getBuildDerivationPath(const StorePath & path)
}
}
- if (!settings.isExperimentalFeatureEnabled(Xp::CaDerivations) || !isValidPath(path))
+ if (!experimentalFeatureSettings.isEnabled(Xp::CaDerivations) || !isValidPath(path))
return path;
auto drv = readDerivation(path);
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 72517c6e4..5edcc0f36 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -55,7 +55,10 @@ namespace nix {
*/
MakeError(SubstError, Error);
-MakeError(BuildError, Error); // denotes a permanent build failure
+/**
+ * denotes a permanent build failure
+ */
+MakeError(BuildError, Error);
MakeError(InvalidPath, Error);
MakeError(Unsupported, Error);
MakeError(SubstituteGone, Error);
@@ -78,7 +81,9 @@ enum CheckSigsFlag : bool { NoCheckSigs = false, CheckSigs = true };
enum SubstituteFlag : bool { NoSubstitute = false, Substitute = true };
enum AllowInvalidFlag : bool { DisallowInvalid = false, AllowInvalid = true };
-/* Magic header of exportPath() output (obsolete). */
+/**
+ * Magic header of exportPath() output (obsolete).
+ */
const uint32_t exportMagic = 0x4558494e;
@@ -101,17 +106,41 @@ struct StoreConfig : public Config
virtual const std::string name() = 0;
+ virtual std::string doc()
+ {
+ return "";
+ }
+
const PathSetting storeDir_{this, false, settings.nixStore,
- "store", "path to the Nix store"};
+ "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_;
- const Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size", "size of the in-memory store path information cache"};
+ const Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size",
+ "Size of the in-memory store path metadata cache."};
- const Setting<bool> isTrusted{this, false, "trusted", "whether paths from this store can be used as substitutes even when they lack trusted signatures"};
+ const Setting<bool> isTrusted{this, false, "trusted",
+ R"(
+ Whether paths from this store can be used as substitutes
+ even if they are not signed by a key listed in the
+ [`trusted-public-keys`](@docroot@/command-ref/conf-file.md#conf-trusted-public-keys)
+ setting.
+ )"};
- Setting<int> priority{this, 0, "priority", "priority of this substituter (lower value means higher priority)"};
+ Setting<int> priority{this, 0, "priority",
+ R"(
+ Priority of this store when used as a substituter. A lower value means a higher priority.
+ )"};
- Setting<bool> wantMassQuery{this, false, "want-mass-query", "whether this substituter can be queried efficiently for path validity"};
+ Setting<bool> wantMassQuery{this, false, "want-mass-query",
+ R"(
+ Whether this store (when used as a substituter) can be
+ queried efficiently for path validity.
+ )"};
Setting<StringSet> systemFeatures{this, getDefaultSystemFeatures(),
"system-features",
@@ -125,23 +154,30 @@ public:
typedef std::map<std::string, std::string> Params;
-
-
protected:
struct PathInfoCacheValue {
- // Time of cache entry creation or update
+ /**
+ * Time of cache entry creation or update
+ */
std::chrono::time_point<std::chrono::steady_clock> time_point = std::chrono::steady_clock::now();
- // Null if missing
+ /**
+ * Null if missing
+ */
std::shared_ptr<const ValidPathInfo> value;
- // Whether the value is valid as a cache entry. The path may not exist.
+ /**
+ * Whether the value is valid as a cache entry. The path may not
+ * exist.
+ */
bool isKnownNow();
- // Past tense, because a path can only be assumed to exists when
- // isKnownNow() && didExist()
+ /**
+ * Past tense, because a path can only be assumed to exists when
+ * isKnownNow() && didExist()
+ */
inline bool didExist() {
return value != nullptr;
}
@@ -175,35 +211,53 @@ public:
std::string printStorePath(const StorePath & path) const;
- // FIXME: remove
+ /**
+ * Deprecated
+ *
+ * \todo remove
+ */
StorePathSet parseStorePathSet(const PathSet & paths) const;
PathSet printStorePathSet(const StorePathSet & path) const;
- /* Display a set of paths in human-readable form (i.e., between quotes
- and separated by commas). */
+ /**
+ * Display a set of paths in human-readable form (i.e., between quotes
+ * and separated by commas).
+ */
std::string showPaths(const StorePathSet & paths);
- /* Return true if ‘path’ is in the Nix store (but not the Nix
- store itself). */
+ /**
+ * @return true if ‘path’ is in the Nix store (but not the Nix
+ * store itself).
+ */
bool isInStore(PathView path) const;
- /* Return true if ‘path’ is a store path, i.e. a direct child of
- the Nix store. */
+ /**
+ * @return true if ‘path’ is a store path, i.e. a direct child of the
+ * Nix store.
+ */
bool isStorePath(std::string_view path) const;
- /* Split a path like /nix/store/<hash>-<name>/<bla> into
- /nix/store/<hash>-<name> and /<bla>. */
+ /**
+ * Split a path like /nix/store/<hash>-<name>/<bla> into
+ * /nix/store/<hash>-<name> and /<bla>.
+ */
std::pair<StorePath, Path> toStorePath(PathView path) const;
- /* Follow symlinks until we end up with a path in the Nix store. */
+ /**
+ * Follow symlinks until we end up with a path in the Nix store.
+ */
Path followLinksToStore(std::string_view path) const;
- /* Same as followLinksToStore(), but apply toStorePath() to the
- result. */
+ /**
+ * Same as followLinksToStore(), but apply toStorePath() to the
+ * result.
+ */
StorePath followLinksToStorePath(std::string_view path) const;
- /* Constructs a unique store path name. */
+ /**
+ * Constructs a unique store path name.
+ */
StorePath makeStorePath(std::string_view type,
std::string_view hash, std::string_view name) const;
StorePath makeStorePath(std::string_view type,
@@ -218,33 +272,40 @@ public:
StorePath makeFixedOutputPathFromCA(std::string_view name, const ContentAddressWithReferences & ca) const;
- /* This is the preparatory part of addToStore(); it computes the
- store path to which srcPath is to be copied. Returns the store
- path and the cryptographic hash of the contents of srcPath. */
+ /**
+ * Preparatory part of addToStore().
+ *
+ * @return the store path to which srcPath is to be copied
+ * and the cryptographic hash of the contents of srcPath.
+ */
std::pair<StorePath, Hash> computeStorePathForPath(std::string_view name,
const Path & srcPath, FileIngestionMethod method = FileIngestionMethod::Recursive,
HashType hashAlgo = htSHA256, PathFilter & filter = defaultPathFilter) const;
- /* Preparatory part of addTextToStore().
-
- !!! Computation of the path should take the references given to
- addTextToStore() into account, otherwise we have a (relatively
- minor) security hole: a caller can register a source file with
- bogus references. If there are too many references, the path may
- not be garbage collected when it has to be (not really a problem,
- the caller could create a root anyway), or it may be garbage
- collected when it shouldn't be (more serious).
-
- Hashing the references would solve this (bogus references would
- simply yield a different store path, so other users wouldn't be
- affected), but it has some backwards compatibility issues (the
- hashing scheme changes), so I'm not doing that for now. */
+ /**
+ * Preparatory part of addTextToStore().
+ *
+ * !!! Computation of the path should take the references given to
+ * addTextToStore() into account, otherwise we have a (relatively
+ * minor) security hole: a caller can register a source file with
+ * bogus references. If there are too many references, the path may
+ * not be garbage collected when it has to be (not really a problem,
+ * the caller could create a root anyway), or it may be garbage
+ * collected when it shouldn't be (more serious).
+ *
+ * Hashing the references would solve this (bogus references would
+ * simply yield a different store path, so other users wouldn't be
+ * affected), but it has some backwards compatibility issues (the
+ * hashing scheme changes), so I'm not doing that for now.
+ */
StorePath computeStorePathForText(
std::string_view name,
std::string_view s,
const StorePathSet & references) const;
- /* Check whether a path is valid. */
+ /**
+ * Check whether a path is valid.
+ */
bool isValidPath(const StorePath & path);
protected:
@@ -253,53 +314,68 @@ protected:
public:
- /* If requested, substitute missing paths. This
- implements nix-copy-closure's --use-substitutes
- flag. */
+ /**
+ * If requested, substitute missing paths. This
+ * implements nix-copy-closure's --use-substitutes
+ * flag.
+ */
void substitutePaths(const StorePathSet & paths);
- /* Query which of the given paths is valid. Optionally, try to
- substitute missing paths. */
+ /**
+ * Query which of the given paths is valid. Optionally, try to
+ * substitute missing paths.
+ */
virtual StorePathSet queryValidPaths(const StorePathSet & paths,
SubstituteFlag maybeSubstitute = NoSubstitute);
- /* Query the set of all valid paths. Note that for some store
- backends, the name part of store paths may be replaced by 'x'
- (i.e. you'll get /nix/store/<hash>-x rather than
- /nix/store/<hash>-<name>). Use queryPathInfo() to obtain the
- full store path. FIXME: should return a set of
- std::variant<StorePath, HashPart> to get rid of this hack. */
+ /**
+ * Query the set of all valid paths. Note that for some store
+ * backends, the name part of store paths may be replaced by 'x'
+ * (i.e. you'll get /nix/store/<hash>-x rather than
+ * /nix/store/<hash>-<name>). Use queryPathInfo() to obtain the
+ * full store path. FIXME: should return a set of
+ * std::variant<StorePath, HashPart> to get rid of this hack.
+ */
virtual StorePathSet queryAllValidPaths()
{ unsupported("queryAllValidPaths"); }
constexpr static const char * MissingName = "x";
- /* Query information about a valid path. It is permitted to omit
- the name part of the store path. */
+ /**
+ * Query information about a valid path. It is permitted to omit
+ * the name part of the store path.
+ */
ref<const ValidPathInfo> queryPathInfo(const StorePath & path);
- /* Asynchronous version of queryPathInfo(). */
+ /**
+ * Asynchronous version of queryPathInfo().
+ */
void queryPathInfo(const StorePath & path,
Callback<ref<const ValidPathInfo>> callback) noexcept;
- /* Query the information about a realisation. */
+ /**
+ * Query the information about a realisation.
+ */
std::shared_ptr<const Realisation> queryRealisation(const DrvOutput &);
- /* Asynchronous version of queryRealisation(). */
+ /**
+ * Asynchronous version of queryRealisation().
+ */
void queryRealisation(const DrvOutput &,
Callback<std::shared_ptr<const Realisation>> callback) noexcept;
- /* Check whether the given valid path info is sufficiently attested, by
- either being signed by a trusted public key or content-addressed, in
- order to be included in the given store.
-
- These same checks would be performed in addToStore, but this allows an
- earlier failure in the case where dependencies need to be added too, but
- the addToStore wouldn't fail until those dependencies are added. Also,
- we don't really want to add the dependencies listed in a nar info we
- don't trust anyyways.
- */
+ /**
+ * Check whether the given valid path info is sufficiently attested, by
+ * either being signed by a trusted public key or content-addressed, in
+ * order to be included in the given store.
+ *
+ * These same checks would be performed in addToStore, but this allows an
+ * earlier failure in the case where dependencies need to be added too, but
+ * the addToStore wouldn't fail until those dependencies are added. Also,
+ * we don't really want to add the dependencies listed in a nar info we
+ * don't trust anyyways.
+ */
virtual bool pathInfoIsUntrusted(const ValidPathInfo &)
{
return true;
@@ -319,53 +395,77 @@ protected:
public:
- /* Queries the set of incoming FS references for a store path.
- The result is not cleared. */
+ /**
+ * Queries the set of incoming FS references for a store path.
+ * The result is not cleared.
+ */
virtual void queryReferrers(const StorePath & path, StorePathSet & referrers)
{ unsupported("queryReferrers"); }
- /* Return all currently valid derivations that have `path' as an
- output. (Note that the result of `queryDeriver()' is the
- derivation that was actually used to produce `path', which may
- not exist anymore.) */
+ /**
+ * @return all currently valid derivations that have `path' as an
+ * output.
+ *
+ * (Note that the result of `queryDeriver()' is the derivation that
+ * was actually used to produce `path', which may not exist
+ * anymore.)
+ */
virtual StorePathSet queryValidDerivers(const StorePath & path) { return {}; };
- /* Query the outputs of the derivation denoted by `path'. */
+ /**
+ * Query the outputs of the derivation denoted by `path'.
+ */
virtual StorePathSet queryDerivationOutputs(const StorePath & path);
- /* Query the mapping outputName => outputPath for the given derivation. All
- outputs are mentioned so ones mising the mapping are mapped to
- `std::nullopt`. */
+ /**
+ * Query the mapping outputName => outputPath for the given
+ * derivation. All outputs are mentioned so ones mising the mapping
+ * are mapped to `std::nullopt`.
+ */
virtual std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path);
- /* Query the mapping outputName=>outputPath for the given derivation.
- Assume every output has a mapping and throw an exception otherwise. */
+ /**
+ * Query the mapping outputName=>outputPath for the given derivation.
+ * Assume every output has a mapping and throw an exception otherwise.
+ */
OutputPathMap queryDerivationOutputMap(const StorePath & path);
- /* Query the full store path given the hash part of a valid store
- path, or empty if the path doesn't exist. */
+ /**
+ * Query the full store path given the hash part of a valid store
+ * path, or empty if the path doesn't exist.
+ */
virtual std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) = 0;
- /* Query which of the given paths have substitutes. */
+ /**
+ * Query which of the given paths have substitutes.
+ */
virtual StorePathSet querySubstitutablePaths(const StorePathSet & paths) { return {}; };
- /* Query substitute info (i.e. references, derivers and download
- sizes) of a map of paths to their optional ca values. The info
- of the first succeeding substituter for each path will be
- returned. If a path does not have substitute info, it's omitted
- from the resulting ‘infos’ map. */
+ /**
+ * Query substitute info (i.e. references, derivers and download
+ * sizes) of a map of paths to their optional ca values. The info of
+ * the first succeeding substituter for each path will be returned.
+ * If a path does not have substitute info, it's omitted from the
+ * resulting ‘infos’ map.
+ */
virtual void querySubstitutablePathInfos(const StorePathCAMap & paths,
SubstitutablePathInfos & infos) { return; };
- /* Import a path into the store. */
+ /**
+ * Import a path into the store.
+ */
virtual void addToStore(const ValidPathInfo & info, Source & narSource,
RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs) = 0;
- // A list of paths infos along with a source providing the content of the
- // associated store path
+ /**
+ * A list of paths infos along with a source providing the content
+ * of the associated store path
+ */
using PathsSource = std::vector<std::pair<ValidPathInfo, std::unique_ptr<Source>>>;
- /* Import multiple paths into the store. */
+ /**
+ * Import multiple paths into the store.
+ */
virtual void addMultipleToStore(
Source & source,
RepairFlag repair = NoRepair,
@@ -377,10 +477,14 @@ public:
RepairFlag repair = NoRepair,
CheckSigsFlag checkSigs = CheckSigs);
- /* Copy the contents of a path to the store and register the
- validity the resulting path. The resulting path is returned.
- The function object `filter' can be used to exclude files (see
- libutil/archive.hh). */
+ /**
+ * Copy the contents of a path to the store and register the
+ * validity the resulting path.
+ *
+ * @return The resulting path is returned.
+ * @param filter This function can be used to exclude files (see
+ * libutil/archive.hh).
+ */
virtual StorePath addToStore(
std::string_view name,
const Path & srcPath,
@@ -390,26 +494,33 @@ public:
RepairFlag repair = NoRepair,
const StorePathSet & references = StorePathSet());
- /* Copy the contents of a path to the store and register the
- validity the resulting path, using a constant amount of
- memory. */
+ /**
+ * Copy the contents of a path to the store and register the
+ * validity the resulting path, using a constant amount of
+ * memory.
+ */
ValidPathInfo addToStoreSlow(std::string_view name, const Path & srcPath,
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
std::optional<Hash> expectedCAHash = {});
- /* Like addToStore(), but the contents of the path are contained
- in `dump', which is either a NAR serialisation (if recursive ==
- true) or simply the contents of a regular file (if recursive ==
- false).
- `dump` may be drained */
- // FIXME: remove?
+ /**
+ * Like addToStore(), but the contents of the path are contained
+ * in `dump', which is either a NAR serialisation (if recursive ==
+ * true) or simply the contents of a regular file (if recursive ==
+ * false).
+ * `dump` may be drained
+ *
+ * \todo remove?
+ */
virtual StorePath addToStoreFromDump(Source & dump, std::string_view name,
FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair,
const StorePathSet & references = StorePathSet())
{ unsupported("addToStoreFromDump"); }
- /* Like addToStore, but the contents written to the output path is
- a regular file containing the given string. */
+ /**
+ * Like addToStore, but the contents written to the output path is a
+ * regular file containing the given string.
+ */
virtual StorePath addTextToStore(
std::string_view name,
std::string_view s,
@@ -430,140 +541,180 @@ public:
virtual void registerDrvOutput(const Realisation & output, CheckSigsFlag checkSigs)
{ return registerDrvOutput(output); }
- /* Write a NAR dump of a store path. */
+ /**
+ * Write a NAR dump of a store path.
+ */
virtual void narFromPath(const StorePath & path, Sink & sink) = 0;
- /* For each path, if it's a derivation, build it. Building a
- derivation means ensuring that the output paths are valid. If
- they are already valid, this is a no-op. Otherwise, validity
- can be reached in two ways. First, if the output paths is
- substitutable, then build the path that way. Second, the
- output paths can be created by running the builder, after
- recursively building any sub-derivations. For inputs that are
- not derivations, substitute them. */
+ /**
+ * For each path, if it's a derivation, build it. Building a
+ * derivation means ensuring that the output paths are valid. If
+ * they are already valid, this is a no-op. Otherwise, validity
+ * can be reached in two ways. First, if the output paths is
+ * substitutable, then build the path that way. Second, the
+ * output paths can be created by running the builder, after
+ * recursively building any sub-derivations. For inputs that are
+ * not derivations, substitute them.
+ */
virtual void buildPaths(
const std::vector<DerivedPath> & paths,
BuildMode buildMode = bmNormal,
std::shared_ptr<Store> evalStore = nullptr);
- /* Like `buildPaths()`, but return a vector of `BuildResult`s
- corresponding to each element in `paths`. Note that in case of
- a build/substitution error, this function won't throw an
- exception, but return a `BuildResult` containing an error
- message. */
+ /**
+ * Like buildPaths(), but return a vector of \ref BuildResult
+ * BuildResults corresponding to each element in paths. Note that in
+ * case of a build/substitution error, this function won't throw an
+ * exception, but return a BuildResult containing an error message.
+ */
virtual std::vector<BuildResult> buildPathsWithResults(
const std::vector<DerivedPath> & paths,
BuildMode buildMode = bmNormal,
std::shared_ptr<Store> evalStore = nullptr);
- /* Build a single non-materialized derivation (i.e. not from an
- on-disk .drv file).
-
- ‘drvPath’ is used to deduplicate worker goals so it is imperative that
- is correct. That said, it doesn't literally need to be store path that
- would be calculated from writing this derivation to the store: it is OK
- if it instead is that of a Derivation which would resolve to this (by
- taking the outputs of it's input derivations and adding them as input
- sources) such that the build time referenceable-paths are the same.
-
- In the input-addressed case, we usually *do* use an "original"
- unresolved derivations's path, as that is what will be used in the
- `buildPaths` case. Also, the input-addressed output paths are verified
- only by that contents of that specific unresolved derivation, so it is
- nice to keep that information around so if the original derivation is
- ever obtained later, it can be verified whether the trusted user in fact
- used the proper output path.
-
- In the content-addressed case, we want to always use the
- resolved drv path calculated from the provided derivation. This serves
- two purposes:
-
- - It keeps the operation trustless, by ruling out a maliciously
- invalid drv path corresponding to a non-resolution-equivalent
- derivation.
-
- - For the floating case in particular, it ensures that the derivation
- to output mapping respects the resolution equivalence relation, so
- one cannot choose different resolution-equivalent derivations to
- subvert dependency coherence (i.e. the property that one doesn't end
- up with multiple different versions of dependencies without
- explicitly choosing to allow it).
- */
+ /**
+ * Build a single non-materialized derivation (i.e. not from an
+ * on-disk .drv file).
+ *
+ * @param drvPath This is used to deduplicate worker goals so it is
+ * imperative that is correct. That said, it doesn't literally need
+ * to be store path that would be calculated from writing this
+ * derivation to the store: it is OK if it instead is that of a
+ * Derivation which would resolve to this (by taking the outputs of
+ * it's input derivations and adding them as input sources) such
+ * that the build time referenceable-paths are the same.
+ *
+ * In the input-addressed case, we usually *do* use an "original"
+ * unresolved derivations's path, as that is what will be used in the
+ * buildPaths case. Also, the input-addressed output paths are verified
+ * only by that contents of that specific unresolved derivation, so it is
+ * nice to keep that information around so if the original derivation is
+ * ever obtained later, it can be verified whether the trusted user in fact
+ * used the proper output path.
+ *
+ * In the content-addressed case, we want to always use the resolved
+ * drv path calculated from the provided derivation. This serves two
+ * purposes:
+ *
+ * - It keeps the operation trustless, by ruling out a maliciously
+ * invalid drv path corresponding to a non-resolution-equivalent
+ * derivation.
+ *
+ * - For the floating case in particular, it ensures that the derivation
+ * to output mapping respects the resolution equivalence relation, so
+ * one cannot choose different resolution-equivalent derivations to
+ * subvert dependency coherence (i.e. the property that one doesn't end
+ * up with multiple different versions of dependencies without
+ * explicitly choosing to allow it).
+ */
virtual BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode = bmNormal);
- /* Ensure that a path is valid. If it is not currently valid, it
- may be made valid by running a substitute (if defined for the
- path). */
+ /**
+ * Ensure that a path is valid. If it is not currently valid, it
+ * may be made valid by running a substitute (if defined for the
+ * path).
+ */
virtual void ensurePath(const StorePath & path);
- /* Add a store path as a temporary root of the garbage collector.
- The root disappears as soon as we exit. */
+ /**
+ * Add a store path as a temporary root of the garbage collector.
+ * The root disappears as soon as we exit.
+ */
virtual void addTempRoot(const StorePath & path)
{ debug("not creating temporary root, store doesn't support GC"); }
- /* Return a string representing information about the path that
- can be loaded into the database using `nix-store --load-db' or
- `nix-store --register-validity'. */
+ /**
+ * @return a string representing information about the path that
+ * can be loaded into the database using `nix-store --load-db' or
+ * `nix-store --register-validity'.
+ */
std::string makeValidityRegistration(const StorePathSet & paths,
bool showDerivers, bool showHash);
- /* Write a JSON representation of store path metadata, such as the
- hash and the references. If ‘includeImpureInfo’ is true,
- variable elements such as the registration time are
- included. If ‘showClosureSize’ is true, the closure size of
- each path is included. */
+ /**
+ * Write a JSON representation of store path metadata, such as the
+ * hash and the references.
+ *
+ * @param includeImpureInfo If true, variable elements such as the
+ * registration time are included.
+ *
+ * @param showClosureSize If true, the closure size of each path is
+ * included.
+ */
nlohmann::json pathInfoToJSON(const StorePathSet & storePaths,
bool includeImpureInfo, bool showClosureSize,
Base hashBase = Base32,
AllowInvalidFlag allowInvalid = DisallowInvalid);
- /* Return the size of the closure of the specified path, that is,
- the sum of the size of the NAR serialisation of each path in
- the closure. */
+ /**
+ * @return the size of the closure of the specified path, that is,
+ * the sum of the size of the NAR serialisation of each path in the
+ * closure.
+ */
std::pair<uint64_t, uint64_t> getClosureSize(const StorePath & storePath);
- /* Optimise the disk space usage of the Nix store by hard-linking files
- with the same contents. */
+ /**
+ * Optimise the disk space usage of the Nix store by hard-linking files
+ * with the same contents.
+ */
virtual void optimiseStore() { };
- /* Check the integrity of the Nix store. Returns true if errors
- remain. */
+ /**
+ * Check the integrity of the Nix store.
+ *
+ * @return true if errors remain.
+ */
virtual bool verifyStore(bool checkContents, RepairFlag repair = NoRepair) { return false; };
- /* Return an object to access files in the Nix store. */
+ /**
+ * @return An object to access files in the Nix store.
+ */
virtual ref<FSAccessor> getFSAccessor()
{ unsupported("getFSAccessor"); }
- /* Repair the contents of the given path by redownloading it using
- a substituter (if available). */
+ /**
+ * Repair the contents of the given path by redownloading it using
+ * a substituter (if available).
+ */
virtual void repairPath(const StorePath & path)
{ unsupported("repairPath"); }
- /* Add signatures to the specified store path. The signatures are
- not verified. */
+ /**
+ * Add signatures to the specified store path. The signatures are
+ * not verified.
+ */
virtual void addSignatures(const StorePath & storePath, const StringSet & sigs)
{ unsupported("addSignatures"); }
/* Utility functions. */
- /* Read a derivation, after ensuring its existence through
- ensurePath(). */
+ /**
+ * Read a derivation, after ensuring its existence through
+ * ensurePath().
+ */
Derivation derivationFromPath(const StorePath & drvPath);
- /* Read a derivation (which must already be valid). */
+ /**
+ * Read a derivation (which must already be valid).
+ */
Derivation readDerivation(const StorePath & drvPath);
- /* Read a derivation from a potentially invalid path. */
+ /**
+ * Read a derivation from a potentially invalid path.
+ */
Derivation readInvalidDerivation(const StorePath & drvPath);
- /* Place in `out' the set of all store paths in the file system
- closure of `storePath'; that is, all paths than can be directly
- or indirectly reached from it. `out' is not cleared. If
- `flipDirection' is true, the set of paths that can reach
- `storePath' is returned; that is, the closures under the
- `referrers' relation instead of the `references' relation is
- returned. */
+ /**
+ * @param [out] out Place in here the set of all store paths in the
+ * file system closure of `storePath'; that is, all paths than can
+ * be directly or indirectly reached from it. `out' is not cleared.
+ *
+ * @param flipDirection If true, the set of paths that can reach
+ * `storePath' is returned; that is, the closures under the
+ * `referrers' relation instead of the `references' relation is
+ * returned.
+ */
virtual void computeFSClosure(const StorePathSet & paths,
StorePathSet & out, bool flipDirection = false,
bool includeOutputs = false, bool includeDerivers = false);
@@ -572,27 +723,34 @@ public:
StorePathSet & out, bool flipDirection = false,
bool includeOutputs = false, bool includeDerivers = false);
- /* Given a set of paths that are to be built, return the set of
- derivations that will be built, and the set of output paths
- that will be substituted. */
+ /**
+ * Given a set of paths that are to be built, return the set of
+ * derivations that will be built, and the set of output paths that
+ * will be substituted.
+ */
virtual void queryMissing(const std::vector<DerivedPath> & targets,
StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown,
uint64_t & downloadSize, uint64_t & narSize);
- /* Sort a set of paths topologically under the references
- relation. If p refers to q, then p precedes q in this list. */
+ /**
+ * Sort a set of paths topologically under the references
+ * relation. If p refers to q, then p precedes q in this list.
+ */
StorePaths topoSortPaths(const StorePathSet & paths);
- /* Export multiple paths in the format expected by ‘nix-store
- --import’. */
+ /**
+ * Export multiple paths in the format expected by ‘nix-store
+ * --import’.
+ */
void exportPaths(const StorePathSet & paths, Sink & sink);
void exportPath(const StorePath & path, Sink & sink);
- /* Import a sequence of NAR dumps created by exportPaths() into
- the Nix store. Optionally, the contents of the NARs are
- preloaded into the specified FS accessor to speed up subsequent
- access. */
+ /**
+ * Import a sequence of NAR dumps created by exportPaths() into the
+ * Nix store. Optionally, the contents of the NARs are preloaded
+ * into the specified FS accessor to speed up subsequent access.
+ */
StorePaths importPaths(Source & source, CheckSigsFlag checkSigs = CheckSigs);
struct Stats
@@ -614,8 +772,9 @@ public:
const Stats & getStats();
- /* Computes the full closure of of a set of store-paths for e.g.
- derivations that need this information for `exportReferencesGraph`.
+ /**
+ * Computes the full closure of of a set of store-paths for e.g.
+ * derivations that need this information for `exportReferencesGraph`.
*/
StorePathSet exportReferences(const StorePathSet & storePaths, const StorePathSet & inputPaths);
@@ -626,18 +785,24 @@ public:
*/
std::optional<StorePath> getBuildDerivationPath(const StorePath &);
- /* Hack to allow long-running processes like hydra-queue-runner to
- occasionally flush their path info cache. */
+ /**
+ * Hack to allow long-running processes like hydra-queue-runner to
+ * occasionally flush their path info cache.
+ */
void clearPathInfoCache()
{
state.lock()->pathInfoCache.clear();
}
- /* Establish a connection to the store, for store types that have
- a notion of connection. Otherwise this is a no-op. */
+ /**
+ * Establish a connection to the store, for store types that have
+ * a notion of connection. Otherwise this is a no-op.
+ */
virtual void connect() { };
- /* Get the protocol version of this store or it's connection. */
+ /**
+ * Get the protocol version of this store or it's connection.
+ */
virtual unsigned int getProtocol()
{
return 0;
@@ -653,7 +818,7 @@ public:
return toRealPath(printStorePath(storePath));
}
- /*
+ /**
* Synchronises the options of the client with those of the daemon
* (a no-op when there’s no daemon)
*/
@@ -665,7 +830,13 @@ protected:
Stats stats;
- /* Unsupported methods. */
+ /**
+ * Helper for methods that are not unsupported: this is used for
+ * default definitions for virtual methods that are meant to be overriden.
+ *
+ * \todo Using this should be a last resort. It is better to make
+ * the method "virtual pure" and/or move it to a subclass.
+ */
[[noreturn]] void unsupported(const std::string & op)
{
throw Unsupported("operation '%s' is not supported by store '%s'", op, getUri());
@@ -674,7 +845,9 @@ protected:
};
-/* Copy a path from one store to another. */
+/**
+ * Copy a path from one store to another.
+ */
void copyStorePath(
Store & srcStore,
Store & dstStore,
@@ -683,12 +856,14 @@ void copyStorePath(
CheckSigsFlag checkSigs = CheckSigs);
-/* Copy store paths from one store to another. The paths may be copied
- in parallel. They are copied in a topologically sorted order (i.e.
- if A is a reference of B, then A is copied before B), but the set
- of store paths is not automatically closed; use copyClosure() for
- that. Returns a map of what each path was copied to the dstStore
- as. */
+/**
+ * Copy store paths from one store to another. The paths may be copied
+ * in parallel. They are copied in a topologically sorted order (i.e. if
+ * A is a reference of B, then A is copied before B), but the set of
+ * store paths is not automatically closed; use copyClosure() for that.
+ *
+ * @return a map of what each path was copied to the dstStore as.
+ */
std::map<StorePath, StorePath> copyPaths(
Store & srcStore, Store & dstStore,
const RealisedPath::Set &,
@@ -703,7 +878,9 @@ std::map<StorePath, StorePath> copyPaths(
CheckSigsFlag checkSigs = CheckSigs,
SubstituteFlag substitute = NoSubstitute);
-/* Copy the closure of `paths` from `srcStore` to `dstStore`. */
+/**
+ * Copy the closure of `paths` from `srcStore` to `dstStore`.
+ */
void copyClosure(
Store & srcStore, Store & dstStore,
const RealisedPath::Set & paths,
@@ -718,52 +895,61 @@ void copyClosure(
CheckSigsFlag checkSigs = CheckSigs,
SubstituteFlag substitute = NoSubstitute);
-/* Remove the temporary roots file for this process. Any temporary
- root becomes garbage after this point unless it has been registered
- as a (permanent) root. */
+/**
+ * Remove the temporary roots file for this process. Any temporary
+ * root becomes garbage after this point unless it has been registered
+ * as a (permanent) root.
+ */
void removeTempRoots();
-/* Resolve the derived path completely, failing if any derivation output
- is unknown. */
+/**
+ * Resolve the derived path completely, failing if any derivation output
+ * is unknown.
+ */
OutputPathMap resolveDerivedPath(Store &, const DerivedPath::Built &, Store * evalStore = nullptr);
-/* Return a Store object to access the Nix store denoted by
- ‘uri’ (slight misnomer...). Supported values are:
-
- * ‘local’: The Nix store in /nix/store and database in
- /nix/var/nix/db, accessed directly.
-
- * ‘daemon’: The Nix store accessed via a Unix domain socket
- connection to nix-daemon.
-
- * ‘unix://<path>’: The Nix store accessed via a Unix domain socket
- connection to nix-daemon, with the socket located at <path>.
-
- * ‘auto’ or ‘’: Equivalent to ‘local’ or ‘daemon’ depending on
- whether the user has write access to the local Nix
- store/database.
-
- * ‘file://<path>’: A binary cache stored in <path>.
-
- * ‘https://<path>’: A binary cache accessed via HTTP.
-
- * ‘s3://<path>’: A writable binary cache stored on Amazon's Simple
- Storage Service.
-
- * ‘ssh://[user@]<host>’: A remote Nix store accessed by running
- ‘nix-store --serve’ via SSH.
-
- You can pass parameters to the store implementation by appending
- ‘?key=value&key=value&...’ to the URI.
-*/
+/**
+ * @return a Store object to access the Nix store denoted by
+ * ‘uri’ (slight misnomer...).
+ *
+ * @param uri Supported values are:
+ *
+ * - ‘local’: The Nix store in /nix/store and database in
+ * /nix/var/nix/db, accessed directly.
+ *
+ * - ‘daemon’: The Nix store accessed via a Unix domain socket
+ * connection to nix-daemon.
+ *
+ * - ‘unix://<path>’: The Nix store accessed via a Unix domain socket
+ * connection to nix-daemon, with the socket located at <path>.
+ *
+ * - ‘auto’ or ‘’: Equivalent to ‘local’ or ‘daemon’ depending on
+ * whether the user has write access to the local Nix
+ * store/database.
+ *
+ * - ‘file://<path>’: A binary cache stored in <path>.
+ *
+ * - ‘https://<path>’: A binary cache accessed via HTTP.
+ *
+ * - ‘s3://<path>’: A writable binary cache stored on Amazon's Simple
+ * Storage Service.
+ *
+ * - ‘ssh://[user@]<host>’: A remote Nix store accessed by running
+ * ‘nix-store --serve’ via SSH.
+ *
+ * You can pass parameters to the store implementation by appending
+ * ‘?key=value&key=value&...’ to the URI.
+ */
ref<Store> openStore(const std::string & uri = settings.storeUri.get(),
const Store::Params & extraParams = Store::Params());
-/* Return the default substituter stores, defined by the
- ‘substituters’ option and various legacy options. */
+/**
+ * @return the default substituter stores, defined by the
+ * ‘substituters’ option and various legacy options.
+ */
std::list<ref<Store>> getDefaultSubstituters();
struct StoreFactory
@@ -806,8 +992,10 @@ struct RegisterStoreImplementation
};
-/* Display a set of paths in human-readable form (i.e., between quotes
- and separated by commas). */
+/**
+ * Display a set of paths in human-readable form (i.e., between quotes
+ * and separated by commas).
+ */
std::string showPaths(const PathSet & paths);
@@ -816,7 +1004,9 @@ std::optional<ValidPathInfo> decodeValidPathInfo(
std::istream & str,
std::optional<HashResult> hashGiven = std::nullopt);
-/* Split URI into protocol+hierarchy part and its parameter set. */
+/**
+ * Split URI into protocol+hierarchy part and its parameter set.
+ */
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri);
std::optional<ContentAddress> getDerivationCA(const BasicDerivation & drv);
diff --git a/src/libstore/uds-remote-store.cc b/src/libstore/uds-remote-store.cc
index 5c38323cd..0fb7c38e9 100644
--- a/src/libstore/uds-remote-store.cc
+++ b/src/libstore/uds-remote-store.cc
@@ -26,9 +26,9 @@ UDSRemoteStore::UDSRemoteStore(const Params & params)
UDSRemoteStore::UDSRemoteStore(
- const std::string scheme,
- std::string socket_path,
- const Params & params)
+ const std::string scheme,
+ std::string socket_path,
+ const Params & params)
: UDSRemoteStore(params)
{
path.emplace(socket_path);
diff --git a/src/libstore/uds-remote-store.hh b/src/libstore/uds-remote-store.hh
index f8dfcca70..caa452919 100644
--- a/src/libstore/uds-remote-store.hh
+++ b/src/libstore/uds-remote-store.hh
@@ -15,6 +15,13 @@ struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreCon
}
const std::string name() override { return "Local Daemon Store"; }
+
+ std::string doc() override
+ {
+ return
+ #include "uds-remote-store.md"
+ ;
+ }
};
class UDSRemoteStore : public virtual UDSRemoteStoreConfig, public virtual LocalFSStore, public virtual RemoteStore
@@ -29,9 +36,6 @@ public:
static std::set<std::string> uriSchemes()
{ return {"unix"}; }
- bool sameMachine() override
- { return true; }
-
ref<FSAccessor> getFSAccessor() override
{ return LocalFSStore::getFSAccessor(); }
diff --git a/src/libstore/uds-remote-store.md b/src/libstore/uds-remote-store.md
new file mode 100644
index 000000000..8df0bd6ff
--- /dev/null
+++ b/src/libstore/uds-remote-store.md
@@ -0,0 +1,9 @@
+R"(
+
+**Store URL format**: `daemon`, `unix://`*path*
+
+This store type accesses a Nix store by talking to a Nix daemon
+listening on the Unix domain socket *path*. The store pseudo-URL
+`daemon` is equivalent to `unix:///nix/var/nix/daemon-socket/socket`.
+
+)"