aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build-remote/build-remote.cc11
-rw-r--r--src/libcmd/command.cc2
-rw-r--r--src/libcmd/command.hh54
-rw-r--r--src/libcmd/installables.cc96
-rw-r--r--src/libcmd/installables.hh61
-rw-r--r--src/libexpr/attr-path.cc16
-rw-r--r--src/libexpr/attr-path.hh7
-rw-r--r--src/libexpr/attr-set.hh2
-rw-r--r--src/libexpr/common-eval-args.cc8
-rw-r--r--src/libexpr/common-eval-args.hh2
-rw-r--r--src/libexpr/eval-cache.cc37
-rw-r--r--src/libexpr/eval-cache.hh8
-rw-r--r--src/libexpr/eval.cc145
-rw-r--r--src/libexpr/eval.hh26
-rw-r--r--src/libexpr/flake/config.cc3
-rw-r--r--src/libexpr/flake/flake.cc21
-rw-r--r--src/libexpr/flake/flakeref.cc6
-rw-r--r--src/libexpr/flake/lockfile.cc4
-rw-r--r--src/libexpr/get-drvs.cc71
-rw-r--r--src/libexpr/get-drvs.hh52
-rw-r--r--src/libexpr/nixexpr.cc29
-rw-r--r--src/libexpr/nixexpr.hh23
-rw-r--r--src/libexpr/parser.y46
-rw-r--r--src/libexpr/primops.cc67
-rw-r--r--src/libexpr/primops/context.cc10
-rw-r--r--src/libexpr/primops/fetchMercurial.cc2
-rw-r--r--src/libexpr/primops/fetchTree.cc30
-rw-r--r--src/libexpr/primops/fromTOML.cc2
-rw-r--r--src/libexpr/symbol-table.hh8
-rw-r--r--src/libexpr/value-to-xml.cc2
-rw-r--r--src/libexpr/value.hh14
-rw-r--r--src/libfetchers/cache.cc8
-rw-r--r--src/libfetchers/cache.hh2
-rw-r--r--src/libfetchers/fetch-settings.cc13
-rw-r--r--src/libfetchers/fetch-settings.hh93
-rw-r--r--src/libfetchers/fetchers.cc8
-rw-r--r--src/libfetchers/fetchers.hh12
-rw-r--r--src/libfetchers/git.cc20
-rw-r--r--src/libfetchers/github.cc103
-rw-r--r--src/libfetchers/mercurial.cc24
-rw-r--r--src/libfetchers/registry.cc4
-rw-r--r--src/libfetchers/tarball.cc14
-rw-r--r--src/libmain/common-args.cc2
-rw-r--r--src/libmain/common-args.hh4
-rw-r--r--src/libmain/shared.cc15
-rw-r--r--src/libmain/shared.hh14
-rw-r--r--src/libstore/binary-cache-store.cc17
-rw-r--r--src/libstore/binary-cache-store.hh20
-rw-r--r--src/libstore/build-result.hh89
-rw-r--r--src/libstore/build/derivation-goal.cc212
-rw-r--r--src/libstore/build/derivation-goal.hh34
-rw-r--r--src/libstore/build/drv-output-substitution-goal.cc14
-rw-r--r--src/libstore/build/drv-output-substitution-goal.hh2
-rw-r--r--src/libstore/build/entry-points.cc64
-rw-r--r--src/libstore/build/goal.cc4
-rw-r--r--src/libstore/build/goal.hh20
-rw-r--r--src/libstore/build/local-derivation-goal.cc173
-rw-r--r--src/libstore/build/local-derivation-goal.hh6
-rw-r--r--src/libstore/build/substitution-goal.cc21
-rw-r--r--src/libstore/build/substitution-goal.hh6
-rw-r--r--src/libstore/build/worker.cc6
-rw-r--r--src/libstore/build/worker.hh4
-rw-r--r--src/libstore/builtins/buildenv.cc4
-rw-r--r--src/libstore/builtins/fetchurl.cc2
-rw-r--r--src/libstore/builtins/unpack-channel.cc2
-rw-r--r--src/libstore/daemon.cc40
-rw-r--r--src/libstore/derivations.cc32
-rw-r--r--src/libstore/derivations.hh12
-rw-r--r--src/libstore/derived-path.cc4
-rw-r--r--src/libstore/dummy-store.cc9
-rw-r--r--src/libstore/filetransfer.cc26
-rw-r--r--src/libstore/filetransfer.hh8
-rw-r--r--src/libstore/gc-store.cc13
-rw-r--r--src/libstore/gc-store.hh84
-rw-r--r--src/libstore/gc.cc25
-rw-r--r--src/libstore/globals.cc4
-rw-r--r--src/libstore/globals.hh75
-rw-r--r--src/libstore/legacy-ssh-store.cc27
-rw-r--r--src/libstore/local-fs-store.cc2
-rw-r--r--src/libstore/local-fs-store.hh5
-rw-r--r--src/libstore/local-store.cc29
-rw-r--r--src/libstore/local-store.hh18
-rw-r--r--src/libstore/lock.hh4
-rw-r--r--src/libstore/machines.cc21
-rw-r--r--src/libstore/machines.hh14
-rw-r--r--src/libstore/names.hh8
-rw-r--r--src/libstore/nar-accessor.cc2
-rw-r--r--src/libstore/nar-info.cc2
-rw-r--r--src/libstore/optimise-store.cc2
-rw-r--r--src/libstore/path-with-outputs.cc10
-rw-r--r--src/libstore/path.hh2
-rw-r--r--src/libstore/pathlocks.cc4
-rw-r--r--src/libstore/pathlocks.hh6
-rw-r--r--src/libstore/profiles.cc16
-rw-r--r--src/libstore/profiles.hh4
-rw-r--r--src/libstore/references.cc4
-rw-r--r--src/libstore/remote-store.cc140
-rw-r--r--src/libstore/remote-store.hh18
-rw-r--r--src/libstore/s3-binary-cache-store.cc11
-rw-r--r--src/libstore/sqlite.cc2
-rw-r--r--src/libstore/ssh.cc2
-rw-r--r--src/libstore/store-api.cc35
-rw-r--r--src/libstore/store-api.hh175
-rw-r--r--src/libstore/worker-protocol.hh4
-rw-r--r--src/libutil/archive.cc28
-rw-r--r--src/libutil/archive.hh6
-rw-r--r--src/libutil/args.cc21
-rw-r--r--src/libutil/args.hh2
-rw-r--r--src/libutil/config.cc16
-rw-r--r--src/libutil/error.cc19
-rw-r--r--src/libutil/error.hh34
-rw-r--r--src/libutil/fmt.hh7
-rw-r--r--src/libutil/hash.cc19
-rw-r--r--src/libutil/hash.hh6
-rw-r--r--src/libutil/logging.cc80
-rw-r--r--src/libutil/logging.hh10
-rw-r--r--src/libutil/serialise.cc4
-rw-r--r--src/libutil/serialise.hh4
-rw-r--r--src/libutil/suggestions.cc114
-rw-r--r--src/libutil/suggestions.hh102
-rw-r--r--src/libutil/tests/logging.cc2
-rw-r--r--src/libutil/tests/suggestions.cc43
-rw-r--r--src/libutil/tests/url.cc18
-rw-r--r--src/libutil/types.hh21
-rw-r--r--src/libutil/util.cc131
-rw-r--r--src/libutil/util.hh48
-rw-r--r--src/libutil/xml-writer.cc10
-rw-r--r--src/libutil/xml-writer.hh14
-rwxr-xr-xsrc/nix-build/nix-build.cc27
-rwxr-xr-xsrc/nix-channel/nix-channel.cc14
-rw-r--r--src/nix-collect-garbage/nix-collect-garbage.cc6
-rw-r--r--src/nix-env/nix-env.cc165
-rw-r--r--src/nix-env/user-env.cc31
-rw-r--r--src/nix-env/user-env.hh2
-rw-r--r--src/nix-instantiate/nix-instantiate.cc11
-rw-r--r--src/nix-store/dotgraph.cc26
-rw-r--r--src/nix-store/graphml.cc8
-rw-r--r--src/nix-store/nix-store.cc35
-rw-r--r--src/nix/app.cc2
-rw-r--r--src/nix/build.cc2
-rw-r--r--src/nix/bundle.cc15
-rw-r--r--src/nix/bundle.md14
-rw-r--r--src/nix/daemon.cc16
-rw-r--r--src/nix/develop.cc16
-rw-r--r--src/nix/develop.md4
-rw-r--r--src/nix/diff-closures.cc4
-rw-r--r--src/nix/flake-init.md8
-rw-r--r--src/nix/flake-show.md11
-rw-r--r--src/nix/flake.cc24
-rw-r--r--src/nix/flake.md34
-rw-r--r--src/nix/hash.cc2
-rw-r--r--src/nix/nix.md6
-rw-r--r--src/nix/path-info.cc2
-rw-r--r--src/nix/prefetch.cc14
-rw-r--r--src/nix/profile-list.md2
-rw-r--r--src/nix/profile.cc126
-rw-r--r--src/nix/profile.md2
-rw-r--r--src/nix/repl.cc94
-rw-r--r--src/nix/run.cc7
-rw-r--r--src/nix/run.md6
-rw-r--r--src/nix/show-derivation.cc2
-rw-r--r--src/nix/store-delete.cc5
-rw-r--r--src/nix/store-gc.cc5
-rw-r--r--src/nix/why-depends.cc29
-rw-r--r--src/resolve-system-dependencies/resolve-system-dependencies.cc16
165 files changed, 2695 insertions, 1657 deletions
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index 9d541b45d..8c9133c17 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -14,6 +14,7 @@
#include "pathlocks.hh"
#include "globals.hh"
#include "serialise.hh"
+#include "build-result.hh"
#include "store-api.hh"
#include "derivations.hh"
#include "local-store.hh"
@@ -32,7 +33,7 @@ std::string escapeUri(std::string uri)
return uri;
}
-static string currentLoad;
+static std::string currentLoad;
static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot)
{
@@ -97,7 +98,7 @@ static int main_build_remote(int argc, char * * argv)
}
std::optional<StorePath> drvPath;
- string storeUri;
+ std::string storeUri;
while (true) {
@@ -183,7 +184,7 @@ static int main_build_remote(int argc, char * * argv)
else
{
// build the hint template.
- string errorText =
+ std::string errorText =
"Failed to find a machine for remote build!\n"
"derivation: %s\nrequired (system, features): (%s, %s)";
errorText += "\n%s available machines:";
@@ -193,7 +194,7 @@ static int main_build_remote(int argc, char * * argv)
errorText += "\n(%s, %s, %s, %s)";
// add the template values.
- string drvstr;
+ std::string drvstr;
if (drvPath.has_value())
drvstr = drvPath->to_string();
else
@@ -208,7 +209,7 @@ static int main_build_remote(int argc, char * * argv)
for (auto & m : machines)
error
- % concatStringsSep<vector<string>>(", ", m.systemTypes)
+ % concatStringsSep<std::vector<std::string>>(", ", m.systemTypes)
% m.maxJobs
% concatStringsSep<StringSet>(", ", m.supportedFeatures)
% concatStringsSep<StringSet>(", ", m.mandatoryFeatures);
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 6d183dfad..dc8fa9e5a 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -153,7 +153,7 @@ void BuiltPathsCommand::run(ref<Store> store)
for (auto & p : store->queryAllValidPaths())
paths.push_back(BuiltPath::Opaque{p});
} else {
- paths = toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
+ paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
if (recursive) {
// XXX: This only computes the store path closure, ignoring
// intermediate realisations
diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh
index bd2a0a7ee..0f6125f11 100644
--- a/src/libcmd/command.hh
+++ b/src/libcmd/command.hh
@@ -5,7 +5,6 @@
#include "common-eval-args.hh"
#include "path.hh"
#include "flake/lockfile.hh"
-#include "store-api.hh"
#include <optional>
@@ -82,14 +81,6 @@ struct MixFlakeOptions : virtual Args, EvalCommand
{ return {}; }
};
-/* How to handle derivations in commands that operate on store paths. */
-enum class OperateOn {
- /* Operate on the output path. */
- Output,
- /* Operate on the .drv path. */
- Derivation
-};
-
struct SourceExprCommand : virtual Args, MixFlakeOptions
{
std::optional<Path> file;
@@ -113,19 +104,6 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
void completeInstallable(std::string_view prefix);
};
-enum class Realise {
- /* Build the derivation. Postcondition: the
- derivation outputs exist. */
- Outputs,
- /* Don't build the derivation. Postcondition: the store derivation
- exists. */
- Derivation,
- /* Evaluate in dry-run mode. Postcondition: nothing. */
- // FIXME: currently unused, but could be revived if we can
- // evaluate derivations in-memory.
- Nothing
-};
-
/* A command that operates on a list of "installables", which can be
store paths, attribute paths, Nix expressions, etc. */
struct InstallablesCommand : virtual Args, SourceExprCommand
@@ -238,38 +216,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
}
-BuiltPaths build(
- ref<Store> evalStore,
- ref<Store> store, Realise mode,
- const std::vector<std::shared_ptr<Installable>> & installables,
- BuildMode bMode = bmNormal);
-
-std::set<StorePath> toStorePaths(
- ref<Store> evalStore,
- ref<Store> store,
- Realise mode,
- OperateOn operateOn,
- const std::vector<std::shared_ptr<Installable>> & installables);
-
-StorePath toStorePath(
- ref<Store> evalStore,
- ref<Store> store,
- Realise mode,
- OperateOn operateOn,
- std::shared_ptr<Installable> installable);
-
-std::set<StorePath> toDerivations(
- ref<Store> store,
- const std::vector<std::shared_ptr<Installable>> & installables,
- bool useDeriver = false);
-
-BuiltPaths toBuiltPaths(
- ref<Store> evalStore,
- ref<Store> store,
- Realise mode,
- OperateOn operateOn,
- const std::vector<std::shared_ptr<Installable>> & installables);
-
/* Helper function to generate args that invoke $EDITOR on
filename:lineno. */
Strings editorFor(const Pos & pos);
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 644954977..b7623d4ba 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -12,6 +12,7 @@
#include "eval-cache.hh"
#include "url.hh"
#include "registry.hh"
+#include "build-result.hh"
#include <regex>
#include <queue>
@@ -158,7 +159,10 @@ SourceExprCommand::SourceExprCommand()
Strings SourceExprCommand::getDefaultFlakeAttrPaths()
{
- return {"defaultPackage." + settings.thisSystem.get()};
+ return {
+ "packages." + settings.thisSystem.get() + ".default",
+ "defaultPackage." + settings.thisSystem.get()
+ };
}
Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes()
@@ -269,9 +273,9 @@ void completeFlakeRefWithFragment(
auto attr = root->findAlongAttrPath(attrPath);
if (!attr) continue;
- for (auto & attr2 : attr->getAttrs()) {
+ for (auto & attr2 : (*attr)->getAttrs()) {
if (hasPrefix(attr2, lastAttr)) {
- auto attrPath2 = attr->getAttrPath(attr2);
+ auto attrPath2 = (*attr)->getAttrPath(attr2);
/* Strip the attrpath prefix. */
attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
completions->add(flakeRefS + "#" + concatStringsSep(".", attrPath2));
@@ -465,11 +469,10 @@ std::vector<InstallableValue::DerivationInfo> InstallableAttrPath::toDerivations
std::vector<DerivationInfo> res;
for (auto & drvInfo : drvInfos) {
- res.push_back({
- state->store->parseStorePath(drvInfo.queryDrvPath()),
- state->store->maybeParseStorePath(drvInfo.queryOutPath()),
- drvInfo.queryOutputName()
- });
+ auto drvPath = drvInfo.queryDrvPath();
+ if (!drvPath)
+ throw Error("'%s' is not a derivation", what());
+ res.push_back({ *drvPath, drvInfo.queryOutputName() });
}
return res;
@@ -566,31 +569,37 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
auto cache = openEvalCache(*state, lockedFlake);
auto root = cache->getRoot();
+ Suggestions suggestions;
+
for (auto & attrPath : getActualAttrPaths()) {
debug("trying flake output attribute '%s'", attrPath);
- auto attr = root->findAlongAttrPath(
+ auto attrOrSuggestions = root->findAlongAttrPath(
parseAttrPath(*state, attrPath),
true
);
- if (!attr) continue;
+ if (!attrOrSuggestions) {
+ suggestions += attrOrSuggestions.getSuggestions();
+ continue;
+ }
+
+ auto attr = *attrOrSuggestions;
if (!attr->isDerivation())
throw Error("flake output attribute '%s' is not a derivation", attrPath);
auto drvPath = attr->forceDerivation();
- auto drvInfo = DerivationInfo{
+ auto drvInfo = DerivationInfo {
std::move(drvPath),
- state->store->maybeParseStorePath(attr->getAttr(state->sOutPath)->getString()),
attr->getAttr(state->sOutputName)->getString()
};
return {attrPath, lockedFlake->flake.lockedRef, std::move(drvInfo)};
}
- throw Error("flake '%s' does not provide attribute %s",
+ throw Error(suggestions, "flake '%s' does not provide attribute %s",
flakeRef, showAttrPaths(getActualAttrPaths()));
}
@@ -609,17 +618,24 @@ std::pair<Value *, Pos> InstallableFlake::toValue(EvalState & state)
auto emptyArgs = state.allocBindings(0);
+ Suggestions suggestions;
+
for (auto & attrPath : getActualAttrPaths()) {
try {
auto [v, pos] = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs);
state.forceValue(*v, pos);
return {v, pos};
} catch (AttrPathNotFound & e) {
+ suggestions += e.info().suggestions;
}
}
- throw Error("flake '%s' does not provide attribute %s",
- flakeRef, showAttrPaths(getActualAttrPaths()));
+ throw Error(
+ suggestions,
+ "flake '%s' does not provide attribute %s",
+ flakeRef,
+ showAttrPaths(getActualAttrPaths())
+ );
}
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
@@ -634,7 +650,7 @@ InstallableFlake::getCursors(EvalState & state)
for (auto & attrPath : getActualAttrPaths()) {
auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
- if (attr) res.push_back({attr, attrPath});
+ if (attr) res.push_back({*attr, attrPath});
}
return res;
@@ -754,8 +770,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa
throw Error(
"the derivation '%s' doesn't have an output named '%s'",
store->printStorePath(bfd.drvPath), output);
- if (settings.isExperimentalFeatureEnabled(
- Xp::CaDerivations)) {
+ if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
auto outputId =
DrvOutput{outputHashes.at(output), output};
auto realisation =
@@ -784,7 +799,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa
return res;
}
-BuiltPaths build(
+BuiltPaths Installable::build(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
@@ -801,15 +816,36 @@ BuiltPaths build(
pathsToBuild.insert(pathsToBuild.end(), b.begin(), b.end());
}
- if (mode == Realise::Nothing || mode == Realise::Derivation)
+ switch (mode) {
+ case Realise::Nothing:
+ case Realise::Derivation:
printMissing(store, pathsToBuild, lvlError);
- else if (mode == Realise::Outputs)
- store->buildPaths(pathsToBuild, bMode, evalStore);
-
- return getBuiltPaths(evalStore, store, pathsToBuild);
+ return getBuiltPaths(evalStore, store, pathsToBuild);
+ case Realise::Outputs: {
+ BuiltPaths res;
+ for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) {
+ if (!buildResult.success())
+ buildResult.rethrow();
+ std::visit(overloaded {
+ [&](const DerivedPath::Built & bfd) {
+ std::map<std::string, StorePath> outputs;
+ for (auto & path : buildResult.builtOutputs)
+ outputs.emplace(path.first.outputName, path.second.outPath);
+ res.push_back(BuiltPath::Built { bfd.drvPath, outputs });
+ },
+ [&](const DerivedPath::Opaque & bo) {
+ res.push_back(BuiltPath::Opaque { bo.path });
+ },
+ }, buildResult.path.raw());
+ }
+ return res;
+ }
+ default:
+ assert(false);
+ }
}
-BuiltPaths toBuiltPaths(
+BuiltPaths Installable::toBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
@@ -817,19 +853,19 @@ BuiltPaths toBuiltPaths(
const std::vector<std::shared_ptr<Installable>> & installables)
{
if (operateOn == OperateOn::Output)
- return build(evalStore, store, mode, installables);
+ return Installable::build(evalStore, store, mode, installables);
else {
if (mode == Realise::Nothing)
settings.readOnlyMode = true;
BuiltPaths res;
- for (auto & drvPath : toDerivations(store, installables, true))
+ for (auto & drvPath : Installable::toDerivations(store, installables, true))
res.push_back(BuiltPath::Opaque{drvPath});
return res;
}
}
-StorePathSet toStorePaths(
+StorePathSet Installable::toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode, OperateOn operateOn,
@@ -843,7 +879,7 @@ StorePathSet toStorePaths(
return outPaths;
}
-StorePath toStorePath(
+StorePath Installable::toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode, OperateOn operateOn,
@@ -857,7 +893,7 @@ StorePath toStorePath(
return *paths.begin();
}
-StorePathSet toDerivations(
+StorePathSet Installable::toDerivations(
ref<Store> store,
const std::vector<std::shared_ptr<Installable>> & installables,
bool useDeriver)
diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh
index 3d2563e4b..e172b71b0 100644
--- a/src/libcmd/installables.hh
+++ b/src/libcmd/installables.hh
@@ -5,6 +5,7 @@
#include "path-with-outputs.hh"
#include "derived-path.hh"
#include "eval.hh"
+#include "store-api.hh"
#include "flake/flake.hh"
#include <optional>
@@ -29,6 +30,27 @@ struct UnresolvedApp
App resolve(ref<Store> evalStore, ref<Store> store);
};
+enum class Realise {
+ /* Build the derivation. Postcondition: the
+ derivation outputs exist. */
+ Outputs,
+ /* Don't build the derivation. Postcondition: the store derivation
+ exists. */
+ Derivation,
+ /* Evaluate in dry-run mode. Postcondition: nothing. */
+ // FIXME: currently unused, but could be revived if we can
+ // evaluate derivations in-memory.
+ Nothing
+};
+
+/* How to handle derivations in commands that operate on store paths. */
+enum class OperateOn {
+ /* Operate on the output path. */
+ Output,
+ /* Operate on the .drv path. */
+ Derivation
+};
+
struct Installable
{
virtual ~Installable() { }
@@ -68,6 +90,39 @@ struct Installable
{
return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
}
+
+ static BuiltPaths build(
+ ref<Store> evalStore,
+ ref<Store> store,
+ Realise mode,
+ const std::vector<std::shared_ptr<Installable>> & installables,
+ BuildMode bMode = bmNormal);
+
+ static std::set<StorePath> toStorePaths(
+ ref<Store> evalStore,
+ ref<Store> store,
+ Realise mode,
+ OperateOn operateOn,
+ const std::vector<std::shared_ptr<Installable>> & installables);
+
+ static StorePath toStorePath(
+ ref<Store> evalStore,
+ ref<Store> store,
+ Realise mode,
+ OperateOn operateOn,
+ std::shared_ptr<Installable> installable);
+
+ static std::set<StorePath> toDerivations(
+ ref<Store> store,
+ const std::vector<std::shared_ptr<Installable>> & installables,
+ bool useDeriver = false);
+
+ static BuiltPaths toBuiltPaths(
+ ref<Store> evalStore,
+ ref<Store> store,
+ Realise mode,
+ OperateOn operateOn,
+ const std::vector<std::shared_ptr<Installable>> & installables);
};
struct InstallableValue : Installable
@@ -79,7 +134,6 @@ struct InstallableValue : Installable
struct DerivationInfo
{
StorePath drvPath;
- std::optional<StorePath> outPath;
std::string outputName;
};
@@ -131,4 +185,9 @@ ref<eval_cache::EvalCache> openEvalCache(
EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake);
+BuiltPaths getBuiltPaths(
+ ref<Store> evalStore,
+ ref<Store> store,
+ const DerivedPaths & hopefullyBuiltPaths);
+
}
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
index bf0c1dabc..32deecfae 100644
--- a/src/libexpr/attr-path.cc
+++ b/src/libexpr/attr-path.cc
@@ -9,7 +9,7 @@ namespace nix {
static Strings parseAttrPath(std::string_view s)
{
Strings res;
- string cur;
+ std::string cur;
auto i = s.begin();
while (i != s.end()) {
if (*i == '.') {
@@ -41,7 +41,7 @@ std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s)
}
-std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attrPath,
+std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const std::string & attrPath,
Bindings & autoArgs, Value & vIn)
{
Strings tokens = parseAttrPath(attrPath);
@@ -74,8 +74,14 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attr
throw Error("empty attribute name in selection path '%1%'", attrPath);
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
- if (a == v->attrs->end())
- throw AttrPathNotFound("attribute '%1%' in selection path '%2%' not found", attr, attrPath);
+ if (a == v->attrs->end()) {
+ std::set<std::string> attrNames;
+ for (auto & attr : *v->attrs)
+ attrNames.insert(attr.name);
+
+ auto suggestions = Suggestions::bestMatches(attrNames, attr);
+ throw AttrPathNotFound(suggestions, "attribute '%1%' in selection path '%2%' not found", attr, attrPath);
+ }
v = &*a->value;
pos = *a->pos;
}
@@ -121,7 +127,7 @@ Pos findPackageFilename(EvalState & state, Value & v, std::string what)
std::string filename(pos, 0, colon);
unsigned int lineno;
try {
- lineno = std::stoi(std::string(pos, colon + 1, string::npos));
+ lineno = std::stoi(std::string(pos, colon + 1, std::string::npos));
} catch (std::invalid_argument & e) {
throw ParseError("cannot parse line number '%s'", pos);
}
diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh
index 2ee3ea089..ff1135a06 100644
--- a/src/libexpr/attr-path.hh
+++ b/src/libexpr/attr-path.hh
@@ -10,8 +10,11 @@ namespace nix {
MakeError(AttrPathNotFound, Error);
MakeError(NoPositionInfo, Error);
-std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attrPath,
- Bindings & autoArgs, Value & vIn);
+std::pair<Value *, Pos> findAlongAttrPath(
+ EvalState & state,
+ const std::string & attrPath,
+ Bindings & autoArgs,
+ Value & vIn);
/* Heuristic to find the filename and lineno or a nix value. */
Pos findPackageFilename(EvalState & state, Value & v, std::string what);
diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh
index 3e4899efc..cad9743ea 100644
--- a/src/libexpr/attr-set.hh
+++ b/src/libexpr/attr-set.hh
@@ -105,7 +105,7 @@ public:
for (size_t n = 0; n < size_; n++)
res.emplace_back(&attrs[n]);
std::sort(res.begin(), res.end(), [](const Attr * a, const Attr * b) {
- return (const string &) a->name < (const string &) b->name;
+ return (const std::string &) a->name < (const std::string &) b->name;
});
return res;
}
diff --git a/src/libexpr/common-eval-args.cc b/src/libexpr/common-eval-args.cc
index fffca4ac5..e50ff244c 100644
--- a/src/libexpr/common-eval-args.cc
+++ b/src/libexpr/common-eval-args.cc
@@ -77,7 +77,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
for (auto & i : autoArgs) {
auto v = state.allocValue();
if (i.second[0] == 'E')
- state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath(".")));
+ state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), absPath(".")));
else
v->mkString(((std::string_view) i.second).substr(1));
res.insert(state.symbols.create(i.first), v);
@@ -85,17 +85,17 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
return res.finish();
}
-Path lookupFileArg(EvalState & state, string s)
+Path lookupFileArg(EvalState & state, std::string_view s)
{
if (isUri(s)) {
return state.store->toRealPath(
fetchers::downloadTarball(
state.store, resolveUri(s), "source", false).first.storePath);
} else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
- Path p = s.substr(1, s.size() - 2);
+ Path p(s.substr(1, s.size() - 2));
return state.findFile(p);
} else
- return absPath(s);
+ return absPath(std::string(s));
}
}
diff --git a/src/libexpr/common-eval-args.hh b/src/libexpr/common-eval-args.hh
index 0e113fff1..03fa226aa 100644
--- a/src/libexpr/common-eval-args.hh
+++ b/src/libexpr/common-eval-args.hh
@@ -22,6 +22,6 @@ private:
std::map<std::string, std::string> autoArgs;
};
-Path lookupFileArg(EvalState & state, string s);
+Path lookupFileArg(EvalState & state, std::string_view s);
}
diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc
index d6b9ea29b..188223957 100644
--- a/src/libexpr/eval-cache.cc
+++ b/src/libexpr/eval-cache.cc
@@ -406,6 +406,16 @@ Value & AttrCursor::forceValue()
return v;
}
+Suggestions AttrCursor::getSuggestionsForAttr(Symbol name)
+{
+ auto attrNames = getAttrs();
+ std::set<std::string> strAttrNames;
+ for (auto & name : attrNames)
+ strAttrNames.insert(std::string(name));
+
+ return Suggestions::bestMatches(strAttrNames, name);
+}
+
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErrors)
{
if (root->db) {
@@ -446,6 +456,11 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
return nullptr;
//throw TypeError("'%s' is not an attribute set", getAttrPathStr());
+ for (auto & attr : *v.attrs) {
+ if (root->db)
+ root->db->setPlaceholder({cachedValue->first, attr.name});
+ }
+
auto attr = v.attrs->get(name);
if (!attr) {
@@ -464,7 +479,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
cachedValue2 = {root->db->setPlaceholder({cachedValue->first, name}), placeholder_t()};
}
- return std::make_shared<AttrCursor>(
+ return make_ref<AttrCursor>(
root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2));
}
@@ -473,27 +488,31 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(std::string_view name)
return maybeGetAttr(root->state.symbols.create(name));
}
-std::shared_ptr<AttrCursor> AttrCursor::getAttr(Symbol name, bool forceErrors)
+ref<AttrCursor> AttrCursor::getAttr(Symbol name, bool forceErrors)
{
auto p = maybeGetAttr(name, forceErrors);
if (!p)
throw Error("attribute '%s' does not exist", getAttrPathStr(name));
- return p;
+ return ref(p);
}
-std::shared_ptr<AttrCursor> AttrCursor::getAttr(std::string_view name)
+ref<AttrCursor> AttrCursor::getAttr(std::string_view name)
{
return getAttr(root->state.symbols.create(name));
}
-std::shared_ptr<AttrCursor> AttrCursor::findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force)
+OrSuggestions<ref<AttrCursor>> AttrCursor::findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force)
{
auto res = shared_from_this();
for (auto & attr : attrPath) {
- res = res->maybeGetAttr(attr, force);
- if (!res) return {};
+ auto child = res->maybeGetAttr(attr, force);
+ if (!child) {
+ auto suggestions = res->getSuggestionsForAttr(attr);
+ return OrSuggestions<ref<AttrCursor>>::failed(suggestions);
+ }
+ res = child;
}
- return res;
+ return ref(res);
}
std::string AttrCursor::getString()
@@ -596,7 +615,7 @@ std::vector<Symbol> AttrCursor::getAttrs()
for (auto & attr : *getValue().attrs)
attrs.push_back(attr.name);
std::sort(attrs.begin(), attrs.end(), [](const Symbol & a, const Symbol & b) {
- return (const string &) a < (const string &) b;
+ return (const std::string &) a < (const std::string &) b;
});
if (root->db)
diff --git a/src/libexpr/eval-cache.hh b/src/libexpr/eval-cache.hh
index 43b34ebcb..40f1d4ffc 100644
--- a/src/libexpr/eval-cache.hh
+++ b/src/libexpr/eval-cache.hh
@@ -94,15 +94,17 @@ public:
std::string getAttrPathStr(Symbol name) const;
+ Suggestions getSuggestionsForAttr(Symbol name);
+
std::shared_ptr<AttrCursor> maybeGetAttr(Symbol name, bool forceErrors = false);
std::shared_ptr<AttrCursor> maybeGetAttr(std::string_view name);
- std::shared_ptr<AttrCursor> getAttr(Symbol name, bool forceErrors = false);
+ ref<AttrCursor> getAttr(Symbol name, bool forceErrors = false);
- std::shared_ptr<AttrCursor> getAttr(std::string_view name);
+ ref<AttrCursor> getAttr(std::string_view name);
- std::shared_ptr<AttrCursor> findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force = false);
+ OrSuggestions<ref<AttrCursor>> findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force = false);
std::string getString();
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 2d4eb57fc..5bf161cc0 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -63,9 +63,15 @@ static char * dupString(const char * s)
}
-static char * dupStringWithLen(const char * s, size_t size)
+// When there's no need to write to the string, we can optimize away empty
+// string allocations.
+// This function handles makeImmutableStringWithLen(null, 0) by returning the
+// empty string.
+static const char * makeImmutableStringWithLen(const char * s, size_t size)
{
char * t;
+ if (size == 0)
+ return "";
#if HAVE_BOEHMGC
t = GC_STRNDUP(s, size);
#else
@@ -75,6 +81,10 @@ static char * dupStringWithLen(const char * s, size_t size)
return t;
}
+static inline const char * makeImmutableString(std::string_view s) {
+ return makeImmutableStringWithLen(s.data(), s.size());
+}
+
RootValue allocRootValue(Value * v)
{
@@ -86,15 +96,10 @@ RootValue allocRootValue(Value * v)
}
-void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v)
+void printValue(std::ostream & str, std::set<const void *> & seen, const Value & v)
{
checkInterrupt();
- if (!active.insert(&v).second) {
- str << "<CYCLE>";
- return;
- }
-
switch (v.internalType) {
case tInt:
str << v.integer;
@@ -120,24 +125,32 @@ void printValue(std::ostream & str, std::set<const Value *> & active, const Valu
str << "null";
break;
case tAttrs: {
- str << "{ ";
- for (auto & i : v.attrs->lexicographicOrder()) {
- str << i->name << " = ";
- printValue(str, active, *i->value);
- str << "; ";
+ if (!v.attrs->empty() && !seen.insert(v.attrs).second)
+ str << "<REPEAT>";
+ else {
+ str << "{ ";
+ for (auto & i : v.attrs->lexicographicOrder()) {
+ str << i->name << " = ";
+ printValue(str, seen, *i->value);
+ str << "; ";
+ }
+ str << "}";
}
- str << "}";
break;
}
case tList1:
case tList2:
case tListN:
- str << "[ ";
- for (auto v2 : v.listItems()) {
- printValue(str, active, *v2);
- str << " ";
+ if (v.listSize() && !seen.insert(v.listElems()).second)
+ str << "<REPEAT>";
+ else {
+ str << "[ ";
+ for (auto v2 : v.listItems()) {
+ printValue(str, seen, *v2);
+ str << " ";
+ }
+ str << "]";
}
- str << "]";
break;
case tThunk:
case tApp:
@@ -161,20 +174,18 @@ void printValue(std::ostream & str, std::set<const Value *> & active, const Valu
default:
abort();
}
-
- active.erase(&v);
}
std::ostream & operator << (std::ostream & str, const Value & v)
{
- std::set<const Value *> active;
- printValue(str, active, v);
+ std::set<const void *> seen;
+ printValue(str, seen, v);
return str;
}
-const Value *getPrimOp(const Value &v) {
+const Value * getPrimOp(const Value &v) {
const Value * primOp = &v;
while (primOp->isPrimOpApp()) {
primOp = primOp->primOpApp.left;
@@ -183,7 +194,7 @@ const Value *getPrimOp(const Value &v) {
return primOp;
}
-string showType(ValueType type)
+std::string_view showType(ValueType type)
{
switch (type) {
case nInt: return "an integer";
@@ -202,20 +213,20 @@ string showType(ValueType type)
}
-string showType(const Value & v)
+std::string showType(const Value & v)
{
switch (v.internalType) {
case tString: return v.string.context ? "a string with context" : "a string";
case tPrimOp:
- return fmt("the built-in function '%s'", string(v.primOp->name));
+ return fmt("the built-in function '%s'", std::string(v.primOp->name));
case tPrimOpApp:
- return fmt("the partially applied built-in function '%s'", string(getPrimOp(v)->primOp->name));
+ return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->primOp->name));
case tExternal: return v.external->showType();
case tThunk: return "a thunk";
case tApp: return "a function application";
case tBlackhole: return "a black hole";
default:
- return showType(v.type());
+ return std::string(showType(v.type()));
}
}
@@ -356,7 +367,7 @@ void initGC()
/* Very hacky way to parse $NIX_PATH, which is colon-separated, but
can contain URLs (e.g. "nixpkgs=https://bla...:foo=https://"). */
-static Strings parseNixPath(const string & s)
+static Strings parseNixPath(const std::string & s)
{
Strings res;
@@ -517,6 +528,14 @@ void EvalState::allowPath(const StorePath & storePath)
allowedPaths->insert(store->toRealPath(storePath));
}
+void EvalState::allowAndSetStorePathString(const StorePath &storePath, Value & v)
+{
+ allowPath(storePath);
+
+ auto path = store->printStorePath(storePath);
+ v.mkString(path, PathSet({path}));
+}
+
Path EvalState::checkSourcePath(const Path & path_)
{
if (!allowedPaths) return path_;
@@ -606,7 +625,7 @@ Path EvalState::toRealPath(const Path & path, const PathSet & context)
}
-Value * EvalState::addConstant(const string & name, Value & v)
+Value * EvalState::addConstant(const std::string & name, Value & v)
{
Value * v2 = allocValue();
*v2 = v;
@@ -615,19 +634,19 @@ Value * EvalState::addConstant(const string & name, Value & v)
}
-void EvalState::addConstant(const string & name, Value * v)
+void EvalState::addConstant(const std::string & name, Value * v)
{
staticBaseEnv.vars.emplace_back(symbols.create(name), baseEnvDispl);
baseEnv.values[baseEnvDispl++] = v;
- string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
+ auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name;
baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v));
}
-Value * EvalState::addPrimOp(const string & name,
+Value * EvalState::addPrimOp(const std::string & name,
size_t arity, PrimOpFun primOp)
{
- auto name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
+ auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name;
Symbol sym = symbols.create(name2);
/* Hack to make constants lazy: turn them into a application of
@@ -675,7 +694,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
}
-Value & EvalState::getBuiltin(const string & name)
+Value & EvalState::getBuiltin(const std::string & name)
{
return *baseEnv.values[0]->attrs->find(symbols.create(name))->value;
}
@@ -703,12 +722,12 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
evaluator. So here are some helper functions for throwing
exceptions. */
-LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2))
+LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2))
{
throw EvalError(s, s2);
}
-LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2))
+LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2))
{
throw EvalError({
.msg = hintfmt(s, s2),
@@ -716,12 +735,12 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const
});
}
-LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3))
+LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2, const std::string & s3))
{
throw EvalError(s, s2, s3);
}
-LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3))
+LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2, const std::string & s3))
{
throw EvalError({
.msg = hintfmt(s, s2, s3),
@@ -759,7 +778,7 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v))
throw TypeError(s, showType(v));
}
-LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1))
+LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const std::string & s1))
{
throw AssertionError({
.msg = hintfmt(s, s1),
@@ -767,7 +786,7 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s,
});
}
-LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1))
+LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const std::string & s1))
{
throw UndefinedVarError({
.msg = hintfmt(s, s1),
@@ -775,7 +794,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char *
});
}
-LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1))
+LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const std::string & s1))
{
throw MissingArgumentError({
.msg = hintfmt(s, s1),
@@ -783,12 +802,12 @@ LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char
});
}
-LocalNoInline(void addErrorTrace(Error & e, const char * s, const string & s2))
+LocalNoInline(void addErrorTrace(Error & e, const char * s, const std::string & s2))
{
e.addTrace(std::nullopt, s, s2);
}
-LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, const string & s2))
+LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, const std::string & s2))
{
e.addTrace(pos, s, s2);
}
@@ -796,7 +815,7 @@ LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, con
void Value::mkString(std::string_view s)
{
- mkString(dupStringWithLen(s.data(), s.size()));
+ mkString(makeImmutableString(s));
}
@@ -827,7 +846,7 @@ void Value::mkStringMove(const char * s, const PathSet & context)
void Value::mkPath(std::string_view s)
{
- mkPath(dupStringWithLen(s.data(), s.size()));
+ mkPath(makeImmutableString(s));
}
@@ -1221,7 +1240,7 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
}
-static string showAttrPath(EvalState & state, Env & env, const AttrPath & attrPath)
+static std::string showAttrPath(EvalState & state, Env & env, const AttrPath & attrPath)
{
std::ostringstream out;
bool first = true;
@@ -1395,7 +1414,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
if (loggerSettings.showTrace.get()) {
addErrorTrace(e, lambda.pos, "while evaluating %s",
(lambda.name.set()
- ? "'" + (string) lambda.name + "'"
+ ? "'" + (const std::string &) lambda.name + "'"
: "anonymous lambda"));
addErrorTrace(e, pos, "from call site%s", "");
}
@@ -1883,7 +1902,7 @@ std::string_view EvalState::forceString(Value & v, const Pos & pos)
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
name>. */
-std::pair<string, string> decodeContext(std::string_view s)
+std::pair<std::string, std::string> decodeContext(std::string_view s)
{
if (s.at(0) == '!') {
size_t index = s.find("!", 1);
@@ -1946,7 +1965,7 @@ bool EvalState::isDerivation(Value & v)
}
-std::optional<string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
+std::optional<std::string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
PathSet & context, bool coerceMore, bool copyToStore)
{
auto i = v.attrs->find(sToString);
@@ -2001,7 +2020,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
if (v.type() == nNull) return "";
if (v.isList()) {
- string result;
+ std::string result;
for (auto [n, v2] : enumerate(v.listItems())) {
result += *coerceToString(pos, *v2, context, coerceMore, copyToStore);
if (n < v.listSize() - 1
@@ -2017,7 +2036,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
}
-string EvalState::copyPathToStore(PathSet & context, const Path & path)
+std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
{
if (nix::isDerivation(path))
throwEvalError("file names are not allowed to end in '%1%'", drvExtension);
@@ -2043,13 +2062,25 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path)
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
{
- string path = coerceToString(pos, v, context, false, false).toOwned();
+ auto path = coerceToString(pos, v, context, false, false).toOwned();
if (path == "" || path[0] != '/')
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path);
return path;
}
+StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context)
+{
+ auto path = coerceToString(pos, v, context, false, false).toOwned();
+ if (auto storePath = store->maybeParseStorePath(path))
+ return *storePath;
+ throw EvalError({
+ .msg = hintfmt("path '%1%' is not in the Nix store", path),
+ .errPos = pos
+ });
+}
+
+
bool EvalState::eqValues(Value & v1, Value & v2)
{
forceValue(v1, noPos);
@@ -2213,11 +2244,11 @@ void EvalState::printStats()
for (auto & i : functionCalls) {
auto obj = list.object();
if (i.first->name.set())
- obj.attr("name", (const string &) i.first->name);
+ obj.attr("name", (const std::string &) i.first->name);
else
obj.attr("name", nullptr);
if (i.first->pos) {
- obj.attr("file", (const string &) i.first->pos.file);
+ obj.attr("file", (const std::string &) i.first->pos.file);
obj.attr("line", i.first->pos.line);
obj.attr("column", i.first->pos.column);
}
@@ -2229,7 +2260,7 @@ void EvalState::printStats()
for (auto & i : attrSelects) {
auto obj = list.object();
if (i.first) {
- obj.attr("file", (const string &) i.first.file);
+ obj.attr("file", (const std::string &) i.first.file);
obj.attr("line", i.first.line);
obj.attr("column", i.first.column);
}
@@ -2246,7 +2277,7 @@ void EvalState::printStats()
}
-string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
+std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
{
throw TypeError({
.msg = hintfmt("cannot coerce %1% to a string", showType()),
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index ce5a16e11..800b00eef 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -150,7 +150,7 @@ public:
const Pos & pos
);
- void addToSearchPath(const string & s);
+ void addToSearchPath(const std::string & s);
SearchPath getSearchPath() { return searchPath; }
@@ -161,6 +161,9 @@ public:
the real store path if `store` is a chroot store. */
void allowPath(const StorePath & storePath);
+ /* Allow access to a store path and return it as a string. */
+ void allowAndSetStorePathString(const StorePath & storePath, Value & v);
+
/* Check whether access to a path is allowed and throw an error if
not. Otherwise return the canonicalised path. */
Path checkSourcePath(const Path & path);
@@ -251,7 +254,7 @@ public:
set with attribute `type = "derivation"'). */
bool isDerivation(Value & v);
- std::optional<string> tryAttrsToString(const Pos & pos, Value & v,
+ std::optional<std::string> tryAttrsToString(const Pos & pos, Value & v,
PathSet & context, bool coerceMore = false, bool copyToStore = true);
/* String coercion. Converts strings, paths and derivations to a
@@ -262,13 +265,16 @@ public:
bool coerceMore = false, bool copyToStore = true,
bool canonicalizePath = true);
- string copyPathToStore(PathSet & context, const Path & path);
+ std::string copyPathToStore(PathSet & context, const Path & path);
/* Path coercion. Converts strings, paths and derivations to a
path. The result is guaranteed to be a canonicalised, absolute
path. Nothing is copied to the store. */
Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
+ /* Like coerceToPath, but the result must be a store path. */
+ StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context);
+
public:
/* The base environment, containing the builtin functions and
@@ -284,18 +290,18 @@ private:
void createBaseEnv();
- Value * addConstant(const string & name, Value & v);
+ Value * addConstant(const std::string & name, Value & v);
- void addConstant(const string & name, Value * v);
+ void addConstant(const std::string & name, Value * v);
- Value * addPrimOp(const string & name,
+ Value * addPrimOp(const std::string & name,
size_t arity, PrimOpFun primOp);
Value * addPrimOp(PrimOp && primOp);
public:
- Value & getBuiltin(const string & name);
+ Value & getBuiltin(const std::string & name);
struct Doc
{
@@ -414,12 +420,12 @@ private:
/* Return a string representing the type of the value `v'. */
-string showType(ValueType type);
-string showType(const Value & v);
+std::string_view showType(ValueType type);
+std::string showType(const Value & v);
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
name>. */
-std::pair<string, string> decodeContext(std::string_view s);
+std::pair<std::string, std::string> decodeContext(std::string_view s);
/* If `path' refers to a directory, then append "/default.nix". */
Path resolveExprPath(Path path);
diff --git a/src/libexpr/flake/config.cc b/src/libexpr/flake/config.cc
index 7ecd61816..a811e59a1 100644
--- a/src/libexpr/flake/config.cc
+++ b/src/libexpr/flake/config.cc
@@ -1,5 +1,6 @@
#include "flake.hh"
#include "globals.hh"
+#include "fetch-settings.hh"
#include <nlohmann/json.hpp>
@@ -53,7 +54,7 @@ void ConfigFile::apply()
auto trustedList = readTrustedList();
bool trusted = false;
- if (nix::settings.acceptFlakeConfig){
+ if (nix::fetchSettings.acceptFlakeConfig){
trusted = true;
} else if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) {
trusted = *saved;
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 9f3b58909..6a1aca40d 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -6,6 +6,7 @@
#include "store-api.hh"
#include "fetchers.hh"
#include "finally.hh"
+#include "fetch-settings.hh"
namespace nix {
@@ -254,7 +255,7 @@ static Flake getFlake(
for (auto & setting : *nixConfig->value->attrs) {
forceTrivialValue(state, *setting.value, *setting.pos);
if (setting.value->type() == nString)
- flake.config.settings.insert({setting.name, string(state.forceStringNoCtx(*setting.value, *setting.pos))});
+ flake.config.settings.insert({setting.name, std::string(state.forceStringNoCtx(*setting.value, *setting.pos))});
else if (setting.value->type() == nPath) {
PathSet emptyContext = {};
flake.config.settings.emplace(
@@ -315,7 +316,7 @@ LockedFlake lockFlake(
FlakeCache flakeCache;
- auto useRegistries = lockFlags.useRegistries.value_or(settings.useRegistries);
+ auto useRegistries = lockFlags.useRegistries.value_or(fetchSettings.useRegistries);
auto flake = getFlake(state, topRef, useRegistries, flakeCache);
@@ -501,7 +502,7 @@ LockedFlake lockFlake(
this input. */
debug("creating new input '%s'", inputPathS);
- if (!lockFlags.allowMutable && !input.ref->input.isImmutable())
+ if (!lockFlags.allowMutable && !input.ref->input.isLocked())
throw Error("cannot update flake input '%s' in pure mode", inputPathS);
if (input.isFlake) {
@@ -591,7 +592,7 @@ LockedFlake lockFlake(
if (lockFlags.writeLockFile) {
if (auto sourcePath = topRef.input.getSourcePath()) {
if (!newLockFile.isImmutable()) {
- if (settings.warnDirty)
+ if (fetchSettings.warnDirty)
warn("will not write lock file of flake '%s' because it has a mutable input", topRef);
} else {
if (!lockFlags.updateLockFile)
@@ -618,7 +619,7 @@ LockedFlake lockFlake(
if (lockFlags.commitLockFile) {
std::string cm;
- cm = settings.commitLockFileSummary.get();
+ cm = fetchSettings.commitLockFileSummary.get();
if (cm == "") {
cm = fmt("%s: %s", relPath, lockFileExists ? "Update" : "Add");
@@ -650,7 +651,7 @@ LockedFlake lockFlake(
now. Corner case: we could have reverted from a
dirty to a clean tree! */
if (flake.lockedRef.input == prevLockedRef.input
- && !flake.lockedRef.input.isImmutable())
+ && !flake.lockedRef.input.isLocked())
throw Error("'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", flake.originalRef);
}
} else
@@ -707,16 +708,16 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
{
state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos);
- string flakeRefS(state.forceStringNoCtx(*args[0], pos));
+ std::string flakeRefS(state.forceStringNoCtx(*args[0], pos));
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
- if (evalSettings.pureEval && !flakeRef.input.isImmutable())
- throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);
+ if (evalSettings.pureEval && !flakeRef.input.isLocked())
+ throw Error("cannot call 'getFlake' on unlocked flake reference '%s', at %s (use --impure to override)", flakeRefS, pos);
callFlake(state,
lockFlake(state, flakeRef,
LockFlags {
.updateLockFile = false,
- .useRegistries = !evalSettings.pureEval && settings.useRegistries,
+ .useRegistries = !evalSettings.pureEval && fetchSettings.useRegistries,
.allowMutable = !evalSettings.pureEval,
}),
v);
diff --git a/src/libexpr/flake/flakeref.cc b/src/libexpr/flake/flakeref.cc
index 930ed9ccd..c1eae413f 100644
--- a/src/libexpr/flake/flakeref.cc
+++ b/src/libexpr/flake/flakeref.cc
@@ -98,7 +98,7 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
if (std::regex_match(url, match, flakeRegex)) {
auto parsedURL = ParsedURL{
.url = url,
- .base = "flake:" + std::string(match[1]),
+ .base = "flake:" + match.str(1),
.scheme = "flake",
.authority = "",
.path = match[1],
@@ -106,12 +106,12 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
return std::make_pair(
FlakeRef(Input::fromURL(parsedURL), ""),
- percentDecode(std::string(match[6])));
+ percentDecode(match.str(6)));
}
else if (std::regex_match(url, match, pathUrlRegex)) {
std::string path = match[1];
- std::string fragment = percentDecode(std::string(match[3]));
+ std::string fragment = percentDecode(match.str(3));
if (baseDir) {
/* Check if 'url' is a path (either absolute or relative
diff --git a/src/libexpr/flake/lockfile.cc b/src/libexpr/flake/lockfile.cc
index fda340789..60b52d578 100644
--- a/src/libexpr/flake/lockfile.cc
+++ b/src/libexpr/flake/lockfile.cc
@@ -35,7 +35,7 @@ LockedNode::LockedNode(const nlohmann::json & json)
, originalRef(getFlakeRef(json, "original", nullptr))
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
{
- if (!lockedRef.input.isImmutable())
+ if (!lockedRef.input.isLocked())
throw Error("lockfile contains mutable lock '%s'",
fetchers::attrsToJSON(lockedRef.input.toAttrs()));
}
@@ -220,7 +220,7 @@ bool LockFile::isImmutable() const
for (auto & i : nodes) {
if (i == root) continue;
auto lockedNode = std::dynamic_pointer_cast<const LockedNode>(i);
- if (lockedNode && !lockedNode->lockedRef.input.isImmutable()) return false;
+ if (lockedNode && !lockedNode->lockedRef.input.isLocked()) return false;
}
return true;
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index 5995a857b..7630c5ff4 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -11,8 +11,8 @@
namespace nix {
-DrvInfo::DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs)
- : state(&state), attrs(attrs), attrPath(attrPath)
+DrvInfo::DrvInfo(EvalState & state, std::string attrPath, Bindings * attrs)
+ : state(&state), attrs(attrs), attrPath(std::move(attrPath))
{
}
@@ -22,7 +22,7 @@ DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPat
{
auto [drvPath, selectedOutputs] = parsePathWithOutputs(*store, drvPathWithOutputs);
- this->drvPath = store->printStorePath(drvPath);
+ this->drvPath = drvPath;
auto drv = store->derivationFromPath(drvPath);
@@ -41,13 +41,11 @@ DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPat
throw Error("derivation '%s' does not have output '%s'", store->printStorePath(drvPath), outputName);
auto & [outputName, output] = *i;
- auto optStorePath = output.path(*store, drv.name, outputName);
- if (optStorePath)
- outPath = store->printStorePath(*optStorePath);
+ outPath = {output.path(*store, drv.name, outputName)};
}
-string DrvInfo::queryName() const
+std::string DrvInfo::queryName() const
{
if (name == "" && attrs) {
auto i = attrs->find(state->sName);
@@ -58,7 +56,7 @@ string DrvInfo::queryName() const
}
-string DrvInfo::querySystem() const
+std::string DrvInfo::querySystem() const
{
if (system == "" && attrs) {
auto i = attrs->find(state->sSystem);
@@ -68,24 +66,35 @@ string DrvInfo::querySystem() const
}
-string DrvInfo::queryDrvPath() const
+std::optional<StorePath> DrvInfo::queryDrvPath() const
{
- if (drvPath == "" && attrs) {
+ if (!drvPath && attrs) {
Bindings::iterator i = attrs->find(state->sDrvPath);
PathSet context;
- drvPath = i != attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : "";
+ if (i == attrs->end())
+ drvPath = {std::nullopt};
+ else
+ drvPath = {state->coerceToStorePath(*i->pos, *i->value, context)};
}
- return drvPath;
+ return drvPath.value_or(std::nullopt);
}
-string DrvInfo::queryOutPath() const
+StorePath DrvInfo::requireDrvPath() const
+{
+ if (auto drvPath = queryDrvPath())
+ return *drvPath;
+ throw Error("derivation does not contain a 'drvPath' attribute");
+}
+
+
+StorePath DrvInfo::queryOutPath() const
{
if (!outPath && attrs) {
Bindings::iterator i = attrs->find(state->sOutPath);
PathSet context;
if (i != attrs->end())
- outPath = state->coerceToPath(*i->pos, *i->value, context);
+ outPath = state->coerceToStorePath(*i->pos, *i->value, context);
}
if (!outPath)
throw UnimplementedError("CA derivations are not yet supported");
@@ -104,7 +113,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
/* For each output... */
for (auto elem : i->value->listItems()) {
/* Evaluate the corresponding set. */
- string name(state->forceStringNoCtx(*elem, *i->pos));
+ std::string name(state->forceStringNoCtx(*elem, *i->pos));
Bindings::iterator out = attrs->find(state->symbols.create(name));
if (out == attrs->end()) continue; // FIXME: throw error?
state->forceAttrs(*out->value, *i->pos);
@@ -113,10 +122,10 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
PathSet context;
- outputs[name] = state->coerceToPath(*outPath->pos, *outPath->value, context);
+ outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context));
}
} else
- outputs["out"] = queryOutPath();
+ outputs.emplace("out", queryOutPath());
}
if (!onlyOutputsToInstall || !attrs)
return outputs;
@@ -138,7 +147,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
}
-string DrvInfo::queryOutputName() const
+std::string DrvInfo::queryOutputName() const
{
if (outputName == "" && attrs) {
Bindings::iterator i = attrs->find(state->sOutputName);
@@ -190,7 +199,7 @@ bool DrvInfo::checkMeta(Value & v)
}
-Value * DrvInfo::queryMeta(const string & name)
+Value * DrvInfo::queryMeta(const std::string & name)
{
if (!getMeta()) return 0;
Bindings::iterator a = meta->find(state->symbols.create(name));
@@ -199,7 +208,7 @@ Value * DrvInfo::queryMeta(const string & name)
}
-string DrvInfo::queryMetaString(const string & name)
+std::string DrvInfo::queryMetaString(const std::string & name)
{
Value * v = queryMeta(name);
if (!v || v->type() != nString) return "";
@@ -207,7 +216,7 @@ string DrvInfo::queryMetaString(const string & name)
}
-NixInt DrvInfo::queryMetaInt(const string & name, NixInt def)
+NixInt DrvInfo::queryMetaInt(const std::string & name, NixInt def)
{
Value * v = queryMeta(name);
if (!v) return def;
@@ -221,7 +230,7 @@ NixInt DrvInfo::queryMetaInt(const string & name, NixInt def)
return def;
}
-NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def)
+NixFloat DrvInfo::queryMetaFloat(const std::string & name, NixFloat def)
{
Value * v = queryMeta(name);
if (!v) return def;
@@ -236,7 +245,7 @@ NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def)
}
-bool DrvInfo::queryMetaBool(const string & name, bool def)
+bool DrvInfo::queryMetaBool(const std::string & name, bool def)
{
Value * v = queryMeta(name);
if (!v) return def;
@@ -251,7 +260,7 @@ bool DrvInfo::queryMetaBool(const string & name, bool def)
}
-void DrvInfo::setMeta(const string & name, Value * v)
+void DrvInfo::setMeta(const std::string & name, Value * v)
{
getMeta();
auto attrs = state->buildBindings(1 + (meta ? meta->size() : 0));
@@ -266,7 +275,7 @@ void DrvInfo::setMeta(const string & name, Value * v)
/* Cache for already considered attrsets. */
-typedef set<Bindings *> Done;
+typedef std::set<Bindings *> Done;
/* Evaluate value `v'. If it evaluates to a set of type `derivation',
@@ -274,7 +283,7 @@ typedef set<Bindings *> Done;
The result boolean indicates whether it makes sense
for the caller to recursively search for derivations in `v'. */
static bool getDerivation(EvalState & state, Value & v,
- const string & attrPath, DrvInfos & drvs, Done & done,
+ const std::string & attrPath, DrvInfos & drvs, Done & done,
bool ignoreAssertionFailures)
{
try {
@@ -311,7 +320,7 @@ std::optional<DrvInfo> getDerivation(EvalState & state, Value & v,
}
-static string addToPath(const string & s1, const string & s2)
+static std::string addToPath(const std::string & s1, const std::string & s2)
{
return s1.empty() ? s2 : s1 + "." + s2;
}
@@ -321,7 +330,7 @@ static std::regex attrRegex("[A-Za-z_][A-Za-z0-9-_+]*");
static void getDerivations(EvalState & state, Value & vIn,
- const string & pathPrefix, Bindings & autoArgs,
+ const std::string & pathPrefix, Bindings & autoArgs,
DrvInfos & drvs, Done & done,
bool ignoreAssertionFailures)
{
@@ -346,7 +355,7 @@ static void getDerivations(EvalState & state, Value & vIn,
debug("evaluating attribute '%1%'", i->name);
if (!std::regex_match(std::string(i->name), attrRegex))
continue;
- string pathPrefix2 = addToPath(pathPrefix, i->name);
+ std::string pathPrefix2 = addToPath(pathPrefix, i->name);
if (combineChannels)
getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
else if (getDerivation(state, *i->value, pathPrefix2, drvs, done, ignoreAssertionFailures)) {
@@ -364,7 +373,7 @@ static void getDerivations(EvalState & state, Value & vIn,
else if (v.type() == nList) {
for (auto [n, elem] : enumerate(v.listItems())) {
- string pathPrefix2 = addToPath(pathPrefix, fmt("%d", n));
+ std::string pathPrefix2 = addToPath(pathPrefix, fmt("%d", n));
if (getDerivation(state, *elem, pathPrefix2, drvs, done, ignoreAssertionFailures))
getDerivations(state, *elem, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures);
}
@@ -374,7 +383,7 @@ static void getDerivations(EvalState & state, Value & vIn,
}
-void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
+void getDerivations(EvalState & state, Value & v, const std::string & pathPrefix,
Bindings & autoArgs, DrvInfos & drvs, bool ignoreAssertionFailures)
{
Done done;
diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh
index 29bb6a660..3ca6f1fca 100644
--- a/src/libexpr/get-drvs.hh
+++ b/src/libexpr/get-drvs.hh
@@ -1,6 +1,7 @@
#pragma once
#include "eval.hh"
+#include "path.hh"
#include <string>
#include <map>
@@ -12,16 +13,16 @@ namespace nix {
struct DrvInfo
{
public:
- typedef std::map<string, Path> Outputs;
+ typedef std::map<std::string, StorePath> Outputs;
private:
EvalState * state;
- mutable string name;
- mutable string system;
- mutable string drvPath;
- mutable std::optional<string> outPath;
- mutable string outputName;
+ mutable std::string name;
+ mutable std::string system;
+ mutable std::optional<std::optional<StorePath>> drvPath;
+ mutable std::optional<StorePath> outPath;
+ mutable std::string outputName;
Outputs outputs;
bool failed = false; // set if we get an AssertionError
@@ -33,36 +34,37 @@ private:
bool checkMeta(Value & v);
public:
- string attrPath; /* path towards the derivation */
+ std::string attrPath; /* path towards the derivation */
DrvInfo(EvalState & state) : state(&state) { };
- DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs);
+ DrvInfo(EvalState & state, std::string attrPath, Bindings * attrs);
DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs);
- string queryName() const;
- string querySystem() const;
- string queryDrvPath() const;
- string queryOutPath() const;
- string queryOutputName() const;
+ std::string queryName() const;
+ std::string querySystem() const;
+ std::optional<StorePath> queryDrvPath() const;
+ StorePath requireDrvPath() const;
+ StorePath queryOutPath() const;
+ std::string queryOutputName() const;
/** Return the list of outputs. The "outputs to install" are determined by `meta.outputsToInstall`. */
Outputs queryOutputs(bool onlyOutputsToInstall = false);
StringSet queryMetaNames();
- Value * queryMeta(const string & name);
- string queryMetaString(const string & name);
- NixInt queryMetaInt(const string & name, NixInt def);
- NixFloat queryMetaFloat(const string & name, NixFloat def);
- bool queryMetaBool(const string & name, bool def);
- void setMeta(const string & name, Value * v);
+ Value * queryMeta(const std::string & name);
+ std::string queryMetaString(const std::string & name);
+ NixInt queryMetaInt(const std::string & name, NixInt def);
+ NixFloat queryMetaFloat(const std::string & name, NixFloat def);
+ bool queryMetaBool(const std::string & name, bool def);
+ void setMeta(const std::string & name, Value * v);
/*
MetaInfo queryMetaInfo(EvalState & state) const;
MetaValue queryMetaInfo(EvalState & state, const string & name) const;
*/
- void setName(const string & s) { name = s; }
- void setDrvPath(const string & s) { drvPath = s; }
- void setOutPath(const string & s) { outPath = s; }
+ void setName(const std::string & s) { name = s; }
+ void setDrvPath(StorePath path) { drvPath = {{std::move(path)}}; }
+ void setOutPath(StorePath path) { outPath = {{std::move(path)}}; }
void setFailed() { failed = true; };
bool hasFailed() { return failed; };
@@ -70,9 +72,9 @@ public:
#if HAVE_BOEHMGC
-typedef list<DrvInfo, traceable_allocator<DrvInfo> > DrvInfos;
+typedef std::list<DrvInfo, traceable_allocator<DrvInfo> > DrvInfos;
#else
-typedef list<DrvInfo> DrvInfos;
+typedef std::list<DrvInfo> DrvInfos;
#endif
@@ -81,7 +83,7 @@ typedef list<DrvInfo> DrvInfos;
std::optional<DrvInfo> getDerivation(EvalState & state,
Value & v, bool ignoreAssertionFailures);
-void getDerivations(EvalState & state, Value & v, const string & pathPrefix,
+void getDerivations(EvalState & state, Value & v, const std::string & pathPrefix,
Bindings & autoArgs, DrvInfos & drvs,
bool ignoreAssertionFailures);
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 2d2cd96cd..a2def65a6 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -16,10 +16,10 @@ std::ostream & operator << (std::ostream & str, const Expr & e)
return str;
}
-static void showString(std::ostream & str, const string & s)
+static void showString(std::ostream & str, std::string_view s)
{
str << '"';
- for (auto c : (string) s)
+ for (auto c : s)
if (c == '"' || c == '\\' || c == '$') str << "\\" << c;
else if (c == '\n') str << "\\n";
else if (c == '\r') str << "\\r";
@@ -28,7 +28,7 @@ static void showString(std::ostream & str, const string & s)
str << '"';
}
-static void showId(std::ostream & str, const string & s)
+static void showId(std::ostream & str, std::string_view s)
{
if (s.empty())
str << "\"\"";
@@ -103,11 +103,18 @@ void ExprAttrs::show(std::ostream & str) const
{
if (recursive) str << "rec ";
str << "{ ";
- for (auto & i : attrs)
- if (i.second.inherited)
- str << "inherit " << i.first << " " << "; ";
+ typedef const decltype(attrs)::value_type * Attr;
+ std::vector<Attr> sorted;
+ for (auto & i : attrs) sorted.push_back(&i);
+ std::sort(sorted.begin(), sorted.end(), [](Attr a, Attr b) {
+ return (const std::string &) a->first < (const std::string &) b->first;
+ });
+ for (auto & i : sorted) {
+ if (i->second.inherited)
+ str << "inherit " << i->first << " " << "; ";
else
- str << i.first << " = " << *i.second.e << "; ";
+ str << i->first << " = " << *i->second.e << "; ";
+ }
for (auto & i : dynamicAttrs)
str << "\"${" << *i.nameExpr << "}\" = " << *i.valueExpr << "; ";
str << "}";
@@ -211,7 +218,7 @@ std::ostream & operator << (std::ostream & str, const Pos & pos)
auto f = format(ANSI_BOLD "%1%" ANSI_NORMAL ":%2%:%3%");
switch (pos.origin) {
case foFile:
- f % (string) pos.file;
+ f % (const std::string &) pos.file;
break;
case foStdin:
case foString:
@@ -227,7 +234,7 @@ std::ostream & operator << (std::ostream & str, const Pos & pos)
}
-string showAttrPath(const AttrPath & attrPath)
+std::string showAttrPath(const AttrPath & attrPath)
{
std::ostringstream out;
bool first = true;
@@ -461,9 +468,9 @@ void ExprLambda::setName(Symbol & name)
}
-string ExprLambda::showNamePos() const
+std::string ExprLambda::showNamePos() const
{
- return (format("%1% at %2%") % (name.set() ? "'" + (string) name + "'" : "anonymous function") % pos).str();
+ return fmt("%1% at %2%", name.set() ? "'" + (std::string) name + "'" : "anonymous function", pos);
}
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index 6f6acb074..12b54b8eb 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -26,18 +26,21 @@ struct Pos
FileOrigin origin;
Symbol file;
unsigned int line, column;
- Pos() : origin(foString), line(0), column(0) { };
+
+ Pos() : origin(foString), line(0), column(0) { }
Pos(FileOrigin origin, const Symbol & file, unsigned int line, unsigned int column)
- : origin(origin), file(file), line(line), column(column) { };
+ : origin(origin), file(file), line(line), column(column) { }
+
operator bool() const
{
return line != 0;
}
+
bool operator < (const Pos & p2) const
{
if (!line) return p2.line;
if (!p2.line) return false;
- int d = ((string) file).compare((string) p2.file);
+ int d = ((const std::string &) file).compare((const std::string &) p2.file);
if (d < 0) return true;
if (d > 0) return false;
if (line < p2.line) return true;
@@ -68,7 +71,7 @@ struct AttrName
typedef std::vector<AttrName> AttrPath;
-string showAttrPath(const AttrPath & attrPath);
+std::string showAttrPath(const AttrPath & attrPath);
/* Abstract syntax of Nix expressions. */
@@ -110,7 +113,7 @@ struct ExprFloat : Expr
struct ExprString : Expr
{
- string s;
+ std::string s;
Value v;
ExprString(std::string s) : s(std::move(s)) { v.mkString(this->s.data()); };
COMMON_METHODS
@@ -119,9 +122,9 @@ struct ExprString : Expr
struct ExprPath : Expr
{
- string s;
+ std::string s;
Value v;
- ExprPath(const string & s) : s(s) { v.mkPath(this->s.c_str()); };
+ ExprPath(std::string s) : s(std::move(s)) { v.mkPath(this->s.c_str()); };
COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env);
};
@@ -249,7 +252,7 @@ struct ExprLambda : Expr
{
};
void setName(Symbol & name);
- string showNamePos() const;
+ std::string showNamePos() const;
inline bool hasFormals() const { return formals != nullptr; }
COMMON_METHODS
};
@@ -335,8 +338,8 @@ struct ExprConcatStrings : Expr
{
Pos pos;
bool forceString;
- vector<std::pair<Pos, Expr *> > * es;
- ExprConcatStrings(const Pos & pos, bool forceString, vector<std::pair<Pos, Expr *> > * es)
+ std::vector<std::pair<Pos, Expr *> > * es;
+ ExprConcatStrings(const Pos & pos, bool forceString, std::vector<std::pair<Pos, Expr *> > * es)
: pos(pos), forceString(forceString), es(es) { };
COMMON_METHODS
};
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index f0c80ebd5..919b9cfae 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -193,7 +193,7 @@ static Formals * toFormals(ParseData & data, ParserFormals * formals,
static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
- vector<std::pair<Pos, std::variant<Expr *, StringToken> > > & es)
+ std::vector<std::pair<Pos, std::variant<Expr *, StringToken> > > & es)
{
if (es.empty()) return new ExprString("");
@@ -233,7 +233,7 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
}
/* Strip spaces from each line. */
- vector<std::pair<Pos, Expr *> > * es2 = new vector<std::pair<Pos, Expr *> >;
+ std::vector<std::pair<Pos, Expr *> > * es2 = new std::vector<std::pair<Pos, Expr *> >;
atStartOfLine = true;
size_t curDropped = 0;
size_t n = es.size();
@@ -244,7 +244,7 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
es2->emplace_back(i->first, e);
};
const auto trimString = [&] (const StringToken & t) {
- string s2;
+ std::string s2;
for (size_t j = 0; j < t.l; ++j) {
if (atStartOfLine) {
if (t.p[j] == ' ') {
@@ -268,9 +268,9 @@ static Expr * stripIndentation(const Pos & pos, SymbolTable & symbols,
/* Remove the last line if it is empty and consists only of
spaces. */
if (n == 1) {
- string::size_type p = s2.find_last_of('\n');
- if (p != string::npos && s2.find_first_not_of(' ', p + 1) == string::npos)
- s2 = string(s2, 0, p + 1);
+ std::string::size_type p = s2.find_last_of('\n');
+ if (p != std::string::npos && s2.find_first_not_of(' ', p + 1) == std::string::npos)
+ s2 = std::string(s2, 0, p + 1);
}
es2->emplace_back(i->first, new ExprString(s2));
@@ -415,7 +415,7 @@ expr_op
| expr_op UPDATE expr_op { $$ = new ExprOpUpdate(CUR_POS, $1, $3); }
| expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); }
| expr_op '+' expr_op
- { $$ = new ExprConcatStrings(CUR_POS, false, new vector<std::pair<Pos, Expr *> >({{makeCurPos(@1, data), $1}, {makeCurPos(@3, data), $3}})); }
+ { $$ = new ExprConcatStrings(CUR_POS, false, new std::vector<std::pair<Pos, Expr *> >({{makeCurPos(@1, data), $1}, {makeCurPos(@3, data), $3}})); }
| expr_op '-' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__sub")), {$1, $3}); }
| expr_op '*' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__mul")), {$1, $3}); }
| expr_op '/' expr_op { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__div")), {$1, $3}); }
@@ -466,7 +466,7 @@ expr_simple
$$ = new ExprConcatStrings(CUR_POS, false, $2);
}
| SPATH {
- string path($1.p + 1, $1.l - 2);
+ std::string path($1.p + 1, $1.l - 2);
$$ = new ExprCall(CUR_POS,
new ExprVar(data->symbols.create("__findFile")),
{new ExprVar(data->symbols.create("__nixPath")),
@@ -479,7 +479,7 @@ expr_simple
.msg = hintfmt("URL literals are disabled"),
.errPos = CUR_POS
});
- $$ = new ExprString(string($1));
+ $$ = new ExprString(std::string($1));
}
| '(' expr ')' { $$ = $2; }
/* Let expressions `let {..., body = ...}' are just desugared
@@ -494,19 +494,19 @@ expr_simple
;
string_parts
- : STR { $$ = new ExprString(string($1)); }
+ : STR { $$ = new ExprString(std::string($1)); }
| string_parts_interpolated { $$ = new ExprConcatStrings(CUR_POS, true, $1); }
| { $$ = new ExprString(""); }
;
string_parts_interpolated
: string_parts_interpolated STR
- { $$ = $1; $1->emplace_back(makeCurPos(@2, data), new ExprString(string($2))); }
+ { $$ = $1; $1->emplace_back(makeCurPos(@2, data), new ExprString(std::string($2))); }
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); }
- | DOLLAR_CURLY expr '}' { $$ = new vector<std::pair<Pos, Expr *> >; $$->emplace_back(makeCurPos(@1, data), $2); }
+ | DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<Pos, Expr *> >; $$->emplace_back(makeCurPos(@1, data), $2); }
| STR DOLLAR_CURLY expr '}' {
- $$ = new vector<std::pair<Pos, Expr *> >;
- $$->emplace_back(makeCurPos(@1, data), new ExprString(string($1)));
+ $$ = new std::vector<std::pair<Pos, Expr *> >;
+ $$->emplace_back(makeCurPos(@1, data), new ExprString(std::string($1)));
$$->emplace_back(makeCurPos(@2, data), $3);
}
;
@@ -520,7 +520,7 @@ path_start
$$ = new ExprPath(path);
}
| HPATH {
- Path path(getHome() + string($1.p + 1, $1.l - 1));
+ Path path(getHome() + std::string($1.p + 1, $1.l - 1));
$$ = new ExprPath(path);
}
;
@@ -528,7 +528,7 @@ path_start
ind_string_parts
: ind_string_parts IND_STR { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $2); }
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(makeCurPos(@2, data), $3); }
- | { $$ = new vector<std::pair<Pos, std::variant<Expr *, StringToken> > >; }
+ | { $$ = new std::vector<std::pair<Pos, std::variant<Expr *, StringToken> > >; }
;
binds
@@ -582,9 +582,9 @@ attrpath
} else
$$->push_back(AttrName($3));
}
- | attr { $$ = new vector<AttrName>; $$->push_back(AttrName(data->symbols.create($1))); }
+ | attr { $$ = new std::vector<AttrName>; $$->push_back(AttrName(data->symbols.create($1))); }
| string_attr
- { $$ = new vector<AttrName>;
+ { $$ = new std::vector<AttrName>;
ExprString *str = dynamic_cast<ExprString *>($1);
if (str) {
$$->push_back(AttrName(data->symbols.create(str->s)));
@@ -738,16 +738,16 @@ Expr * EvalState::parseStdin()
}
-void EvalState::addToSearchPath(const string & s)
+void EvalState::addToSearchPath(const std::string & s)
{
size_t pos = s.find('=');
- string prefix;
+ std::string prefix;
Path path;
- if (pos == string::npos) {
+ if (pos == std::string::npos) {
path = s;
} else {
- prefix = string(s, 0, pos);
- path = string(s, pos + 1);
+ prefix = std::string(s, 0, pos);
+ path = std::string(s, pos + 1);
}
searchPath.emplace_back(prefix, path);
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index defb861e6..3124025aa 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -141,7 +141,7 @@ static void mkOutputString(
BindingsBuilder & attrs,
const StorePath & drvPath,
const BasicDerivation & drv,
- const std::pair<string, DerivationOutput> & o)
+ const std::pair<std::string, DerivationOutput> & o)
{
auto optOutputPath = o.second.path(*state.store, drv.name, o.first);
attrs.alloc(o.first).mkString(
@@ -314,7 +314,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
{
auto path = realisePath(state, pos, *args[0]);
- string sym(state.forceStringNoCtx(*args[1], pos));
+ std::string sym(state.forceStringNoCtx(*args[1], pos));
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle)
@@ -386,7 +386,7 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
- string t;
+ std::string t;
switch (args[0]->type()) {
case nInt: t = "int"; break;
case nBool: t = "bool"; break;
@@ -574,9 +574,9 @@ struct CompareValues
#if HAVE_BOEHMGC
-typedef list<Value *, gc_allocator<Value *> > ValueList;
+typedef std::list<Value *, gc_allocator<Value *> > ValueList;
#else
-typedef list<Value *> ValueList;
+typedef std::list<Value *> ValueList;
#endif
@@ -654,7 +654,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
// `doneKeys' doesn't need to be a GC root, because its values are
// reachable from res.
auto cmp = CompareValues(state);
- set<Value *, decltype(cmp)> doneKeys(cmp);
+ std::set<Value *, decltype(cmp)> doneKeys(cmp);
while (!workSet.empty()) {
Value * e = *(workSet.begin());
workSet.pop_front();
@@ -707,7 +707,7 @@ static RegisterPrimOp primop_abort({
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string s = state.coerceToString(pos, *args[0], context).toOwned();
+ auto s = state.coerceToString(pos, *args[0], context).toOwned();
throw Abort("evaluation aborted with the following error message: '%1%'", s);
}
});
@@ -725,7 +725,7 @@ static RegisterPrimOp primop_throw({
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string s = state.coerceToString(pos, *args[0], context).toOwned();
+ auto s = state.coerceToString(pos, *args[0], context).toOwned();
throw ThrownError(s);
}
});
@@ -826,7 +826,7 @@ static RegisterPrimOp primop_tryEval({
/* Return an environment variable. Use with care. */
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- string name(state.forceStringNoCtx(*args[0], pos));
+ std::string name(state.forceStringNoCtx(*args[0], pos));
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
}
@@ -935,7 +935,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
pos
);
- string drvName;
+ std::string drvName;
Pos & posDrvName(*attr->pos);
try {
drvName = state.forceStringNoCtx(*attr->value, pos);
@@ -973,7 +973,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
for (auto & i : args[0]->attrs->lexicographicOrder()) {
if (i->name == state.sIgnoreNulls) continue;
- const string & key = i->name;
+ const std::string & key = i->name;
vomit("processing attribute '%1%'", key);
auto handleHashMode = [&](const std::string_view s) {
@@ -1031,7 +1031,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
else if (i->name == state.sArgs) {
state.forceList(*i->value, pos);
for (auto elem : i->value->listItems()) {
- string s = state.coerceToString(posDrvName, *elem, context, true).toOwned();
+ auto s = state.coerceToString(posDrvName, *elem, context, true).toOwned();
drv.args.push_back(s);
}
}
@@ -1118,7 +1118,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* Handle derivation outputs of the form ‘!<name>!<path>’. */
else if (path.at(0) == '!') {
- std::pair<string, string> ctx = decodeContext(path);
+ auto ctx = decodeContext(path);
drv.inputDrvs[state.store->parseStorePath(ctx.first)].insert(ctx.second);
}
@@ -1440,8 +1440,8 @@ static RegisterPrimOp primop_dirOf({
static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
- string s = readFile(path);
- if (s.find((char) 0) != string::npos)
+ auto s = readFile(path);
+ if (s.find((char) 0) != std::string::npos)
throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path);
StorePathSet refs;
if (state.store->isInStore(path)) {
@@ -1474,7 +1474,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
for (auto v2 : args[0]->listItems()) {
state.forceAttrs(*v2, pos);
- string prefix;
+ std::string prefix;
Bindings::iterator i = v2->attrs->find(state.sPrefix);
if (i != v2->attrs->end())
prefix = state.forceStringNoCtx(*i->value, pos);
@@ -1488,7 +1488,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
);
PathSet context;
- string path = state.coerceToString(pos, *i->value, context, false, false).toOwned();
+ auto path = state.coerceToString(pos, *i->value, context, false, false).toOwned();
try {
auto rewrites = state.realiseContext(context);
@@ -1754,8 +1754,8 @@ static RegisterPrimOp primop_fromJSON({
static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
- string name(state.forceStringNoCtx(*args[0], pos));
- string contents(state.forceString(*args[1], context, pos));
+ std::string name(state.forceStringNoCtx(*args[0], pos));
+ std::string contents(state.forceString(*args[1], context, pos));
StorePathSet refs;
@@ -1863,7 +1863,7 @@ static RegisterPrimOp primop_toFile({
static void addPath(
EvalState & state,
const Pos & pos,
- const string & name,
+ const std::string & name,
Path path,
Value * filterFun,
FileIngestionMethod method,
@@ -1919,20 +1919,15 @@ static void addPath(
if (expectedHash)
expectedStorePath = state.store->makeFixedOutputPath(method, *expectedHash, name);
- Path dstPath;
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
- dstPath = state.store->printStorePath(settings.readOnlyMode
+ StorePath dstPath = settings.readOnlyMode
? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first
- : state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs));
- if (expectedHash && expectedStorePath != state.store->parseStorePath(dstPath))
+ : state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs);
+ if (expectedHash && expectedStorePath != dstPath)
throw Error("store path mismatch in (possibly filtered) path added from '%s'", path);
+ state.allowAndSetStorePathString(dstPath, v);
} else
- dstPath = state.store->printStorePath(*expectedStorePath);
-
- v.mkString(dstPath, {dstPath});
-
- state.allowPath(dstPath);
-
+ state.allowAndSetStorePathString(*expectedStorePath, v);
} catch (Error & e) {
e.addTrace(pos, "while adding path '%s'", path);
throw;
@@ -2016,14 +2011,14 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
{
state.forceAttrs(*args[0], pos);
Path path;
- string name;
+ std::string name;
Value * filterFun = nullptr;
auto method = FileIngestionMethod::Recursive;
std::optional<Hash> expectedHash;
PathSet context;
for (auto & attr : *args[0]->attrs) {
- const string & n(attr.name);
+ auto & n(attr.name);
if (n == "path")
path = state.coerceToPath(*attr.pos, *attr.value, context);
else if (attr.name == state.sName)
@@ -3616,7 +3611,7 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * *
auto sep = state.forceString(*args[0], context, pos);
state.forceList(*args[1], pos);
- string res;
+ std::string res;
res.reserve((args[1]->listSize() + 32) * sep.size());
bool first = true;
@@ -3649,12 +3644,12 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
.errPos = pos
});
- vector<string> from;
+ std::vector<std::string> from;
from.reserve(args[0]->listSize());
for (auto elem : args[0]->listItems())
from.emplace_back(state.forceString(*elem, pos));
- vector<std::pair<string, PathSet>> to;
+ std::vector<std::pair<std::string, PathSet>> to;
to.reserve(args[1]->listSize());
for (auto elem : args[1]->listItems()) {
PathSet ctx;
@@ -3665,7 +3660,7 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
PathSet context;
auto s = state.forceString(*args[2], context, pos);
- string res;
+ std::string res;
// Loops one past last character to handle the case where 'from' contains an empty string.
for (size_t p = 0; p <= s.size(); ) {
bool found = false;
diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc
index 654251c23..3701bd442 100644
--- a/src/libexpr/primops/context.cc
+++ b/src/libexpr/primops/context.cc
@@ -37,7 +37,7 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & po
PathSet context2;
for (auto & p : context)
- context2.insert(p.at(0) == '=' ? string(p, 1) : p);
+ context2.insert(p.at(0) == '=' ? std::string(p, 1) : p);
v.mkString(*s, context2);
}
@@ -76,13 +76,13 @@ static void prim_getContext(EvalState & state, const Pos & pos, Value * * args,
auto contextInfos = std::map<Path, ContextInfo>();
for (const auto & p : context) {
Path drv;
- string output;
+ std::string output;
const Path * path = &p;
if (p.at(0) == '=') {
- drv = string(p, 1);
+ drv = std::string(p, 1);
path = &drv;
} else if (p.at(0) == '!') {
- std::pair<string, string> ctx = decodeContext(p);
+ std::pair<std::string, std::string> ctx = decodeContext(p);
drv = ctx.first;
output = ctx.second;
path = &drv;
@@ -166,7 +166,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
.errPos = *i.pos
});
}
- context.insert("=" + string(i.name));
+ context.insert("=" + std::string(i.name));
}
}
diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc
index c4e1a7bf0..b7f715859 100644
--- a/src/libexpr/primops/fetchMercurial.cc
+++ b/src/libexpr/primops/fetchMercurial.cc
@@ -62,7 +62,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
fetchers::Attrs attrs;
attrs.insert_or_assign("type", "hg");
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
- attrs.insert_or_assign("name", string(name));
+ attrs.insert_or_assign("name", std::string(name));
if (ref) attrs.insert_or_assign("ref", *ref);
if (rev) attrs.insert_or_assign("rev", rev->gitRev());
auto input = fetchers::Input::fromAttrs(std::move(attrs));
diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc
index d09e2d9e1..9c2da2178 100644
--- a/src/libexpr/primops/fetchTree.cc
+++ b/src/libexpr/primops/fetchTree.cc
@@ -19,7 +19,7 @@ void emitTreeAttrs(
bool emptyRevFallback,
bool forceDirty)
{
- assert(input.isImmutable());
+ assert(input.isLocked());
auto attrs = state.buildBindings(8);
@@ -166,8 +166,8 @@ static void fetchTree(
if (!evalSettings.pureEval && !input.isDirect())
input = lookupInRegistries(state.store, input).first;
- if (evalSettings.pureEval && !input.isImmutable())
- throw Error("in pure evaluation mode, 'fetchTree' requires an immutable input, at %s", pos);
+ if (evalSettings.pureEval && !input.isLocked())
+ throw Error("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", pos);
auto [tree, input2] = input.fetch(state.store);
@@ -186,7 +186,7 @@ static void prim_fetchTree(EvalState & state, const Pos & pos, Value * * args, V
static RegisterPrimOp primop_fetchTree("fetchTree", 1, prim_fetchTree);
static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
- const string & who, bool unpack, std::string name)
+ const std::string & who, bool unpack, std::string name)
{
std::optional<std::string> url;
std::optional<Hash> expectedHash;
@@ -198,7 +198,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
state.forceAttrs(*args[0], pos);
for (auto & attr : *args[0]->attrs) {
- string n(attr.name);
+ std::string n(attr.name);
if (n == "url")
url = state.forceStringNoCtx(*attr.value, *attr.pos);
else if (n == "sha256")
@@ -230,6 +230,21 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
if (evalSettings.pureEval && !expectedHash)
throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who);
+ // early exit if pinned and already in the store
+ if (expectedHash && expectedHash->type == htSHA256) {
+ auto expectedPath =
+ unpack
+ ? state.store->makeFixedOutputPath(FileIngestionMethod::Recursive, *expectedHash, name, {})
+ : state.store->makeFixedOutputPath(FileIngestionMethod::Flat, *expectedHash, name, {});
+
+ if (state.store->isValidPath(expectedPath)) {
+ state.allowAndSetStorePathString(expectedPath, v);
+ return;
+ }
+ }
+
+ // TODO: fetching may fail, yet the path may be substitutable.
+ // https://github.com/NixOS/nix/issues/4313
auto storePath =
unpack
? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).first.storePath
@@ -244,10 +259,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
*url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true));
}
- state.allowPath(storePath);
-
- auto path = state.store->printStorePath(storePath);
- v.mkString(path, PathSet({path}));
+ state.allowAndSetStorePathString(storePath, v);
}
static void prim_fetchurl(EvalState & state, const Pos & pos, Value * * args, Value & v)
diff --git a/src/libexpr/primops/fromTOML.cc b/src/libexpr/primops/fromTOML.cc
index c0e858b61..dd4280030 100644
--- a/src/libexpr/primops/fromTOML.cc
+++ b/src/libexpr/primops/fromTOML.cc
@@ -9,7 +9,7 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
{
auto toml = state.forceStringNoCtx(*args[0], pos);
- std::istringstream tomlStream(string{toml});
+ std::istringstream tomlStream(std::string{toml});
std::function<void(Value &, toml::value)> visit;
diff --git a/src/libexpr/symbol-table.hh b/src/libexpr/symbol-table.hh
index a090ebae5..48d20c29d 100644
--- a/src/libexpr/symbol-table.hh
+++ b/src/libexpr/symbol-table.hh
@@ -17,8 +17,8 @@ namespace nix {
class Symbol
{
private:
- const string * s; // pointer into SymbolTable
- Symbol(const string * s) : s(s) { };
+ const std::string * s; // pointer into SymbolTable
+ Symbol(const std::string * s) : s(s) { };
friend class SymbolTable;
public:
@@ -72,7 +72,7 @@ class SymbolTable
{
private:
std::unordered_map<std::string_view, Symbol> symbols;
- std::list<string> store;
+ std::list<std::string> store;
public:
Symbol create(std::string_view s)
@@ -84,7 +84,7 @@ public:
auto it = symbols.find(s);
if (it != symbols.end()) return it->second;
- const string & rawSym = store.emplace_back(s);
+ auto & rawSym = store.emplace_back(s);
return symbols.emplace(rawSym, Symbol(&rawSym)).first->second;
}
diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc
index a9fb60b0e..afeaf5694 100644
--- a/src/libexpr/value-to-xml.cc
+++ b/src/libexpr/value-to-xml.cc
@@ -9,7 +9,7 @@
namespace nix {
-static XMLAttrs singletonAttrs(const string & name, const string & value)
+static XMLAttrs singletonAttrs(const std::string & name, const std::string & value)
{
XMLAttrs attrs;
attrs[name] = value;
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index bef5cd6bd..d0fa93e92 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -77,20 +77,20 @@ class ExternalValueBase
public:
/* Return a simple string describing the type */
- virtual string showType() const = 0;
+ virtual std::string showType() const = 0;
/* Return a string to be used in builtins.typeOf */
- virtual string typeOf() const = 0;
+ virtual std::string typeOf() const = 0;
/* Coerce the value to a string. Defaults to uncoercable, i.e. throws an
- * error
+ * error.
*/
- virtual string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const;
+ virtual std::string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const;
/* Compare to another value of the same type. Defaults to uncomparable,
* i.e. always false.
*/
- virtual bool operator==(const ExternalValueBase & b) const;
+ virtual bool operator ==(const ExternalValueBase & b) const;
/* Print the value as JSON. Defaults to unconvertable, i.e. throws an error */
virtual void printValueAsJSON(EvalState & state, bool strict,
@@ -114,8 +114,8 @@ struct Value
private:
InternalType internalType;
-friend std::string showType(const Value & v);
-friend void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v);
+ friend std::string showType(const Value & v);
+ friend void printValue(std::ostream & str, std::set<const void *> & seen, const Value & v);
public:
diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc
index 34ff6f85b..0c8ecac9d 100644
--- a/src/libfetchers/cache.cc
+++ b/src/libfetchers/cache.cc
@@ -52,13 +52,13 @@ struct CacheImpl : Cache
const Attrs & inAttrs,
const Attrs & infoAttrs,
const StorePath & storePath,
- bool immutable) override
+ bool locked) override
{
_state.lock()->add.use()
(attrsToJSON(inAttrs).dump())
(attrsToJSON(infoAttrs).dump())
(store->printStorePath(storePath))
- (immutable)
+ (locked)
(time(0)).exec();
}
@@ -91,7 +91,7 @@ struct CacheImpl : Cache
auto infoJSON = stmt.getStr(0);
auto storePath = store->parseStorePath(stmt.getStr(1));
- auto immutable = stmt.getInt(2) != 0;
+ auto locked = stmt.getInt(2) != 0;
auto timestamp = stmt.getInt(3);
store->addTempRoot(storePath);
@@ -105,7 +105,7 @@ struct CacheImpl : Cache
inAttrsJSON, infoJSON, store->printStorePath(storePath));
return Result {
- .expired = !immutable && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)),
+ .expired = !locked && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)),
.infoAttrs = jsonToAttrs(nlohmann::json::parse(infoJSON)),
.storePath = std::move(storePath)
};
diff --git a/src/libfetchers/cache.hh b/src/libfetchers/cache.hh
index 3db4f081c..3763ee2a6 100644
--- a/src/libfetchers/cache.hh
+++ b/src/libfetchers/cache.hh
@@ -13,7 +13,7 @@ struct Cache
const Attrs & inAttrs,
const Attrs & infoAttrs,
const StorePath & storePath,
- bool immutable) = 0;
+ bool locked) = 0;
virtual std::optional<std::pair<Attrs, StorePath>> lookup(
ref<Store> store,
diff --git a/src/libfetchers/fetch-settings.cc b/src/libfetchers/fetch-settings.cc
new file mode 100644
index 000000000..e7d5244dc
--- /dev/null
+++ b/src/libfetchers/fetch-settings.cc
@@ -0,0 +1,13 @@
+#include "fetch-settings.hh"
+
+namespace nix {
+
+FetchSettings::FetchSettings()
+{
+}
+
+FetchSettings fetchSettings;
+
+static GlobalConfig::Register rFetchSettings(&fetchSettings);
+
+}
diff --git a/src/libfetchers/fetch-settings.hh b/src/libfetchers/fetch-settings.hh
new file mode 100644
index 000000000..04c9feda0
--- /dev/null
+++ b/src/libfetchers/fetch-settings.hh
@@ -0,0 +1,93 @@
+#pragma once
+
+#include "types.hh"
+#include "config.hh"
+#include "util.hh"
+
+#include <map>
+#include <limits>
+
+#include <sys/types.h>
+
+namespace nix {
+
+struct FetchSettings : public Config
+{
+ FetchSettings();
+
+ Setting<StringMap> accessTokens{this, {}, "access-tokens",
+ R"(
+ Access tokens used to access protected GitHub, GitLab, or
+ other locations requiring token-based authentication.
+
+ Access tokens are specified as a string made up of
+ space-separated `host=token` values. The specific token
+ used is selected by matching the `host` portion against the
+ "host" specification of the input. The actual use of the
+ `token` value is determined by the type of resource being
+ accessed:
+
+ * Github: the token value is the OAUTH-TOKEN string obtained
+ as the Personal Access Token from the Github server (see
+ https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps).
+
+ * Gitlab: the token value is either the OAuth2 token or the
+ Personal Access Token (these are different types tokens
+ for gitlab, see
+ https://docs.gitlab.com/12.10/ee/api/README.html#authentication).
+ The `token` value should be `type:tokenstring` where
+ `type` is either `OAuth2` or `PAT` to indicate which type
+ of token is being specified.
+
+ Example `~/.config/nix/nix.conf`:
+
+ ```
+ access-tokens = github.com=23ac...b289 gitlab.mycompany.com=PAT:A123Bp_Cd..EfG gitlab.com=OAuth2:1jklw3jk
+ ```
+
+ Example `~/code/flake.nix`:
+
+ ```nix
+ input.foo = {
+ type = "gitlab";
+ host = "gitlab.mycompany.com";
+ owner = "mycompany";
+ repo = "pro";
+ };
+ ```
+
+ This example specifies three tokens, one each for accessing
+ github.com, gitlab.mycompany.com, and sourceforge.net.
+
+ The `input.foo` uses the "gitlab" fetcher, which might
+ requires specifying the token type along with the token
+ value.
+ )"};
+
+ Setting<bool> allowDirty{this, true, "allow-dirty",
+ "Whether to allow dirty Git/Mercurial trees."};
+
+ Setting<bool> warnDirty{this, true, "warn-dirty",
+ "Whether to warn about dirty Git/Mercurial trees."};
+
+ Setting<std::string> flakeRegistry{this, "https://github.com/NixOS/flake-registry/raw/master/flake-registry.json", "flake-registry",
+ "Path or URI of the global flake registry."};
+
+ Setting<bool> useRegistries{this, true, "use-registries",
+ "Whether to use flake registries to resolve flake references."};
+
+ Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config",
+ "Whether to accept nix configuration from a flake without prompting."};
+
+ Setting<std::string> commitLockFileSummary{
+ this, "", "commit-lockfile-summary",
+ R"(
+ The commit summary to use when committing changed flake lock files. If
+ empty, the summary is generated based on the action performed.
+ )"};
+};
+
+// FIXME: don't use a global variable.
+extern FetchSettings fetchSettings;
+
+}
diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc
index c06ccb929..976f40d3b 100644
--- a/src/libfetchers/fetchers.cc
+++ b/src/libfetchers/fetchers.cc
@@ -24,11 +24,11 @@ static void fixupInput(Input & input)
input.getType();
input.getRef();
if (input.getRev())
- input.immutable = true;
+ input.locked = true;
input.getRevCount();
input.getLastModified();
if (input.getNarHash())
- input.immutable = true;
+ input.locked = true;
}
Input Input::fromURL(const ParsedURL & url)
@@ -165,7 +165,7 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const
input.to_string(), *prevRevCount);
}
- input.immutable = true;
+ input.locked = true;
assert(input.hasAllInfo());
@@ -209,7 +209,7 @@ StorePath Input::computeStorePath(Store & store) const
{
auto narHash = getNarHash();
if (!narHash)
- throw Error("cannot compute store path for mutable input '%s'", to_string());
+ throw Error("cannot compute store path for unlocked input '%s'", to_string());
return store.makeFixedOutputPath(FileIngestionMethod::Recursive, *narHash, getName());
}
diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh
index 2836af5fa..bc9a76b0b 100644
--- a/src/libfetchers/fetchers.hh
+++ b/src/libfetchers/fetchers.hh
@@ -34,7 +34,7 @@ struct Input
std::shared_ptr<InputScheme> scheme; // note: can be null
Attrs attrs;
- bool immutable = false;
+ bool locked = false;
bool direct = true;
/* path of the parent of this input, used for relative path resolution */
@@ -59,9 +59,9 @@ public:
one that goes through a registry. */
bool isDirect() const { return direct; }
- /* Check whether this is an "immutable" input, that is,
+ /* Check whether this is a "locked" input, that is,
one that contains a commit hash or content hash. */
- bool isImmutable() const { return immutable; }
+ bool isLocked() const { return locked; }
bool hasAllInfo() const;
@@ -69,6 +69,8 @@ public:
bool contains(const Input & other) const;
+ /* Fetch the input into the Nix store, returning the location in
+ the Nix store and the locked input. */
std::pair<Tree, Input> fetch(ref<Store> store) const;
Input applyOverrides(
@@ -146,14 +148,14 @@ DownloadFileResult downloadFile(
ref<Store> store,
const std::string & url,
const std::string & name,
- bool immutable,
+ bool locked,
const Headers & headers = {});
std::pair<Tree, time_t> downloadTarball(
ref<Store> store,
const std::string & url,
const std::string & name,
- bool immutable,
+ bool locked,
const Headers & headers = {});
}
diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc
index 6571a9d02..6884e8de7 100644
--- a/src/libfetchers/git.cc
+++ b/src/libfetchers/git.cc
@@ -6,6 +6,8 @@
#include "url-parts.hh"
#include "pathlocks.hh"
+#include "fetch-settings.hh"
+
#include <sys/time.h>
#include <sys/wait.h>
@@ -187,7 +189,7 @@ struct GitInputScheme : InputScheme
if (submodules) cacheType += "-submodules";
if (allRefs) cacheType += "-all-refs";
- auto getImmutableAttrs = [&]()
+ auto getLockedAttrs = [&]()
{
return Attrs({
{"type", cacheType},
@@ -208,7 +210,7 @@ struct GitInputScheme : InputScheme
};
if (input.getRev()) {
- if (auto res = getCache()->lookup(store, getImmutableAttrs()))
+ if (auto res = getCache()->lookup(store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second));
}
@@ -270,10 +272,10 @@ struct GitInputScheme : InputScheme
/* This is an unclean working tree. So copy all tracked files. */
- if (!settings.allowDirty)
+ if (!fetchSettings.allowDirty)
throw Error("Git tree '%s' is dirty", actualUrl);
- if (settings.warnDirty)
+ if (fetchSettings.warnDirty)
warn("Git tree '%s' is dirty", actualUrl);
auto gitOpts = Strings({ "-C", actualUrl, "ls-files", "-z" });
@@ -312,7 +314,7 @@ struct GitInputScheme : InputScheme
if (!input.getRef()) input.attrs.insert_or_assign("ref", isLocal ? readHead(actualUrl) : "master");
- Attrs mutableAttrs({
+ Attrs unlockedAttrs({
{"type", cacheType},
{"name", name},
{"url", actualUrl},
@@ -331,7 +333,7 @@ struct GitInputScheme : InputScheme
} else {
- if (auto res = getCache()->lookup(store, mutableAttrs)) {
+ if (auto res = getCache()->lookup(store, unlockedAttrs)) {
auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1);
if (!input.getRev() || input.getRev() == rev2) {
input.attrs.insert_or_assign("rev", rev2.gitRev());
@@ -428,7 +430,7 @@ struct GitInputScheme : InputScheme
/* Now that we know the ref, check again whether we have it in
the store. */
- if (auto res = getCache()->lookup(store, getImmutableAttrs()))
+ if (auto res = getCache()->lookup(store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second));
Path tmpDir = createTempDir();
@@ -500,14 +502,14 @@ struct GitInputScheme : InputScheme
if (!_input.getRev())
getCache()->add(
store,
- mutableAttrs,
+ unlockedAttrs,
infoAttrs,
storePath,
false);
getCache()->add(
store,
- getImmutableAttrs(),
+ getLockedAttrs(),
infoAttrs,
storePath,
true);
diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc
index 8ba6935f9..a1430f087 100644
--- a/src/libfetchers/github.cc
+++ b/src/libfetchers/github.cc
@@ -1,13 +1,16 @@
#include "filetransfer.hh"
#include "cache.hh"
-#include "fetchers.hh"
#include "globals.hh"
#include "store-api.hh"
#include "types.hh"
#include "url-parts.hh"
+#include "fetchers.hh"
+#include "fetch-settings.hh"
+
#include <optional>
#include <nlohmann/json.hpp>
+#include <fstream>
namespace nix::fetchers {
@@ -17,7 +20,7 @@ struct DownloadUrl
Headers headers;
};
-// A github or gitlab host
+// A github, gitlab, or sourcehut host
const static std::string hostRegexS = "[a-zA-Z0-9.]*"; // FIXME: check
std::regex hostRegex(hostRegexS, std::regex::ECMAScript);
@@ -156,7 +159,7 @@ struct GitArchiveInputScheme : InputScheme
std::optional<std::string> getAccessToken(const std::string & host) const
{
- auto tokens = settings.accessTokens.get();
+ auto tokens = fetchSettings.accessTokens.get();
if (auto token = get(tokens, host))
return *token;
return {};
@@ -192,12 +195,12 @@ struct GitArchiveInputScheme : InputScheme
input.attrs.erase("ref");
input.attrs.insert_or_assign("rev", rev->gitRev());
- Attrs immutableAttrs({
+ Attrs lockedAttrs({
{"type", "git-tarball"},
{"rev", rev->gitRev()},
});
- if (auto res = getCache()->lookup(store, immutableAttrs)) {
+ if (auto res = getCache()->lookup(store, lockedAttrs)) {
input.attrs.insert_or_assign("lastModified", getIntAttr(res->first, "lastModified"));
return {std::move(res->second), input};
}
@@ -210,7 +213,7 @@ struct GitArchiveInputScheme : InputScheme
getCache()->add(
store,
- immutableAttrs,
+ lockedAttrs,
{
{"rev", rev->gitRev()},
{"lastModified", uint64_t(lastModified)}
@@ -345,7 +348,95 @@ struct GitLabInputScheme : GitArchiveInputScheme
}
};
+struct SourceHutInputScheme : GitArchiveInputScheme
+{
+ std::string type() override { return "sourcehut"; }
+
+ std::optional<std::pair<std::string, std::string>> accessHeaderFromToken(const std::string & token) const override
+ {
+ // SourceHut supports both PAT and OAuth2. See
+ // https://man.sr.ht/meta.sr.ht/oauth.md
+ return std::pair<std::string, std::string>("Authorization", fmt("Bearer %s", token));
+ // Note: This currently serves no purpose, as this kind of authorization
+ // does not allow for downloading tarballs on sourcehut private repos.
+ // Once it is implemented, however, should work as expected.
+ }
+
+ Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override
+ {
+ // TODO: In the future, when the sourcehut graphql API is implemented for mercurial
+ // and with anonymous access, this method should use it instead.
+
+ auto ref = *input.getRef();
+
+ auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
+ auto base_url = fmt("https://%s/%s/%s",
+ host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"));
+
+ Headers headers = makeHeadersWithAuthTokens(host);
+
+ std::string ref_uri;
+ if (ref == "HEAD") {
+ auto file = store->toRealPath(
+ downloadFile(store, fmt("%s/HEAD", base_url), "source", false, headers).storePath);
+ std::ifstream is(file);
+ std::string line;
+ getline(is, line);
+
+ auto ref_index = line.find("ref: ");
+ if (ref_index == std::string::npos) {
+ throw BadURL("in '%d', couldn't resolve HEAD ref '%d'", input.to_string(), ref);
+ }
+
+ ref_uri = line.substr(ref_index+5, line.length()-1);
+ } else
+ ref_uri = fmt("refs/heads/%s", ref);
+
+ auto file = store->toRealPath(
+ downloadFile(store, fmt("%s/info/refs", base_url), "source", false, headers).storePath);
+ std::ifstream is(file);
+
+ std::string line;
+ std::string id;
+ while(getline(is, line)) {
+ auto index = line.find(ref_uri);
+ if (index != std::string::npos) {
+ id = line.substr(0, index-1);
+ break;
+ }
+ }
+
+ if(id.empty())
+ throw BadURL("in '%d', couldn't find ref '%d'", input.to_string(), ref);
+
+ auto rev = Hash::parseAny(id, htSHA1);
+ debug("HEAD revision for '%s' is %s", fmt("%s/%s", base_url, ref), rev.gitRev());
+ return rev;
+ }
+
+ DownloadUrl getDownloadUrl(const Input & input) const override
+ {
+ auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
+ auto url = fmt("https://%s/%s/%s/archive/%s.tar.gz",
+ host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"),
+ input.getRev()->to_string(Base16, false));
+
+ Headers headers = makeHeadersWithAuthTokens(host);
+ return DownloadUrl { url, headers };
+ }
+
+ void clone(const Input & input, const Path & destDir) override
+ {
+ auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
+ Input::fromURL(fmt("git+https://%s/%s/%s",
+ host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")))
+ .applyOverrides(input.getRef(), input.getRev())
+ .clone(destDir);
+ }
+};
+
static auto rGitHubInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitHubInputScheme>()); });
static auto rGitLabInputScheme = OnStartup([] { registerInputScheme(std::make_unique<GitLabInputScheme>()); });
+static auto rSourceHutInputScheme = OnStartup([] { registerInputScheme(std::make_unique<SourceHutInputScheme>()); });
}
diff --git a/src/libfetchers/mercurial.cc b/src/libfetchers/mercurial.cc
index 5123bcda4..8b82e9daa 100644
--- a/src/libfetchers/mercurial.cc
+++ b/src/libfetchers/mercurial.cc
@@ -5,6 +5,8 @@
#include "store-api.hh"
#include "url-parts.hh"
+#include "fetch-settings.hh"
+
#include <sys/time.h>
using namespace std::string_literals;
@@ -26,7 +28,7 @@ static RunOptions hgOptions(const Strings & args)
}
// runProgram wrapper that uses hgOptions instead of stock RunOptions.
-static string runHg(const Strings & args, const std::optional<std::string> & input = {})
+static std::string runHg(const Strings & args, const std::optional<std::string> & input = {})
{
RunOptions opts = hgOptions(args);
opts.input = input;
@@ -165,10 +167,10 @@ struct MercurialInputScheme : InputScheme
/* This is an unclean working tree. So copy all tracked
files. */
- if (!settings.allowDirty)
+ if (!fetchSettings.allowDirty)
throw Error("Mercurial tree '%s' is unclean", actualUrl);
- if (settings.warnDirty)
+ if (fetchSettings.warnDirty)
warn("Mercurial tree '%s' is unclean", actualUrl);
input.attrs.insert_or_assign("ref", chomp(runHg({ "branch", "-R", actualUrl })));
@@ -199,7 +201,7 @@ struct MercurialInputScheme : InputScheme
if (!input.getRef()) input.attrs.insert_or_assign("ref", "default");
- auto getImmutableAttrs = [&]()
+ auto getLockedAttrs = [&]()
{
return Attrs({
{"type", "hg"},
@@ -218,20 +220,20 @@ struct MercurialInputScheme : InputScheme
};
if (input.getRev()) {
- if (auto res = getCache()->lookup(store, getImmutableAttrs()))
+ if (auto res = getCache()->lookup(store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second));
}
auto revOrRef = input.getRev() ? input.getRev()->gitRev() : *input.getRef();
- Attrs mutableAttrs({
+ Attrs unlockedAttrs({
{"type", "hg"},
{"name", name},
{"url", actualUrl},
{"ref", *input.getRef()},
});
- if (auto res = getCache()->lookup(store, mutableAttrs)) {
+ if (auto res = getCache()->lookup(store, unlockedAttrs)) {
auto rev2 = Hash::parseAny(getStrAttr(res->first, "rev"), htSHA1);
if (!input.getRev() || input.getRev() == rev2) {
input.attrs.insert_or_assign("rev", rev2.gitRev());
@@ -254,7 +256,7 @@ struct MercurialInputScheme : InputScheme
runHg({ "pull", "-R", cacheDir, "--", actualUrl });
}
catch (ExecError & e) {
- string transJournal = cacheDir + "/.hg/store/journal";
+ auto transJournal = cacheDir + "/.hg/store/journal";
/* hg throws "abandoned transaction" error only if this file exists */
if (pathExists(transJournal)) {
runHg({ "recover", "-R", cacheDir });
@@ -277,7 +279,7 @@ struct MercurialInputScheme : InputScheme
auto revCount = std::stoull(tokens[1]);
input.attrs.insert_or_assign("ref", tokens[2]);
- if (auto res = getCache()->lookup(store, getImmutableAttrs()))
+ if (auto res = getCache()->lookup(store, getLockedAttrs()))
return makeResult(res->first, std::move(res->second));
Path tmpDir = createTempDir();
@@ -297,14 +299,14 @@ struct MercurialInputScheme : InputScheme
if (!_input.getRev())
getCache()->add(
store,
- mutableAttrs,
+ unlockedAttrs,
infoAttrs,
storePath,
false);
getCache()->add(
store,
- getImmutableAttrs(),
+ getLockedAttrs(),
infoAttrs,
storePath,
true);
diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc
index f35359d4b..acd1ff866 100644
--- a/src/libfetchers/registry.cc
+++ b/src/libfetchers/registry.cc
@@ -5,6 +5,8 @@
#include "store-api.hh"
#include "local-fs-store.hh"
+#include "fetch-settings.hh"
+
#include <nlohmann/json.hpp>
namespace nix::fetchers {
@@ -150,7 +152,7 @@ void overrideRegistry(
static std::shared_ptr<Registry> getGlobalRegistry(ref<Store> store)
{
static auto reg = [&]() {
- auto path = settings.flakeRegistry.get();
+ auto path = fetchSettings.flakeRegistry.get();
if (!hasPrefix(path, "/")) {
auto storePath = downloadFile(store, path, "flake-registry.json", false).storePath;
diff --git a/src/libfetchers/tarball.cc b/src/libfetchers/tarball.cc
index 74c8097ff..dde0ad761 100644
--- a/src/libfetchers/tarball.cc
+++ b/src/libfetchers/tarball.cc
@@ -13,7 +13,7 @@ DownloadFileResult downloadFile(
ref<Store> store,
const std::string & url,
const std::string & name,
- bool immutable,
+ bool locked,
const Headers & headers)
{
// FIXME: check store
@@ -88,7 +88,7 @@ DownloadFileResult downloadFile(
inAttrs,
infoAttrs,
*storePath,
- immutable);
+ locked);
if (url != res.effectiveUri)
getCache()->add(
@@ -100,7 +100,7 @@ DownloadFileResult downloadFile(
},
infoAttrs,
*storePath,
- immutable);
+ locked);
return {
.storePath = std::move(*storePath),
@@ -113,7 +113,7 @@ std::pair<Tree, time_t> downloadTarball(
ref<Store> store,
const std::string & url,
const std::string & name,
- bool immutable,
+ bool locked,
const Headers & headers)
{
Attrs inAttrs({
@@ -130,7 +130,7 @@ std::pair<Tree, time_t> downloadTarball(
getIntAttr(cached->infoAttrs, "lastModified")
};
- auto res = downloadFile(store, url, name, immutable, headers);
+ auto res = downloadFile(store, url, name, locked, headers);
std::optional<StorePath> unpackedStorePath;
time_t lastModified;
@@ -160,7 +160,7 @@ std::pair<Tree, time_t> downloadTarball(
inAttrs,
infoAttrs,
*unpackedStorePath,
- immutable);
+ locked);
return {
Tree { .actualPath = store->toRealPath(*unpackedStorePath), .storePath = std::move(*unpackedStorePath) },
@@ -202,7 +202,7 @@ struct TarballInputScheme : InputScheme
Input input;
input.attrs = attrs;
- //input.immutable = (bool) maybeGetStrAttr(input.attrs, "hash");
+ //input.locked = (bool) maybeGetStrAttr(input.attrs, "hash");
return input;
}
diff --git a/src/libmain/common-args.cc b/src/libmain/common-args.cc
index c43e9ebd2..12f5403ea 100644
--- a/src/libmain/common-args.cc
+++ b/src/libmain/common-args.cc
@@ -4,7 +4,7 @@
namespace nix {
-MixCommonArgs::MixCommonArgs(const string & programName)
+MixCommonArgs::MixCommonArgs(const std::string & programName)
: programName(programName)
{
addFlag({
diff --git a/src/libmain/common-args.hh b/src/libmain/common-args.hh
index 31bdf527a..25453b8c6 100644
--- a/src/libmain/common-args.hh
+++ b/src/libmain/common-args.hh
@@ -11,8 +11,8 @@ class MixCommonArgs : public virtual Args
{
void initialFlagsProcessed() override;
public:
- string programName;
- MixCommonArgs(const string & programName);
+ std::string programName;
+ MixCommonArgs(const std::string & programName);
protected:
virtual void pluginsInited() {}
};
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index f605184bb..562d1b414 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -1,6 +1,7 @@
#include "globals.hh"
#include "shared.hh"
#include "store-api.hh"
+#include "gc-store.hh"
#include "util.hh"
#include "loggers.hh"
@@ -94,7 +95,7 @@ void printMissing(ref<Store> store, const StorePathSet & willBuild,
}
-string getArg(const string & opt,
+std::string getArg(const std::string & opt,
Strings::iterator & i, const Strings::iterator & end)
{
++i;
@@ -322,14 +323,14 @@ void parseCmdLine(int argc, char * * argv,
}
-void parseCmdLine(const string & programName, const Strings & args,
+void parseCmdLine(const std::string & programName, const Strings & args,
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
LegacyArgs(programName, parseArg).parseCmdline(args);
}
-void printVersion(const string & programName)
+void printVersion(const std::string & programName)
{
std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
if (verbosity > lvlInfo) {
@@ -352,7 +353,7 @@ void printVersion(const string & programName)
}
-void showManPage(const string & name)
+void showManPage(const std::string & name)
{
restoreProcessContext();
setenv("MANPATH", settings.nixManDir.c_str(), 1);
@@ -361,13 +362,13 @@ void showManPage(const string & name)
}
-int handleExceptions(const string & programName, std::function<void()> fun)
+int handleExceptions(const std::string & programName, std::function<void()> fun)
{
ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this
ErrorInfo::programName = baseNameOf(programName);
- string error = ANSI_RED "error:" ANSI_NORMAL " ";
+ std::string error = ANSI_RED "error:" ANSI_NORMAL " ";
try {
try {
fun();
@@ -407,7 +408,7 @@ RunPager::RunPager()
if (!isatty(STDOUT_FILENO)) return;
char * pager = getenv("NIX_PAGER");
if (!pager) pager = getenv("PAGER");
- if (pager && ((string) pager == "" || (string) pager == "cat")) return;
+ if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) return;
Pipe toPager;
toPager.create();
diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh
index ed012959b..0cc56d47d 100644
--- a/src/libmain/shared.hh
+++ b/src/libmain/shared.hh
@@ -22,7 +22,7 @@ public:
virtual ~Exit();
};
-int handleExceptions(const string & programName, std::function<void()> fun);
+int handleExceptions(const std::string & programName, std::function<void()> fun);
/* Don't forget to call initPlugins() after settings are initialized! */
void initNix();
@@ -30,10 +30,10 @@ void initNix();
void parseCmdLine(int argc, char * * argv,
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg);
-void parseCmdLine(const string & programName, const Strings & args,
+void parseCmdLine(const std::string & programName, const Strings & args,
std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg);
-void printVersion(const string & programName);
+void printVersion(const std::string & programName);
/* Ugh. No better place to put this. */
void printGCWarning();
@@ -50,10 +50,10 @@ void printMissing(ref<Store> store, const StorePathSet & willBuild,
const StorePathSet & willSubstitute, const StorePathSet & unknown,
uint64_t downloadSize, uint64_t narSize, Verbosity lvl = lvlInfo);
-string getArg(const string & opt,
+std::string getArg(const std::string & opt,
Strings::iterator & i, const Strings::iterator & end);
-template<class N> N getIntArg(const string & opt,
+template<class N> N getIntArg(const std::string & opt,
Strings::iterator & i, const Strings::iterator & end, bool allowUnit)
{
++i;
@@ -76,7 +76,7 @@ struct LegacyArgs : public MixCommonArgs
/* Show the manual page for the specified program. */
-void showManPage(const string & name);
+void showManPage(const std::string & name);
/* The constructor of this class starts a pager if stdout is a
terminal and $PAGER is set. Stdout is redirected to the pager. */
@@ -96,7 +96,7 @@ extern volatile ::sig_atomic_t blockInt;
/* GC helpers. */
-string showBytes(uint64_t bytes);
+std::string showBytes(uint64_t bytes);
struct GCResults;
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index b3fd991a1..9226c4e19 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -385,8 +385,14 @@ void BinaryCacheStore::queryPathInfoUncached(const StorePath & storePath,
}});
}
-StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath,
- FileIngestionMethod method, HashType hashAlgo, PathFilter & filter, RepairFlag repair, const StorePathSet & references)
+StorePath BinaryCacheStore::addToStore(
+ std::string_view name,
+ const Path & srcPath,
+ FileIngestionMethod method,
+ HashType hashAlgo,
+ PathFilter & filter,
+ RepairFlag repair,
+ const StorePathSet & references)
{
/* FIXME: Make BinaryCacheStore::addToStoreCommon support
non-recursive+sha256 so we can just use the default
@@ -418,8 +424,11 @@ StorePath BinaryCacheStore::addToStore(const string & name, const Path & srcPath
})->path;
}
-StorePath BinaryCacheStore::addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair)
+StorePath BinaryCacheStore::addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair)
{
auto textHash = hashString(htSHA256, s);
auto path = makeTextPath(name, textHash, references);
diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh
index 5b5d064f3..9603a8caa 100644
--- a/src/libstore/binary-cache-store.hh
+++ b/src/libstore/binary-cache-store.hh
@@ -101,12 +101,20 @@ public:
StorePath addToStoreFromDump(Source & dump, std::string_view name,
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override;
- StorePath addToStore(const string & name, const Path & srcPath,
- FileIngestionMethod method, HashType hashAlgo,
- PathFilter & filter, RepairFlag repair, const StorePathSet & references) override;
-
- StorePath addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair) override;
+ StorePath addToStore(
+ std::string_view name,
+ const Path & srcPath,
+ FileIngestionMethod method,
+ HashType hashAlgo,
+ PathFilter & filter,
+ RepairFlag repair,
+ const StorePathSet & references) override;
+
+ StorePath addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair) override;
void registerDrvOutput(const Realisation & info) override;
diff --git a/src/libstore/build-result.hh b/src/libstore/build-result.hh
new file mode 100644
index 000000000..cb6d19b8e
--- /dev/null
+++ b/src/libstore/build-result.hh
@@ -0,0 +1,89 @@
+#pragma once
+
+#include "realisation.hh"
+
+#include <string>
+#include <chrono>
+
+
+namespace nix {
+
+struct BuildResult
+{
+ /* Note: don't remove status codes, and only add new status codes
+ at the end of the list, to prevent client/server
+ incompatibilities in the nix-store --serve protocol. */
+ enum Status {
+ Built = 0,
+ Substituted,
+ AlreadyValid,
+ PermanentFailure,
+ InputRejected,
+ OutputRejected,
+ TransientFailure, // possibly transient
+ CachedFailure, // no longer used
+ TimedOut,
+ MiscFailure,
+ DependencyFailed,
+ LogLimitExceeded,
+ NotDeterministic,
+ ResolvesToAlreadyValid,
+ NoSubstituters,
+ } status = MiscFailure;
+ std::string errorMsg;
+
+ std::string toString() const {
+ auto strStatus = [&]() {
+ switch (status) {
+ case Built: return "Built";
+ case Substituted: return "Substituted";
+ case AlreadyValid: return "AlreadyValid";
+ case PermanentFailure: return "PermanentFailure";
+ case InputRejected: return "InputRejected";
+ case OutputRejected: return "OutputRejected";
+ case TransientFailure: return "TransientFailure";
+ case CachedFailure: return "CachedFailure";
+ case TimedOut: return "TimedOut";
+ case MiscFailure: return "MiscFailure";
+ case DependencyFailed: return "DependencyFailed";
+ case LogLimitExceeded: return "LogLimitExceeded";
+ case NotDeterministic: return "NotDeterministic";
+ case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid";
+ default: return "Unknown";
+ };
+ }();
+ return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg);
+ }
+
+ /* How many times this build was performed. */
+ unsigned int timesBuilt = 0;
+
+ /* If timesBuilt > 1, whether some builds did not produce the same
+ result. (Note that 'isNonDeterministic = false' does not mean
+ the build is deterministic, just that we don't have evidence of
+ non-determinism.) */
+ bool isNonDeterministic = false;
+
+ /* The derivation we built or the store path we substituted. */
+ DerivedPath path;
+
+ /* For derivations, a mapping from the names of the wanted outputs
+ to actual paths. */
+ DrvOutputs builtOutputs;
+
+ /* The start/stop times of the build (or one of the rounds, if it
+ was repeated). */
+ time_t startTime = 0, stopTime = 0;
+
+ bool success()
+ {
+ return status == Built || status == Substituted || status == AlreadyValid || status == ResolvesToAlreadyValid;
+ }
+
+ void rethrow()
+ {
+ throw Error("%s", errorMsg);
+ }
+};
+
+}
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 151217b8b..afed9bf16 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -66,7 +66,7 @@ namespace nix {
DerivationGoal::DerivationGoal(const StorePath & drvPath,
const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode)
- : Goal(worker)
+ : Goal(worker, DerivedPath::Built { .drvPath = drvPath, .outputs = wantedOutputs })
, useDerivation(true)
, drvPath(drvPath)
, wantedOutputs(wantedOutputs)
@@ -85,7 +85,7 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath,
DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode)
- : Goal(worker)
+ : Goal(worker, DerivedPath::Built { .drvPath = drvPath, .outputs = wantedOutputs })
, useDerivation(false)
, drvPath(drvPath)
, wantedOutputs(wantedOutputs)
@@ -116,7 +116,7 @@ DerivationGoal::~DerivationGoal()
}
-string DerivationGoal::key()
+std::string DerivationGoal::key()
{
/* Ensure that derivations get built in order of their name,
i.e. a derivation named "aardvark" always comes before
@@ -135,7 +135,7 @@ void DerivationGoal::killChild()
void DerivationGoal::timedOut(Error && ex)
{
killChild();
- done(BuildResult::TimedOut, ex);
+ done(BuildResult::TimedOut, {}, ex);
}
@@ -182,7 +182,7 @@ void DerivationGoal::loadDerivation()
trace("loading derivation");
if (nrFailed != 0) {
- done(BuildResult::MiscFailure, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
+ done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
return;
}
@@ -215,28 +215,20 @@ void DerivationGoal::haveDerivation()
auto outputHashes = staticOutputHashes(worker.evalStore, *drv);
for (auto & [outputName, outputHash] : outputHashes)
- initialOutputs.insert({
+ initialOutputs.insert({
outputName,
- InitialOutput{
+ InitialOutput {
.wanted = true, // Will be refined later
.outputHash = outputHash
}
- });
+ });
/* Check what outputs paths are not already valid. */
- checkPathValidity();
- bool allValid = true;
- for (auto & [_, status] : initialOutputs) {
- if (!status.wanted) continue;
- if (!status.known || !status.known->isValid()) {
- allValid = false;
- break;
- }
- }
+ auto [allValid, validOutputs] = checkPathValidity();
/* If they are all valid, then we're done. */
if (allValid && buildMode == bmNormal) {
- done(BuildResult::AlreadyValid);
+ done(BuildResult::AlreadyValid, std::move(validOutputs));
return;
}
@@ -277,7 +269,7 @@ void DerivationGoal::outputsSubstitutionTried()
trace("all outputs substituted (maybe)");
if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) {
- done(BuildResult::TransientFailure,
+ done(BuildResult::TransientFailure, {},
Error("some substitutes for the outputs of derivation '%s' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ",
worker.store.printStorePath(drvPath)));
return;
@@ -301,23 +293,17 @@ void DerivationGoal::outputsSubstitutionTried()
return;
}
- checkPathValidity();
- size_t nrInvalid = 0;
- for (auto & [_, status] : initialOutputs) {
- if (!status.wanted) continue;
- if (!status.known || !status.known->isValid())
- nrInvalid++;
- }
+ auto [allValid, validOutputs] = checkPathValidity();
- if (buildMode == bmNormal && nrInvalid == 0) {
- done(BuildResult::Substituted);
+ if (buildMode == bmNormal && allValid) {
+ done(BuildResult::Substituted, std::move(validOutputs));
return;
}
- if (buildMode == bmRepair && nrInvalid == 0) {
+ if (buildMode == bmRepair && allValid) {
repairClosure();
return;
}
- if (buildMode == bmCheck && nrInvalid > 0)
+ if (buildMode == bmCheck && !allValid)
throw Error("some outputs of '%s' are not valid, so checking is not possible",
worker.store.printStorePath(drvPath));
@@ -409,7 +395,7 @@ void DerivationGoal::repairClosure()
}
if (waitees.empty()) {
- done(BuildResult::AlreadyValid);
+ done(BuildResult::AlreadyValid, assertPathValidity());
return;
}
@@ -423,7 +409,7 @@ void DerivationGoal::closureRepaired()
if (nrFailed > 0)
throw Error("some paths in the output closure of derivation '%s' could not be repaired",
worker.store.printStorePath(drvPath));
- done(BuildResult::AlreadyValid);
+ done(BuildResult::AlreadyValid, assertPathValidity());
}
@@ -434,7 +420,7 @@ void DerivationGoal::inputsRealised()
if (nrFailed != 0) {
if (!useDerivation)
throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath));
- done(BuildResult::DependencyFailed, Error(
+ done(BuildResult::DependencyFailed, {}, Error(
"%s dependencies of derivation '%s' failed to build",
nrFailed, worker.store.printStorePath(drvPath)));
return;
@@ -523,10 +509,11 @@ void DerivationGoal::inputsRealised()
state = &DerivationGoal::tryToBuild;
worker.wakeUp(shared_from_this());
- result = BuildResult();
+ buildResult = BuildResult { .path = buildResult.path };
}
-void DerivationGoal::started() {
+void DerivationGoal::started()
+{
auto msg = fmt(
buildMode == bmRepair ? "repairing outputs of '%s'" :
buildMode == bmCheck ? "checking outputs of '%s'" :
@@ -588,19 +575,12 @@ void DerivationGoal::tryToBuild()
omitted, but that would be less efficient.) Note that since we
now hold the locks on the output paths, no other process can
build this derivation, so no further checks are necessary. */
- checkPathValidity();
- bool allValid = true;
- for (auto & [_, status] : initialOutputs) {
- if (!status.wanted) continue;
- if (!status.known || !status.known->isValid()) {
- allValid = false;
- break;
- }
- }
+ auto [allValid, validOutputs] = checkPathValidity();
+
if (buildMode != bmCheck && allValid) {
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
outputLocks.setDeletion(true);
- done(BuildResult::AlreadyValid);
+ done(BuildResult::AlreadyValid, std::move(validOutputs));
return;
}
@@ -626,7 +606,7 @@ void DerivationGoal::tryToBuild()
/* Yes, it has started doing so. Wait until we get
EOF from the hook. */
actLock.reset();
- result.startTime = time(0); // inexact
+ buildResult.startTime = time(0); // inexact
state = &DerivationGoal::buildDone;
started();
return;
@@ -830,8 +810,8 @@ void DerivationGoal::buildDone()
debug("builder process for '%s' finished", worker.store.printStorePath(drvPath));
- result.timesBuilt++;
- result.stopTime = time(0);
+ buildResult.timesBuilt++;
+ buildResult.stopTime = time(0);
/* So the child is gone now. */
worker.childTerminated(this);
@@ -876,11 +856,11 @@ void DerivationGoal::buildDone()
/* Compute the FS closure of the outputs and register them as
being valid. */
- registerOutputs();
+ auto builtOutputs = registerOutputs();
StorePathSet outputPaths;
- for (auto & [_, path] : finalOutputs)
- outputPaths.insert(path);
+ for (auto & [_, output] : buildResult.builtOutputs)
+ outputPaths.insert(output.outPath);
runPostBuildHook(
worker.store,
*logger,
@@ -890,7 +870,7 @@ void DerivationGoal::buildDone()
if (buildMode == bmCheck) {
cleanupPostOutputsRegisteredModeCheck();
- done(BuildResult::Built);
+ done(BuildResult::Built, std::move(builtOutputs));
return;
}
@@ -911,6 +891,8 @@ void DerivationGoal::buildDone()
outputLocks.setDeletion(true);
outputLocks.unlock();
+ done(BuildResult::Built, std::move(builtOutputs));
+
} catch (BuildError & e) {
outputLocks.unlock();
@@ -930,14 +912,13 @@ void DerivationGoal::buildDone()
BuildResult::PermanentFailure;
}
- done(st, e);
+ done(st, {}, e);
return;
}
-
- done(BuildResult::Built);
}
-void DerivationGoal::resolvedFinished() {
+void DerivationGoal::resolvedFinished()
+{
assert(resolvedDrvGoal);
auto resolvedDrv = *resolvedDrvGoal->drv;
@@ -950,11 +931,13 @@ void DerivationGoal::resolvedFinished() {
if (realWantedOutputs.empty())
realWantedOutputs = resolvedDrv.outputNames();
+ DrvOutputs builtOutputs;
+
for (auto & wantedOutput : realWantedOutputs) {
assert(initialOutputs.count(wantedOutput) != 0);
assert(resolvedHashes.count(wantedOutput) != 0);
auto realisation = worker.store.queryRealisation(
- DrvOutput{resolvedHashes.at(wantedOutput), wantedOutput}
+ DrvOutput{resolvedHashes.at(wantedOutput), wantedOutput}
);
// We've just built it, but maybe the build failed, in which case the
// realisation won't be there
@@ -966,10 +949,11 @@ void DerivationGoal::resolvedFinished() {
signRealisation(newRealisation);
worker.store.registerDrvOutput(newRealisation);
outputPaths.insert(realisation->outPath);
+ builtOutputs.emplace(realisation->id, *realisation);
} else {
// If we don't have a realisation, then it must mean that something
// failed when building the resolved drv
- assert(!result.success());
+ assert(!buildResult.success());
}
}
@@ -981,7 +965,7 @@ void DerivationGoal::resolvedFinished() {
);
auto status = [&]() {
- auto resolvedResult = resolvedDrvGoal->getResult();
+ auto & resolvedResult = resolvedDrvGoal->buildResult;
switch (resolvedResult.status) {
case BuildResult::AlreadyValid:
return BuildResult::ResolvesToAlreadyValid;
@@ -990,7 +974,7 @@ void DerivationGoal::resolvedFinished() {
}
}();
- done(status);
+ done(status, std::move(builtOutputs));
}
HookReply DerivationGoal::tryBuildHook()
@@ -1013,7 +997,7 @@ HookReply DerivationGoal::tryBuildHook()
/* Read the first line of input, which should be a word indicating
whether the hook wishes to perform the build. */
- string reply;
+ std::string reply;
while (true) {
auto s = [&]() {
try {
@@ -1025,8 +1009,8 @@ HookReply DerivationGoal::tryBuildHook()
}();
if (handleJSONLogMessage(s, worker.act, worker.hook->activities, true))
;
- else if (string(s, 0, 2) == "# ") {
- reply = string(s, 2);
+ else if (s.substr(0, 2) == "# ") {
+ reply = s.substr(2);
break;
}
else {
@@ -1091,7 +1075,7 @@ HookReply DerivationGoal::tryBuildHook()
/* Create the log file and pipe. */
Path logFile = openLogFile();
- set<int> fds;
+ std::set<int> fds;
fds.insert(hook->fromHook.readSide.get());
fds.insert(hook->builderOut.readSide.get());
worker.childStarted(shared_from_this(), fds, false, false);
@@ -1100,7 +1084,7 @@ HookReply DerivationGoal::tryBuildHook()
}
-void DerivationGoal::registerOutputs()
+DrvOutputs DerivationGoal::registerOutputs()
{
/* When using a build hook, the build hook can register the output
as valid (by doing `nix-store --import'). If so we don't have
@@ -1109,21 +1093,7 @@ void DerivationGoal::registerOutputs()
We can only early return when the outputs are known a priori. For
floating content-addressed derivations this isn't the case.
*/
- for (auto & [outputName, optOutputPath] : worker.store.queryPartialDerivationOutputMap(drvPath)) {
- if (!wantOutput(outputName, wantedOutputs))
- continue;
- if (!optOutputPath)
- throw BuildError(
- "output '%s' from derivation '%s' does not have a known output path",
- outputName, worker.store.printStorePath(drvPath));
- auto & outputPath = *optOutputPath;
- if (!worker.store.isValidPath(outputPath))
- throw BuildError(
- "output '%s' from derivation '%s' is supposed to be at '%s' but that path is not valid",
- outputName, worker.store.printStorePath(drvPath), worker.store.printStorePath(outputPath));
-
- finalOutputs.insert_or_assign(outputName, outputPath);
- }
+ return assertPathValidity();
}
Path DerivationGoal::openLogFile()
@@ -1140,10 +1110,10 @@ Path DerivationGoal::openLogFile()
logDir = localStore->logDir;
else
logDir = settings.nixLogDir;
- Path dir = fmt("%s/%s/%s/", logDir, LocalFSStore::drvsLogDir, string(baseName, 0, 2));
+ Path dir = fmt("%s/%s/%s/", logDir, LocalFSStore::drvsLogDir, baseName.substr(0, 2));
createDirs(dir);
- Path logFileName = fmt("%s/%s%s", dir, string(baseName, 2),
+ Path logFileName = fmt("%s/%s%s", dir, baseName.substr(2),
settings.compressLog ? ".bz2" : "");
fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
@@ -1175,16 +1145,17 @@ bool DerivationGoal::isReadDesc(int fd)
return fd == hook->builderOut.readSide.get();
}
-
-void DerivationGoal::handleChildOutput(int fd, const string & data)
+void DerivationGoal::handleChildOutput(int fd, std::string_view data)
{
- if (isReadDesc(fd))
+ // local & `ssh://`-builds are dealt with here.
+ auto isWrittenToLog = isReadDesc(fd);
+ if (isWrittenToLog)
{
logSize += data.size();
if (settings.maxLogSize && logSize > settings.maxLogSize) {
killChild();
done(
- BuildResult::LogLimitExceeded,
+ BuildResult::LogLimitExceeded, {},
Error("%s killed after writing more than %d bytes of log output",
getName(), settings.maxLogSize));
return;
@@ -1207,7 +1178,16 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
if (hook && fd == hook->fromHook.readSide.get()) {
for (auto c : data)
if (c == '\n') {
- handleJSONLogMessage(currentHookLine, worker.act, hook->activities, true);
+ auto json = parseJSONMessage(currentHookLine);
+ if (json) {
+ auto s = handleJSONLogMessage(*json, worker.act, hook->activities, true);
+ // ensure that logs from a builder using `ssh-ng://` as protocol
+ // are also available to `nix log`.
+ if (s && !isWrittenToLog && logSink && (*json)["type"] == resBuildLogLine) {
+ auto f = (*json)["fields"];
+ (*logSink)((f.size() > 0 ? f.at(0).get<std::string>() : "") + "\n");
+ }
+ }
currentHookLine.clear();
} else
currentHookLine += c;
@@ -1264,10 +1244,12 @@ OutputPathMap DerivationGoal::queryDerivationOutputMap()
}
-void DerivationGoal::checkPathValidity()
+std::pair<bool, DrvOutputs> DerivationGoal::checkPathValidity()
{
bool checkHash = buildMode == bmRepair;
auto wantedOutputsLeft = wantedOutputs;
+ DrvOutputs validOutputs;
+
for (auto & i : queryPartialDerivationOutputMap()) {
InitialOutput & info = initialOutputs.at(i.first);
info.wanted = wantOutput(i.first, wantedOutputs);
@@ -1284,26 +1266,28 @@ void DerivationGoal::checkPathValidity()
: PathStatus::Corrupt,
};
}
+ auto drvOutput = DrvOutput{initialOutputs.at(i.first).outputHash, i.first};
if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
- auto drvOutput = DrvOutput{initialOutputs.at(i.first).outputHash, i.first};
if (auto real = worker.store.queryRealisation(drvOutput)) {
info.known = {
.path = real->outPath,
.status = PathStatus::Valid,
};
- } else if (info.known && info.known->status == PathStatus::Valid) {
- // We know the output because it' a static output of the
+ } else if (info.known && info.known->isValid()) {
+ // We know the output because it's a static output of the
// derivation, and the output path is valid, but we don't have
// its realisation stored (probably because it has been built
- // without the `ca-derivations` experimental flag)
+ // without the `ca-derivations` experimental flag).
worker.store.registerDrvOutput(
- Realisation{
+ Realisation {
drvOutput,
info.known->path,
}
);
}
}
+ if (info.wanted && info.known && info.known->isValid())
+ validOutputs.emplace(drvOutput, Realisation { drvOutput, info.known->path });
}
// If we requested all the outputs via the empty set, we are always fine.
// If we requested specific elements, the loop above removes all the valid
@@ -1312,24 +1296,50 @@ void DerivationGoal::checkPathValidity()
throw Error("derivation '%s' does not have wanted outputs %s",
worker.store.printStorePath(drvPath),
concatStringsSep(", ", quoteStrings(wantedOutputsLeft)));
+
+ bool allValid = true;
+ for (auto & [_, status] : initialOutputs) {
+ if (!status.wanted) continue;
+ if (!status.known || !status.known->isValid()) {
+ allValid = false;
+ break;
+ }
+ }
+
+ return { allValid, validOutputs };
+}
+
+
+DrvOutputs DerivationGoal::assertPathValidity()
+{
+ auto [allValid, validOutputs] = checkPathValidity();
+ if (!allValid)
+ throw Error("some outputs are unexpectedly invalid");
+ return validOutputs;
}
-void DerivationGoal::done(BuildResult::Status status, std::optional<Error> ex)
+void DerivationGoal::done(
+ BuildResult::Status status,
+ DrvOutputs builtOutputs,
+ std::optional<Error> ex)
{
- result.status = status;
+ buildResult.status = status;
if (ex)
- result.errorMsg = ex->what();
- amDone(result.success() ? ecSuccess : ecFailed, ex);
- if (result.status == BuildResult::TimedOut)
+ // FIXME: strip: "error: "
+ buildResult.errorMsg = ex->what();
+ amDone(buildResult.success() ? ecSuccess : ecFailed, ex);
+ if (buildResult.status == BuildResult::TimedOut)
worker.timedOut = true;
- if (result.status == BuildResult::PermanentFailure)
+ if (buildResult.status == BuildResult::PermanentFailure)
worker.permanentFailure = true;
mcExpectedBuilds.reset();
mcRunningBuilds.reset();
- if (result.success()) {
+ if (buildResult.success()) {
+ assert(!builtOutputs.empty());
+ buildResult.builtOutputs = std::move(builtOutputs);
if (status == BuildResult::Built)
worker.doneBuilds++;
} else {
@@ -1343,7 +1353,7 @@ void DerivationGoal::done(BuildResult::Status status, std::optional<Error> ex)
if (traceBuiltOutputsFile != "") {
std::fstream fs;
fs.open(traceBuiltOutputsFile, std::fstream::out);
- fs << worker.store.printStorePath(drvPath) << "\t" << result.toString() << std::endl;
+ fs << worker.store.printStorePath(drvPath) << "\t" << buildResult.toString() << std::endl;
}
}
diff --git a/src/libstore/build/derivation-goal.hh b/src/libstore/build/derivation-goal.hh
index e112542c7..ea2db89b2 100644
--- a/src/libstore/build/derivation-goal.hh
+++ b/src/libstore/build/derivation-goal.hh
@@ -104,20 +104,8 @@ struct DerivationGoal : public Goal
typedef void (DerivationGoal::*GoalState)();
GoalState state;
- /* The final output paths of the build.
-
- - For input-addressed derivations, always the precomputed paths
-
- - For content-addressed derivations, calcuated from whatever the hash
- ends up being. (Note that fixed outputs derivations that produce the
- "wrong" output still install that data under its true content-address.)
- */
- OutputPathMap finalOutputs;
-
BuildMode buildMode;
- BuildResult result;
-
/* The current round, if we're building multiple times. */
size_t curRound = 1;
@@ -145,15 +133,13 @@ struct DerivationGoal : public Goal
void timedOut(Error && ex) override;
- string key() override;
+ std::string key() override;
void work() override;
/* Add wanted outputs to an already existing derivation goal. */
void addWantedOutputs(const StringSet & outputs);
- BuildResult getResult() { return result; }
-
/* The states. */
void getDerivation();
void loadDerivation();
@@ -175,7 +161,7 @@ struct DerivationGoal : public Goal
/* Check that the derivation outputs all exist and register them
as valid. */
- virtual void registerOutputs();
+ virtual DrvOutputs registerOutputs();
/* Open a log file and a pipe to it. */
Path openLogFile();
@@ -200,7 +186,7 @@ struct DerivationGoal : public Goal
virtual bool isReadDesc(int fd);
/* Callback used by the worker to write to the log. */
- void handleChildOutput(int fd, const string & data) override;
+ void handleChildOutput(int fd, std::string_view data) override;
void handleEOF(int fd) override;
void flushLine();
@@ -210,8 +196,17 @@ struct DerivationGoal : public Goal
std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap();
OutputPathMap queryDerivationOutputMap();
- /* Return the set of (in)valid paths. */
- void checkPathValidity();
+ /* Update 'initialOutputs' to determine the current status of the
+ outputs of the derivation. Also returns a Boolean denoting
+ whether all outputs are valid and non-corrupt, and a
+ 'DrvOutputs' structure containing the valid and wanted
+ outputs. */
+ std::pair<bool, DrvOutputs> checkPathValidity();
+
+ /* Aborts if any output is not valid or corrupt, and otherwise
+ returns a 'DrvOutputs' structure containing the wanted
+ outputs. */
+ DrvOutputs assertPathValidity();
/* Forcibly kill the child process, if any. */
virtual void killChild();
@@ -222,6 +217,7 @@ struct DerivationGoal : public Goal
void done(
BuildResult::Status status,
+ DrvOutputs builtOutputs = {},
std::optional<Error> ex = {});
StorePathSet exportReferences(const StorePathSet & storePaths);
diff --git a/src/libstore/build/drv-output-substitution-goal.cc b/src/libstore/build/drv-output-substitution-goal.cc
index b9602e696..e50292c1e 100644
--- a/src/libstore/build/drv-output-substitution-goal.cc
+++ b/src/libstore/build/drv-output-substitution-goal.cc
@@ -6,8 +6,12 @@
namespace nix {
-DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal(const DrvOutput& id, Worker & worker, RepairFlag repair, std::optional<ContentAddress> ca)
- : Goal(worker)
+DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal(
+ const DrvOutput & id,
+ Worker & worker,
+ RepairFlag repair,
+ std::optional<ContentAddress> ca)
+ : Goal(worker, DerivedPath::Opaque { StorePath::dummy })
, id(id)
{
state = &DrvOutputSubstitutionGoal::init;
@@ -32,7 +36,7 @@ void DrvOutputSubstitutionGoal::init()
void DrvOutputSubstitutionGoal::tryNext()
{
- trace("Trying next substituter");
+ trace("trying next substituter");
if (subs.size() == 0) {
/* None left. Terminate this goal and let someone else deal
@@ -119,7 +123,7 @@ void DrvOutputSubstitutionGoal::realisationFetched()
void DrvOutputSubstitutionGoal::outPathValid()
{
assert(outputInfo);
- trace("Output path substituted");
+ trace("output path substituted");
if (nrFailed > 0) {
debug("The output path of the derivation output '%s' could not be substituted", id.to_string());
@@ -137,7 +141,7 @@ void DrvOutputSubstitutionGoal::finished()
amDone(ecSuccess);
}
-string DrvOutputSubstitutionGoal::key()
+std::string DrvOutputSubstitutionGoal::key()
{
/* "a$" ensures substitution goals happen before derivation
goals. */
diff --git a/src/libstore/build/drv-output-substitution-goal.hh b/src/libstore/build/drv-output-substitution-goal.hh
index 67ae2624a..948dbda8f 100644
--- a/src/libstore/build/drv-output-substitution-goal.hh
+++ b/src/libstore/build/drv-output-substitution-goal.hh
@@ -51,7 +51,7 @@ public:
void timedOut(Error && ex) override { abort(); };
- string key() override;
+ std::string key() override;
void work() override;
void handleEOF(int fd) override;
diff --git a/src/libstore/build/entry-points.cc b/src/libstore/build/entry-points.cc
index 9b4cfd835..bea7363db 100644
--- a/src/libstore/build/entry-points.cc
+++ b/src/libstore/build/entry-points.cc
@@ -47,43 +47,51 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod
}
}
+std::vector<BuildResult> Store::buildPathsWithResults(
+ const std::vector<DerivedPath> & reqs,
+ BuildMode buildMode,
+ std::shared_ptr<Store> evalStore)
+{
+ Worker worker(*this, evalStore ? *evalStore : *this);
+
+ Goals goals;
+ for (const auto & br : reqs) {
+ std::visit(overloaded {
+ [&](const DerivedPath::Built & bfd) {
+ goals.insert(worker.makeDerivationGoal(bfd.drvPath, bfd.outputs, buildMode));
+ },
+ [&](const DerivedPath::Opaque & bo) {
+ goals.insert(worker.makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair));
+ },
+ }, br.raw());
+ }
+
+ worker.run(goals);
+
+ std::vector<BuildResult> results;
+
+ for (auto & i : goals)
+ results.push_back(i->buildResult);
+
+ return results;
+}
+
BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode)
{
Worker worker(*this, *this);
auto goal = worker.makeBasicDerivationGoal(drvPath, drv, {}, buildMode);
- BuildResult result;
-
try {
worker.run(Goals{goal});
- result = goal->getResult();
+ return goal->buildResult;
} catch (Error & e) {
- result.status = BuildResult::MiscFailure;
- result.errorMsg = e.msg();
- }
- // XXX: Should use `goal->queryPartialDerivationOutputMap()` once it's
- // extended to return the full realisation for each output
- auto staticDrvOutputs = drv.outputsAndOptPaths(*this);
- auto outputHashes = staticOutputHashes(*this, drv);
- for (auto & [outputName, staticOutput] : staticDrvOutputs) {
- auto outputId = DrvOutput{outputHashes.at(outputName), outputName};
- if (staticOutput.second)
- result.builtOutputs.insert_or_assign(
- outputId,
- Realisation{ outputId, *staticOutput.second}
- );
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) && !derivationHasKnownOutputPaths(drv.type())) {
- auto realisation = this->queryRealisation(outputId);
- if (realisation)
- result.builtOutputs.insert_or_assign(
- outputId,
- *realisation
- );
- }
- }
-
- return result;
+ return BuildResult {
+ .status = BuildResult::MiscFailure,
+ .errorMsg = e.msg(),
+ .path = DerivedPath::Built { .drvPath = drvPath },
+ };
+ };
}
diff --git a/src/libstore/build/goal.cc b/src/libstore/build/goal.cc
index 7c985128b..d2420b107 100644
--- a/src/libstore/build/goal.cc
+++ b/src/libstore/build/goal.cc
@@ -5,8 +5,8 @@ namespace nix {
bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) const {
- string s1 = a->key();
- string s2 = b->key();
+ std::string s1 = a->key();
+ std::string s2 = b->key();
return s1 < s2;
}
diff --git a/src/libstore/build/goal.hh b/src/libstore/build/goal.hh
index 192e416d2..07c752bb9 100644
--- a/src/libstore/build/goal.hh
+++ b/src/libstore/build/goal.hh
@@ -2,6 +2,7 @@
#include "types.hh"
#include "store-api.hh"
+#include "build-result.hh"
namespace nix {
@@ -18,8 +19,8 @@ struct CompareGoalPtrs {
};
/* Set of goals. */
-typedef set<GoalPtr, CompareGoalPtrs> Goals;
-typedef set<WeakGoalPtr, std::owner_less<WeakGoalPtr>> WeakGoals;
+typedef std::set<GoalPtr, CompareGoalPtrs> Goals;
+typedef std::set<WeakGoalPtr, std::owner_less<WeakGoalPtr>> WeakGoals;
/* A map of paths to goals (and the other way around). */
typedef std::map<StorePath, WeakGoalPtr> WeakGoalMap;
@@ -50,15 +51,20 @@ struct Goal : public std::enable_shared_from_this<Goal>
unsigned int nrIncompleteClosure;
/* Name of this goal for debugging purposes. */
- string name;
+ std::string name;
/* Whether the goal is finished. */
ExitCode exitCode;
+ /* Build result. */
+ BuildResult buildResult;
+
/* Exception containing an error message, if any. */
std::optional<Error> ex;
- Goal(Worker & worker) : worker(worker)
+ Goal(Worker & worker, DerivedPath path)
+ : worker(worker)
+ , buildResult { .path = std::move(path) }
{
nrFailed = nrNoSubstituters = nrIncompleteClosure = 0;
exitCode = ecBusy;
@@ -75,7 +81,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
virtual void waiteeDone(GoalPtr waitee, ExitCode result);
- virtual void handleChildOutput(int fd, const string & data)
+ virtual void handleChildOutput(int fd, std::string_view data)
{
abort();
}
@@ -87,7 +93,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
void trace(const FormatOrString & fs);
- string getName()
+ std::string getName()
{
return name;
}
@@ -97,7 +103,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
by the worker (important!), etc. */
virtual void timedOut(Error && ex) = 0;
- virtual string key() = 0;
+ virtual std::string key() = 0;
void amDone(ExitCode result, std::optional<Error> ex = {});
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 8861d2c7b..a372728f5 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -1,4 +1,5 @@
#include "local-derivation-goal.hh"
+#include "gc-store.hh"
#include "hook-instance.hh"
#include "worker.hh"
#include "builtins.hh"
@@ -193,7 +194,7 @@ void LocalDerivationGoal::tryLocalBuild() {
outputLocks.unlock();
buildUser.reset();
worker.permanentFailure = true;
- done(BuildResult::InputRejected, e);
+ done(BuildResult::InputRejected, {}, e);
return;
}
@@ -481,12 +482,12 @@ void LocalDerivationGoal::startBuilder()
temporary build directory. The text files have the format used
by `nix-store --register-validity'. However, the deriver
fields are left empty. */
- string s = get(drv->env, "exportReferencesGraph").value_or("");
+ auto s = get(drv->env, "exportReferencesGraph").value_or("");
Strings ss = tokenizeString<Strings>(s);
if (ss.size() % 2 != 0)
throw BuildError("odd number of tokens in 'exportReferencesGraph': '%1%'", s);
for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
- string fileName = *i++;
+ auto fileName = *i++;
static std::regex regex("[A-Za-z_][A-Za-z0-9_.-]*");
if (!std::regex_match(fileName, regex))
throw Error("invalid file name '%s' in 'exportReferencesGraph'", fileName);
@@ -517,10 +518,10 @@ void LocalDerivationGoal::startBuilder()
i.pop_back();
}
size_t p = i.find('=');
- if (p == string::npos)
+ if (p == std::string::npos)
dirsInChroot[i] = {i, optional};
else
- dirsInChroot[string(i, 0, p)] = {string(i, p + 1), optional};
+ dirsInChroot[i.substr(0, p)] = {i.substr(p + 1), optional};
}
dirsInChroot[tmpDirInSandbox] = tmpDir;
@@ -671,9 +672,10 @@ void LocalDerivationGoal::startBuilder()
auto state = stBegin;
auto lines = runProgram(settings.preBuildHook, false, args);
auto lastPos = std::string::size_type{0};
- for (auto nlPos = lines.find('\n'); nlPos != string::npos;
- nlPos = lines.find('\n', lastPos)) {
- auto line = std::string{lines, lastPos, nlPos - lastPos};
+ for (auto nlPos = lines.find('\n'); nlPos != std::string::npos;
+ nlPos = lines.find('\n', lastPos))
+ {
+ auto line = lines.substr(lastPos, nlPos - lastPos);
lastPos = nlPos + 1;
if (state == stBegin) {
if (line == "extra-sandbox-paths" || line == "extra-chroot-dirs") {
@@ -686,10 +688,10 @@ void LocalDerivationGoal::startBuilder()
state = stBegin;
} else {
auto p = line.find('=');
- if (p == string::npos)
+ if (p == std::string::npos)
dirsInChroot[line] = line;
else
- dirsInChroot[string(line, 0, p)] = string(line, p + 1);
+ dirsInChroot[line.substr(0, p)] = line.substr(p + 1);
}
}
}
@@ -754,7 +756,7 @@ void LocalDerivationGoal::startBuilder()
if (tcsetattr(builderOut.writeSide.get(), TCSANOW, &term))
throw SysError("putting pseudoterminal into raw mode");
- result.startTime = time(0);
+ buildResult.startTime = time(0);
/* Fork a child to build the package. */
@@ -941,7 +943,7 @@ void LocalDerivationGoal::startBuilder()
/* Check if setting up the build environment failed. */
std::vector<std::string> msgs;
while (true) {
- string msg = [&]() {
+ std::string msg = [&]() {
try {
return readLine(builderOut.readSide.get());
} catch (Error & e) {
@@ -953,8 +955,8 @@ void LocalDerivationGoal::startBuilder()
throw;
}
}();
- if (string(msg, 0, 1) == "\2") break;
- if (string(msg, 0, 1) == "\1") {
+ if (msg.substr(0, 1) == "\2") break;
+ if (msg.substr(0, 1) == "\1") {
FdSource source(builderOut.readSide.get());
auto ex = readError(source);
ex.addTrace({}, "while setting up the build environment");
@@ -990,7 +992,7 @@ void LocalDerivationGoal::initTmpDir() {
env[i.first] = i.second;
} else {
auto hash = hashString(htSHA256, i.first);
- string fn = ".attr-" + hash.to_string(Base32, false);
+ std::string fn = ".attr-" + hash.to_string(Base32, false);
Path p = tmpDir + "/" + fn;
writeFile(p, rewriteStrings(i.second, inputRewrites));
chownToBuilder(p);
@@ -1081,7 +1083,7 @@ void LocalDerivationGoal::writeStructuredAttrs()
for (auto & [i, v] : json["outputs"].get<nlohmann::json::object_t>()) {
/* The placeholder must have a rewrite, so we use it to cover both the
cases where we know or don't know the output path ahead of time. */
- rewritten[i] = rewriteStrings(v, inputRewrites);
+ rewritten[i] = rewriteStrings((std::string) v, inputRewrites);
}
json["outputs"] = rewritten;
@@ -1126,7 +1128,7 @@ struct RestrictedStoreConfig : virtual LocalFSStoreConfig
/* A wrapper around LocalStore that only allows building/querying of
paths that are in the input closures of the build or were added via
recursive Nix calls. */
-struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual LocalFSStore
+struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual LocalFSStore, public virtual GcStore
{
ref<LocalStore> next;
@@ -1187,10 +1189,14 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ throw Error("queryPathFromHashPart"); }
- StorePath addToStore(const string & name, const Path & srcPath,
- FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
- PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair,
- const StorePathSet & references = StorePathSet()) override
+ StorePath addToStore(
+ std::string_view name,
+ const Path & srcPath,
+ FileIngestionMethod method,
+ HashType hashAlgo,
+ PathFilter & filter,
+ RepairFlag repair,
+ const StorePathSet & references) override
{ throw Error("addToStore"); }
void addToStore(const ValidPathInfo & info, Source & narSource,
@@ -1200,17 +1206,24 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
goal.addDependency(info.path);
}
- StorePath addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair = NoRepair) override
+ StorePath addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair = NoRepair) override
{
auto path = next->addTextToStore(name, s, references, repair);
goal.addDependency(path);
return path;
}
- StorePath addToStoreFromDump(Source & dump, std::string_view name,
- FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair,
- const StorePathSet & references = StorePathSet()) override
+ StorePath addToStoreFromDump(
+ Source & dump,
+ std::string_view name,
+ FileIngestionMethod method,
+ HashType hashAlgo,
+ RepairFlag repair,
+ const StorePathSet & references) override
{
auto path = next->addToStoreFromDump(dump, name, method, hashAlgo, repair, references);
goal.addDependency(path);
@@ -1248,6 +1261,16 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
void buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode, std::shared_ptr<Store> evalStore) override
{
+ for (auto & result : buildPathsWithResults(paths, buildMode, evalStore))
+ if (!result.success())
+ result.rethrow();
+ }
+
+ std::vector<BuildResult> buildPathsWithResults(
+ const std::vector<DerivedPath> & paths,
+ BuildMode buildMode = bmNormal,
+ std::shared_ptr<Store> evalStore = nullptr) override
+ {
assert(!evalStore);
if (buildMode != bmNormal) throw Error("unsupported build mode");
@@ -1260,26 +1283,13 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
throw InvalidPath("cannot build '%s' in recursive Nix because path is unknown", req.to_string(*next));
}
- next->buildPaths(paths, buildMode);
-
- for (auto & path : paths) {
- auto p = std::get_if<DerivedPath::Built>(&path);
- if (!p) continue;
- auto & bfd = *p;
- auto drv = readDerivation(bfd.drvPath);
- auto drvHashes = staticOutputHashes(*this, drv);
- auto outputs = next->queryDerivationOutputMap(bfd.drvPath);
- for (auto & [outputName, outputPath] : outputs)
- if (wantOutput(outputName, bfd.outputs)) {
- newPaths.insert(outputPath);
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
- auto thisRealisation = next->queryRealisation(
- DrvOutput{drvHashes.at(outputName), outputName}
- );
- assert(thisRealisation);
- newRealisations.insert(*thisRealisation);
- }
- }
+ auto results = next->buildPathsWithResults(paths, buildMode);
+
+ for (auto & result : results) {
+ for (auto & [outputName, output] : result.builtOutputs) {
+ newPaths.insert(output.outPath);
+ newRealisations.insert(output);
+ }
}
StorePathSet closure;
@@ -1288,6 +1298,8 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
goal.addDependency(path);
for (auto & real : Realisation::closure(*next, newRealisations))
goal.addedDrvOutputs.insert(real.id);
+
+ return results;
}
BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
@@ -1921,7 +1933,7 @@ void LocalDerivationGoal::runChild()
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin",
i.first, i.second.source);
- string path = i.first;
+ std::string path = i.first;
struct stat st;
if (lstat(path.c_str(), &st)) {
if (i.second.optional && errno == ENOENT)
@@ -1973,7 +1985,7 @@ void LocalDerivationGoal::runChild()
args.push_back("IMPORT_DIR=" + settings.nixDataDir + "/nix/sandbox/");
if (allowLocalNetworking) {
args.push_back("-D");
- args.push_back(string("_ALLOW_LOCAL_NETWORKING=1"));
+ args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1"));
}
args.push_back(drv->builder);
} else {
@@ -1992,7 +2004,7 @@ void LocalDerivationGoal::runChild()
args.push_back(rewriteStrings(i, inputRewrites));
/* Indicate that we managed to set up the build environment. */
- writeFull(STDERR_FILENO, string("\2\n"));
+ writeFull(STDERR_FILENO, std::string("\2\n"));
/* Execute the program. This should not return. */
if (drv->isBuiltin()) {
@@ -2010,7 +2022,7 @@ void LocalDerivationGoal::runChild()
else if (drv->builder == "builtin:unpack-channel")
builtinUnpackChannel(drv2);
else
- throw Error("unsupported builtin builder '%1%'", string(drv->builder, 8));
+ throw Error("unsupported builtin builder '%1%'", drv->builder.substr(8));
_exit(0);
} catch (std::exception & e) {
writeFull(STDERR_FILENO, e.what() + std::string("\n"));
@@ -2056,7 +2068,7 @@ void LocalDerivationGoal::runChild()
}
-void LocalDerivationGoal::registerOutputs()
+DrvOutputs LocalDerivationGoal::registerOutputs()
{
/* When using a build hook, the build hook can register the output
as valid (by doing `nix-store --import'). If so we don't have
@@ -2065,10 +2077,8 @@ void LocalDerivationGoal::registerOutputs()
We can only early return when the outputs are known a priori. For
floating content-addressed derivations this isn't the case.
*/
- if (hook) {
- DerivationGoal::registerOutputs();
- return;
- }
+ if (hook)
+ return DerivationGoal::registerOutputs();
std::map<std::string, ValidPathInfo> infos;
@@ -2191,6 +2201,8 @@ void LocalDerivationGoal::registerOutputs()
std::reverse(sortedOutputNames.begin(), sortedOutputNames.end());
+ OutputPathMap finalOutputs;
+
for (auto & outputName : sortedOutputNames) {
auto output = drv->outputs.at(outputName);
auto & scratchPath = scratchOutputs.at(outputName);
@@ -2327,6 +2339,7 @@ void LocalDerivationGoal::registerOutputs()
};
ValidPathInfo newInfo = std::visit(overloaded {
+
[&](const DerivationOutputInputAddressed & output) {
/* input-addressed case */
auto requiredFinalPath = output.path;
@@ -2346,6 +2359,7 @@ void LocalDerivationGoal::registerOutputs()
newInfo0.references.insert(newInfo0.path);
return newInfo0;
},
+
[&](const DerivationOutputCAFixed & dof) {
auto newInfo0 = newInfoFromCA(DerivationOutputCAFloating {
.method = dof.hash.method,
@@ -2368,18 +2382,17 @@ void LocalDerivationGoal::registerOutputs()
}
return newInfo0;
},
- [&](DerivationOutputCAFloating dof) {
+
+ [&](DerivationOutputCAFloating & dof) {
return newInfoFromCA(dof);
},
- [&](DerivationOutputDeferred) {
+
+ [&](DerivationOutputDeferred) -> ValidPathInfo {
// No derivation should reach that point without having been
// rewritten first
assert(false);
- // Ugly, but the compiler insists on having this return a value
- // of type `ValidPathInfo` despite the `assert(false)`, so
- // let's provide it
- return *(ValidPathInfo*)0;
},
+
}, output.output);
/* FIXME: set proper permissions in restorePath() so
@@ -2490,11 +2503,12 @@ void LocalDerivationGoal::registerOutputs()
}
if (buildMode == bmCheck) {
- // In case of FOD mismatches on `--check` an error must be thrown as this is also
- // a source for non-determinism.
+ /* In case of fixed-output derivations, if there are
+ mismatches on `--check` an error must be thrown as this is
+ also a source for non-determinism. */
if (delayedException)
std::rethrow_exception(delayedException);
- return;
+ return assertPathValidity();
}
/* Apply output checks. */
@@ -2506,7 +2520,7 @@ void LocalDerivationGoal::registerOutputs()
assert(prevInfos.size() == infos.size());
for (auto i = prevInfos.begin(), j = infos.begin(); i != prevInfos.end(); ++i, ++j)
if (!(*i == *j)) {
- result.isNonDeterministic = true;
+ buildResult.isNonDeterministic = true;
Path prev = worker.store.printStorePath(i->second.path) + checkSuffix;
bool prevExists = keepPreviousRound && pathExists(prev);
hintformat hint = prevExists
@@ -2544,7 +2558,7 @@ void LocalDerivationGoal::registerOutputs()
if (curRound < nrRounds) {
prevInfos = std::move(infos);
- return;
+ return {};
}
/* Remove the .check directories if we're done. FIXME: keep them
@@ -2579,17 +2593,24 @@ void LocalDerivationGoal::registerOutputs()
means it's safe to link the derivation to the output hash. We must do
that for floating CA derivations, which otherwise couldn't be cached,
but it's fine to do in all cases. */
+ DrvOutputs builtOutputs;
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
- for (auto& [outputName, newInfo] : infos) {
- auto thisRealisation = Realisation{
- .id = DrvOutput{initialOutputs.at(outputName).outputHash,
- outputName},
- .outPath = newInfo.path};
+ for (auto & [outputName, newInfo] : infos) {
+ auto thisRealisation = Realisation {
+ .id = DrvOutput {
+ initialOutputs.at(outputName).outputHash,
+ outputName
+ },
+ .outPath = newInfo.path
+ };
+ if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
signRealisation(thisRealisation);
worker.store.registerDrvOutput(thisRealisation);
}
+ builtOutputs.emplace(thisRealisation.id, thisRealisation);
}
+
+ return builtOutputs;
}
void LocalDerivationGoal::signRealisation(Realisation & realisation)
@@ -2598,7 +2619,7 @@ void LocalDerivationGoal::signRealisation(Realisation & realisation)
}
-void LocalDerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
+void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo> & outputs)
{
std::map<Path, const ValidPathInfo &> outputsByPath;
for (auto & output : outputs)
@@ -2670,8 +2691,8 @@ void LocalDerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & out
for (auto & i : *value) {
if (worker.store.isStorePath(i))
spec.insert(worker.store.parseStorePath(i));
- else if (finalOutputs.count(i))
- spec.insert(finalOutputs.at(i));
+ else if (outputs.count(i))
+ spec.insert(outputs.at(i).path);
else throw BuildError("derivation contains an illegal reference specifier '%s'", i);
}
@@ -2694,7 +2715,7 @@ void LocalDerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & out
}
if (!badPaths.empty()) {
- string badPathsStr;
+ std::string badPathsStr;
for (auto & i : badPaths) {
badPathsStr += "\n ";
badPathsStr += worker.store.printStorePath(i);
diff --git a/src/libstore/build/local-derivation-goal.hh b/src/libstore/build/local-derivation-goal.hh
index bfdf91d89..d456e9cae 100644
--- a/src/libstore/build/local-derivation-goal.hh
+++ b/src/libstore/build/local-derivation-goal.hh
@@ -58,11 +58,11 @@ struct LocalDerivationGoal : public DerivationGoal
typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path
DirsInChroot dirsInChroot;
- typedef map<string, string> Environment;
+ typedef map<std::string, std::string> Environment;
Environment env;
#if __APPLE__
- typedef string SandboxProfile;
+ typedef std::string SandboxProfile;
SandboxProfile additionalSandboxProfile;
#endif
@@ -169,7 +169,7 @@ struct LocalDerivationGoal : public DerivationGoal
/* Check that the derivation outputs all exist and register them
as valid. */
- void registerOutputs() override;
+ DrvOutputs registerOutputs() override;
void signRealisation(Realisation &) override;
diff --git a/src/libstore/build/substitution-goal.cc b/src/libstore/build/substitution-goal.cc
index 5ecf1da7e..31e6dbc9f 100644
--- a/src/libstore/build/substitution-goal.cc
+++ b/src/libstore/build/substitution-goal.cc
@@ -6,7 +6,7 @@
namespace nix {
PathSubstitutionGoal::PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair, std::optional<ContentAddress> ca)
- : Goal(worker)
+ : Goal(worker, DerivedPath::Opaque { storePath })
, storePath(storePath)
, repair(repair)
, ca(ca)
@@ -24,6 +24,13 @@ PathSubstitutionGoal::~PathSubstitutionGoal()
}
+void PathSubstitutionGoal::done(ExitCode result, BuildResult::Status status)
+{
+ buildResult.status = status;
+ amDone(result);
+}
+
+
void PathSubstitutionGoal::work()
{
(this->*state)();
@@ -38,7 +45,7 @@ void PathSubstitutionGoal::init()
/* If the path already exists we're done. */
if (!repair && worker.store.isValidPath(storePath)) {
- amDone(ecSuccess);
+ done(ecSuccess, BuildResult::AlreadyValid);
return;
}
@@ -65,7 +72,7 @@ void PathSubstitutionGoal::tryNext()
/* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a
build. */
- amDone(substituterFailed ? ecFailed : ecNoSubstituters);
+ done(substituterFailed ? ecFailed : ecNoSubstituters, BuildResult::NoSubstituters);
if (substituterFailed) {
worker.failedSubstitutions++;
@@ -163,7 +170,9 @@ void PathSubstitutionGoal::referencesValid()
if (nrFailed > 0) {
debug("some references of path '%s' could not be realised", worker.store.printStorePath(storePath));
- amDone(nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed);
+ done(
+ nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
+ BuildResult::DependencyFailed);
return;
}
@@ -268,11 +277,11 @@ void PathSubstitutionGoal::finished()
worker.updateProgress();
- amDone(ecSuccess);
+ done(ecSuccess, BuildResult::Substituted);
}
-void PathSubstitutionGoal::handleChildOutput(int fd, const string & data)
+void PathSubstitutionGoal::handleChildOutput(int fd, std::string_view data)
{
}
diff --git a/src/libstore/build/substitution-goal.hh b/src/libstore/build/substitution-goal.hh
index 70c806d23..946f13841 100644
--- a/src/libstore/build/substitution-goal.hh
+++ b/src/libstore/build/substitution-goal.hh
@@ -53,13 +53,15 @@ struct PathSubstitutionGoal : public Goal
/* Content address for recomputing store path */
std::optional<ContentAddress> ca;
+ void done(ExitCode result, BuildResult::Status status);
+
public:
PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
~PathSubstitutionGoal();
void timedOut(Error && ex) override { abort(); };
- string key() override
+ std::string key() override
{
/* "a$" ensures substitution goals happen before derivation
goals. */
@@ -77,7 +79,7 @@ public:
void finished();
/* Callback used by the worker to write to the log. */
- void handleChildOutput(int fd, const string & data) override;
+ void handleChildOutput(int fd, std::string_view data) override;
void handleEOF(int fd) override;
void cleanup() override;
diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc
index f11c5ce68..f72c1cc9c 100644
--- a/src/libstore/build/worker.cc
+++ b/src/libstore/build/worker.cc
@@ -161,7 +161,7 @@ unsigned Worker::getNrLocalBuilds()
}
-void Worker::childStarted(GoalPtr goal, const set<int> & fds,
+void Worker::childStarted(GoalPtr goal, const std::set<int> & fds,
bool inBuildSlot, bool respectTimeouts)
{
Child child;
@@ -377,7 +377,7 @@ void Worker::waitForInput()
GoalPtr goal = j->goal.lock();
assert(goal);
- set<int> fds2(j->fds);
+ std::set<int> fds2(j->fds);
std::vector<unsigned char> buffer(4096);
for (auto & k : fds2) {
if (pollStatus.at(fdToPollStatus.at(k)).revents) {
@@ -394,7 +394,7 @@ void Worker::waitForInput()
} else {
printMsg(lvlVomit, "%1%: read %2% bytes",
goal->getName(), rd);
- string data((char *) buffer.data(), rd);
+ std::string data((char *) buffer.data(), rd);
j->lastOutput = after;
goal->handleChildOutput(k, data);
}
diff --git a/src/libstore/build/worker.hh b/src/libstore/build/worker.hh
index 6a3b99c02..a1e036a96 100644
--- a/src/libstore/build/worker.hh
+++ b/src/libstore/build/worker.hh
@@ -38,7 +38,7 @@ struct Child
{
WeakGoalPtr goal;
Goal * goal2; // ugly hackery
- set<int> fds;
+ std::set<int> fds;
bool respectTimeouts;
bool inBuildSlot;
steady_time_point lastOutput; /* time we last got output on stdout/stderr */
@@ -167,7 +167,7 @@ public:
/* Registers a running child process. `inBuildSlot' means that
the process counts towards the jobs limit. */
- void childStarted(GoalPtr goal, const set<int> & fds,
+ void childStarted(GoalPtr goal, const std::set<int> & fds,
bool inBuildSlot, bool respectTimeouts);
/* Unregisters a running child process. `wakeSleepers' should be
diff --git a/src/libstore/builtins/buildenv.cc b/src/libstore/builtins/buildenv.cc
index e88fc687a..25d015cb9 100644
--- a/src/libstore/builtins/buildenv.cc
+++ b/src/libstore/builtins/buildenv.cc
@@ -123,7 +123,7 @@ void buildProfile(const Path & out, Packages && pkgs)
createLinks(state, pkgDir, out, priority);
try {
- for (const auto & p : tokenizeString<std::vector<string>>(
+ for (const auto & p : tokenizeString<std::vector<std::string>>(
readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n"))
if (!done.count(p))
postponed.insert(p);
@@ -161,7 +161,7 @@ void buildProfile(const Path & out, Packages && pkgs)
void builtinBuildenv(const BasicDerivation & drv)
{
- auto getAttr = [&](const string & name) {
+ auto getAttr = [&](const std::string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second;
diff --git a/src/libstore/builtins/fetchurl.cc b/src/libstore/builtins/fetchurl.cc
index 4fb5d8a06..af3dfc409 100644
--- a/src/libstore/builtins/fetchurl.cc
+++ b/src/libstore/builtins/fetchurl.cc
@@ -16,7 +16,7 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
writeFile(settings.netrcFile, netrcData, 0600);
}
- auto getAttr = [&](const string & name) {
+ auto getAttr = [&](const std::string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second;
diff --git a/src/libstore/builtins/unpack-channel.cc b/src/libstore/builtins/unpack-channel.cc
index d18e3ddaf..426d58a53 100644
--- a/src/libstore/builtins/unpack-channel.cc
+++ b/src/libstore/builtins/unpack-channel.cc
@@ -5,7 +5,7 @@ namespace nix {
void builtinUnpackChannel(const BasicDerivation & drv)
{
- auto getAttr = [&](const string & name) {
+ auto getAttr = [&](const std::string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second;
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index 1ddd1a4d5..e6760664c 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -1,7 +1,9 @@
#include "daemon.hh"
#include "monitor-fd.hh"
#include "worker-protocol.hh"
+#include "build-result.hh"
#include "store-api.hh"
+#include "gc-store.hh"
#include "path-with-outputs.hh"
#include "finally.hh"
#include "archive.hh"
@@ -479,8 +481,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
}
case wopAddTextToStore: {
- string suffix = readString(from);
- string s = readString(from);
+ std::string suffix = readString(from);
+ std::string s = readString(from);
auto refs = worker_proto::read(*store, from, Phantom<StorePathSet> {});
logger->startWork();
auto path = store->addTextToStore(suffix, s, refs, NoRepair);
@@ -530,6 +532,25 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
break;
}
+ case wopBuildPathsWithResults: {
+ auto drvs = readDerivedPaths(*store, clientVersion, from);
+ BuildMode mode = bmNormal;
+ mode = (BuildMode) readInt(from);
+
+ /* Repairing is not atomic, so disallowed for "untrusted"
+ clients. */
+ if (mode == bmRepair && !trusted)
+ throw Error("repairing is not allowed because you are not in 'trusted-users'");
+
+ logger->startWork();
+ auto results = store->buildPathsWithResults(drvs, mode);
+ logger->stopWork();
+
+ worker_proto::write(*store, to, results);
+
+ break;
+ }
+
case wopBuildDerivation: {
auto drvPath = store->parseStorePath(readString(from));
BasicDerivation drv;
@@ -622,9 +643,12 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopAddIndirectRoot: {
Path path = absPath(readString(from));
+
logger->startWork();
- store->addIndirectRoot(path);
+ auto & gcStore = requireGcStore(*store);
+ gcStore.addIndirectRoot(path);
logger->stopWork();
+
to << 1;
break;
}
@@ -639,7 +663,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case wopFindRoots: {
logger->startWork();
- Roots roots = store->findRoots(!trusted);
+ auto & gcStore = requireGcStore(*store);
+ Roots roots = gcStore.findRoots(!trusted);
logger->stopWork();
size_t size = 0;
@@ -670,7 +695,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
logger->startWork();
if (options.ignoreLiveness)
throw Error("you are not allowed to ignore liveness");
- store->collectGarbage(options, results);
+ auto & gcStore = requireGcStore(*store);
+ gcStore.collectGarbage(options, results);
logger->stopWork();
to << results.paths << results.bytesFreed << 0 /* obsolete */;
@@ -698,8 +724,8 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
if (GET_PROTOCOL_MINOR(clientVersion) >= 12) {
unsigned int n = readInt(from);
for (unsigned int i = 0; i < n; i++) {
- string name = readString(from);
- string value = readString(from);
+ auto name = readString(from);
+ auto value = readString(from);
clientSettings.overrides.emplace(name, value);
}
}
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index 40af6a775..a49be0057 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -82,7 +82,7 @@ bool derivationIsImpure(DerivationType dt) {
bool BasicDerivation::isBuiltin() const
{
- return string(builder, 0, 8) == "builtin:";
+ return builder.substr(0, 8) == "builtin:";
}
@@ -104,19 +104,19 @@ StorePath writeDerivation(Store & store,
/* Read string `s' from stream `str'. */
-static void expect(std::istream & str, const string & s)
+static void expect(std::istream & str, std::string_view s)
{
char s2[s.size()];
str.read(s2, s.size());
- if (string(s2, s.size()) != s)
+ if (std::string(s2, s.size()) != s)
throw FormatError("expected string '%1%'", s);
}
/* Read a C-style string from stream `str'. */
-static string parseString(std::istream & str)
+static std::string parseString(std::istream & str)
{
- string res;
+ std::string res;
expect(str, "\"");
int c;
while ((c = str.get()) != '"')
@@ -172,7 +172,7 @@ static DerivationOutput parseDerivationOutput(const Store & store,
{
if (hashAlgo != "") {
auto method = FileIngestionMethod::Flat;
- if (string(hashAlgo, 0, 2) == "r:") {
+ if (hashAlgo.substr(0, 2) == "r:") {
method = FileIngestionMethod::Recursive;
hashAlgo = hashAlgo.substr(2);
}
@@ -260,8 +260,8 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi
/* Parse the environment variables. */
expect(str, ",[");
while (!endOfList(str)) {
- expect(str, "("); string name = parseString(str);
- expect(str, ","); string value = parseString(str);
+ expect(str, "("); auto name = parseString(str);
+ expect(str, ","); auto value = parseString(str);
expect(str, ")");
drv.env[name] = value;
}
@@ -271,7 +271,7 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi
}
-static void printString(string & res, std::string_view s)
+static void printString(std::string & res, std::string_view s)
{
boost::container::small_vector<char, 64 * 1024> buffer;
buffer.reserve(s.size() * 2 + 2);
@@ -289,7 +289,7 @@ static void printString(string & res, std::string_view s)
}
-static void printUnquotedString(string & res, std::string_view s)
+static void printUnquotedString(std::string & res, std::string_view s)
{
res += '"';
res.append(s);
@@ -298,7 +298,7 @@ static void printUnquotedString(string & res, std::string_view s)
template<class ForwardIterator>
-static void printStrings(string & res, ForwardIterator i, ForwardIterator j)
+static void printStrings(std::string & res, ForwardIterator i, ForwardIterator j)
{
res += '[';
bool first = true;
@@ -311,7 +311,7 @@ static void printStrings(string & res, ForwardIterator i, ForwardIterator j)
template<class ForwardIterator>
-static void printUnquotedStrings(string & res, ForwardIterator i, ForwardIterator j)
+static void printUnquotedStrings(std::string & res, ForwardIterator i, ForwardIterator j)
{
res += '[';
bool first = true;
@@ -323,10 +323,10 @@ static void printUnquotedStrings(string & res, ForwardIterator i, ForwardIterato
}
-string Derivation::unparse(const Store & store, bool maskOutputs,
+std::string Derivation::unparse(const Store & store, bool maskOutputs,
std::map<std::string, StringSet> * actualInputs) const
{
- string s;
+ std::string s;
s.reserve(65536);
s += "Derive([";
@@ -401,7 +401,7 @@ string Derivation::unparse(const Store & store, bool maskOutputs,
// FIXME: remove
-bool isDerivation(const string & fileName)
+bool isDerivation(const std::string & fileName)
{
return hasSuffix(fileName, drvExtension);
}
@@ -593,7 +593,7 @@ std::map<std::string, Hash> staticOutputHashes(Store & store, const Derivation &
}
-bool wantOutput(const string & output, const std::set<string> & wanted)
+bool wantOutput(const std::string & output, const std::set<std::string> & wanted)
{
return wanted.empty() || wanted.find(output) != wanted.end();
}
diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh
index a644cec60..132de82b6 100644
--- a/src/libstore/derivations.hh
+++ b/src/libstore/derivations.hh
@@ -59,21 +59,19 @@ struct DerivationOutput
std::optional<StorePath> path(const Store & store, std::string_view drvName, std::string_view outputName) const;
};
-typedef std::map<string, DerivationOutput> DerivationOutputs;
+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 */
-typedef std::map<string, std::pair<DerivationOutput, std::optional<StorePath>>>
+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. */
typedef std::map<StorePath, StringSet> DerivationInputs;
-typedef std::map<string, string> StringPairs;
-
enum struct DerivationType : uint8_t {
InputAddressed,
DeferredInputAddressed,
@@ -103,7 +101,7 @@ struct BasicDerivation
{
DerivationOutputs outputs; /* keyed on symbolic IDs */
StorePathSet inputSrcs; /* inputs that are sources */
- string platform;
+ std::string platform;
Path builder;
Strings args;
StringPairs env;
@@ -164,7 +162,7 @@ StorePath writeDerivation(Store & store,
Derivation parseDerivation(const Store & store, std::string && s, std::string_view name);
// FIXME: remove
-bool isDerivation(const string & fileName);
+bool isDerivation(const std::string & fileName);
/* Calculate the name that will be used for the store path for this
output.
@@ -222,7 +220,7 @@ typedef std::map<StorePath, DrvHashModulo> DrvHashes;
// FIXME: global, though at least thread-safe.
extern Sync<DrvHashes> drvHashes;
-bool wantOutput(const string & output, const std::set<string> & wanted);
+bool wantOutput(const std::string & output, const std::set<std::string> & wanted);
struct Source;
struct Sink;
diff --git a/src/libstore/derived-path.cc b/src/libstore/derived-path.cc
index 3d188e981..194489580 100644
--- a/src/libstore/derived-path.cc
+++ b/src/libstore/derived-path.cc
@@ -75,9 +75,9 @@ DerivedPath::Built DerivedPath::Built::parse(const Store & store, std::string_vi
assert(n != s.npos);
auto drvPath = store.parseStorePath(s.substr(0, n));
auto outputsS = s.substr(n + 1);
- std::set<string> outputs;
+ std::set<std::string> outputs;
if (outputsS != "*")
- outputs = tokenizeString<std::set<string>>(outputsS, ",");
+ outputs = tokenizeString<std::set<std::string>>(outputsS, ",");
return {drvPath, outputs};
}
diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc
index 62dc21c59..b4fbe0b70 100644
--- a/src/libstore/dummy-store.cc
+++ b/src/libstore/dummy-store.cc
@@ -21,7 +21,7 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store
, Store(params)
{ }
- string getUri() override
+ std::string getUri() override
{
return *uriSchemes().begin();
}
@@ -43,8 +43,11 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store
RepairFlag repair, CheckSigsFlag checkSigs) override
{ unsupported("addToStore"); }
- StorePath addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair) override
+ StorePath addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair) override
{ unsupported("addTextToStore"); }
void narFromPath(const StorePath & path, Sink & sink) override
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 76fed11db..c46262299 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -33,12 +33,12 @@ FileTransferSettings fileTransferSettings;
static GlobalConfig::Register rFileTransferSettings(&fileTransferSettings);
-std::string resolveUri(const std::string & uri)
+std::string resolveUri(std::string_view uri)
{
if (uri.compare(0, 8, "channel:") == 0)
- return "https://nixos.org/channels/" + std::string(uri, 8) + "/nixexprs.tar.xz";
+ return "https://nixos.org/channels/" + std::string(uri.substr(8)) + "/nixexprs.tar.xz";
else
- return uri;
+ return std::string(uri);
}
struct curlFileTransfer : public FileTransfer
@@ -197,15 +197,15 @@ struct curlFileTransfer : public FileTransfer
result.etag = "";
result.data.clear();
result.bodySize = 0;
- statusMsg = trim(match[1]);
+ statusMsg = trim(match.str(1));
acceptRanges = false;
encoding = "";
} else {
auto i = line.find(':');
- if (i != string::npos) {
- string name = toLower(trim(string(line, 0, i)));
+ if (i != std::string::npos) {
+ std::string name = toLower(trim(line.substr(0, i)));
if (name == "etag") {
- result.etag = trim(string(line, i + 1));
+ result.etag = trim(line.substr(i + 1));
/* Hack to work around a GitHub bug: it sends
ETags, but ignores If-None-Match. So if we get
the expected ETag on a 200 response, then shut
@@ -218,8 +218,8 @@ struct curlFileTransfer : public FileTransfer
return 0;
}
} else if (name == "content-encoding")
- encoding = trim(string(line, i + 1));
- else if (name == "accept-ranges" && toLower(trim(std::string(line, i + 1))) == "bytes")
+ encoding = trim(line.substr(i + 1));
+ else if (name == "accept-ranges" && toLower(trim(line.substr(i + 1))) == "bytes")
acceptRanges = true;
}
}
@@ -866,18 +866,18 @@ FileTransferError::FileTransferError(FileTransfer::Error error, std::optional<st
// FIXME: Due to https://github.com/NixOS/nix/issues/3841 we don't know how
// to print different messages for different verbosity levels. For now
// we add some heuristics for detecting when we want to show the response.
- if (response && (response->size() < 1024 || response->find("<html>") != string::npos))
+ if (response && (response->size() < 1024 || response->find("<html>") != std::string::npos))
err.msg = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), chomp(*response));
else
err.msg = hf;
}
-bool isUri(const string & s)
+bool isUri(std::string_view s)
{
if (s.compare(0, 8, "channel:") == 0) return true;
size_t pos = s.find("://");
- if (pos == string::npos) return false;
- string scheme(s, 0, pos);
+ if (pos == std::string::npos) return false;
+ std::string scheme(s, 0, pos);
return scheme == "http" || scheme == "https" || scheme == "file" || scheme == "channel" || scheme == "git" || scheme == "s3" || scheme == "ssh";
}
diff --git a/src/libstore/filetransfer.hh b/src/libstore/filetransfer.hh
index 3e61b23b1..ca61e3937 100644
--- a/src/libstore/filetransfer.hh
+++ b/src/libstore/filetransfer.hh
@@ -119,17 +119,17 @@ class FileTransferError : public Error
{
public:
FileTransfer::Error error;
- std::optional<string> response; // intentionally optional
+ std::optional<std::string> response; // intentionally optional
template<typename... Args>
- FileTransferError(FileTransfer::Error error, std::optional<string> response, const Args & ... args);
+ FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args);
virtual const char* sname() const override { return "FileTransferError"; }
};
-bool isUri(const string & s);
+bool isUri(std::string_view s);
/* Resolve deprecated 'channel:<foo>' URLs. */
-std::string resolveUri(const std::string & uri);
+std::string resolveUri(std::string_view uri);
}
diff --git a/src/libstore/gc-store.cc b/src/libstore/gc-store.cc
new file mode 100644
index 000000000..3dbdec53b
--- /dev/null
+++ b/src/libstore/gc-store.cc
@@ -0,0 +1,13 @@
+#include "gc-store.hh"
+
+namespace nix {
+
+GcStore & requireGcStore(Store & store)
+{
+ auto * gcStore = dynamic_cast<GcStore *>(&store);
+ if (!gcStore)
+ throw UsageError("Garbage collection not supported by this store");
+ return *gcStore;
+}
+
+}
diff --git a/src/libstore/gc-store.hh b/src/libstore/gc-store.hh
new file mode 100644
index 000000000..829f70dc4
--- /dev/null
+++ b/src/libstore/gc-store.hh
@@ -0,0 +1,84 @@
+#pragma once
+
+#include "store-api.hh"
+
+
+namespace nix {
+
+
+typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots;
+
+
+struct GCOptions
+{
+ /* Garbage collector operation:
+
+ - `gcReturnLive': return the set of paths reachable from
+ (i.e. in the closure of) the roots.
+
+ - `gcReturnDead': return the set of paths not reachable from
+ the roots.
+
+ - `gcDeleteDead': actually delete the latter set.
+
+ - `gcDeleteSpecific': delete the paths listed in
+ `pathsToDelete', insofar as they are not reachable.
+ */
+ typedef enum {
+ gcReturnLive,
+ gcReturnDead,
+ gcDeleteDead,
+ gcDeleteSpecific,
+ } GCAction;
+
+ GCAction action{gcDeleteDead};
+
+ /* If `ignoreLiveness' is set, then reachability from the roots is
+ ignored (dangerous!). However, the paths must still be
+ unreferenced *within* the store (i.e., there can be no other
+ store paths that depend on them). */
+ bool ignoreLiveness{false};
+
+ /* For `gcDeleteSpecific', the paths to delete. */
+ StorePathSet pathsToDelete;
+
+ /* Stop after at least `maxFreed' bytes have been freed. */
+ uint64_t maxFreed{std::numeric_limits<uint64_t>::max()};
+};
+
+
+struct GCResults
+{
+ /* Depending on the action, the GC roots, or the paths that would
+ be or have been deleted. */
+ PathSet paths;
+
+ /* For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the
+ number of bytes that would be or was freed. */
+ uint64_t bytesFreed = 0;
+};
+
+
+struct GcStore : public virtual Store
+{
+ /* Add an indirect root, which is merely a symlink to `path' from
+ /nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed
+ to be a symlink to a store path. The garbage collector will
+ automatically remove the indirect root when it finds that
+ `path' has disappeared. */
+ virtual void addIndirectRoot(const Path & path) = 0;
+
+ /* Find the roots of the garbage collector. Each root is a pair
+ (link, storepath) where `link' is the path of the symlink
+ outside of the Nix store that point to `storePath'. If
+ 'censor' is true, privacy-sensitive information about roots
+ found in /proc is censored. */
+ virtual Roots findRoots(bool censor) = 0;
+
+ /* Perform a garbage collection. */
+ virtual void collectGarbage(const GCOptions & options, GCResults & results) = 0;
+};
+
+GcStore & requireGcStore(Store & store);
+
+}
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index e35199b3d..024da66c1 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -47,9 +47,8 @@ static void makeSymlink(const Path & link, const Path & target)
void LocalStore::addIndirectRoot(const Path & path)
{
- string hash = hashString(htSHA1, path).to_string(Base32, false);
- Path realRoot = canonPath((format("%1%/%2%/auto/%3%")
- % stateDir % gcRootsDir % hash).str());
+ std::string hash = hashString(htSHA1, path).to_string(Base32, false);
+ Path realRoot = canonPath(fmt("%1%/%2%/auto/%3%", stateDir, gcRootsDir, hash));
makeSymlink(realRoot, path);
}
@@ -162,7 +161,7 @@ void LocalStore::addTempRoot(const StorePath & path)
}
/* Append the store path to the temporary roots file. */
- string s = printStorePath(path) + '\0';
+ auto s = printStorePath(path) + '\0';
writeFull(state->fdTempRoots.get(), s);
}
@@ -203,12 +202,12 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
}
/* Read the entire file. */
- string contents = readFile(fd.get());
+ auto contents = readFile(fd.get());
/* Extract the roots. */
- string::size_type pos = 0, end;
+ std::string::size_type pos = 0, end;
- while ((end = contents.find((char) 0, pos)) != string::npos) {
+ while ((end = contents.find((char) 0, pos)) != std::string::npos) {
Path root(contents, pos, end - pos);
debug("got temporary root '%s'", root);
tempRoots[parseStorePath(root)].emplace(censor ? censored : fmt("{temp:%d}", pid));
@@ -305,7 +304,7 @@ Roots LocalStore::findRoots(bool censor)
typedef std::unordered_map<Path, std::unordered_set<std::string>> UncheckedRoots;
-static void readProcLink(const string & file, UncheckedRoots & roots)
+static void readProcLink(const std::string & file, UncheckedRoots & roots)
{
/* 64 is the starting buffer size gnu readlink uses... */
auto bufsiz = ssize_t{64};
@@ -328,7 +327,7 @@ try_again:
.emplace(file);
}
-static string quoteRegexChars(const string & raw)
+static std::string quoteRegexChars(const std::string & raw)
{
static auto specialRegex = std::regex(R"([.^$\\*+?()\[\]{}|])");
return std::regex_replace(raw, specialRegex, R"(\$&)");
@@ -383,7 +382,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
try {
auto mapFile = fmt("/proc/%s/maps", ent->d_name);
- auto mapLines = tokenizeString<std::vector<string>>(readFile(mapFile), "\n");
+ auto mapLines = tokenizeString<std::vector<std::string>>(readFile(mapFile), "\n");
for (const auto & line : mapLines) {
auto match = std::smatch{};
if (std::regex_match(line, match, mapRegex))
@@ -414,7 +413,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
try {
std::regex lsofRegex(R"(^n(/.*)$)");
auto lsofLines =
- tokenizeString<std::vector<string>>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n");
+ tokenizeString<std::vector<std::string>>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n");
for (const auto & line : lsofLines) {
std::smatch match;
if (std::regex_match(line, match, lsofRegex))
@@ -784,7 +783,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) {
checkInterrupt();
- string name = dirent->d_name;
+ std::string name = dirent->d_name;
if (name == "." || name == ".." || name == linksName) continue;
if (auto storePath = maybeParseStorePath(storeDir + "/" + name))
@@ -825,7 +824,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) {
checkInterrupt();
- string name = dirent->d_name;
+ std::string name = dirent->d_name;
if (name == "." || name == "..") continue;
Path path = linksDir + "/" + name;
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 81ca9cc0f..cc009a026 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -100,7 +100,7 @@ std::vector<Path> getUserConfigFiles()
// Use the paths specified in NIX_USER_CONF_FILES if it has been defined
auto nixConfFiles = getEnv("NIX_USER_CONF_FILES");
if (nixConfFiles.has_value()) {
- return tokenizeString<std::vector<string>>(nixConfFiles.value(), ":");
+ return tokenizeString<std::vector<std::string>>(nixConfFiles.value(), ":");
}
// Use the paths specified by the XDG spec
@@ -181,7 +181,7 @@ bool Settings::isWSL1()
return hasSuffix(utsbuf.release, "-Microsoft");
}
-const string nixVersion = PACKAGE_VERSION;
+const std::string nixVersion = PACKAGE_VERSION;
NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, {
{SandboxMode::smEnabled, true},
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 893c95bd6..feb6899cd 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -113,7 +113,7 @@ public:
bool verboseBuild = true;
Setting<size_t> logLines{this, 10, "log-lines",
- "If `verbose-build` is false, the number of lines of the tail of "
+ "The number of lines of the tail of "
"the log to show if a build fails."};
MaxBuildJobsSetting maxBuildJobs{
@@ -880,55 +880,6 @@ public:
are loaded as plugins (non-recursively).
)"};
- Setting<StringMap> accessTokens{this, {}, "access-tokens",
- R"(
- Access tokens used to access protected GitHub, GitLab, or
- other locations requiring token-based authentication.
-
- Access tokens are specified as a string made up of
- space-separated `host=token` values. The specific token
- used is selected by matching the `host` portion against the
- "host" specification of the input. The actual use of the
- `token` value is determined by the type of resource being
- accessed:
-
- * Github: the token value is the OAUTH-TOKEN string obtained
- as the Personal Access Token from the Github server (see
- https://docs.github.com/en/developers/apps/authorizing-oath-apps).
-
- * Gitlab: the token value is either the OAuth2 token or the
- Personal Access Token (these are different types tokens
- for gitlab, see
- https://docs.gitlab.com/12.10/ee/api/README.html#authentication).
- The `token` value should be `type:tokenstring` where
- `type` is either `OAuth2` or `PAT` to indicate which type
- of token is being specified.
-
- Example `~/.config/nix/nix.conf`:
-
- ```
- access-tokens = github.com=23ac...b289 gitlab.mycompany.com=PAT:A123Bp_Cd..EfG gitlab.com=OAuth2:1jklw3jk
- ```
-
- Example `~/code/flake.nix`:
-
- ```nix
- input.foo = {
- type = "gitlab";
- host = "gitlab.mycompany.com";
- owner = "mycompany";
- repo = "pro";
- };
- ```
-
- This example specifies three tokens, one each for accessing
- github.com, gitlab.mycompany.com, and sourceforge.net.
-
- The `input.foo` uses the "gitlab" fetcher, which might
- requires specifying the token type along with the token
- value.
- )"};
-
Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features",
"Experimental Nix features to enable."};
@@ -936,18 +887,9 @@ public:
void requireExperimentalFeature(const ExperimentalFeature &);
- Setting<bool> allowDirty{this, true, "allow-dirty",
- "Whether to allow dirty Git/Mercurial trees."};
-
- Setting<bool> warnDirty{this, true, "warn-dirty",
- "Whether to warn about dirty Git/Mercurial trees."};
-
Setting<size_t> narBufferSize{this, 32 * 1024 * 1024, "nar-buffer-size",
"Maximum size of NARs before spilling them to disk."};
- Setting<std::string> flakeRegistry{this, "https://github.com/NixOS/flake-registry/raw/master/flake-registry.json", "flake-registry",
- "Path or URI of the global flake registry."};
-
Setting<bool> allowSymlinkedStore{
this, false, "allow-symlinked-store",
R"(
@@ -960,19 +902,6 @@ public:
resolves to a different location from that of the build machine. You
can enable this setting if you are sure you're not going to do that.
)"};
-
- Setting<bool> useRegistries{this, true, "use-registries",
- "Whether to use flake registries to resolve flake references."};
-
- Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config",
- "Whether to accept nix configuration from a flake without prompting."};
-
- Setting<std::string> commitLockFileSummary{
- this, "", "commit-lockfile-summary",
- R"(
- The commit summary to use when committing changed flake lock files. If
- empty, the summary is generated based on the action performed.
- )"};
};
@@ -988,6 +917,6 @@ void loadConfFile();
// Used by the Settings constructor
std::vector<Path> getUserConfigFiles();
-extern const string nixVersion;
+extern const std::string nixVersion;
}
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index f8b2662af..dd34b19c6 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -2,6 +2,7 @@
#include "pool.hh"
#include "remote-store.hh"
#include "serve-protocol.hh"
+#include "build-result.hh"
#include "store-api.hh"
#include "path-with-outputs.hh"
#include "worker-protocol.hh"
@@ -48,7 +49,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
static std::set<std::string> uriSchemes() { return {"ssh"}; }
- LegacySSHStore(const string & scheme, const string & host, const Params & params)
+ LegacySSHStore(const std::string & scheme, const std::string & host, const Params & params)
: StoreConfig(params)
, LegacySSHStoreConfig(params)
, Store(params)
@@ -107,7 +108,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
return conn;
};
- string getUri() override
+ std::string getUri() override
{
return *uriSchemes().begin() + "://" + host;
}
@@ -225,13 +226,21 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ unsupported("queryPathFromHashPart"); }
- StorePath addToStore(const string & name, const Path & srcPath,
- FileIngestionMethod method, HashType hashAlgo,
- PathFilter & filter, RepairFlag repair, const StorePathSet & references) override
+ StorePath addToStore(
+ std::string_view name,
+ const Path & srcPath,
+ FileIngestionMethod method,
+ HashType hashAlgo,
+ PathFilter & filter,
+ RepairFlag repair,
+ const StorePathSet & references) override
{ unsupported("addToStore"); }
- StorePath addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair) override
+ StorePath addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair) override
{ unsupported("addTextToStore"); }
private:
@@ -270,7 +279,7 @@ public:
conn->to.flush();
- BuildResult status;
+ BuildResult status { .path = DerivedPath::Built { .drvPath = drvPath } };
status.status = (BuildResult::Status) readInt(conn->from);
conn->from >> status.errorMsg;
@@ -308,7 +317,7 @@ public:
conn->to.flush();
- BuildResult result;
+ BuildResult result { .path = DerivedPath::Opaque { StorePath::dummy } };
result.status = (BuildResult::Status) readInt(conn->from);
if (!result.success()) {
diff --git a/src/libstore/local-fs-store.cc b/src/libstore/local-fs-store.cc
index c933251db..c5ae7536f 100644
--- a/src/libstore/local-fs-store.cc
+++ b/src/libstore/local-fs-store.cc
@@ -85,7 +85,7 @@ void LocalFSStore::narFromPath(const StorePath & path, Sink & sink)
dumpPath(getRealStoreDir() + std::string(printStorePath(path), storeDir.size()), sink);
}
-const string LocalFSStore::drvsLogDir = "drvs";
+const std::string LocalFSStore::drvsLogDir = "drvs";
std::optional<std::string> LocalFSStore::getBuildLog(const StorePath & path_)
{
diff --git a/src/libstore/local-fs-store.hh b/src/libstore/local-fs-store.hh
index e44b27cc2..fbd49dc2c 100644
--- a/src/libstore/local-fs-store.hh
+++ b/src/libstore/local-fs-store.hh
@@ -1,6 +1,7 @@
#pragma once
#include "store-api.hh"
+#include "gc-store.hh"
namespace nix {
@@ -23,11 +24,11 @@ struct LocalFSStoreConfig : virtual StoreConfig
"physical path to the Nix store"};
};
-class LocalFSStore : public virtual LocalFSStoreConfig, public virtual Store
+class LocalFSStore : public virtual LocalFSStoreConfig, public virtual Store, virtual GcStore
{
public:
- const static string drvsLogDir;
+ const static std::string drvsLogDir;
LocalFSStore(const Params & params);
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 1a02b916a..1ee71b1c0 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -70,7 +70,7 @@ int getSchema(Path schemaPath)
{
int curSchema = 0;
if (pathExists(schemaPath)) {
- string s = readFile(schemaPath);
+ auto s = readFile(schemaPath);
auto n = string2Int<int>(s);
if (!n)
throw Error("'%1%' is corrupt", schemaPath);
@@ -239,7 +239,7 @@ LocalStore::LocalStore(const Params & params)
res = posix_fallocate(fd.get(), 0, settings.reservedSize);
#endif
if (res == -1) {
- writeFull(fd.get(), string(settings.reservedSize, 'X'));
+ writeFull(fd.get(), std::string(settings.reservedSize, 'X'));
[[gnu::unused]] auto res2 = ftruncate(fd.get(), settings.reservedSize);
}
}
@@ -450,7 +450,7 @@ void LocalStore::openDB(State & state, bool create)
throw SysError("Nix database directory '%1%' is not writable", dbDir);
/* Open the Nix database. */
- string dbPath = dbDir + "/db.sqlite";
+ std::string dbPath = dbDir + "/db.sqlite";
auto & db(state.db);
state.db = SQLite(dbPath, create);
@@ -471,19 +471,19 @@ void LocalStore::openDB(State & state, bool create)
should be safe enough. If the user asks for it, don't sync at
all. This can cause database corruption if the system
crashes. */
- string syncMode = settings.fsyncMetadata ? "normal" : "off";
+ std::string syncMode = settings.fsyncMetadata ? "normal" : "off";
db.exec("pragma synchronous = " + syncMode);
/* Set the SQLite journal mode. WAL mode is fastest, so it's the
default. */
- string mode = settings.useSQLiteWAL ? "wal" : "truncate";
- string prevMode;
+ std::string mode = settings.useSQLiteWAL ? "wal" : "truncate";
+ std::string prevMode;
{
SQLiteStmt stmt;
stmt.create(db, "pragma main.journal_mode;");
if (sqlite3_step(stmt) != SQLITE_ROW)
throwSQLiteError(db, "querying journal mode");
- prevMode = string((const char *) sqlite3_column_text(stmt, 0));
+ prevMode = std::string((const char *) sqlite3_column_text(stmt, 0));
}
if (prevMode != mode &&
sqlite3_exec(db, ("pragma main.journal_mode = " + mode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
@@ -679,7 +679,7 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
{
assert(drvPath.isDerivation());
std::string drvName(drvPath.name());
- drvName = string(drvName, 0, drvName.size() - drvExtension.size());
+ drvName = drvName.substr(0, drvName.size() - drvExtension.size());
auto envHasRightPath = [&](const StorePath & actual, const std::string & varName)
{
@@ -786,7 +786,11 @@ void LocalStore::registerDrvOutput(const Realisation & info)
});
}
-void LocalStore::cacheDrvOutputMapping(State & state, const uint64_t deriver, const string & outputName, const StorePath & output)
+void LocalStore::cacheDrvOutputMapping(
+ State & state,
+ const uint64_t deriver,
+ const std::string & outputName,
+ const StorePath & output)
{
retrySQLite<void>([&]() {
state.stmts->AddDerivationOutput.use()
@@ -795,7 +799,6 @@ void LocalStore::cacheDrvOutputMapping(State & state, const uint64_t deriver, co
(printStorePath(output))
.exec();
});
-
}
@@ -1436,7 +1439,9 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
}
-StorePath LocalStore::addTextToStore(const string & name, const string & s,
+StorePath LocalStore::addTextToStore(
+ std::string_view name,
+ std::string_view s,
const StorePathSet & references, RepairFlag repair)
{
auto hash = hashString(htSHA256, s);
@@ -1548,7 +1553,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
for (auto & link : readDirectory(linksDir)) {
printMsg(lvlTalkative, "checking contents of '%s'", link.name);
Path linkPath = linksDir + "/" + link.name;
- string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false);
+ std::string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false);
if (hash != link.name) {
printError("link '%s' was modified! expected hash '%s', got '%s'",
linkPath, link.name, hash);
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 46aed9bcb..70d225be3 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -5,6 +5,7 @@
#include "pathlocks.hh"
#include "store-api.hh"
#include "local-fs-store.hh"
+#include "gc-store.hh"
#include "sync.hh"
#include "util.hh"
@@ -43,7 +44,7 @@ struct LocalStoreConfig : virtual LocalFSStoreConfig
};
-class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore
+class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore, public virtual GcStore
{
private:
@@ -147,8 +148,11 @@ public:
StorePath addToStoreFromDump(Source & dump, std::string_view name,
FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override;
- StorePath addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair) override;
+ StorePath addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair) override;
void addTempRoot(const StorePath & path) override;
@@ -204,7 +208,11 @@ public:
derivation 'deriver'. */
void registerDrvOutput(const Realisation & info) override;
void registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) override;
- void cacheDrvOutputMapping(State & state, const uint64_t deriver, const string & outputName, const StorePath & output);
+ void cacheDrvOutputMapping(
+ State & state,
+ const uint64_t deriver,
+ const std::string & outputName,
+ const StorePath & output);
std::optional<const Realisation> queryRealisation_(State & state, const DrvOutput & id);
std::optional<std::pair<int64_t, Realisation>> queryRealisationCore_(State & state, const DrvOutput & id);
@@ -292,7 +300,7 @@ private:
typedef std::pair<dev_t, ino_t> Inode;
-typedef set<Inode> InodesSeen;
+typedef std::set<Inode> InodesSeen;
/* "Fix", or canonicalise, the meta-data of the files in a store path
diff --git a/src/libstore/lock.hh b/src/libstore/lock.hh
index 8fbb67ddc..3d29a7b5b 100644
--- a/src/libstore/lock.hh
+++ b/src/libstore/lock.hh
@@ -13,7 +13,7 @@ private:
AutoCloseFD fdUserLock;
bool isEnabled = false;
- string user;
+ std::string user;
uid_t uid = 0;
gid_t gid = 0;
std::vector<gid_t> supplementaryGIDs;
@@ -23,7 +23,7 @@ public:
void kill();
- string getUser() { return user; }
+ std::string getUser() { return user; }
uid_t getUID() { assert(uid); return uid; }
uid_t getGID() { assert(gid); return gid; }
std::vector<gid_t> getSupplementaryGIDs() { return supplementaryGIDs; }
diff --git a/src/libstore/machines.cc b/src/libstore/machines.cc
index b6270a81b..e87f46980 100644
--- a/src/libstore/machines.cc
+++ b/src/libstore/machines.cc
@@ -39,19 +39,19 @@ Machine::Machine(decltype(storeUri) storeUri,
sshPublicHostKey(sshPublicHostKey)
{}
-bool Machine::allSupported(const std::set<string> & features) const
+bool Machine::allSupported(const std::set<std::string> & features) const
{
return std::all_of(features.begin(), features.end(),
- [&](const string & feature) {
+ [&](const std::string & feature) {
return supportedFeatures.count(feature) ||
mandatoryFeatures.count(feature);
});
}
-bool Machine::mandatoryMet(const std::set<string> & features) const
+bool Machine::mandatoryMet(const std::set<std::string> & features) const
{
return std::all_of(mandatoryFeatures.begin(), mandatoryFeatures.end(),
- [&](const string & feature) {
+ [&](const std::string & feature) {
return features.count(feature);
});
}
@@ -89,7 +89,7 @@ ref<Store> Machine::openStore() const
static std::vector<std::string> expandBuilderLines(const std::string & builders)
{
std::vector<std::string> result;
- for (auto line : tokenizeString<std::vector<string>>(builders, "\n;")) {
+ for (auto line : tokenizeString<std::vector<std::string>>(builders, "\n;")) {
trim(line);
line.erase(std::find(line.begin(), line.end(), '#'), line.end());
if (line.empty()) continue;
@@ -117,7 +117,7 @@ static std::vector<std::string> expandBuilderLines(const std::string & builders)
static Machine parseBuilderLine(const std::string & line)
{
- const auto tokens = tokenizeString<std::vector<string>>(line);
+ const auto tokens = tokenizeString<std::vector<std::string>>(line);
auto isSet = [&](size_t fieldIndex) {
return tokens.size() > fieldIndex && tokens[fieldIndex] != "" && tokens[fieldIndex] != "-";
@@ -146,17 +146,18 @@ static Machine parseBuilderLine(const std::string & line)
return {
tokens[0],
- isSet(1) ? tokenizeString<std::vector<string>>(tokens[1], ",") : std::vector<string>{settings.thisSystem},
+ isSet(1) ? tokenizeString<std::vector<std::string>>(tokens[1], ",") : std::vector<std::string>{settings.thisSystem},
isSet(2) ? tokens[2] : "",
isSet(3) ? parseUnsignedIntField(3) : 1U,
isSet(4) ? parseUnsignedIntField(4) : 1U,
- isSet(5) ? tokenizeString<std::set<string>>(tokens[5], ",") : std::set<string>{},
- isSet(6) ? tokenizeString<std::set<string>>(tokens[6], ",") : std::set<string>{},
+ isSet(5) ? tokenizeString<std::set<std::string>>(tokens[5], ",") : std::set<std::string>{},
+ isSet(6) ? tokenizeString<std::set<std::string>>(tokens[6], ",") : std::set<std::string>{},
isSet(7) ? ensureBase64(7) : ""
};
}
-static Machines parseBuilderLines(const std::vector<std::string>& builders) {
+static Machines parseBuilderLines(const std::vector<std::string> & builders)
+{
Machines result;
std::transform(builders.begin(), builders.end(), std::back_inserter(result), parseBuilderLine);
return result;
diff --git a/src/libstore/machines.hh b/src/libstore/machines.hh
index 341d9bd97..834626de9 100644
--- a/src/libstore/machines.hh
+++ b/src/libstore/machines.hh
@@ -8,19 +8,19 @@ class Store;
struct Machine {
- const string storeUri;
- const std::vector<string> systemTypes;
- const string sshKey;
+ const std::string storeUri;
+ const std::vector<std::string> systemTypes;
+ const std::string sshKey;
const unsigned int maxJobs;
const unsigned int speedFactor;
- const std::set<string> supportedFeatures;
- const std::set<string> mandatoryFeatures;
+ const std::set<std::string> supportedFeatures;
+ const std::set<std::string> mandatoryFeatures;
const std::string sshPublicHostKey;
bool enabled = true;
- bool allSupported(const std::set<string> & features) const;
+ bool allSupported(const std::set<std::string> & features) const;
- bool mandatoryMet(const std::set<string> & features) const;
+ bool mandatoryMet(const std::set<std::string> & features) const;
Machine(decltype(storeUri) storeUri,
decltype(systemTypes) systemTypes,
diff --git a/src/libstore/names.hh b/src/libstore/names.hh
index 6f01fe2a1..3977fc6cc 100644
--- a/src/libstore/names.hh
+++ b/src/libstore/names.hh
@@ -10,9 +10,9 @@ struct Regex;
struct DrvName
{
- string fullName;
- string name;
- string version;
+ std::string fullName;
+ std::string name;
+ std::string version;
unsigned int hits;
DrvName();
@@ -25,7 +25,7 @@ private:
std::unique_ptr<Regex> regex;
};
-typedef list<DrvName> DrvNames;
+typedef std::list<DrvName> DrvNames;
std::string_view nextComponent(std::string_view::const_iterator & p,
const std::string_view::const_iterator end);
diff --git a/src/libstore/nar-accessor.cc b/src/libstore/nar-accessor.cc
index 7d27d7667..72d41cc94 100644
--- a/src/libstore/nar-accessor.cc
+++ b/src/libstore/nar-accessor.cc
@@ -90,7 +90,7 @@ struct NarAccessor : public FSAccessor
void receiveContents(std::string_view data) override
{ }
- void createSymlink(const Path & path, const string & target) override
+ void createSymlink(const Path & path, const std::string & target) override
{
createMember(path,
NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target});
diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc
index 49079388a..2d75e7a82 100644
--- a/src/libstore/nar-info.cc
+++ b/src/libstore/nar-info.cc
@@ -11,7 +11,7 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
return Error("NAR info file '%1%' is corrupt", whence);
};
- auto parseHashField = [&](const string & s) {
+ auto parseHashField = [&](const std::string & s) {
try {
return Hash::parseAnyPrefixed(s);
} catch (BadHash &) {
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index 13cb142f8..8af9b1dde 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -77,7 +77,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa
continue;
}
- string name = dirent->d_name;
+ std::string name = dirent->d_name;
if (name == "." || name == "..") continue;
names.push_back(name);
}
diff --git a/src/libstore/path-with-outputs.cc b/src/libstore/path-with-outputs.cc
index e5a121e00..078c117bd 100644
--- a/src/libstore/path-with-outputs.cc
+++ b/src/libstore/path-with-outputs.cc
@@ -22,9 +22,9 @@ DerivedPath StorePathWithOutputs::toDerivedPath() const
std::vector<DerivedPath> toDerivedPaths(const std::vector<StorePathWithOutputs> ss)
{
- std::vector<DerivedPath> reqs;
- for (auto & s : ss) reqs.push_back(s.toDerivedPath());
- return reqs;
+ std::vector<DerivedPath> reqs;
+ for (auto & s : ss) reqs.push_back(s.toDerivedPath());
+ return reqs;
}
@@ -49,9 +49,9 @@ std::pair<std::string_view, StringSet> parsePathWithOutputs(std::string_view s)
{
size_t n = s.find("!");
return n == s.npos
- ? std::make_pair(s, std::set<string>())
+ ? std::make_pair(s, std::set<std::string>())
: std::make_pair(((std::string_view) s).substr(0, n),
- tokenizeString<std::set<string>>(((std::string_view) s).substr(n + 1), ","));
+ tokenizeString<std::set<std::string>>(((std::string_view) s).substr(n + 1), ","));
}
diff --git a/src/libstore/path.hh b/src/libstore/path.hh
index 06ba0663b..e65fee622 100644
--- a/src/libstore/path.hh
+++ b/src/libstore/path.hh
@@ -62,7 +62,7 @@ public:
typedef std::set<StorePath> StorePathSet;
typedef std::vector<StorePath> StorePaths;
-typedef std::map<string, StorePath> OutputPathMap;
+typedef std::map<std::string, StorePath> OutputPathMap;
typedef std::map<StorePath, std::optional<ContentAddress>> StorePathCAMap;
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index 2da74e262..42023cd0a 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -74,7 +74,7 @@ PathLocks::PathLocks()
}
-PathLocks::PathLocks(const PathSet & paths, const string & waitMsg)
+PathLocks::PathLocks(const PathSet & paths, const std::string & waitMsg)
: deletePaths(false)
{
lockPaths(paths, waitMsg);
@@ -82,7 +82,7 @@ PathLocks::PathLocks(const PathSet & paths, const string & waitMsg)
bool PathLocks::lockPaths(const PathSet & paths,
- const string & waitMsg, bool wait)
+ const std::string & waitMsg, bool wait)
{
assert(fds.empty());
diff --git a/src/libstore/pathlocks.hh b/src/libstore/pathlocks.hh
index 919c8904c..5e3a734b4 100644
--- a/src/libstore/pathlocks.hh
+++ b/src/libstore/pathlocks.hh
@@ -20,15 +20,15 @@ class PathLocks
{
private:
typedef std::pair<int, Path> FDPair;
- list<FDPair> fds;
+ std::list<FDPair> fds;
bool deletePaths;
public:
PathLocks();
PathLocks(const PathSet & paths,
- const string & waitMsg = "");
+ const std::string & waitMsg = "");
bool lockPaths(const PathSet & _paths,
- const string & waitMsg = "",
+ const std::string & waitMsg = "",
bool wait = true);
~PathLocks();
void unlock();
diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc
index 73163424c..3e4188188 100644
--- a/src/libstore/profiles.cc
+++ b/src/libstore/profiles.cc
@@ -15,12 +15,12 @@ namespace nix {
/* Parse a generation name of the format
`<profilename>-<number>-link'. */
-static std::optional<GenerationNumber> parseName(const string & profileName, const string & name)
+static std::optional<GenerationNumber> parseName(const std::string & profileName, const std::string & name)
{
- if (string(name, 0, profileName.size() + 1) != profileName + "-") return {};
- string s = string(name, profileName.size() + 1);
- string::size_type p = s.find("-link");
- if (p == string::npos) return {};
+ if (name.substr(0, profileName.size() + 1) != profileName + "-") return {};
+ auto s = name.substr(profileName.size() + 1);
+ auto p = s.find("-link");
+ if (p == std::string::npos) return {};
if (auto n = string2Int<unsigned int>(s.substr(0, p)))
return *n;
else
@@ -209,13 +209,13 @@ void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun)
}
-void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, bool dryRun)
+void deleteGenerationsOlderThan(const Path & profile, std::string_view timeSpec, bool dryRun)
{
if (timeSpec.empty() || timeSpec[timeSpec.size() - 1] != 'd')
throw UsageError("invalid number of days specifier '%1%', expected something like '14d'", timeSpec);
time_t curTime = time(0);
- string strDays = string(timeSpec, 0, timeSpec.size() - 1);
+ auto strDays = timeSpec.substr(0, timeSpec.size() - 1);
auto days = string2Int<int>(strDays);
if (!days || *days < 1)
@@ -274,7 +274,7 @@ void lockProfile(PathLocks & lock, const Path & profile)
}
-string optimisticLockProfile(const Path & profile)
+std::string optimisticLockProfile(const Path & profile)
{
return pathExists(profile) ? readLink(profile) : "";
}
diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh
index d100c970c..408ca039c 100644
--- a/src/libstore/profiles.hh
+++ b/src/libstore/profiles.hh
@@ -42,7 +42,7 @@ void deleteOldGenerations(const Path & profile, bool dryRun);
void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun);
-void deleteGenerationsOlderThan(const Path & profile, const string & timeSpec, bool dryRun);
+void deleteGenerationsOlderThan(const Path & profile, std::string_view timeSpec, bool dryRun);
void switchLink(Path link, Path target);
@@ -66,7 +66,7 @@ void lockProfile(PathLocks & lock, const Path & profile);
generally cheap, since the build results are still in the Nix
store. Most of the time, only the user environment has to be
rebuilt. */
-string optimisticLockProfile(const Path & profile);
+std::string optimisticLockProfile(const Path & profile);
/* Resolve ~/.nix-profile. If ~/.nix-profile doesn't exist yet, create
it. */
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index 91b3fc142..34dce092c 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -68,7 +68,7 @@ void RefScanSink::operator () (std::string_view data)
std::pair<StorePathSet, HashResult> scanForReferences(
- const string & path,
+ const std::string & path,
const StorePathSet & refs)
{
HashSink hashSink { htSHA256 };
@@ -121,7 +121,7 @@ void RewritingSink::operator () (std::string_view data)
s.append(data);
size_t j = 0;
- while ((j = s.find(from, j)) != string::npos) {
+ while ((j = s.find(from, j)) != std::string::npos) {
matches.push_back(pos + j);
s.replace(j, from.size(), to);
}
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index c6f083dea..347e32094 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -1,7 +1,9 @@
#include "serialise.hh"
#include "util.hh"
#include "path-with-outputs.hh"
+#include "gc-store.hh"
#include "remote-fs-accessor.hh"
+#include "build-result.hh"
#include "remote-store.hh"
#include "worker-protocol.hh"
#include "archive.hh"
@@ -89,6 +91,35 @@ void write(const Store & store, Sink & out, const DrvOutput & drvOutput)
}
+BuildResult read(const Store & store, Source & from, Phantom<BuildResult> _)
+{
+ auto path = worker_proto::read(store, from, Phantom<DerivedPath> {});
+ BuildResult res { .path = path };
+ res.status = (BuildResult::Status) readInt(from);
+ from
+ >> res.errorMsg
+ >> res.timesBuilt
+ >> res.isNonDeterministic
+ >> res.startTime
+ >> res.stopTime;
+ res.builtOutputs = worker_proto::read(store, from, Phantom<DrvOutputs> {});
+ return res;
+}
+
+void write(const Store & store, Sink & to, const BuildResult & res)
+{
+ worker_proto::write(store, to, res.path);
+ to
+ << res.status
+ << res.errorMsg
+ << res.timesBuilt
+ << res.isNonDeterministic
+ << res.startTime
+ << res.stopTime;
+ worker_proto::write(store, to, res.builtOutputs);
+}
+
+
std::optional<StorePath> read(const Store & store, Source & from, Phantom<std::optional<StorePath>> _)
{
auto s = readString(from);
@@ -661,8 +692,11 @@ void RemoteStore::addMultipleToStore(
}
-StorePath RemoteStore::addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair)
+StorePath RemoteStore::addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair)
{
StringSource source(s);
return addCAToStore(source, name, TextHashMethod{}, references, repair)->path;
@@ -742,17 +776,24 @@ static void writeDerivedPaths(RemoteStore & store, ConnectionHandle & conn, cons
}
}
-void RemoteStore::buildPaths(const std::vector<DerivedPath> & drvPaths, BuildMode buildMode, std::shared_ptr<Store> evalStore)
+void RemoteStore::copyDrvsFromEvalStore(
+ const std::vector<DerivedPath> & paths,
+ std::shared_ptr<Store> evalStore)
{
if (evalStore && evalStore.get() != this) {
/* The remote doesn't have a way to access evalStore, so copy
the .drvs. */
RealisedPath::Set drvPaths2;
- for (auto & i : drvPaths)
+ for (auto & i : paths)
if (auto p = std::get_if<DerivedPath::Built>(&i))
drvPaths2.insert(p->drvPath);
copyClosure(*evalStore, *this, drvPaths2);
}
+}
+
+void RemoteStore::buildPaths(const std::vector<DerivedPath> & drvPaths, BuildMode buildMode, std::shared_ptr<Store> evalStore)
+{
+ copyDrvsFromEvalStore(drvPaths, evalStore);
auto conn(getConnection());
conn->to << wopBuildPaths;
@@ -769,6 +810,91 @@ void RemoteStore::buildPaths(const std::vector<DerivedPath> & drvPaths, BuildMod
readInt(conn->from);
}
+std::vector<BuildResult> RemoteStore::buildPathsWithResults(
+ const std::vector<DerivedPath> & paths,
+ BuildMode buildMode,
+ std::shared_ptr<Store> evalStore)
+{
+ copyDrvsFromEvalStore(paths, evalStore);
+
+ std::optional<ConnectionHandle> conn_(getConnection());
+ auto & conn = *conn_;
+
+ if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 34) {
+ conn->to << wopBuildPathsWithResults;
+ writeDerivedPaths(*this, conn, paths);
+ conn->to << buildMode;
+ conn.processStderr();
+ return worker_proto::read(*this, conn->from, Phantom<std::vector<BuildResult>> {});
+ } else {
+ // Avoid deadlock.
+ conn_.reset();
+
+ // Note: this throws an exception if a build/substitution
+ // fails, but meh.
+ buildPaths(paths, buildMode, evalStore);
+
+ std::vector<BuildResult> results;
+
+ for (auto & path : paths) {
+ std::visit(
+ overloaded {
+ [&](const DerivedPath::Opaque & bo) {
+ results.push_back(BuildResult {
+ .status = BuildResult::Substituted,
+ .path = bo,
+ });
+ },
+ [&](const DerivedPath::Built & bfd) {
+ BuildResult res {
+ .status = BuildResult::Built,
+ .path = bfd,
+ };
+
+ OutputPathMap outputs;
+ auto drv = evalStore->readDerivation(bfd.drvPath);
+ auto outputHashes = staticOutputHashes(*evalStore, drv); // FIXME: expensive
+ auto drvOutputs = drv.outputsAndOptPaths(*this);
+ for (auto & output : bfd.outputs) {
+ if (!outputHashes.count(output))
+ throw Error(
+ "the derivation '%s' doesn't have an output named '%s'",
+ printStorePath(bfd.drvPath), output);
+ auto outputId =
+ DrvOutput{outputHashes.at(output), output};
+ if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ auto realisation =
+ queryRealisation(outputId);
+ if (!realisation)
+ throw Error(
+ "cannot operate on an output of unbuilt "
+ "content-addressed derivation '%s'",
+ outputId.to_string());
+ res.builtOutputs.emplace(realisation->id, *realisation);
+ } else {
+ // If ca-derivations isn't enabled, assume that
+ // the output path is statically known.
+ assert(drvOutputs.count(output));
+ assert(drvOutputs.at(output).second);
+ res.builtOutputs.emplace(
+ outputId,
+ Realisation {
+ .id = outputId,
+ .outPath = *drvOutputs.at(output).second
+ });
+ }
+ }
+
+ results.push_back(res);
+ }
+ },
+ path.raw());
+ }
+
+ return results;
+ }
+}
+
BuildResult RemoteStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode)
@@ -778,7 +904,7 @@ BuildResult RemoteStore::buildDerivation(const StorePath & drvPath, const BasicD
writeDerivation(conn->to, *this, drv);
conn->to << buildMode;
conn.processStderr();
- BuildResult res;
+ BuildResult res { .path = DerivedPath::Built { .drvPath = drvPath } };
res.status = (BuildResult::Status) readInt(conn->from);
conn->from >> res.errorMsg;
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 29) {
@@ -1000,7 +1126,7 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
auto msg = readNum<uint64_t>(from);
if (msg == STDERR_WRITE) {
- string s = readString(from);
+ auto s = readString(from);
if (!sink) throw Error("no sink");
(*sink)(s);
}
@@ -1017,7 +1143,7 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
if (GET_PROTOCOL_MINOR(daemonVersion) >= 26) {
return std::make_exception_ptr(readError(from));
} else {
- string error = readString(from);
+ auto error = readString(from);
unsigned int status = readInt(from);
return std::make_exception_ptr(Error(status, error));
}
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 55cfd5cc6..9f6f50593 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -4,6 +4,7 @@
#include <string>
#include "store-api.hh"
+#include "gc-store.hh"
namespace nix {
@@ -29,7 +30,7 @@ struct RemoteStoreConfig : virtual StoreConfig
/* FIXME: RemoteStore is a misnomer - should be something like
DaemonStore. */
-class RemoteStore : public virtual RemoteStoreConfig, public virtual Store
+class RemoteStore : public virtual RemoteStoreConfig, public virtual Store, public virtual GcStore
{
public:
@@ -83,8 +84,11 @@ public:
RepairFlag repair,
CheckSigsFlag checkSigs) override;
- StorePath addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair) override;
+ StorePath addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair) override;
void registerDrvOutput(const Realisation & info) override;
@@ -93,6 +97,11 @@ public:
void buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode, std::shared_ptr<Store> evalStore) override;
+ std::vector<BuildResult> buildPathsWithResults(
+ const std::vector<DerivedPath> & paths,
+ BuildMode buildMode,
+ std::shared_ptr<Store> evalStore) override;
+
BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode) override;
@@ -167,6 +176,9 @@ private:
std::atomic_bool failed{false};
+ void copyDrvsFromEvalStore(
+ const std::vector<DerivedPath> & paths,
+ std::shared_ptr<Store> evalStore);
};
diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc
index a024e971d..844553ad3 100644
--- a/src/libstore/s3-binary-cache-store.cc
+++ b/src/libstore/s3-binary-cache-store.cc
@@ -87,7 +87,11 @@ static void initAWS()
});
}
-S3Helper::S3Helper(const string & profile, const string & region, const string & scheme, const string & endpoint)
+S3Helper::S3Helper(
+ const std::string & profile,
+ const std::string & region,
+ const std::string & scheme,
+ const std::string & endpoint)
: config(makeConfig(region, scheme, endpoint))
, client(make_ref<Aws::S3::S3Client>(
profile == ""
@@ -121,7 +125,10 @@ class RetryStrategy : public Aws::Client::DefaultRetryStrategy
}
};
-ref<Aws::Client::ClientConfiguration> S3Helper::makeConfig(const string & region, const string & scheme, const string & endpoint)
+ref<Aws::Client::ClientConfiguration> S3Helper::makeConfig(
+ const std::string & region,
+ const std::string & scheme,
+ const std::string & endpoint)
{
initAWS();
auto res = make_ref<Aws::Client::ClientConfiguration>();
diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc
index 1d6baf02d..e6ecadd7f 100644
--- a/src/libstore/sqlite.cc
+++ b/src/libstore/sqlite.cc
@@ -71,7 +71,7 @@ uint64_t SQLite::getLastInsertedRowId()
return sqlite3_last_insert_rowid(db);
}
-void SQLiteStmt::create(sqlite3 * db, const string & sql)
+void SQLiteStmt::create(sqlite3 * db, const std::string & sql)
{
checkInterrupt();
assert(!stmt);
diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc
index 93f72675d..1bbad71f2 100644
--- a/src/libstore/ssh.cc
+++ b/src/libstore/ssh.cc
@@ -29,7 +29,7 @@ void SSHMaster::addCommonSSHOpts(Strings & args)
if (!sshPublicHostKey.empty()) {
Path fileName = (Path) *state->tmpDir + "/host-key";
auto p = host.rfind("@");
- string thost = p != string::npos ? string(host, p + 1) : host;
+ std::string thost = p != std::string::npos ? std::string(host, p + 1) : host;
writeFile(fileName, thost + " " + base64Decode(sshPublicHostKey) + "\n");
args.insert(args.end(), {"-oUserKnownHostsFile=" + fileName});
}
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 84767e917..86fa6a211 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -39,7 +39,7 @@ Path Store::followLinksToStore(std::string_view _path) const
Path path = absPath(std::string(_path));
while (!isInStore(path)) {
if (!isLink(path)) break;
- string target = readLink(path);
+ auto target = readLink(path);
path = absPath(target, dirOf(path));
}
if (!isInStore(path))
@@ -138,8 +138,8 @@ StorePath Store::makeStorePath(std::string_view type,
std::string_view hash, std::string_view name) const
{
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
- string s = std::string { type } + ":" + std::string { hash }
- + ":" + storeDir + ":" + std::string { name };
+ auto s = std::string(type) + ":" + std::string(hash)
+ + ":" + storeDir + ":" + std::string(name);
auto h = compressHash(hashString(htSHA256, s), 20);
return StorePath(h, name);
}
@@ -161,7 +161,7 @@ StorePath Store::makeOutputPath(std::string_view id,
static std::string makeType(
const Store & store,
- string && type,
+ std::string && type,
const StorePathSet & references,
bool hasSelfReference = false)
{
@@ -229,15 +229,23 @@ std::pair<StorePath, Hash> Store::computeStorePathForPath(std::string_view name,
}
-StorePath Store::computeStorePathForText(const string & name, const string & s,
+StorePath Store::computeStorePathForText(
+ std::string_view name,
+ std::string_view s,
const StorePathSet & references) const
{
return makeTextPath(name, hashString(htSHA256, s), references);
}
-StorePath Store::addToStore(const string & name, const Path & _srcPath,
- FileIngestionMethod method, HashType hashAlgo, PathFilter & filter, RepairFlag repair, const StorePathSet & references)
+StorePath Store::addToStore(
+ std::string_view name,
+ const Path & _srcPath,
+ FileIngestionMethod method,
+ HashType hashAlgo,
+ PathFilter & filter,
+ RepairFlag repair,
+ const StorePathSet & references)
{
Path srcPath(absPath(_srcPath));
auto source = sinkToSource([&](Sink & sink) {
@@ -688,10 +696,10 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m
/* Return a string accepted by decodeValidPathInfo() that
registers the specified paths as valid. Note: it's the
responsibility of the caller to provide a closure. */
-string Store::makeValidityRegistration(const StorePathSet & paths,
+std::string Store::makeValidityRegistration(const StorePathSet & paths,
bool showDerivers, bool showHash)
{
- string s = "";
+ std::string s = "";
for (auto & i : paths) {
s += printStorePath(i) + "\n";
@@ -761,11 +769,11 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store
for (auto & storePath : storePaths) {
auto jsonPath = jsonList.object();
- jsonPath.attr("path", printStorePath(storePath));
try {
auto info = queryPathInfo(storePath);
+ jsonPath.attr("path", printStorePath(info->path));
jsonPath
.attr("narHash", info->narHash.to_string(hashBase, true))
.attr("narSize", info->narSize);
@@ -819,6 +827,7 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store
}
} catch (InvalidPath &) {
+ jsonPath.attr("path", printStorePath(storePath));
jsonPath.attr("valid", false);
}
}
@@ -1130,7 +1139,7 @@ std::optional<ValidPathInfo> decodeValidPathInfo(const Store & store, std::istre
getline(str, path);
if (str.eof()) { return {}; }
if (!hashGiven) {
- string s;
+ std::string s;
getline(str, s);
auto narHash = Hash::parseAny(s, htSHA256);
getline(str, s);
@@ -1143,7 +1152,7 @@ std::optional<ValidPathInfo> decodeValidPathInfo(const Store & store, std::istre
std::string deriver;
getline(str, deriver);
if (deriver != "") info.deriver = store.parseStorePath(deriver);
- string s;
+ std::string s;
getline(str, s);
auto n = string2Int<int>(s);
if (!n) throw Error("number expected");
@@ -1167,7 +1176,7 @@ std::string Store::showPaths(const StorePathSet & paths)
}
-string showPaths(const PathSet & paths)
+std::string showPaths(const PathSet & paths)
{
return concatStringsSep(", ", quoteStrings(paths));
}
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 90d2e93ed..e99a3f2cb 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -76,127 +76,10 @@ enum AllowInvalidFlag : bool { DisallowInvalid = false, AllowInvalid = true };
const uint32_t exportMagic = 0x4558494e;
-typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots;
-
-
-struct GCOptions
-{
- /* Garbage collector operation:
-
- - `gcReturnLive': return the set of paths reachable from
- (i.e. in the closure of) the roots.
-
- - `gcReturnDead': return the set of paths not reachable from
- the roots.
-
- - `gcDeleteDead': actually delete the latter set.
-
- - `gcDeleteSpecific': delete the paths listed in
- `pathsToDelete', insofar as they are not reachable.
- */
- typedef enum {
- gcReturnLive,
- gcReturnDead,
- gcDeleteDead,
- gcDeleteSpecific,
- } GCAction;
-
- GCAction action{gcDeleteDead};
-
- /* If `ignoreLiveness' is set, then reachability from the roots is
- ignored (dangerous!). However, the paths must still be
- unreferenced *within* the store (i.e., there can be no other
- store paths that depend on them). */
- bool ignoreLiveness{false};
-
- /* For `gcDeleteSpecific', the paths to delete. */
- StorePathSet pathsToDelete;
-
- /* Stop after at least `maxFreed' bytes have been freed. */
- uint64_t maxFreed{std::numeric_limits<uint64_t>::max()};
-};
-
-
-struct GCResults
-{
- /* Depending on the action, the GC roots, or the paths that would
- be or have been deleted. */
- PathSet paths;
-
- /* For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the
- number of bytes that would be or was freed. */
- uint64_t bytesFreed = 0;
-};
-
-
enum BuildMode { bmNormal, bmRepair, bmCheck };
+struct BuildResult;
-struct BuildResult
-{
- /* Note: don't remove status codes, and only add new status codes
- at the end of the list, to prevent client/server
- incompatibilities in the nix-store --serve protocol. */
- enum Status {
- Built = 0,
- Substituted,
- AlreadyValid,
- PermanentFailure,
- InputRejected,
- OutputRejected,
- TransientFailure, // possibly transient
- CachedFailure, // no longer used
- TimedOut,
- MiscFailure,
- DependencyFailed,
- LogLimitExceeded,
- NotDeterministic,
- ResolvesToAlreadyValid,
- } status = MiscFailure;
- std::string errorMsg;
-
- std::string toString() const {
- auto strStatus = [&]() {
- switch (status) {
- case Built: return "Built";
- case Substituted: return "Substituted";
- case AlreadyValid: return "AlreadyValid";
- case PermanentFailure: return "PermanentFailure";
- case InputRejected: return "InputRejected";
- case OutputRejected: return "OutputRejected";
- case TransientFailure: return "TransientFailure";
- case CachedFailure: return "CachedFailure";
- case TimedOut: return "TimedOut";
- case MiscFailure: return "MiscFailure";
- case DependencyFailed: return "DependencyFailed";
- case LogLimitExceeded: return "LogLimitExceeded";
- case NotDeterministic: return "NotDeterministic";
- case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid";
- default: return "Unknown";
- };
- }();
- return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg);
- }
-
- /* How many times this build was performed. */
- unsigned int timesBuilt = 0;
-
- /* If timesBuilt > 1, whether some builds did not produce the same
- result. (Note that 'isNonDeterministic = false' does not mean
- the build is deterministic, just that we don't have evidence of
- non-determinism.) */
- bool isNonDeterministic = false;
-
- DrvOutputs builtOutputs;
-
- /* The start/stop times of the build (or one of the rounds, if it
- was repeated). */
- time_t startTime = 0, stopTime = 0;
-
- bool success() {
- return status == Built || status == Substituted || status == AlreadyValid || status == ResolvesToAlreadyValid;
- }
-};
struct StoreConfig : public Config
{
@@ -352,7 +235,9 @@ public:
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(const string & name, const string & s,
+ StorePath computeStorePathForText(
+ std::string_view name,
+ std::string_view s,
const StorePathSet & references) const;
/* Check whether a path is valid. */
@@ -482,9 +367,14 @@ public:
validity the resulting path. The resulting path is returned.
The function object `filter' can be used to exclude files (see
libutil/archive.hh). */
- virtual StorePath addToStore(const string & name, const Path & srcPath,
- FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256,
- PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair, const StorePathSet & references = StorePathSet());
+ virtual StorePath addToStore(
+ std::string_view name,
+ const Path & srcPath,
+ FileIngestionMethod method = FileIngestionMethod::Recursive,
+ HashType hashAlgo = htSHA256,
+ PathFilter & filter = defaultPathFilter,
+ 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
@@ -506,8 +396,11 @@ public:
/* Like addToStore, but the contents written to the output path is
a regular file containing the given string. */
- virtual StorePath addTextToStore(const string & name, const string & s,
- const StorePathSet & references, RepairFlag repair = NoRepair) = 0;
+ virtual StorePath addTextToStore(
+ std::string_view name,
+ std::string_view s,
+ const StorePathSet & references,
+ RepairFlag repair = NoRepair) = 0;
/**
* Add a mapping indicating that `deriver!outputName` maps to the output path
@@ -539,6 +432,16 @@ public:
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. */
+ 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).
@@ -585,30 +488,10 @@ public:
virtual void addTempRoot(const StorePath & path)
{ debug("not creating temporary root, store doesn't support GC"); }
- /* Add an indirect root, which is merely a symlink to `path' from
- /nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed
- to be a symlink to a store path. The garbage collector will
- automatically remove the indirect root when it finds that
- `path' has disappeared. */
- virtual void addIndirectRoot(const Path & path)
- { unsupported("addIndirectRoot"); }
-
- /* Find the roots of the garbage collector. Each root is a pair
- (link, storepath) where `link' is the path of the symlink
- outside of the Nix store that point to `storePath'. If
- 'censor' is true, privacy-sensitive information about roots
- found in /proc is censored. */
- virtual Roots findRoots(bool censor)
- { unsupported("findRoots"); }
-
- /* Perform a garbage collection. */
- virtual void collectGarbage(const GCOptions & options, GCResults & results)
- { unsupported("collectGarbage"); }
-
/* 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'. */
- string makeValidityRegistration(const StorePathSet & paths,
+ std::string makeValidityRegistration(const StorePathSet & paths,
bool showDerivers, bool showHash);
/* Write a JSON representation of store path metadata, such as the
@@ -910,7 +793,7 @@ struct RegisterStoreImplementation
/* Display a set of paths in human-readable form (i.e., between quotes
and separated by commas). */
-string showPaths(const PathSet & paths);
+std::string showPaths(const PathSet & paths);
std::optional<ValidPathInfo> decodeValidPathInfo(
diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh
index c8332afe6..87088a3ac 100644
--- a/src/libstore/worker-protocol.hh
+++ b/src/libstore/worker-protocol.hh
@@ -9,7 +9,7 @@ namespace nix {
#define WORKER_MAGIC_1 0x6e697863
#define WORKER_MAGIC_2 0x6478696f
-#define PROTOCOL_VERSION (1 << 8 | 33)
+#define PROTOCOL_VERSION (1 << 8 | 34)
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
@@ -57,6 +57,7 @@ typedef enum {
wopQueryRealisation = 43,
wopAddMultipleToStore = 44,
wopAddBuildLog = 45,
+ wopBuildPathsWithResults = 46,
} WorkerOp;
@@ -91,6 +92,7 @@ MAKE_WORKER_PROTO(, ContentAddress);
MAKE_WORKER_PROTO(, DerivedPath);
MAKE_WORKER_PROTO(, Realisation);
MAKE_WORKER_PROTO(, DrvOutput);
+MAKE_WORKER_PROTO(, BuildResult);
MAKE_WORKER_PROTO(template<typename T>, std::vector<T>);
MAKE_WORKER_PROTO(template<typename T>, std::set<T>);
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index fdee643b1..eda004756 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -37,7 +37,7 @@ static GlobalConfig::Register rArchiveSettings(&archiveSettings);
const std::string narVersionMagic1 = "nix-archive-1";
-static string caseHackSuffix = "~nix~case~hack~";
+static std::string caseHackSuffix = "~nix~case~hack~";
PathFilter defaultPathFilter = [](const Path &) { return true; };
@@ -84,12 +84,12 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
/* If we're on a case-insensitive system like macOS, undo
the case hack applied by restorePath(). */
- std::map<string, string> unhacked;
+ std::map<std::string, std::string> unhacked;
for (auto & i : readDirectory(path))
if (archiveSettings.useCaseHack) {
- string name(i.name);
+ std::string name(i.name);
size_t pos = i.name.find(caseHackSuffix);
- if (pos != string::npos) {
+ if (pos != std::string::npos) {
debug(format("removing case hack suffix from '%1%'") % (path + "/" + i.name));
name.erase(pos);
}
@@ -124,13 +124,13 @@ void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
}
-void dumpString(const std::string & s, Sink & sink)
+void dumpString(std::string_view s, Sink & sink)
{
sink << narVersionMagic1 << "(" << "type" << "regular" << "contents" << s << ")";
}
-static SerialisationError badArchive(string s)
+static SerialisationError badArchive(const std::string & s)
{
return SerialisationError("bad archive: " + s);
}
@@ -171,7 +171,7 @@ static void parseContents(ParseSink & sink, Source & source, const Path & path)
struct CaseInsensitiveCompare
{
- bool operator() (const string & a, const string & b) const
+ bool operator() (const std::string & a, const std::string & b) const
{
return strcasecmp(a.c_str(), b.c_str()) < 0;
}
@@ -180,7 +180,7 @@ struct CaseInsensitiveCompare
static void parse(ParseSink & sink, Source & source, const Path & path)
{
- string s;
+ std::string s;
s = readString(source);
if (s != "(") throw badArchive("expected open tag");
@@ -201,7 +201,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
else if (s == "type") {
if (type != tpUnknown)
throw badArchive("multiple type fields");
- string t = readString(source);
+ std::string t = readString(source);
if (t == "regular") {
type = tpRegular;
@@ -232,7 +232,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
}
else if (s == "entry" && type == tpDirectory) {
- string name, prevName;
+ std::string name, prevName;
s = readString(source);
if (s != "(") throw badArchive("expected open tag");
@@ -246,7 +246,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
break;
} else if (s == "name") {
name = readString(source);
- if (name.empty() || name == "." || name == ".." || name.find('/') != string::npos || name.find((char) 0) != string::npos)
+ if (name.empty() || name == "." || name == ".." || name.find('/') != std::string::npos || name.find((char) 0) != std::string::npos)
throw Error("NAR contains invalid file name '%1%'", name);
if (name <= prevName)
throw Error("NAR directory is not sorted");
@@ -269,7 +269,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
}
else if (s == "target" && type == tpSymlink) {
- string target = readString(source);
+ std::string target = readString(source);
sink.createSymlink(path, target);
}
@@ -281,7 +281,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
void parseDump(ParseSink & sink, Source & source)
{
- string version;
+ std::string version;
try {
version = readString(source, narVersionMagic1.size());
} catch (SerialisationError & e) {
@@ -345,7 +345,7 @@ struct RestoreSink : ParseSink
writeFull(fd.get(), data);
}
- void createSymlink(const Path & path, const string & target) override
+ void createSymlink(const Path & path, const std::string & target) override
{
Path p = dstPath + path;
nix::createSymlink(target, p);
diff --git a/src/libutil/archive.hh b/src/libutil/archive.hh
index 9e9e11b1a..fca351605 100644
--- a/src/libutil/archive.hh
+++ b/src/libutil/archive.hh
@@ -48,7 +48,7 @@ namespace nix {
void dumpPath(const Path & path, Sink & sink,
PathFilter & filter = defaultPathFilter);
-void dumpString(const std::string & s, Sink & sink);
+void dumpString(std::string_view s, Sink & sink);
/* FIXME: fix this API, it sucks. */
struct ParseSink
@@ -60,7 +60,7 @@ struct ParseSink
virtual void preallocateContents(uint64_t size) { };
virtual void receiveContents(std::string_view data) { };
- virtual void createSymlink(const Path & path, const string & target) { };
+ virtual void createSymlink(const Path & path, const std::string & target) { };
};
/* If the NAR archive contains a single file at top-level, then save
@@ -82,7 +82,7 @@ struct RetrieveRegularNARSink : ParseSink
sink(data);
}
- void createSymlink(const Path & path, const string & target) override
+ void createSymlink(const Path & path, const std::string & target) override
{
regular = false;
}
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index a739d6b4e..69aa0d094 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -76,13 +76,13 @@ void Args::parseCmdline(const Strings & _cmdline)
/* Expand compound dash options (i.e., `-qlf' -> `-q -l -f',
`-j3` -> `-j 3`). */
if (!dashDash && arg.length() > 2 && arg[0] == '-' && arg[1] != '-' && isalpha(arg[1])) {
- *pos = (string) "-" + arg[1];
+ *pos = (std::string) "-" + arg[1];
auto next = pos; ++next;
for (unsigned int j = 2; j < arg.length(); j++)
if (isalpha(arg[j]))
- cmdline.insert(next, (string) "-" + arg[j]);
+ cmdline.insert(next, (std::string) "-" + arg[j]);
else {
- cmdline.insert(next, string(arg, j));
+ cmdline.insert(next, std::string(arg, j));
break;
}
arg = *pos;
@@ -139,7 +139,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
return true;
};
- if (string(*pos, 0, 2) == "--") {
+ if (std::string(*pos, 0, 2) == "--") {
if (auto prefix = needsCompletion(*pos)) {
for (auto & [name, flag] : longFlags) {
if (!hiddenCategories.count(flag->category)
@@ -147,12 +147,12 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
completions->add("--" + name, flag->description);
}
}
- auto i = longFlags.find(string(*pos, 2));
+ auto i = longFlags.find(std::string(*pos, 2));
if (i == longFlags.end()) return false;
return process("--" + i->first, *i->second);
}
- if (string(*pos, 0, 1) == "-" && pos->size() == 2) {
+ if (std::string(*pos, 0, 1) == "-" && pos->size() == 2) {
auto c = (*pos)[1];
auto i = shortFlags.find(c);
if (i == shortFlags.end()) return false;
@@ -328,8 +328,13 @@ MultiCommand::MultiCommand(const Commands & commands_)
completions->add(name);
}
auto i = commands.find(s);
- if (i == commands.end())
- throw UsageError("'%s' is not a recognised command", s);
+ if (i == commands.end()) {
+ std::set<std::string> commandNames;
+ for (auto & [name, _] : commands)
+ commandNames.insert(name);
+ auto suggestions = Suggestions::bestMatches(commandNames, s);
+ throw UsageError(suggestions, "'%s' is not a recognised command", s);
+ }
command = {s, i->second()};
command->second->parent = this;
}}
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index 76b1cfe92..fdd036f9a 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -158,7 +158,7 @@ public:
}
/* Expect a string argument. */
- void expectArg(const std::string & label, string * dest, bool optional = false)
+ void expectArg(const std::string & label, std::string * dest, bool optional = false)
{
expectArgs({
.label = label,
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index 92ab265d3..9bb412b4f 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -81,16 +81,16 @@ void AbstractConfig::applyConfig(const std::string & contents, const std::string
unsigned int pos = 0;
while (pos < contents.size()) {
- string line;
+ std::string line;
while (pos < contents.size() && contents[pos] != '\n')
line += contents[pos++];
pos++;
- string::size_type hash = line.find('#');
- if (hash != string::npos)
- line = string(line, 0, hash);
+ auto hash = line.find('#');
+ if (hash != std::string::npos)
+ line = std::string(line, 0, hash);
- vector<string> tokens = tokenizeString<vector<string> >(line);
+ auto tokens = tokenizeString<std::vector<std::string>>(line);
if (tokens.empty()) continue;
if (tokens.size() < 2)
@@ -120,9 +120,9 @@ void AbstractConfig::applyConfig(const std::string & contents, const std::string
if (tokens[1] != "=")
throw UsageError("illegal configuration line '%1%' in '%2%'", line, path);
- string name = tokens[0];
+ std::string name = tokens[0];
- vector<string>::iterator i = tokens.begin();
+ auto i = tokens.begin();
advance(i, 2);
set(name, concatStringsSep(" ", Strings(i, tokens.end()))); // FIXME: slow
@@ -132,7 +132,7 @@ void AbstractConfig::applyConfig(const std::string & contents, const std::string
void AbstractConfig::applyConfigFile(const Path & path)
{
try {
- string contents = readFile(path);
+ std::string contents = readFile(path);
applyConfig(contents, path);
} catch (SysError &) { }
}
diff --git a/src/libutil/error.cc b/src/libutil/error.cc
index dd9678ee7..b2dfb35b2 100644
--- a/src/libutil/error.cc
+++ b/src/libutil/error.cc
@@ -17,7 +17,7 @@ BaseError & BaseError::addTrace(std::optional<ErrPos> e, hintformat hint)
// c++ std::exception descendants must have a 'const char* what()' function.
// This stringifies the error and caches it for use by what(), or similarly by msg().
-const string & BaseError::calcWhat() const
+const std::string & BaseError::calcWhat() const
{
if (what_.has_value())
return *what_;
@@ -32,14 +32,14 @@ const string & BaseError::calcWhat() const
}
}
-std::optional<string> ErrorInfo::programName = std::nullopt;
+std::optional<std::string> ErrorInfo::programName = std::nullopt;
std::ostream & operator<<(std::ostream & os, const hintformat & hf)
{
return os << hf.str();
}
-string showErrPos(const ErrPos & errPos)
+std::string showErrPos(const ErrPos & errPos)
{
if (errPos.line > 0) {
if (errPos.column > 0) {
@@ -68,7 +68,7 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos & errPos)
// count the newlines.
int count = 0;
- string line;
+ std::string line;
int pl = errPos.line - 1;
do
{
@@ -100,7 +100,7 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos & errPos)
std::istringstream iss(errPos.file);
// count the newlines.
int count = 0;
- string line;
+ std::string line;
int pl = errPos.line - 1;
LinesOfCode loc;
@@ -132,7 +132,7 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos & errPos)
// print lines of code to the ostream, indicating the error column.
void printCodeLines(std::ostream & out,
- const string & prefix,
+ const std::string & prefix,
const ErrPos & errPos,
const LinesOfCode & loc)
{
@@ -282,6 +282,13 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s
}
}
+ auto suggestions = einfo.suggestions.trim();
+ if (! suggestions.suggestions.empty()){
+ oss << "Did you mean " <<
+ suggestions.trim() <<
+ "?" << std::endl;
+ }
+
// traces
if (showTrace && !einfo.traces.empty()) {
for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) {
diff --git a/src/libutil/error.hh b/src/libutil/error.hh
index 6fe5e4857..600e94888 100644
--- a/src/libutil/error.hh
+++ b/src/libutil/error.hh
@@ -1,5 +1,6 @@
#pragma once
+#include "suggestions.hh"
#include "ref.hh"
#include "types.hh"
#include "fmt.hh"
@@ -61,16 +62,16 @@ typedef enum {
// the lines of code surrounding an error.
struct LinesOfCode {
- std::optional<string> prevLineOfCode;
- std::optional<string> errLineOfCode;
- std::optional<string> nextLineOfCode;
+ std::optional<std::string> prevLineOfCode;
+ std::optional<std::string> errLineOfCode;
+ std::optional<std::string> nextLineOfCode;
};
// ErrPos indicates the location of an error in a nix file.
struct ErrPos {
int line = 0;
int column = 0;
- string file;
+ std::string file;
FileOrigin origin;
operator bool() const
@@ -80,7 +81,7 @@ struct ErrPos {
// convert from the Pos struct, found in libexpr.
template <class P>
- ErrPos& operator=(const P &pos)
+ ErrPos & operator=(const P & pos)
{
origin = pos.origin;
line = pos.line;
@@ -94,7 +95,7 @@ struct ErrPos {
}
template <class P>
- ErrPos(const P &p)
+ ErrPos(const P & p)
{
*this = p;
}
@@ -107,15 +108,17 @@ struct Trace {
struct ErrorInfo {
Verbosity level;
- string name; // FIXME: rename
+ std::string name; // FIXME: rename
hintformat msg;
std::optional<ErrPos> errPos;
std::list<Trace> traces;
- static std::optional<string> programName;
+ Suggestions suggestions;
+
+ static std::optional<std::string> programName;
};
-std::ostream& showErrorInfo(std::ostream &out, const ErrorInfo &einfo, bool showTrace);
+std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace);
/* BaseError should generally not be caught, as it has Interrupted as
a subclass. Catch Error instead. */
@@ -124,8 +127,8 @@ class BaseError : public std::exception
protected:
mutable ErrorInfo err;
- mutable std::optional<string> what_;
- const string& calcWhat() const;
+ mutable std::optional<std::string> what_;
+ const std::string & calcWhat() const;
public:
unsigned int status = 1; // exit status
@@ -141,6 +144,11 @@ public:
: err { .level = lvlError, .msg = hintfmt(fs, args...) }
{ }
+ template<typename... Args>
+ BaseError(const Suggestions & sug, const Args & ... args)
+ : err { .level = lvlError, .msg = hintfmt(args...), .suggestions = sug }
+ { }
+
BaseError(hintformat hint)
: err { .level = lvlError, .msg = hint }
{ }
@@ -162,11 +170,11 @@ public:
const char * what() const noexcept override { return calcWhat().c_str(); }
#endif
- const string & msg() const { return calcWhat(); }
+ const std::string & msg() const { return calcWhat(); }
const ErrorInfo & info() const { calcWhat(); return err; }
template<typename... Args>
- BaseError & addTrace(std::optional<ErrPos> e, const string &fs, const Args & ... args)
+ BaseError & addTrace(std::optional<ErrPos> e, const std::string & fs, const Args & ... args)
{
return addTrace(e, hintfmt(fs, args...));
}
diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh
index a7126fb65..0821b3b74 100644
--- a/src/libutil/fmt.hh
+++ b/src/libutil/fmt.hh
@@ -10,7 +10,6 @@ namespace nix {
/* Inherit some names from other namespaces for convenience. */
-using std::string;
using boost::format;
@@ -21,8 +20,8 @@ struct nop { template<typename... T> nop(T...) {} };
struct FormatOrString
{
- string s;
- FormatOrString(const string & s) : s(s) { };
+ std::string s;
+ FormatOrString(std::string s) : s(std::move(s)) { };
template<class F>
FormatOrString(const F & f) : s(f.str()) { };
FormatOrString(const char * s) : s(s) { };
@@ -102,7 +101,7 @@ std::ostream & operator<<(std::ostream & out, const normaltxt<T> & y)
class hintformat
{
public:
- hintformat(const string & format) : fmt(format)
+ hintformat(const std::string & format) : fmt(format)
{
fmt.exceptions(boost::io::all_error_bits ^
boost::io::too_many_args_bit ^
diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc
index 6ed00d43c..a4d632161 100644
--- a/src/libutil/hash.cc
+++ b/src/libutil/hash.cc
@@ -66,31 +66,31 @@ bool Hash::operator < (const Hash & h) const
}
-const string base16Chars = "0123456789abcdef";
+const std::string base16Chars = "0123456789abcdef";
-static string printHash16(const Hash & hash)
+static std::string printHash16(const Hash & hash)
{
char buf[hash.hashSize * 2];
for (unsigned int i = 0; i < hash.hashSize; i++) {
buf[i * 2] = base16Chars[hash.hash[i] >> 4];
buf[i * 2 + 1] = base16Chars[hash.hash[i] & 0x0f];
}
- return string(buf, hash.hashSize * 2);
+ return std::string(buf, hash.hashSize * 2);
}
// omitted: E O U T
-const string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
+const std::string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
-static string printHash32(const Hash & hash)
+static std::string printHash32(const Hash & hash)
{
assert(hash.hashSize);
size_t len = hash.base32Len();
assert(len);
- string s;
+ std::string s;
s.reserve(len);
for (int n = (int) len - 1; n >= 0; n--) {
@@ -107,7 +107,7 @@ static string printHash32(const Hash & hash)
}
-string printHash16or32(const Hash & hash)
+std::string printHash16or32(const Hash & hash)
{
assert(hash.type);
return hash.to_string(hash.type == htMD5 ? Base16 : Base32, false);
@@ -151,7 +151,8 @@ Hash Hash::parseSRI(std::string_view original) {
}
// Mutates the string to eliminate the prefixes when found
-static std::pair<std::optional<HashType>, bool> getParsedTypeAndSRI(std::string_view & rest) {
+static std::pair<std::optional<HashType>, bool> getParsedTypeAndSRI(std::string_view & rest)
+{
bool isSRI = false;
// Parse the has type before the separater, if there was one.
@@ -402,7 +403,7 @@ HashType parseHashType(std::string_view s)
throw UsageError("unknown hash algorithm '%1%'", s);
}
-string printHashType(HashType ht)
+std::string printHashType(HashType ht)
{
switch (ht) {
case htMD5: return "md5";
diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh
index dff46542f..56b5938b3 100644
--- a/src/libutil/hash.hh
+++ b/src/libutil/hash.hh
@@ -20,7 +20,7 @@ const int sha512HashSize = 64;
extern std::set<std::string> hashTypes;
-extern const string base32Chars;
+extern const std::string base32Chars;
enum Base : int { Base64, Base32, Base16, SRI };
@@ -110,7 +110,7 @@ public:
Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht);
/* Print a hash in base-16 if it's MD5, or base-32 otherwise. */
-string printHash16or32(const Hash & hash);
+std::string printHash16or32(const Hash & hash);
/* Compute the hash of the given string. */
Hash hashString(HashType ht, std::string_view s);
@@ -135,7 +135,7 @@ HashType parseHashType(std::string_view s);
std::optional<HashType> parseHashTypeOpt(std::string_view s);
/* And the reverse. */
-string printHashType(HashType ht);
+std::string printHashType(HashType ht);
union Ctx;
diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc
index f8a121ed1..cb2b15b41 100644
--- a/src/libutil/logging.cc
+++ b/src/libutil/logging.cc
@@ -113,7 +113,7 @@ void warnOnce(bool & haveWarned, const FormatOrString & fs)
}
}
-void writeToStderr(const string & s)
+void writeToStderr(std::string_view s)
{
try {
writeFull(STDERR_FILENO, s, false);
@@ -266,51 +266,63 @@ static Logger::Fields getFields(nlohmann::json & json)
return fields;
}
-bool handleJSONLogMessage(const std::string & msg,
- const Activity & act, std::map<ActivityId, Activity> & activities, bool trusted)
+std::optional<nlohmann::json> parseJSONMessage(const std::string & msg)
{
- if (!hasPrefix(msg, "@nix ")) return false;
-
+ if (!hasPrefix(msg, "@nix ")) return std::nullopt;
try {
- auto json = nlohmann::json::parse(std::string(msg, 5));
-
- std::string action = json["action"];
-
- if (action == "start") {
- auto type = (ActivityType) json["type"];
- if (trusted || type == actFileTransfer)
- activities.emplace(std::piecewise_construct,
- std::forward_as_tuple(json["id"]),
- std::forward_as_tuple(*logger, (Verbosity) json["level"], type,
- json["text"], getFields(json["fields"]), act.id));
- }
+ return nlohmann::json::parse(std::string(msg, 5));
+ } catch (std::exception & e) {
+ printError("bad JSON log message from builder: %s", e.what());
+ }
+ return std::nullopt;
+}
- else if (action == "stop")
- activities.erase((ActivityId) json["id"]);
+bool handleJSONLogMessage(nlohmann::json & json,
+ const Activity & act, std::map<ActivityId, Activity> & activities,
+ bool trusted)
+{
+ std::string action = json["action"];
+
+ if (action == "start") {
+ auto type = (ActivityType) json["type"];
+ if (trusted || type == actFileTransfer)
+ activities.emplace(std::piecewise_construct,
+ std::forward_as_tuple(json["id"]),
+ std::forward_as_tuple(*logger, (Verbosity) json["level"], type,
+ json["text"], getFields(json["fields"]), act.id));
+ }
- else if (action == "result") {
- auto i = activities.find((ActivityId) json["id"]);
- if (i != activities.end())
- i->second.result((ResultType) json["type"], getFields(json["fields"]));
- }
+ else if (action == "stop")
+ activities.erase((ActivityId) json["id"]);
- else if (action == "setPhase") {
- std::string phase = json["phase"];
- act.result(resSetPhase, phase);
- }
+ else if (action == "result") {
+ auto i = activities.find((ActivityId) json["id"]);
+ if (i != activities.end())
+ i->second.result((ResultType) json["type"], getFields(json["fields"]));
+ }
- else if (action == "msg") {
- std::string msg = json["msg"];
- logger->log((Verbosity) json["level"], msg);
- }
+ else if (action == "setPhase") {
+ std::string phase = json["phase"];
+ act.result(resSetPhase, phase);
+ }
- } catch (std::exception & e) {
- printError("bad JSON log message from builder: %s", e.what());
+ else if (action == "msg") {
+ std::string msg = json["msg"];
+ logger->log((Verbosity) json["level"], msg);
}
return true;
}
+bool handleJSONLogMessage(const std::string & msg,
+ const Activity & act, std::map<ActivityId, Activity> & activities, bool trusted)
+{
+ auto json = parseJSONMessage(msg);
+ if (!json) return false;
+
+ return handleJSONLogMessage(*json, act, activities, trusted);
+}
+
Activity::~Activity()
{
try {
diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh
index 5560d2bed..6f81b92de 100644
--- a/src/libutil/logging.hh
+++ b/src/libutil/logging.hh
@@ -4,6 +4,8 @@
#include "error.hh"
#include "config.hh"
+#include <nlohmann/json_fwd.hpp>
+
namespace nix {
typedef enum {
@@ -166,6 +168,12 @@ Logger * makeSimpleLogger(bool printBuildLogs = true);
Logger * makeJSONLogger(Logger & prevLogger);
+std::optional<nlohmann::json> parseJSONMessage(const std::string & msg);
+
+bool handleJSONLogMessage(nlohmann::json & json,
+ const Activity & act, std::map<ActivityId, Activity> & activities,
+ bool trusted);
+
bool handleJSONLogMessage(const std::string & msg,
const Activity & act, std::map<ActivityId, Activity> & activities,
bool trusted);
@@ -216,6 +224,6 @@ inline void warn(const std::string & fs, const Args & ... args)
void warnOnce(bool & haveWarned, const FormatOrString & fs);
-void writeToStderr(const string & s);
+void writeToStderr(std::string_view s);
}
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc
index fe703de06..6445b3f1b 100644
--- a/src/libutil/serialise.cc
+++ b/src/libutil/serialise.cc
@@ -391,7 +391,7 @@ size_t readString(char * buf, size_t max, Source & source)
}
-string readString(Source & source, size_t max)
+std::string readString(Source & source, size_t max)
{
auto len = readNum<size_t>(source);
if (len > max) throw SerialisationError("string is too long");
@@ -401,7 +401,7 @@ string readString(Source & source, size_t max)
return res;
}
-Source & operator >> (Source & in, string & s)
+Source & operator >> (Source & in, std::string & s)
{
s = readString(in);
return in;
diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh
index fdd35aa00..13da26c6a 100644
--- a/src/libutil/serialise.hh
+++ b/src/libutil/serialise.hh
@@ -364,10 +364,10 @@ inline uint64_t readLongLong(Source & source)
void readPadding(size_t len, Source & source);
size_t readString(char * buf, size_t max, Source & source);
-string readString(Source & source, size_t max = std::numeric_limits<size_t>::max());
+std::string readString(Source & source, size_t max = std::numeric_limits<size_t>::max());
template<class T> T readStrings(Source & source);
-Source & operator >> (Source & in, string & s);
+Source & operator >> (Source & in, std::string & s);
template<typename T>
Source & operator >> (Source & in, T & n)
diff --git a/src/libutil/suggestions.cc b/src/libutil/suggestions.cc
new file mode 100644
index 000000000..9510a5f0c
--- /dev/null
+++ b/src/libutil/suggestions.cc
@@ -0,0 +1,114 @@
+#include "suggestions.hh"
+#include "ansicolor.hh"
+#include "util.hh"
+#include <algorithm>
+
+namespace nix {
+
+int levenshteinDistance(std::string_view first, std::string_view second)
+{
+ // Implementation borrowed from
+ // https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows
+
+ int m = first.size();
+ int n = second.size();
+
+ auto v0 = std::vector<int>(n+1);
+ auto v1 = std::vector<int>(n+1);
+
+ for (auto i = 0; i <= n; i++)
+ v0[i] = i;
+
+ for (auto i = 0; i < m; i++) {
+ v1[0] = i+1;
+
+ for (auto j = 0; j < n; j++) {
+ auto deletionCost = v0[j+1] + 1;
+ auto insertionCost = v1[j] + 1;
+ auto substitutionCost = first[i] == second[j] ? v0[j] : v0[j] + 1;
+ v1[j+1] = std::min({deletionCost, insertionCost, substitutionCost});
+ }
+
+ std::swap(v0, v1);
+ }
+
+ return v0[n];
+}
+
+Suggestions Suggestions::bestMatches (
+ std::set<std::string> allMatches,
+ std::string query)
+{
+ std::set<Suggestion> res;
+ for (const auto & possibleMatch : allMatches) {
+ res.insert(Suggestion {
+ .distance = levenshteinDistance(query, possibleMatch),
+ .suggestion = possibleMatch,
+ });
+ }
+ return Suggestions { res };
+}
+
+Suggestions Suggestions::trim(int limit, int maxDistance) const
+{
+ std::set<Suggestion> res;
+
+ int count = 0;
+
+ for (auto & elt : suggestions) {
+ if (count >= limit || elt.distance > maxDistance)
+ break;
+ count++;
+ res.insert(elt);
+ }
+
+ return Suggestions{res};
+}
+
+std::string Suggestion::to_string() const
+{
+ return ANSI_WARNING + filterANSIEscapes(suggestion) + ANSI_NORMAL;
+}
+
+std::string Suggestions::to_string() const
+{
+ switch (suggestions.size()) {
+ case 0:
+ return "";
+ case 1:
+ return suggestions.begin()->to_string();
+ default: {
+ std::string res = "one of ";
+ auto iter = suggestions.begin();
+ res += iter->to_string(); // Iter can’t be end() because the container isn’t null
+ iter++;
+ auto last = suggestions.end(); last--;
+ for ( ; iter != suggestions.end() ; iter++) {
+ res += (iter == last) ? " or " : ", ";
+ res += iter->to_string();
+ }
+ return res;
+ }
+ }
+}
+
+Suggestions & Suggestions::operator+=(const Suggestions & other)
+{
+ suggestions.insert(
+ other.suggestions.begin(),
+ other.suggestions.end()
+ );
+ return *this;
+}
+
+std::ostream & operator<<(std::ostream & str, const Suggestion & suggestion)
+{
+ return str << suggestion.to_string();
+}
+
+std::ostream & operator<<(std::ostream & str, const Suggestions & suggestions)
+{
+ return str << suggestions.to_string();
+}
+
+}
diff --git a/src/libutil/suggestions.hh b/src/libutil/suggestions.hh
new file mode 100644
index 000000000..d54dd8e31
--- /dev/null
+++ b/src/libutil/suggestions.hh
@@ -0,0 +1,102 @@
+#pragma once
+
+#include "comparator.hh"
+#include "types.hh"
+#include <set>
+
+namespace nix {
+
+int levenshteinDistance(std::string_view first, std::string_view second);
+
+/**
+ * A potential suggestion for the cli interface.
+ */
+class Suggestion {
+public:
+ int distance; // The smaller the better
+ std::string suggestion;
+
+ std::string to_string() const;
+
+ GENERATE_CMP(Suggestion, me->distance, me->suggestion)
+};
+
+class Suggestions {
+public:
+ std::set<Suggestion> suggestions;
+
+ std::string to_string() const;
+
+ Suggestions trim(
+ int limit = 5,
+ int maxDistance = 2
+ ) const;
+
+ static Suggestions bestMatches (
+ std::set<std::string> allMatches,
+ std::string query
+ );
+
+ Suggestions& operator+=(const Suggestions & other);
+};
+
+std::ostream & operator<<(std::ostream & str, const Suggestion &);
+std::ostream & operator<<(std::ostream & str, const Suggestions &);
+
+// Either a value of type `T`, or some suggestions
+template<typename T>
+class OrSuggestions {
+public:
+ using Raw = std::variant<T, Suggestions>;
+
+ Raw raw;
+
+ T* operator ->()
+ {
+ return &**this;
+ }
+
+ T& operator *()
+ {
+ return std::get<T>(raw);
+ }
+
+ operator bool() const noexcept
+ {
+ return std::holds_alternative<T>(raw);
+ }
+
+ OrSuggestions(T t)
+ : raw(t)
+ {
+ }
+
+ OrSuggestions()
+ : raw(Suggestions{})
+ {
+ }
+
+ static OrSuggestions<T> failed(const Suggestions & s)
+ {
+ auto res = OrSuggestions<T>();
+ res.raw = s;
+ return res;
+ }
+
+ static OrSuggestions<T> failed()
+ {
+ return OrSuggestions<T>::failed(Suggestions{});
+ }
+
+ const Suggestions & getSuggestions()
+ {
+ static Suggestions noSuggestions;
+ if (const auto & suggestions = std::get_if<Suggestions>(&raw))
+ return *suggestions;
+ else
+ return noSuggestions;
+ }
+
+};
+
+}
diff --git a/src/libutil/tests/logging.cc b/src/libutil/tests/logging.cc
index cef3bd481..2ffdc2e9b 100644
--- a/src/libutil/tests/logging.cc
+++ b/src/libutil/tests/logging.cc
@@ -359,7 +359,7 @@ namespace nix {
// constructing without access violation.
ErrPos ep(invalid);
-
+
// assignment without access violation.
ep = invalid;
diff --git a/src/libutil/tests/suggestions.cc b/src/libutil/tests/suggestions.cc
new file mode 100644
index 000000000..279994abc
--- /dev/null
+++ b/src/libutil/tests/suggestions.cc
@@ -0,0 +1,43 @@
+#include "suggestions.hh"
+#include <gtest/gtest.h>
+
+namespace nix {
+
+ struct LevenshteinDistanceParam {
+ std::string s1, s2;
+ int distance;
+ };
+
+ class LevenshteinDistanceTest :
+ public testing::TestWithParam<LevenshteinDistanceParam> {
+ };
+
+ TEST_P(LevenshteinDistanceTest, CorrectlyComputed) {
+ auto params = GetParam();
+
+ ASSERT_EQ(levenshteinDistance(params.s1, params.s2), params.distance);
+ ASSERT_EQ(levenshteinDistance(params.s2, params.s1), params.distance);
+ }
+
+ INSTANTIATE_TEST_SUITE_P(LevenshteinDistance, LevenshteinDistanceTest,
+ testing::Values(
+ LevenshteinDistanceParam{"foo", "foo", 0},
+ LevenshteinDistanceParam{"foo", "", 3},
+ LevenshteinDistanceParam{"", "", 0},
+ LevenshteinDistanceParam{"foo", "fo", 1},
+ LevenshteinDistanceParam{"foo", "oo", 1},
+ LevenshteinDistanceParam{"foo", "fao", 1},
+ LevenshteinDistanceParam{"foo", "abc", 3}
+ )
+ );
+
+ TEST(Suggestions, Trim) {
+ auto suggestions = Suggestions::bestMatches({"foooo", "bar", "fo", "gao"}, "foo");
+ auto onlyOne = suggestions.trim(1);
+ ASSERT_EQ(onlyOne.suggestions.size(), 1);
+ ASSERT_TRUE(onlyOne.suggestions.begin()->suggestion == "fo");
+
+ auto closest = suggestions.trim(999, 2);
+ ASSERT_EQ(closest.suggestions.size(), 3);
+ }
+}
diff --git a/src/libutil/tests/url.cc b/src/libutil/tests/url.cc
index aff58e9ee..f20e2dc41 100644
--- a/src/libutil/tests/url.cc
+++ b/src/libutil/tests/url.cc
@@ -5,9 +5,9 @@ namespace nix {
/* ----------- tests for url.hh --------------------------------------------------*/
- string print_map(std::map<string, string> m) {
- std::map<string, string>::iterator it;
- string s = "{ ";
+ std::string print_map(std::map<std::string, std::string> m) {
+ std::map<std::string, std::string>::iterator it;
+ std::string s = "{ ";
for (it = m.begin(); it != m.end(); ++it) {
s += "{ ";
s += it->first;
@@ -262,21 +262,21 @@ namespace nix {
* --------------------------------------------------------------------------*/
TEST(percentDecode, decodesUrlEncodedString) {
- string s = "==@==";
- string d = percentDecode("%3D%3D%40%3D%3D");
+ std::string s = "==@==";
+ std::string d = percentDecode("%3D%3D%40%3D%3D");
ASSERT_EQ(d, s);
}
TEST(percentDecode, multipleDecodesAreIdempotent) {
- string once = percentDecode("%3D%3D%40%3D%3D");
- string twice = percentDecode(once);
+ std::string once = percentDecode("%3D%3D%40%3D%3D");
+ std::string twice = percentDecode(once);
ASSERT_EQ(once, twice);
}
TEST(percentDecode, trailingPercent) {
- string s = "==@==%";
- string d = percentDecode("%3D%3D%40%3D%3D%25");
+ std::string s = "==@==%";
+ std::string d = percentDecode("%3D%3D%40%3D%3D%25");
ASSERT_EQ(d, s);
}
diff --git a/src/libutil/types.hh b/src/libutil/types.hh
index e3aca20c9..00ba567c6 100644
--- a/src/libutil/types.hh
+++ b/src/libutil/types.hh
@@ -11,23 +11,18 @@
namespace nix {
-using std::list;
-using std::set;
-using std::vector;
-using std::string;
-
-typedef list<string> Strings;
-typedef set<string> StringSet;
-typedef std::map<string, string> StringMap;
+typedef std::list<std::string> Strings;
+typedef std::set<std::string> StringSet;
+typedef std::map<std::string, std::string> StringMap;
+typedef std::map<std::string, std::string> StringPairs;
/* Paths are just strings. */
-
-typedef string Path;
+typedef std::string Path;
typedef std::string_view PathView;
-typedef list<Path> Paths;
-typedef set<Path> PathSet;
+typedef std::list<Path> Paths;
+typedef std::set<Path> PathSet;
-typedef vector<std::pair<string, string>> Headers;
+typedef std::vector<std::pair<std::string, std::string>> Headers;
/* Helper class to run code at startup. */
template<typename T>
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 8b317f6a8..b833038a9 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -110,13 +110,13 @@ Path canonPath(PathView path, bool resolveSymlinks)
{
assert(path != "");
- string s;
+ std::string s;
s.reserve(256);
if (path[0] != '/')
throw Error("not an absolute path: '%1%'", path);
- string temp;
+ std::string temp;
/* Count the number of times we follow a symlink and stop at some
arbitrary (but high) limit to prevent infinite loops. */
@@ -142,7 +142,7 @@ Path canonPath(PathView path, bool resolveSymlinks)
/* Normal component; copy it. */
else {
s += '/';
- if (const auto slash = path.find('/'); slash == string::npos) {
+ if (const auto slash = path.find('/'); slash == std::string::npos) {
s += path;
path = {};
} else {
@@ -175,7 +175,7 @@ Path canonPath(PathView path, bool resolveSymlinks)
Path dirOf(const PathView path)
{
Path::size_type pos = path.rfind('/');
- if (pos == string::npos)
+ if (pos == std::string::npos)
return ".";
return pos == 0 ? "/" : Path(path, 0, pos);
}
@@ -191,7 +191,7 @@ std::string_view baseNameOf(std::string_view path)
last -= 1;
auto pos = path.rfind('/', last);
- if (pos == string::npos)
+ if (pos == std::string::npos)
pos = 0;
else
pos += 1;
@@ -249,7 +249,7 @@ Path readLink(const Path & path)
else
throw SysError("reading symbolic link '%1%'", path);
else if (rlSize < bufSize)
- return string(buf.data(), rlSize);
+ return std::string(buf.data(), rlSize);
}
}
@@ -269,7 +269,7 @@ DirEntries readDirectory(DIR *dir, const Path & path)
struct dirent * dirent;
while (errno = 0, dirent = readdir(dir)) { /* sic */
checkInterrupt();
- string name = dirent->d_name;
+ std::string name = dirent->d_name;
if (name == "." || name == "..") continue;
entries.emplace_back(name, dirent->d_ino,
#ifdef HAVE_STRUCT_DIRENT_D_TYPE
@@ -303,7 +303,7 @@ unsigned char getFileType(const Path & path)
}
-string readFile(int fd)
+std::string readFile(int fd)
{
struct stat st;
if (fstat(fd, &st) == -1)
@@ -313,7 +313,7 @@ string readFile(int fd)
}
-string readFile(const Path & path)
+std::string readFile(const Path & path)
{
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
if (!fd)
@@ -366,9 +366,9 @@ void writeFile(const Path & path, Source & source, mode_t mode)
}
}
-string readLine(int fd)
+std::string readLine(int fd)
{
- string s;
+ std::string s;
while (1) {
checkInterrupt();
char ch;
@@ -387,7 +387,7 @@ string readLine(int fd)
}
-void writeLine(int fd, string s)
+void writeLine(int fd, std::string s)
{
s += '\n';
writeFull(fd, s);
@@ -398,7 +398,7 @@ static void _deletePath(int parentfd, const Path & path, uint64_t & bytesFreed)
{
checkInterrupt();
- string name(baseNameOf(path));
+ std::string name(baseNameOf(path));
struct stat st;
if (fstatat(parentfd, name.c_str(), &st, AT_SYMLINK_NOFOLLOW) == -1) {
@@ -566,8 +566,8 @@ Path getConfigDir()
std::vector<Path> getConfigDirs()
{
Path configHome = getConfigDir();
- string configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg");
- std::vector<Path> result = tokenizeString<std::vector<string>>(configDirs, ":");
+ auto configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg");
+ std::vector<Path> result = tokenizeString<std::vector<std::string>>(configDirs, ":");
result.insert(result.begin(), configHome);
return result;
}
@@ -670,7 +670,7 @@ void writeFull(int fd, std::string_view s, bool allowInterrupts)
}
-string drainFD(int fd, bool block, const size_t reserveSize)
+std::string drainFD(int fd, bool block, const size_t reserveSize)
{
// the parser needs two extra bytes to append terminating characters, other users will
// not care very much about the extra memory.
@@ -719,7 +719,7 @@ void drainFD(int fd, Sink & sink, bool block)
AutoDelete::AutoDelete() : del{false} {}
-AutoDelete::AutoDelete(const string & p, bool recursive) : path(p)
+AutoDelete::AutoDelete(const std::string & p, bool recursive) : path(p)
{
del = true;
this->recursive = recursive;
@@ -1036,7 +1036,7 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss)
return res;
}
-string runProgram(Path program, bool searchPath, const Strings & args,
+std::string runProgram(Path program, bool searchPath, const Strings & args,
const std::optional<std::string> & input)
{
auto res = runProgram(RunOptions {.program = program, .searchPath = searchPath, .args = args, .input = input});
@@ -1174,7 +1174,7 @@ void runProgram2(const RunOptions & options)
}
-void closeMostFDs(const set<int> & exceptions)
+void closeMostFDs(const std::set<int> & exceptions)
{
#if __linux__
try {
@@ -1238,11 +1238,11 @@ void _interrupted()
template<class C> C tokenizeString(std::string_view s, std::string_view separators)
{
C result;
- string::size_type pos = s.find_first_not_of(separators, 0);
- while (pos != string::npos) {
- string::size_type end = s.find_first_of(separators, pos + 1);
- if (end == string::npos) end = s.size();
- result.insert(result.end(), string(s, pos, end - pos));
+ auto pos = s.find_first_not_of(separators, 0);
+ while (pos != std::string::npos) {
+ auto end = s.find_first_of(separators, pos + 1);
+ if (end == std::string::npos) end = s.size();
+ result.insert(result.end(), std::string(s, pos, end - pos));
pos = s.find_first_not_of(separators, end);
}
return result;
@@ -1250,29 +1250,30 @@ template<class C> C tokenizeString(std::string_view s, std::string_view separato
template Strings tokenizeString(std::string_view s, std::string_view separators);
template StringSet tokenizeString(std::string_view s, std::string_view separators);
-template vector<string> tokenizeString(std::string_view s, std::string_view separators);
+template std::vector<std::string> tokenizeString(std::string_view s, std::string_view separators);
-string chomp(std::string_view s)
+std::string chomp(std::string_view s)
{
size_t i = s.find_last_not_of(" \n\r\t");
- return i == string::npos ? "" : string(s, 0, i + 1);
+ return i == std::string_view::npos ? "" : std::string(s, 0, i + 1);
}
-string trim(const string & s, const string & whitespace)
+std::string trim(std::string_view s, std::string_view whitespace)
{
auto i = s.find_first_not_of(whitespace);
- if (i == string::npos) return "";
+ if (i == s.npos) return "";
auto j = s.find_last_not_of(whitespace);
- return string(s, i, j == string::npos ? j : j - i + 1);
+ return std::string(s, i, j == s.npos ? j : j - i + 1);
}
-string replaceStrings(std::string_view s,
- const std::string & from, const std::string & to)
+std::string replaceStrings(
+ std::string res,
+ std::string_view from,
+ std::string_view to)
{
- string res(s);
if (from.empty()) return res;
size_t pos = 0;
while ((pos = res.find(from, pos)) != std::string::npos) {
@@ -1283,20 +1284,19 @@ string replaceStrings(std::string_view s,
}
-std::string rewriteStrings(const std::string & _s, const StringMap & rewrites)
+std::string rewriteStrings(std::string s, const StringMap & rewrites)
{
- auto s = _s;
for (auto & i : rewrites) {
if (i.first == i.second) continue;
size_t j = 0;
- while ((j = s.find(i.first, j)) != string::npos)
+ while ((j = s.find(i.first, j)) != std::string::npos)
s.replace(j, i.first.size(), i.second);
}
return s;
}
-string statusToString(int status)
+std::string statusToString(int status)
{
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
if (WIFEXITED(status))
@@ -1412,7 +1412,7 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in
}
}
- else if (*i == '\r')
+ else if (*i == '\r' || *i == '\a')
// do nothing for now
i++;
@@ -1448,9 +1448,9 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in
constexpr char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-string base64Encode(std::string_view s)
+std::string base64Encode(std::string_view s)
{
- string res;
+ std::string res;
int data = 0, nbits = 0;
for (char c : s) {
@@ -1469,7 +1469,7 @@ string base64Encode(std::string_view s)
}
-string base64Decode(std::string_view s)
+std::string base64Decode(std::string_view s)
{
constexpr char npos = -1;
constexpr std::array<char, 256> base64DecodeChars = [&]() {
@@ -1481,7 +1481,7 @@ string base64Decode(std::string_view s)
return result;
}();
- string res;
+ std::string res;
unsigned int d = 0, bits = 0;
for (char c : s) {
@@ -1565,7 +1565,22 @@ std::pair<unsigned short, unsigned short> getWindowSize()
}
-static Sync<std::list<std::function<void()>>> _interruptCallbacks;
+/* We keep track of interrupt callbacks using integer tokens, so we can iterate
+ safely without having to lock the data structure while executing arbitrary
+ functions.
+ */
+struct InterruptCallbacks {
+ typedef int64_t Token;
+
+ /* We use unique tokens so that we can't accidentally delete the wrong
+ handler because of an erroneous double delete. */
+ Token nextToken = 0;
+
+ /* Used as a list, see InterruptCallbacks comment. */
+ std::map<Token, std::function<void()>> callbacks;
+};
+
+static Sync<InterruptCallbacks> _interruptCallbacks;
static void signalHandlerThread(sigset_t set)
{
@@ -1587,8 +1602,19 @@ void triggerInterrupt()
_isInterrupted = true;
{
- auto interruptCallbacks(_interruptCallbacks.lock());
- for (auto & callback : *interruptCallbacks) {
+ InterruptCallbacks::Token i = 0;
+ while (true) {
+ std::function<void()> callback;
+ {
+ auto interruptCallbacks(_interruptCallbacks.lock());
+ auto lb = interruptCallbacks->callbacks.lower_bound(i);
+ if (lb == interruptCallbacks->callbacks.end())
+ break;
+
+ callback = lb->second;
+ i = lb->first + 1;
+ }
+
try {
callback();
} catch (...) {
@@ -1698,21 +1724,22 @@ void restoreProcessContext(bool restoreMounts)
/* RAII helper to automatically deregister a callback. */
struct InterruptCallbackImpl : InterruptCallback
{
- std::list<std::function<void()>>::iterator it;
+ InterruptCallbacks::Token token;
~InterruptCallbackImpl() override
{
- _interruptCallbacks.lock()->erase(it);
+ auto interruptCallbacks(_interruptCallbacks.lock());
+ interruptCallbacks->callbacks.erase(token);
}
};
std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> callback)
{
auto interruptCallbacks(_interruptCallbacks.lock());
- interruptCallbacks->push_back(callback);
+ auto token = interruptCallbacks->nextToken++;
+ interruptCallbacks->callbacks.emplace(token, callback);
auto res = std::make_unique<InterruptCallbackImpl>();
- res->it = interruptCallbacks->end();
- res->it--;
+ res->token = token;
return std::unique_ptr<InterruptCallback>(res.release());
}
@@ -1808,7 +1835,7 @@ void connect(int fd, const std::string & path)
}
-string showBytes(uint64_t bytes)
+std::string showBytes(uint64_t bytes)
{
return fmt("%.2f MiB", bytes / (1024.0 * 1024.0));
}
@@ -1819,7 +1846,7 @@ void commonChildInit(Pipe & logPipe)
{
logger = makeSimpleLogger();
- const static string pathNullDevice = "/dev/null";
+ const static std::string pathNullDevice = "/dev/null";
restoreProcessContext(false);
/* Put the child in a separate session (and thus a separate
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 579a42785..20591952d 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -92,22 +92,22 @@ bool isLink(const Path & path);
removed. */
struct DirEntry
{
- string name;
+ std::string name;
ino_t ino;
unsigned char type; // one of DT_*
- DirEntry(const string & name, ino_t ino, unsigned char type)
- : name(name), ino(ino), type(type) { }
+ DirEntry(std::string name, ino_t ino, unsigned char type)
+ : name(std::move(name)), ino(ino), type(type) { }
};
-typedef vector<DirEntry> DirEntries;
+typedef std::vector<DirEntry> DirEntries;
DirEntries readDirectory(const Path & path);
unsigned char getFileType(const Path & path);
/* Read the contents of a file into a string. */
-string readFile(int fd);
-string readFile(const Path & path);
+std::string readFile(int fd);
+std::string readFile(const Path & path);
void readFile(const Path & path, Sink & sink);
/* Write a string to a file. */
@@ -116,10 +116,10 @@ void writeFile(const Path & path, std::string_view s, mode_t mode = 0666);
void writeFile(const Path & path, Source & source, mode_t mode = 0666);
/* Read a line from a file descriptor. */
-string readLine(int fd);
+std::string readLine(int fd);
/* Write a line to a file descriptor. */
-void writeLine(int fd, string s);
+void writeLine(int fd, std::string s);
/* Delete a path; i.e., in the case of a directory, it is deleted
recursively. It's not an error if the path does not exist. The
@@ -170,7 +170,7 @@ MakeError(EndOfFile, Error);
/* Read a file descriptor until EOF occurs. */
-string drainFD(int fd, bool block = true, const size_t reserveSize=0);
+std::string drainFD(int fd, bool block = true, const size_t reserveSize=0);
void drainFD(int fd, Sink & sink, bool block = true);
@@ -268,7 +268,7 @@ void killUser(uid_t uid);
pid to the caller. */
struct ProcessOptions
{
- string errorPrefix = "";
+ std::string errorPrefix = "";
bool dieWithParent = true;
bool runExitHandlers = false;
bool allowVfork = false;
@@ -279,7 +279,7 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = P
/* Run a program and return its stdout in a string (i.e., like the
shell backtick operator). */
-string runProgram(Path program, bool searchPath = false,
+std::string runProgram(Path program, bool searchPath = false,
const Strings & args = Strings(),
const std::optional<std::string> & input = {});
@@ -343,7 +343,7 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss);
/* Close all file descriptors except those listed in the given set.
Good practice in child processes. */
-void closeMostFDs(const set<int> & exceptions);
+void closeMostFDs(const std::set<int> & exceptions);
/* Set the close-on-exec flag for the given file descriptor. */
void closeOnExec(int fd);
@@ -378,12 +378,12 @@ template<class C> C tokenizeString(std::string_view s, std::string_view separato
/* Concatenate the given strings with a separator between the
elements. */
template<class C>
-string concatStringsSep(const std::string_view sep, const C & ss)
+std::string concatStringsSep(const std::string_view sep, const C & ss)
{
size_t size = 0;
// need a cast to string_view since this is also called with Symbols
for (const auto & s : ss) size += sep.size() + std::string_view(s).size();
- string s;
+ std::string s;
s.reserve(size);
for (auto & i : ss) {
if (s.size() != 0) s += sep;
@@ -394,7 +394,7 @@ string concatStringsSep(const std::string_view sep, const C & ss)
template<class ... Parts>
auto concatStrings(Parts && ... parts)
- -> std::enable_if_t<(... && std::is_convertible_v<Parts, std::string_view>), string>
+ -> std::enable_if_t<(... && std::is_convertible_v<Parts, std::string_view>), std::string>
{
std::string_view views[sizeof...(parts)] = { parts... };
return concatStringsSep({}, views);
@@ -413,24 +413,26 @@ template<class C> Strings quoteStrings(const C & c)
/* Remove trailing whitespace from a string. FIXME: return
std::string_view. */
-string chomp(std::string_view s);
+std::string chomp(std::string_view s);
/* Remove whitespace from the start and end of a string. */
-string trim(const string & s, const string & whitespace = " \n\r\t");
+std::string trim(std::string_view s, std::string_view whitespace = " \n\r\t");
/* Replace all occurrences of a string inside another string. */
-string replaceStrings(std::string_view s,
- const std::string & from, const std::string & to);
+std::string replaceStrings(
+ std::string s,
+ std::string_view from,
+ std::string_view to);
-std::string rewriteStrings(const std::string & s, const StringMap & rewrites);
+std::string rewriteStrings(std::string s, const StringMap & rewrites);
/* Convert the exit status of a child as returned by wait() into an
error string. */
-string statusToString(int status);
+std::string statusToString(int status);
bool statusOk(int status);
@@ -525,8 +527,8 @@ std::string filterANSIEscapes(const std::string & s,
/* Base64 encoding/decoding. */
-string base64Encode(std::string_view s);
-string base64Decode(std::string_view s);
+std::string base64Encode(std::string_view s);
+std::string base64Decode(std::string_view s);
/* Remove common leading whitespace from the lines in the string
diff --git a/src/libutil/xml-writer.cc b/src/libutil/xml-writer.cc
index 68857e34d..7993bee9a 100644
--- a/src/libutil/xml-writer.cc
+++ b/src/libutil/xml-writer.cc
@@ -31,11 +31,12 @@ void XMLWriter::close()
void XMLWriter::indent_(size_t depth)
{
if (!indent) return;
- output << string(depth * 2, ' ');
+ output << std::string(depth * 2, ' ');
}
-void XMLWriter::openElement(const string & name,
+void XMLWriter::openElement(
+ std::string_view name,
const XMLAttrs & attrs)
{
assert(!closed);
@@ -44,7 +45,7 @@ void XMLWriter::openElement(const string & name,
writeAttrs(attrs);
output << ">";
if (indent) output << std::endl;
- pendingElems.push_back(name);
+ pendingElems.push_back(std::string(name));
}
@@ -59,7 +60,8 @@ void XMLWriter::closeElement()
}
-void XMLWriter::writeEmptyElement(const string & name,
+void XMLWriter::writeEmptyElement(
+ std::string_view name,
const XMLAttrs & attrs)
{
assert(!closed);
diff --git a/src/libutil/xml-writer.hh b/src/libutil/xml-writer.hh
index b98b44526..4c91adee6 100644
--- a/src/libutil/xml-writer.hh
+++ b/src/libutil/xml-writer.hh
@@ -8,12 +8,8 @@
namespace nix {
-using std::string;
-using std::map;
-using std::list;
-
-typedef map<string, string> XMLAttrs;
+typedef std::map<std::string, std::string> XMLAttrs;
class XMLWriter
@@ -25,7 +21,7 @@ private:
bool indent;
bool closed;
- list<string> pendingElems;
+ std::list<std::string> pendingElems;
public:
@@ -34,11 +30,11 @@ public:
void close();
- void openElement(const string & name,
+ void openElement(std::string_view name,
const XMLAttrs & attrs = XMLAttrs());
void closeElement();
- void writeEmptyElement(const string & name,
+ void writeEmptyElement(std::string_view name,
const XMLAttrs & attrs = XMLAttrs());
private:
@@ -53,7 +49,7 @@ class XMLOpenElement
private:
XMLWriter & writer;
public:
- XMLOpenElement(XMLWriter & writer, const string & name,
+ XMLOpenElement(XMLWriter & writer, std::string_view name,
const XMLAttrs & attrs = XMLAttrs())
: writer(writer)
{
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index aeabdcdd4..795a4f7bd 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -32,11 +32,11 @@ extern char * * environ __attribute__((weak));
/* Recreate the effect of the perl shellwords function, breaking up a
* string into arguments like a shell word, including escapes
*/
-std::vector<string> shellwords(const string & s)
+static std::vector<std::string> shellwords(const std::string & s)
{
std::regex whitespace("^(\\s+).*");
auto begin = s.cbegin();
- std::vector<string> res;
+ std::vector<std::string> res;
std::string cur;
enum state {
sBegin,
@@ -96,14 +96,14 @@ static void main_nix_build(int argc, char * * argv)
auto inShebang = false;
std::string script;
- std::vector<string> savedArgs;
+ std::vector<std::string> savedArgs;
AutoDelete tmpDir(createTempDir("", myName));
std::string outLink = "./result";
// List of environment variables kept for --pure
- std::set<string> keepVars{
+ std::set<std::string> keepVars{
"HOME", "XDG_RUNTIME_DIR", "USER", "LOGNAME", "DISPLAY",
"WAYLAND_DISPLAY", "WAYLAND_SOCKET", "PATH", "TERM", "IN_NIX_SHELL",
"NIX_SHELL_PRESERVE_PROMPT", "TZ", "PAGER", "NIX_BUILD_SHELL", "SHLVL",
@@ -346,7 +346,7 @@ static void main_nix_build(int argc, char * * argv)
throw UsageError("nix-shell requires a single derivation");
auto & drvInfo = drvs.front();
- auto drv = evalStore->derivationFromPath(evalStore->parseStorePath(drvInfo.queryDrvPath()));
+ auto drv = evalStore->derivationFromPath(drvInfo.requireDrvPath());
std::vector<StorePathWithOutputs> pathsToBuild;
RealisedPath::Set pathsToCopy;
@@ -369,7 +369,7 @@ static void main_nix_build(int argc, char * * argv)
if (!drv)
throw Error("the 'bashInteractive' attribute in <nixpkgs> did not evaluate to a derivation");
- auto bashDrv = store->parseStorePath(drv->queryDrvPath());
+ auto bashDrv = drv->requireDrvPath();
pathsToBuild.push_back({bashDrv});
pathsToCopy.insert(bashDrv);
shellDrv = bashDrv;
@@ -384,7 +384,9 @@ static void main_nix_build(int argc, char * * argv)
// Build or fetch all dependencies of the derivation.
for (const auto & input : drv.inputDrvs)
if (std::all_of(envExclude.cbegin(), envExclude.cend(),
- [&](const string & exclude) { return !std::regex_search(store->printStorePath(input.first), std::regex(exclude)); }))
+ [&](const std::string & exclude) {
+ return !std::regex_search(store->printStorePath(input.first), std::regex(exclude));
+ }))
{
pathsToBuild.push_back({input.first, input.second});
pathsToCopy.insert(input.first);
@@ -437,7 +439,7 @@ static void main_nix_build(int argc, char * * argv)
for (auto & var : drv.env)
if (passAsFile.count(var.first)) {
keepTmp = true;
- string fn = ".attr-" + std::to_string(fileNr++);
+ auto fn = ".attr-" + std::to_string(fileNr++);
Path p = (Path) tmpDir + "/" + fn;
writeFile(p, var.second);
env[var.first + "Path"] = p;
@@ -456,10 +458,7 @@ static void main_nix_build(int argc, char * * argv)
}
}
- ParsedDerivation parsedDrv(
- StorePath(store->parseStorePath(drvInfo.queryDrvPath())),
- drv
- );
+ ParsedDerivation parsedDrv(drvInfo.requireDrvPath(), drv);
if (auto structAttrs = parsedDrv.prepareStructuredAttrs(*store, inputs)) {
auto json = structAttrs.value();
@@ -514,7 +513,7 @@ static void main_nix_build(int argc, char * * argv)
(pure ? "" : "PATH=$PATH:$p; unset p; "),
shellEscape(dirOf(*shell)),
shellEscape(*shell),
- (getenv("TZ") ? (string("export TZ=") + shellEscape(getenv("TZ")) + "; ") : ""),
+ (getenv("TZ") ? (std::string("export TZ=") + shellEscape(getenv("TZ")) + "; ") : ""),
envCommand);
vomit("Sourcing nix-shell with file %s and contents:\n%s", rcfile, rc);
writeFile(rcfile, rc);
@@ -551,7 +550,7 @@ static void main_nix_build(int argc, char * * argv)
std::map<StorePath, std::pair<size_t, StringSet>> drvMap;
for (auto & drvInfo : drvs) {
- auto drvPath = store->parseStorePath(drvInfo.queryDrvPath());
+ auto drvPath = drvInfo.requireDrvPath();
auto outputName = drvInfo.queryOutputName();
if (outputName == "")
diff --git a/src/nix-channel/nix-channel.cc b/src/nix-channel/nix-channel.cc
index eae15885a..cf52b03b4 100755
--- a/src/nix-channel/nix-channel.cc
+++ b/src/nix-channel/nix-channel.cc
@@ -11,7 +11,7 @@
using namespace nix;
-typedef std::map<string,string> Channels;
+typedef std::map<std::string, std::string> Channels;
static Channels channels;
static Path channelsList;
@@ -22,11 +22,11 @@ static void readChannels()
if (!pathExists(channelsList)) return;
auto channelsFile = readFile(channelsList);
- for (const auto & line : tokenizeString<std::vector<string>>(channelsFile, "\n")) {
+ for (const auto & line : tokenizeString<std::vector<std::string>>(channelsFile, "\n")) {
chomp(line);
if (std::regex_search(line, std::regex("^\\s*\\#")))
continue;
- auto split = tokenizeString<std::vector<string>>(line, " ");
+ auto split = tokenizeString<std::vector<std::string>>(line, " ");
auto url = std::regex_replace(split[0], std::regex("/*$"), "");
auto name = split.size() > 1 ? split[1] : std::string(baseNameOf(url));
channels[name] = url;
@@ -44,7 +44,7 @@ static void writeChannels()
}
// Adds a channel.
-static void addChannel(const string & url, const string & name)
+static void addChannel(const std::string & url, const std::string & name)
{
if (!regex_search(url, std::regex("^(file|http|https)://")))
throw Error("invalid channel URL '%1%'", url);
@@ -58,7 +58,7 @@ static void addChannel(const string & url, const string & name)
static Path profile;
// Remove a channel.
-static void removeChannel(const string & name)
+static void removeChannel(const std::string & name)
{
readChannels();
channels.erase(name);
@@ -96,7 +96,7 @@ static void update(const StringSet & channelNames)
std::smatch match;
auto urlBase = std::string(baseNameOf(url));
if (std::regex_search(urlBase, match, std::regex("(-\\d.*)$")))
- cname = cname + (string) match[1];
+ cname = cname + match.str(1);
std::string extraAttrs;
@@ -176,7 +176,7 @@ static int main_nix_channel(int argc, char ** argv)
cUpdate,
cRollback
} cmd = cNone;
- std::vector<string> args;
+ std::vector<std::string> args;
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
if (*arg == "--help") {
showManPage("nix-channel");
diff --git a/src/nix-collect-garbage/nix-collect-garbage.cc b/src/nix-collect-garbage/nix-collect-garbage.cc
index 4f953fab4..4b28ea6a4 100644
--- a/src/nix-collect-garbage/nix-collect-garbage.cc
+++ b/src/nix-collect-garbage/nix-collect-garbage.cc
@@ -1,4 +1,5 @@
#include "store-api.hh"
+#include "gc-store.hh"
#include "profiles.hh"
#include "shared.hh"
#include "globals.hh"
@@ -36,7 +37,7 @@ void removeOldGenerations(std::string dir)
} catch (SysError & e) {
if (e.errNo == ENOENT) continue;
}
- if (link.find("link") != string::npos) {
+ if (link.find("link") != std::string::npos) {
printInfo(format("removing old generations of profile %1%") % path);
if (deleteOlderThan != "")
deleteGenerationsOlderThan(path, deleteOlderThan, dryRun);
@@ -80,10 +81,11 @@ static int main_nix_collect_garbage(int argc, char * * argv)
// Run the actual garbage collector.
if (!dryRun) {
auto store = openStore();
+ auto & gcStore = requireGcStore(*store);
options.action = GCOptions::gcDeleteDead;
GCResults results;
PrintFreed freed(true, results);
- store->collectGarbage(options, results);
+ gcStore.collectGarbage(options, results);
}
return 0;
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index d2636abf7..40c3c5d65 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -46,7 +46,7 @@ struct InstallSourceInfo
InstallSourceType type;
Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
Path profile; /* for srcProfile */
- string systemFilter; /* for srcNixExprDrvs */
+ std::string systemFilter; /* for srcNixExprDrvs */
Bindings * autoArgs;
};
@@ -59,7 +59,7 @@ struct Globals
bool dryRun;
bool preserveInstalled;
bool removeAll;
- string forceName;
+ std::string forceName;
bool prebuiltOnly;
};
@@ -68,8 +68,8 @@ typedef void (* Operation) (Globals & globals,
Strings opFlags, Strings opArgs);
-static string needArg(Strings::iterator & i,
- Strings & args, const string & arg)
+static std::string needArg(Strings::iterator & i,
+ Strings & args, const std::string & arg)
{
if (i == args.end()) throw UsageError("'%1%' requires an argument", arg);
return *i++;
@@ -77,7 +77,7 @@ static string needArg(Strings::iterator & i,
static bool parseInstallSourceOptions(Globals & globals,
- Strings::iterator & i, Strings & args, const string & arg)
+ Strings::iterator & i, Strings & args, const std::string & arg)
{
if (arg == "--from-expression" || arg == "-E")
globals.instSource.type = srcNixExprs;
@@ -124,9 +124,9 @@ static void getAllExprs(EvalState & state,
otherwise the attribute cannot be selected with the
`-A' option. Useful if you want to stick a Nix
expression directly in ~/.nix-defexpr. */
- string attrName = i;
+ std::string attrName = i;
if (hasSuffix(attrName, ".nix"))
- attrName = string(attrName, 0, attrName.size() - 4);
+ attrName = std::string(attrName, 0, attrName.size() - 4);
if (!seen.insert(attrName).second) {
printError("warning: name collision in input Nix expressions, skipping '%1%'", path2);
continue;
@@ -175,8 +175,8 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
static void loadDerivations(EvalState & state, Path nixExprPath,
- string systemFilter, Bindings & autoArgs,
- const string & pathPrefix, DrvInfos & elems)
+ std::string systemFilter, Bindings & autoArgs,
+ const std::string & pathPrefix, DrvInfos & elems)
{
Value vRoot;
loadSourceExpr(state, nixExprPath, vRoot);
@@ -211,7 +211,7 @@ static long comparePriorities(EvalState & state, DrvInfo & drv1, DrvInfo & drv2)
// at a time.
static bool isPrebuilt(EvalState & state, DrvInfo & elem)
{
- auto path = state.store->parseStorePath(elem.queryOutPath());
+ auto path = elem.queryOutPath();
if (state.store->isValidPath(path)) return true;
return state.store->querySubstitutablePaths({path}).count(path);
}
@@ -343,9 +343,9 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
if (selector.hits == 0 && selector.fullName != "*") {
const auto prefixHits = searchByPrefix(allElems, selector.name);
-
+
if (prefixHits.empty()) {
- throw Error("selector '%1%' matches no derivations", selector.fullName);
+ throw Error("selector '%1%' matches no derivations", selector.fullName);
} else {
std::string suggestionMessage = ", maybe you meant:";
for (const auto & drvName : prefixHits) {
@@ -360,9 +360,9 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems,
}
-static bool isPath(const string & s)
+static bool isPath(std::string_view s)
{
- return s.find('/') != string::npos;
+ return s.find('/') != std::string_view::npos;
}
@@ -429,14 +429,15 @@ static void queryInstSources(EvalState & state,
elem.setName(name);
if (path.isDerivation()) {
- elem.setDrvPath(state.store->printStorePath(path));
+ elem.setDrvPath(path);
auto outputs = state.store->queryDerivationOutputMap(path);
- elem.setOutPath(state.store->printStorePath(outputs.at("out")));
+ elem.setOutPath(outputs.at("out"));
if (name.size() >= drvExtension.size() &&
- string(name, name.size() - drvExtension.size()) == drvExtension)
- name = string(name, 0, name.size() - drvExtension.size());
+ std::string(name, name.size() - drvExtension.size()) == drvExtension)
+ name = name.substr(0, name.size() - drvExtension.size());
}
- else elem.setOutPath(state.store->printStorePath(path));
+ else
+ elem.setOutPath(path);
elems.push_back(elem);
}
@@ -470,13 +471,11 @@ static void queryInstSources(EvalState & state,
static void printMissing(EvalState & state, DrvInfos & elems)
{
std::vector<DerivedPath> targets;
- for (auto & i : elems) {
- Path drvPath = i.queryDrvPath();
- if (drvPath != "")
- targets.push_back(DerivedPath::Built{state.store->parseStorePath(drvPath)});
+ for (auto & i : elems)
+ if (auto drvPath = i.queryDrvPath())
+ targets.push_back(DerivedPath::Built{*drvPath});
else
- targets.push_back(DerivedPath::Opaque{state.store->parseStorePath(i.queryOutPath())});
- }
+ targets.push_back(DerivedPath::Opaque{i.queryOutPath()});
printMissing(state.store, targets);
}
@@ -515,7 +514,7 @@ static void installDerivations(Globals & globals,
while (true) {
- string lockToken = optimisticLockProfile(profile);
+ auto lockToken = optimisticLockProfile(profile);
DrvInfos allElems(newElems);
@@ -551,7 +550,7 @@ static void installDerivations(Globals & globals,
static void opInstall(Globals & globals, Strings opFlags, Strings opArgs)
{
for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) {
- string arg = *i++;
+ auto arg = *i++;
if (parseInstallSourceOptions(globals, i, opFlags, arg)) ;
else if (arg == "--preserve-installed" || arg == "-P")
globals.preserveInstalled = true;
@@ -578,7 +577,7 @@ static void upgradeDerivations(Globals & globals,
name and a higher version number. */
while (true) {
- string lockToken = optimisticLockProfile(globals.profile);
+ auto lockToken = optimisticLockProfile(globals.profile);
DrvInfos installedElems = queryInstalled(*globals.state, globals.profile);
@@ -606,7 +605,7 @@ static void upgradeDerivations(Globals & globals,
take the one with the highest version.
Do not upgrade if it would decrease the priority. */
DrvInfos::iterator bestElem = availElems.end();
- string bestVersion;
+ std::string bestVersion;
for (auto j = availElems.begin(); j != availElems.end(); ++j) {
if (comparePriorities(*globals.state, i, *j) > 0)
continue;
@@ -662,7 +661,7 @@ static void opUpgrade(Globals & globals, Strings opFlags, Strings opArgs)
{
UpgradeType upgradeType = utLt;
for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) {
- string arg = *i++;
+ std::string arg = *i++;
if (parseInstallSourceOptions(globals, i, opFlags, arg)) ;
else if (arg == "--lt") upgradeType = utLt;
else if (arg == "--leq") upgradeType = utLeq;
@@ -676,7 +675,7 @@ static void opUpgrade(Globals & globals, Strings opFlags, Strings opArgs)
static void setMetaFlag(EvalState & state, DrvInfo & drv,
- const string & name, const string & value)
+ const std::string & name, const std::string & value)
{
auto v = state.allocValue();
v->mkString(value);
@@ -692,12 +691,12 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs)
throw UsageError("not enough arguments to '--set-flag'");
Strings::iterator arg = opArgs.begin();
- string flagName = *arg++;
- string flagValue = *arg++;
+ std::string flagName = *arg++;
+ std::string flagValue = *arg++;
DrvNames selectors = drvNamesFromArgs(Strings(arg, opArgs.end()));
while (true) {
- string lockToken = optimisticLockProfile(globals.profile);
+ std::string lockToken = optimisticLockProfile(globals.profile);
DrvInfos installedElems = queryInstalled(*globals.state, globals.profile);
@@ -728,7 +727,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
if (!store2) throw Error("--set is not supported for this Nix store");
for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) {
- string arg = *i++;
+ std::string arg = *i++;
if (parseInstallSourceOptions(globals, i, opFlags, arg)) ;
else throw UsageError("unknown flag '%1%'", arg);
}
@@ -744,14 +743,11 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
if (globals.forceName != "")
drv.setName(globals.forceName);
+ auto drvPath = drv.queryDrvPath();
std::vector<DerivedPath> paths {
- (drv.queryDrvPath() != "")
- ? (DerivedPath) (DerivedPath::Built {
- globals.state->store->parseStorePath(drv.queryDrvPath())
- })
- : (DerivedPath) (DerivedPath::Opaque {
- globals.state->store->parseStorePath(drv.queryOutPath())
- }),
+ drvPath
+ ? (DerivedPath) (DerivedPath::Built { *drvPath })
+ : (DerivedPath) (DerivedPath::Opaque { drv.queryOutPath() }),
};
printMissing(globals.state->store, paths);
if (globals.dryRun) return;
@@ -759,8 +755,9 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
debug(format("switching to new user environment"));
Path generation = createGeneration(
- ref<LocalFSStore>(store2), globals.profile,
- store2->parseStorePath(drv.queryOutPath()));
+ ref<LocalFSStore>(store2),
+ globals.profile,
+ drv.queryOutPath());
switchLink(globals.profile, generation);
}
@@ -769,7 +766,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
Path & profile)
{
while (true) {
- string lockToken = optimisticLockProfile(profile);
+ auto lockToken = optimisticLockProfile(profile);
DrvInfos workingElems = queryInstalled(*globals.state, profile);
@@ -780,7 +777,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors,
split = std::partition(
workingElems.begin(), workingElems.end(),
[&selectorStorePath, globals](auto &elem) {
- return selectorStorePath != globals.state->store->parseStorePath(elem.queryOutPath());
+ return selectorStorePath != elem.queryOutPath();
}
);
} else {
@@ -833,14 +830,14 @@ static bool cmpElemByName(const DrvInfo & a, const DrvInfo & b)
}
-typedef list<Strings> Table;
+typedef std::list<Strings> Table;
void printTable(Table & table)
{
auto nrColumns = table.size() > 0 ? table.front().size() : 0;
- vector<size_t> widths;
+ std::vector<size_t> widths;
widths.resize(nrColumns);
for (auto & i : table) {
@@ -855,11 +852,11 @@ void printTable(Table & table)
Strings::iterator j;
size_t column;
for (j = i.begin(), column = 0; j != i.end(); ++j, ++column) {
- string s = *j;
+ std::string s = *j;
replace(s.begin(), s.end(), '\n', ' ');
cout << s;
if (column < nrColumns - 1)
- cout << string(widths[column] - s.size() + 2, ' ');
+ cout << std::string(widths[column] - s.size() + 2, ' ');
}
cout << std::endl;
}
@@ -876,7 +873,7 @@ void printTable(Table & table)
typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff;
static VersionDiff compareVersionAgainstSet(
- const DrvInfo & elem, const DrvInfos & elems, string & version)
+ const DrvInfo & elem, const DrvInfos & elems, std::string & version)
{
DrvName name(elem.queryName());
@@ -907,7 +904,7 @@ static VersionDiff compareVersionAgainstSet(
}
-static void queryJSON(Globals & globals, vector<DrvInfo> & elems, bool printOutPath, bool printMeta)
+static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool printOutPath, bool printMeta)
{
JSONObject topObj(cout, true);
for (auto & i : elems) {
@@ -925,9 +922,8 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems, bool printOutP
if (printOutPath) {
DrvInfo::Outputs outputs = i.queryOutputs();
JSONObject outputObj = pkgObj.object("outputs");
- for (auto & j : outputs) {
- outputObj.attr(j.first, j.second);
- }
+ for (auto & j : outputs)
+ outputObj.attr(j.first, globals.state->store->printStorePath(j.second));
}
if (printMeta) {
@@ -957,8 +953,10 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems, bool printOutP
static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
{
+ auto & store { *globals.state->store };
+
Strings remaining;
- string attrPath;
+ std::string attrPath;
bool printStatus = false;
bool printName = true;
@@ -977,7 +975,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
settings.readOnlyMode = true; /* makes evaluation a bit faster */
for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) {
- string arg = *i++;
+ auto arg = *i++;
if (arg == "--status" || arg == "-s") printStatus = true;
else if (arg == "--no-name") printName = false;
else if (arg == "--system") printSystem = true;
@@ -1020,19 +1018,18 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
/* Sort them by name. */
/* !!! */
- vector<DrvInfo> elems;
+ std::vector<DrvInfo> elems;
for (auto & i : elems_) elems.push_back(i);
sort(elems.begin(), elems.end(), cmpElemByName);
/* We only need to know the installed paths when we are querying
the status of the derivation. */
- PathSet installed; /* installed paths */
+ StorePathSet installed; /* installed paths */
- if (printStatus) {
+ if (printStatus)
for (auto & i : installedElems)
installed.insert(i.queryOutPath());
- }
/* Query which paths have substitutes. */
@@ -1042,13 +1039,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
StorePathSet paths;
for (auto & i : elems)
try {
- paths.insert(globals.state->store->parseStorePath(i.queryOutPath()));
+ paths.insert(i.queryOutPath());
} catch (AssertionError & e) {
printMsg(lvlTalkative, "skipping derivation named '%s' which gives an assertion failure", i.queryName());
i.setFailed();
}
- validPaths = globals.state->store->queryValidPaths(paths);
- substitutablePaths = globals.state->store->querySubstitutablePaths(paths);
+ validPaths = store.queryValidPaths(paths);
+ substitutablePaths = store.querySubstitutablePaths(paths);
}
@@ -1073,8 +1070,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
//Activity act(*logger, lvlDebug, format("outputting query result '%1%'") % i.attrPath);
if (globals.prebuiltOnly &&
- !validPaths.count(globals.state->store->parseStorePath(i.queryOutPath())) &&
- !substitutablePaths.count(globals.state->store->parseStorePath(i.queryOutPath())))
+ !validPaths.count(i.queryOutPath()) &&
+ !substitutablePaths.count(i.queryOutPath()))
continue;
/* For table output. */
@@ -1084,17 +1081,17 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
XMLAttrs attrs;
if (printStatus) {
- Path outPath = i.queryOutPath();
- bool hasSubs = substitutablePaths.count(globals.state->store->parseStorePath(outPath));
- bool isInstalled = installed.find(outPath) != installed.end();
- bool isValid = validPaths.count(globals.state->store->parseStorePath(outPath));
+ auto outPath = i.queryOutPath();
+ bool hasSubs = substitutablePaths.count(outPath);
+ bool isInstalled = installed.count(outPath);
+ bool isValid = validPaths.count(outPath);
if (xmlOutput) {
attrs["installed"] = isInstalled ? "1" : "0";
attrs["valid"] = isValid ? "1" : "0";
attrs["substitutable"] = hasSubs ? "1" : "0";
} else
columns.push_back(
- (string) (isInstalled ? "I" : "-")
+ (std::string) (isInstalled ? "I" : "-")
+ (isValid ? "P" : "-")
+ (hasSubs ? "S" : "-"));
}
@@ -1118,7 +1115,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
same named packages in either the set of available
elements, or the set of installed elements. !!!
This is O(N * M), should be O(N * lg M). */
- string version;
+ std::string version;
VersionDiff diff = compareVersionAgainstSet(i, otherElems, version);
char ch;
@@ -1136,7 +1133,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
attrs["maxComparedVersion"] = version;
}
} else {
- string column = (string) "" + ch + " " + version;
+ auto column = (std::string) "" + ch + " " + version;
if (diff == cvGreater && tty)
column = ANSI_RED + column + ANSI_NORMAL;
columns.push_back(column);
@@ -1150,26 +1147,26 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
columns.push_back(i.querySystem());
if (printDrvPath) {
- string drvPath = i.queryDrvPath();
+ auto drvPath = i.queryDrvPath();
if (xmlOutput) {
- if (drvPath != "") attrs["drvPath"] = drvPath;
+ if (drvPath) attrs["drvPath"] = store.printStorePath(*drvPath);
} else
- columns.push_back(drvPath == "" ? "-" : drvPath);
+ columns.push_back(drvPath ? store.printStorePath(*drvPath) : "-");
}
if (printOutPath && !xmlOutput) {
DrvInfo::Outputs outputs = i.queryOutputs();
- string s;
+ std::string s;
for (auto & j : outputs) {
if (!s.empty()) s += ';';
if (j.first != "out") { s += j.first; s += "="; }
- s += j.second;
+ s += store.printStorePath(j.second);
}
columns.push_back(s);
}
if (printDescription) {
- string descr = i.queryMetaString("description");
+ auto descr = i.queryMetaString("description");
if (xmlOutput) {
if (descr != "") attrs["description"] = descr;
} else
@@ -1184,7 +1181,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
for (auto & j : outputs) {
XMLAttrs attrs2;
attrs2["name"] = j.first;
- attrs2["path"] = j.second;
+ attrs2["path"] = store.printStorePath(j.second);
xml.writeEmptyElement("output", attrs2);
}
}
@@ -1331,12 +1328,12 @@ static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opAr
if (opArgs.size() == 1 && opArgs.front() == "old") {
deleteOldGenerations(globals.profile, globals.dryRun);
- } else if (opArgs.size() == 1 && opArgs.front().find('d') != string::npos) {
+ } else if (opArgs.size() == 1 && opArgs.front().find('d') != std::string::npos) {
deleteGenerationsOlderThan(globals.profile, opArgs.front(), globals.dryRun);
- } else if (opArgs.size() == 1 && opArgs.front().find('+') != string::npos) {
+ } else if (opArgs.size() == 1 && opArgs.front().find('+') != std::string::npos) {
if (opArgs.front().size() < 2)
throw Error("invalid number of generations '%1%'", opArgs.front());
- string str_max = string(opArgs.front(), 1, opArgs.front().size());
+ auto str_max = opArgs.front().substr(1);
auto max = string2Int<GenerationNumber>(str_max);
if (!max || *max == 0)
throw Error("invalid number of generations to keep '%1%'", opArgs.front());
@@ -1366,7 +1363,7 @@ static int main_nix_env(int argc, char * * argv)
Strings opFlags, opArgs;
Operation op = 0;
RepairFlag repair = NoRepair;
- string file;
+ std::string file;
Globals globals;
diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc
index 5842e6501..af4f350ff 100644
--- a/src/nix-env/user-env.cc
+++ b/src/nix-env/user-env.cc
@@ -32,14 +32,14 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
bool createUserEnv(EvalState & state, DrvInfos & elems,
const Path & profile, bool keepDerivations,
- const string & lockToken)
+ const std::string & lockToken)
{
/* Build the components in the user environment, if they don't
exist already. */
std::vector<StorePathWithOutputs> drvsToBuild;
for (auto & i : elems)
- if (i.queryDrvPath() != "")
- drvsToBuild.push_back({state.store->parseStorePath(i.queryDrvPath())});
+ if (auto drvPath = i.queryDrvPath())
+ drvsToBuild.push_back({*drvPath});
debug(format("building user environment dependencies"));
state.store->buildPaths(
@@ -55,7 +55,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
/* Create a pseudo-derivation containing the name, system,
output paths, and optionally the derivation path, as well
as the meta attributes. */
- Path drvPath = keepDerivations ? i.queryDrvPath() : "";
+ std::optional<StorePath> drvPath = keepDerivations ? i.queryDrvPath() : std::nullopt;
DrvInfo::Outputs outputs = i.queryOutputs(true);
StringSet metaNames = i.queryMetaNames();
@@ -66,9 +66,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
auto system = i.querySystem();
if (!system.empty())
attrs.alloc(state.sSystem).mkString(system);
- attrs.alloc(state.sOutPath).mkString(i.queryOutPath());
- if (drvPath != "")
- attrs.alloc(state.sDrvPath).mkString(i.queryDrvPath());
+ attrs.alloc(state.sOutPath).mkString(state.store->printStorePath(i.queryOutPath()));
+ if (drvPath)
+ attrs.alloc(state.sDrvPath).mkString(state.store->printStorePath(*drvPath));
// Copy each output meant for installation.
auto & vOutputs = attrs.alloc(state.sOutputs);
@@ -76,15 +76,15 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
for (const auto & [m, j] : enumerate(outputs)) {
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
auto outputAttrs = state.buildBindings(2);
- outputAttrs.alloc(state.sOutPath).mkString(j.second);
+ outputAttrs.alloc(state.sOutPath).mkString(state.store->printStorePath(j.second));
attrs.alloc(j.first).mkAttrs(outputAttrs);
/* This is only necessary when installing store paths, e.g.,
`nix-env -i /nix/store/abcd...-foo'. */
- state.store->addTempRoot(state.store->parseStorePath(j.second));
- state.store->ensurePath(state.store->parseStorePath(j.second));
+ state.store->addTempRoot(j.second);
+ state.store->ensurePath(j.second);
- references.insert(state.store->parseStorePath(j.second));
+ references.insert(j.second);
}
// Copy the meta attributes.
@@ -99,7 +99,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
(manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs);
- if (drvPath != "") references.insert(state.store->parseStorePath(drvPath));
+ if (drvPath) references.insert(*drvPath);
}
/* Also write a copy of the list of user environment elements to
@@ -132,9 +132,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); });
PathSet context;
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
- auto topLevelDrv = state.store->parseStorePath(state.coerceToPath(*aDrvPath.pos, *aDrvPath.value, context));
+ auto topLevelDrv = state.coerceToStorePath(*aDrvPath.pos, *aDrvPath.value, context);
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
- Path topLevelOut = state.coerceToPath(*aOutPath.pos, *aOutPath.value, context);
+ auto topLevelOut = state.coerceToStorePath(*aOutPath.pos, *aOutPath.value, context);
/* Realise the resulting store expression. */
debug("building user environment");
@@ -158,8 +158,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
}
debug(format("switching to new user environment"));
- Path generation = createGeneration(ref<LocalFSStore>(store2), profile,
- store2->parseStorePath(topLevelOut));
+ Path generation = createGeneration(ref<LocalFSStore>(store2), profile, topLevelOut);
switchLink(profile, generation);
}
diff --git a/src/nix-env/user-env.hh b/src/nix-env/user-env.hh
index f188efe9b..10646f713 100644
--- a/src/nix-env/user-env.hh
+++ b/src/nix-env/user-env.hh
@@ -8,6 +8,6 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv);
bool createUserEnv(EvalState & state, DrvInfos & elems,
const Path & profile, bool keepDerivations,
- const string & lockToken);
+ const std::string & lockToken);
}
diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc
index a08683be1..3ec0e6e7c 100644
--- a/src/nix-instantiate/nix-instantiate.cc
+++ b/src/nix-instantiate/nix-instantiate.cc
@@ -61,12 +61,13 @@ void processExpr(EvalState & state, const Strings & attrPaths,
DrvInfos drvs;
getDerivations(state, v, "", autoArgs, drvs, false);
for (auto & i : drvs) {
- Path drvPath = i.queryDrvPath();
+ auto drvPath = i.requireDrvPath();
+ auto drvPathS = state.store->printStorePath(drvPath);
/* What output do we want? */
- string outputName = i.queryOutputName();
+ std::string outputName = i.queryOutputName();
if (outputName == "")
- throw Error("derivation '%1%' lacks an 'outputName' attribute ", drvPath);
+ throw Error("derivation '%1%' lacks an 'outputName' attribute", drvPathS);
if (gcRoot == "")
printGCWarning();
@@ -75,9 +76,9 @@ void processExpr(EvalState & state, const Strings & attrPaths,
if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
if (store2)
- drvPath = store2->addPermRoot(store2->parseStorePath(drvPath), rootName);
+ drvPathS = store2->addPermRoot(drvPath, rootName);
}
- std::cout << fmt("%s%s\n", drvPath, (outputName != "out" ? "!" + outputName : ""));
+ std::cout << fmt("%s%s\n", drvPathS, (outputName != "out" ? "!" + outputName : ""));
}
}
}
diff --git a/src/nix-store/dotgraph.cc b/src/nix-store/dotgraph.cc
index 8b699f39b..577cadceb 100644
--- a/src/nix-store/dotgraph.cc
+++ b/src/nix-store/dotgraph.cc
@@ -10,37 +10,35 @@ using std::cout;
namespace nix {
-static string dotQuote(std::string_view s)
+static std::string dotQuote(std::string_view s)
{
return "\"" + std::string(s) + "\"";
}
-static string nextColour()
+static const std::string & nextColour()
{
static int n = 0;
- static string colours[] =
+ static std::vector<std::string> colours
{ "black", "red", "green", "blue"
, "magenta", "burlywood" };
- return colours[n++ % (sizeof(colours) / sizeof(string))];
+ return colours[n++ % colours.size()];
}
-static string makeEdge(const string & src, const string & dst)
+static std::string makeEdge(std::string_view src, std::string_view dst)
{
- format f = format("%1% -> %2% [color = %3%];\n")
- % dotQuote(src) % dotQuote(dst) % dotQuote(nextColour());
- return f.str();
+ return fmt("%1% -> %2% [color = %3%];\n",
+ dotQuote(src), dotQuote(dst), dotQuote(nextColour()));
}
-static string makeNode(const string & id, std::string_view label,
- const string & colour)
+static std::string makeNode(std::string_view id, std::string_view label,
+ std::string_view colour)
{
- format f = format("%1% [label = %2%, shape = box, "
- "style = filled, fillcolor = %3%];\n")
- % dotQuote(id) % dotQuote(label) % dotQuote(colour);
- return f.str();
+ return fmt("%1% [label = %2%, shape = box, "
+ "style = filled, fillcolor = %3%];\n",
+ dotQuote(id), dotQuote(label), dotQuote(colour));
}
diff --git a/src/nix-store/graphml.cc b/src/nix-store/graphml.cc
index 8ca5c9c8d..425d61e53 100644
--- a/src/nix-store/graphml.cc
+++ b/src/nix-store/graphml.cc
@@ -19,20 +19,20 @@ static inline std::string_view xmlQuote(std::string_view s)
}
-static string symbolicName(const std::string & p)
+static std::string symbolicName(std::string_view p)
{
- return string(p, p.find('-') + 1);
+ return std::string(p.substr(0, p.find('-') + 1));
}
-static string makeEdge(std::string_view src, std::string_view dst)
+static std::string makeEdge(std::string_view src, std::string_view dst)
{
return fmt(" <edge source=\"%1%\" target=\"%2%\"/>\n",
xmlQuote(src), xmlQuote(dst));
}
-static string makeNode(const ValidPathInfo & info)
+static std::string makeNode(const ValidPathInfo & info)
{
return fmt(
" <node id=\"%1%\">\n"
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index f0ce0368a..8ebaf9387 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -2,6 +2,8 @@
#include "derivations.hh"
#include "dotgraph.hh"
#include "globals.hh"
+#include "build-result.hh"
+#include "gc-store.hh"
#include "local-store.hh"
#include "monitor-fd.hh"
#include "serve-protocol.hh"
@@ -208,8 +210,8 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs)
Strings::iterator i = opArgs.begin();
HashType hashAlgo = parseHashType(*i++);
- string hash = *i++;
- string name = *i++;
+ std::string hash = *i++;
+ std::string name = *i++;
cout << fmt("%s\n", store->printStorePath(store->makeFixedOutputPath(recursive, Hash::parseAny(hash, hashAlgo), name)));
}
@@ -238,7 +240,7 @@ static StorePathSet maybeUseOutputs(const StorePath & storePath, bool useOutput,
graph. Topological sorting is used to keep the tree relatively
flat. */
static void printTree(const StorePath & path,
- const string & firstPad, const string & tailPad, StorePathSet & done)
+ const std::string & firstPad, const std::string & tailPad, StorePathSet & done)
{
if (!done.insert(path).second) {
cout << fmt("%s%s [...]\n", firstPad, store->printStorePath(path));
@@ -277,7 +279,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
bool useOutput = false;
bool includeOutputs = false;
bool forceRealise = false;
- string bindingName;
+ std::string bindingName;
for (auto & i : opFlags) {
QueryType prev = query;
@@ -427,11 +429,12 @@ static void opQuery(Strings opFlags, Strings opArgs)
store->computeFSClosure(
args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations);
- Roots roots = store->findRoots(false);
+ auto & gcStore = requireGcStore(*store);
+ Roots roots = gcStore.findRoots(false);
for (auto & [target, links] : roots)
if (referrers.find(target) != referrers.end())
for (auto & link : links)
- cout << fmt("%1% -> %2%\n", link, store->printStorePath(target));
+ cout << fmt("%1% -> %2%\n", link, gcStore.printStorePath(target));
break;
}
@@ -587,20 +590,22 @@ static void opGC(Strings opFlags, Strings opArgs)
if (!opArgs.empty()) throw UsageError("no arguments expected");
+ auto & gcStore = requireGcStore(*store);
+
if (printRoots) {
- Roots roots = store->findRoots(false);
+ Roots roots = gcStore.findRoots(false);
std::set<std::pair<Path, StorePath>> roots2;
// Transpose and sort the roots.
for (auto & [target, links] : roots)
for (auto & link : links)
roots2.emplace(link, target);
for (auto & [link, target] : roots2)
- std::cout << link << " -> " << store->printStorePath(target) << "\n";
+ std::cout << link << " -> " << gcStore.printStorePath(target) << "\n";
}
else {
PrintFreed freed(options.action == GCOptions::gcDeleteDead, results);
- store->collectGarbage(options, results);
+ gcStore.collectGarbage(options, results);
if (options.action != GCOptions::gcDeleteDead)
for (auto & i : results.paths)
@@ -624,9 +629,11 @@ static void opDelete(Strings opFlags, Strings opArgs)
for (auto & i : opArgs)
options.pathsToDelete.insert(store->followLinksToStorePath(i));
+ auto & gcStore = requireGcStore(*store);
+
GCResults results;
PrintFreed freed(true, results);
- store->collectGarbage(options, results);
+ gcStore.collectGarbage(options, results);
}
@@ -637,7 +644,7 @@ static void opDump(Strings opFlags, Strings opArgs)
if (opArgs.size() != 1) throw UsageError("only one argument allowed");
FdSink sink(STDOUT_FILENO);
- string path = *opArgs.begin();
+ std::string path = *opArgs.begin();
dumpPath(path, sink);
sink.flush();
}
@@ -975,9 +982,9 @@ static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
if (opArgs.size() != 3) throw UsageError("three arguments expected");
auto i = opArgs.begin();
- string keyName = *i++;
- string secretKeyFile = *i++;
- string publicKeyFile = *i++;
+ std::string keyName = *i++;
+ std::string secretKeyFile = *i++;
+ std::string publicKeyFile = *i++;
auto secretKey = SecretKey::generate(keyName);
diff --git a/src/nix/app.cc b/src/nix/app.cc
index e104cc9c1..2563180fb 100644
--- a/src/nix/app.cc
+++ b/src/nix/app.cc
@@ -114,7 +114,7 @@ App UnresolvedApp::resolve(ref<Store> evalStore, ref<Store> store)
installableContext.push_back(
std::make_shared<InstallableDerivedPath>(store, ctxElt.toDerivedPath()));
- auto builtContext = build(evalStore, store, Realise::Outputs, installableContext);
+ auto builtContext = Installable::build(evalStore, store, Realise::Outputs, installableContext);
res.program = resolveString(*store, unresolved.program, builtContext);
if (!store->isInStore(res.program))
throw Error("app program '%s' is not in the Nix store", res.program);
diff --git a/src/nix/build.cc b/src/nix/build.cc
index 6e31757a2..680db1c60 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -52,7 +52,7 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
void run(ref<Store> store) override
{
- auto buildables = build(
+ auto buildables = Installable::build(
getEvalStore(), store,
dryRun ? Realise::Derivation : Realise::Outputs,
installables, buildMode);
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index c13018328..7ed558dee 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -49,9 +49,11 @@ struct CmdBundle : InstallableCommand
Category category() override { return catSecondary; }
+ // FIXME: cut&paste from CmdRun.
Strings getDefaultFlakeAttrPaths() override
{
Strings res{
+ "apps." + settings.thisSystem.get() + ".default",
"defaultApp." + settings.thisSystem.get()
};
for (auto & s : SourceExprCommand::getDefaultFlakeAttrPaths())
@@ -61,10 +63,7 @@ struct CmdBundle : InstallableCommand
Strings getDefaultFlakeAttrPathPrefixes() override
{
- Strings res{
- "apps." + settings.thisSystem.get() + "."
-
- };
+ Strings res{"apps." + settings.thisSystem.get() + "."};
for (auto & s : SourceExprCommand::getDefaultFlakeAttrPathPrefixes())
res.push_back(s);
return res;
@@ -80,7 +79,9 @@ struct CmdBundle : InstallableCommand
const flake::LockFlags lockFlags{ .writeLockFile = false };
InstallableFlake bundler{this,
evalState, std::move(bundlerFlakeRef), bundlerName,
- {"defaultBundler." + settings.thisSystem.get()},
+ {"bundlers." + settings.thisSystem.get() + ".default",
+ "defaultBundler." + settings.thisSystem.get()
+ },
{"bundlers." + settings.thisSystem.get() + "."},
lockFlags
};
@@ -96,13 +97,13 @@ struct CmdBundle : InstallableCommand
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
PathSet context2;
- StorePath drvPath = store->parseStorePath(evalState->coerceToPath(*attr1->pos, *attr1->value, context2));
+ auto drvPath = evalState->coerceToStorePath(*attr1->pos, *attr1->value, context2);
auto attr2 = vRes->attrs->get(evalState->sOutPath);
if (!attr2)
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
- StorePath outPath = store->parseStorePath(evalState->coerceToPath(*attr2->pos, *attr2->value, context2));
+ auto outPath = evalState->coerceToStorePath(*attr2->pos, *attr2->value, context2);
store->buildPaths({ DerivedPath::Built { drvPath } });
diff --git a/src/nix/bundle.md b/src/nix/bundle.md
index a5186a996..2bb70711f 100644
--- a/src/nix/bundle.md
+++ b/src/nix/bundle.md
@@ -42,24 +42,26 @@ homepage](https://github.com/NixOS/bundlers) for more details.
If no flake output attribute is given, `nix bundle` tries the following
flake output attributes:
-* `defaultBundler.<system>`
+* `bundlers.<system>.default`
If an attribute *name* is given, `nix run` tries the following flake
output attributes:
-* `bundler.<system>.<name>`
+* `bundlers.<system>.<name>`
# Bundlers
A bundler is specified by a flake output attribute named
-`bundlers.<system>.<name>` or `defaultBundler.<system>`. It looks like this:
+`bundlers.<system>.<name>`. It looks like this:
```nix
-bundlers.x86_64-linux.identity = drv: drv;
+bundlers.x86_64-linux = rec {
+ identity = drv: drv;
-bundlers.x86_64-linux.blender_2_79 = drv: self.packages.x86_64-linux.blender_2_79;
+ blender_2_79 = drv: self.packages.x86_64-linux.blender_2_79;
-defaultBundler.x86_64-linux = drv: drv;
+ default = identity;
+};
```
A bundler must be a function that accepts an arbitrary value (typically a
diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc
index 6a40a0bd3..940923d3b 100644
--- a/src/nix/daemon.cc
+++ b/src/nix/daemon.cc
@@ -76,7 +76,7 @@ static void setSigChldAction(bool autoReap)
}
-bool matchUser(const string & user, const string & group, const Strings & users)
+bool matchUser(const std::string & user, const std::string & group, const Strings & users)
{
if (find(users.begin(), users.end(), "*") != users.end())
return true;
@@ -85,12 +85,12 @@ bool matchUser(const string & user, const string & group, const Strings & users)
return true;
for (auto & i : users)
- if (string(i, 0, 1) == "@") {
- if (group == string(i, 1)) return true;
+ if (i.substr(0, 1) == "@") {
+ if (group == i.substr(1)) return true;
struct group * gr = getgrnam(i.c_str() + 1);
if (!gr) continue;
for (char * * mem = gr->gr_mem; *mem; mem++)
- if (user == string(*mem)) return true;
+ if (user == std::string(*mem)) return true;
}
return false;
@@ -198,10 +198,10 @@ static void daemonLoop()
PeerInfo peer = getPeerInfo(remote.get());
struct passwd * pw = peer.uidKnown ? getpwuid(peer.uid) : 0;
- string user = pw ? pw->pw_name : std::to_string(peer.uid);
+ std::string user = pw ? pw->pw_name : std::to_string(peer.uid);
struct group * gr = peer.gidKnown ? getgrgid(peer.gid) : 0;
- string group = gr ? gr->gr_name : std::to_string(peer.gid);
+ std::string group = gr ? gr->gr_name : std::to_string(peer.gid);
Strings trustedUsers = settings.trustedUsers;
Strings allowedUsers = settings.allowedUsers;
@@ -212,7 +212,7 @@ static void daemonLoop()
if ((!trusted && !matchUser(user, group, allowedUsers)) || group == settings.buildUsersGroup)
throw Error("user '%1%' is not allowed to connect to the Nix daemon", user);
- printInfo(format((string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""))
+ printInfo(format((std::string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""))
% (peer.pidKnown ? std::to_string(peer.pid) : "<unknown>")
% (peer.uidKnown ? user : "<unknown>"));
@@ -234,7 +234,7 @@ static void daemonLoop()
// For debugging, stuff the pid into argv[1].
if (peer.pidKnown && savedArgv[1]) {
- string processName = std::to_string(peer.pid);
+ auto processName = std::to_string(peer.pid);
strncpy(savedArgv[1], processName.c_str(), strlen(savedArgv[1]));
}
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index f88f5909c..8af5da9d0 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -307,7 +307,7 @@ struct Common : InstallableCommand, MixProfile
for (auto & [installable_, dir_] : redirects) {
auto dir = absPath(dir_);
auto installable = parseInstallable(store, installable_);
- auto builtPaths = toStorePaths(
+ auto builtPaths = Installable::toStorePaths(
getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable});
for (auto & path: builtPaths) {
auto from = store->printStorePath(path);
@@ -325,8 +325,15 @@ struct Common : InstallableCommand, MixProfile
Strings getDefaultFlakeAttrPaths() override
{
- return {"devShell." + settings.thisSystem.get(), "defaultPackage." + settings.thisSystem.get()};
+ Strings paths{
+ "devShells." + settings.thisSystem.get() + ".default",
+ "devShell." + settings.thisSystem.get(),
+ };
+ for (auto & p : SourceExprCommand::getDefaultFlakeAttrPaths())
+ paths.push_back(p);
+ return paths;
}
+
Strings getDefaultFlakeAttrPathPrefixes() override
{
auto res = SourceExprCommand::getDefaultFlakeAttrPathPrefixes();
@@ -340,7 +347,7 @@ struct Common : InstallableCommand, MixProfile
if (path && hasSuffix(path->to_string(), "-env"))
return *path;
else {
- auto drvs = toDerivations(store, {installable});
+ auto drvs = Installable::toDerivations(store, {installable});
if (drvs.size() != 1)
throw Error("'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations",
@@ -504,7 +511,8 @@ struct CmdDevelop : Common, MixEnvironment
nixpkgsLockFlags);
shell = store->printStorePath(
- toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash";
+ Installable::toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable))
+ + "/bin/bash";
} catch (Error &) {
ignoreException();
}
diff --git a/src/nix/develop.md b/src/nix/develop.md
index 3e7e339d5..8bcff66c9 100644
--- a/src/nix/develop.md
+++ b/src/nix/develop.md
@@ -88,9 +88,9 @@ the flake's `nixConfig` attribute.
If no flake output attribute is given, `nix develop` tries the following
flake output attributes:
-* `devShell.<system>`
+* `devShells.<system>.default`
-* `defaultPackage.<system>`
+* `packages.<system>.default`
If a flake output *name* is given, `nix develop` tries the following flake
output attributes:
diff --git a/src/nix/diff-closures.cc b/src/nix/diff-closures.cc
index 734c41e0e..0621d662c 100644
--- a/src/nix/diff-closures.cc
+++ b/src/nix/diff-closures.cc
@@ -131,9 +131,9 @@ struct CmdDiffClosures : SourceExprCommand
void run(ref<Store> store) override
{
auto before = parseInstallable(store, _before);
- auto beforePath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before);
+ auto beforePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before);
auto after = parseInstallable(store, _after);
- auto afterPath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after);
+ auto afterPath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after);
printClosureDiff(store, beforePath, afterPath, "");
}
};
diff --git a/src/nix/flake-init.md b/src/nix/flake-init.md
index c13b22248..fc1f4f805 100644
--- a/src/nix/flake-init.md
+++ b/src/nix/flake-init.md
@@ -24,13 +24,13 @@ R""(
This command creates a flake in the current directory by copying the
files of a template. It will not overwrite existing files. The default
-template is `templates#defaultTemplate`, but this can be overridden
+template is `templates#templates.default`, but this can be overridden
using `-t`.
# Template definitions
-A flake can declare templates through its `templates` and
-`defaultTemplate` output attributes. A template has two attributes:
+A flake can declare templates through its `templates` output
+attribute. A template has two attributes:
* `description`: A one-line description of the template, in CommonMark
syntax.
@@ -61,7 +61,7 @@ outputs = { self }: {
'';
};
- templates.defaultTemplate = self.templates.rust;
+ templates.default = self.templates.rust;
}
```
diff --git a/src/nix/flake-show.md b/src/nix/flake-show.md
index e484cf47e..f3b74285d 100644
--- a/src/nix/flake-show.md
+++ b/src/nix/flake-show.md
@@ -13,10 +13,13 @@ R""(
│ │ └───build: derivation 'patchelf-0.12.20201207.f34751b'
│ └───x86_64-linux
│ └───build: derivation 'patchelf-0.12.20201207.f34751b'
- ├───defaultPackage
- │ ├───aarch64-linux: package 'patchelf-0.12.20201207.f34751b'
- │ ├───i686-linux: package 'patchelf-0.12.20201207.f34751b'
- │ └───x86_64-linux: package 'patchelf-0.12.20201207.f34751b'
+ ├───packages
+ │ ├───aarch64-linux
+ │ │ └───default: package 'patchelf-0.12.20201207.f34751b'
+ │ ├───i686-linux
+ │ │ └───default: package 'patchelf-0.12.20201207.f34751b'
+ │ └───x86_64-linux
+ │ └───default: package 'patchelf-0.12.20201207.f34751b'
├───hydraJobs
│ ├───build
│ │ ├───aarch64-linux: derivation 'patchelf-0.12.20201207.f34751b'
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index cd85bcea6..47a380238 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -327,7 +327,7 @@ struct CmdFlakeCheck : FlakeCommand
if (!drvInfo)
throw Error("flake attribute '%s' is not a derivation", attrPath);
// FIXME: check meta attributes
- return std::make_optional(store->parseStorePath(drvInfo->queryDrvPath()));
+ return drvInfo->queryDrvPath();
} catch (Error & e) {
e.addTrace(pos, hintfmt("while checking the derivation '%s'", attrPath));
reportError(e);
@@ -501,6 +501,17 @@ struct CmdFlakeCheck : FlakeCommand
state->forceValue(vOutput, pos);
+ std::string_view replacement =
+ name == "defaultPackage" ? "packages.<system>.default" :
+ name == "defaultApps" ? "apps.<system>.default" :
+ name == "defaultTemplate" ? "templates.default" :
+ name == "defaultBundler" ? "bundlers.<system>.default" :
+ name == "overlay" ? "overlays.default" :
+ name == "devShell" ? "devShells.<system>.default" :
+ "";
+ if (replacement != "")
+ warn("flake output attribute '%s' is deprecated; use '%s' instead", name, replacement);
+
if (name == "checks") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
@@ -651,7 +662,7 @@ struct CmdFlakeCheck : FlakeCommand
};
static Strings defaultTemplateAttrPathsPrefixes{"templates."};
-static Strings defaultTemplateAttrPaths = {"defaultTemplate"};
+static Strings defaultTemplateAttrPaths = {"templates.default", "defaultTemplate"};
struct CmdFlakeInitCommon : virtual Args, EvalCommand
{
@@ -695,9 +706,14 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
auto [cursor, attrPath] = installable.getCursor(*evalState);
- auto templateDir = cursor->getAttr("path")->getString();
+ auto templateDirAttr = cursor->getAttr("path");
+ auto templateDir = templateDirAttr->getString();
- assert(store->isInStore(templateDir));
+ if (!store->isInStore(templateDir))
+ throw TypeError(
+ "'%s' was not found in the Nix store\n"
+ "If you've set '%s' to a string, try using a path instead.",
+ templateDir, templateDirAttr->getAttrPathStr());
std::vector<Path> files;
diff --git a/src/nix/flake.md b/src/nix/flake.md
index accddd436..d59915eeb 100644
--- a/src/nix/flake.md
+++ b/src/nix/flake.md
@@ -209,6 +209,38 @@ Currently the `type` attribute can be one of the following:
* `github:edolstra/dwarffs/unstable`
* `github:edolstra/dwarffs/d3f2baba8f425779026c6ec04021b2e927f61e31`
+* `sourcehut`: Similar to `github`, is a more efficient way to fetch
+ SourceHut repositories. The following attributes are required:
+
+ * `owner`: The owner of the repository (including leading `~`).
+
+ * `repo`: The name of the repository.
+
+ Like `github`, these are downloaded as tarball archives.
+
+ The URL syntax for `sourcehut` flakes is:
+
+ `sourcehut:<owner>/<repo>(/<rev-or-ref>)?(\?<params>)?`
+
+ `<rev-or-ref>` works the same as `github`. Either a branch or tag name
+ (`ref`), or a commit hash (`rev`) can be specified.
+
+ Since SourceHut allows for self-hosting, you can specify `host` as
+ a parameter, to point to any instances other than `git.sr.ht`.
+
+ Currently, `ref` name resolution only works for Git repositories.
+ You can refer to Mercurial repositories by simply changing `host` to
+ `hg.sr.ht` (or any other Mercurial instance). With the caveat
+ that you must explicitly specify a commit hash (`rev`).
+
+ Some examples:
+
+ * `sourcehut:~misterio/nix-colors`
+ * `sourcehut:~misterio/nix-colors/main`
+ * `sourcehut:~misterio/nix-colors?host=git.example.org`
+ * `sourcehut:~misterio/nix-colors/182b4b8709b8ffe4e9774a4c5d6877bf6bb9a21c`
+ * `sourcehut:~misterio/nix-colors/21c1a380a6915d890d408e9f22203436a35bb2de?host=hg.sr.ht`
+
* `indirect`: Indirections through the flake registry. These have the
form
@@ -236,7 +268,7 @@ derivation):
outputs = { self, nixpkgs }: {
- defaultPackage.x86_64-linux =
+ packages.x86_64-linux.default =
# Notice the reference to nixpkgs here.
with import nixpkgs { system = "x86_64-linux"; };
stdenv.mkDerivation {
diff --git a/src/nix/hash.cc b/src/nix/hash.cc
index 4535e4ab0..60d9593a7 100644
--- a/src/nix/hash.cc
+++ b/src/nix/hash.cc
@@ -177,7 +177,7 @@ static int compatNixHash(int argc, char * * argv)
else if (*arg == "--base32") base32 = true;
else if (*arg == "--truncate") truncate = true;
else if (*arg == "--type") {
- string s = getArg(*arg, arg, end);
+ std::string s = getArg(*arg, arg, end);
ht = parseHashType(s);
}
else if (*arg == "--to-base16") op = opTo16;
diff --git a/src/nix/nix.md b/src/nix/nix.md
index 1dc59362d..0dacadee6 100644
--- a/src/nix/nix.md
+++ b/src/nix/nix.md
@@ -97,11 +97,9 @@ the Nix store. Here are the recognised types of installables:
For example, if `/foo/bar/flake.nix` exists, then `/foo/bar/baz/` will resolve to
`path:/foo/bar`
-
-
If *attrpath* is omitted, Nix tries some default values; for most
- subcommands, the default is `defaultPackage.`*system*
- (e.g. `defaultPackage.x86_64-linux`), but some subcommands have
+ subcommands, the default is `packages.`*system*`.default`
+ (e.g. `packages.x86_64-linux.default`), but some subcommands have
other defaults. If *attrpath* *is* specified, *attrpath* is
interpreted as relative to one or more prefixes; for most
subcommands, these are `packages.`*system*,
diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc
index 3743d7504..d690fe594 100644
--- a/src/nix/path-info.cc
+++ b/src/nix/path-info.cc
@@ -97,7 +97,7 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
for (auto & storePath : storePaths) {
auto info = store->queryPathInfo(storePath);
- auto storePathS = store->printStorePath(storePath);
+ auto storePathS = store->printStorePath(info->path);
std::cout << storePathS;
diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc
index 094d2a519..f2dd44ba4 100644
--- a/src/nix/prefetch.cc
+++ b/src/nix/prefetch.cc
@@ -16,7 +16,7 @@ using namespace nix;
/* If ‘url’ starts with ‘mirror://’, then resolve it using the list of
mirrors defined in Nixpkgs. */
-string resolveMirrorUrl(EvalState & state, string url)
+std::string resolveMirrorUrl(EvalState & state, const std::string & url)
{
if (url.substr(0, 9) != "mirror://") return url;
@@ -38,8 +38,8 @@ string resolveMirrorUrl(EvalState & state, string url)
if (mirrorList->value->listSize() < 1)
throw Error("mirror URL '%s' did not expand to anything", url);
- string mirror(state.forceString(*mirrorList->value->listElems()[0]));
- return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1);
+ std::string mirror(state.forceString(*mirrorList->value->listElems()[0]));
+ return mirror + (hasSuffix(mirror, "/") ? "" : "/") + s.substr(p + 1);
}
std::tuple<StorePath, Hash> prefetchFile(
@@ -128,10 +128,10 @@ static int main_nix_prefetch_url(int argc, char * * argv)
{
{
HashType ht = htSHA256;
- std::vector<string> args;
+ std::vector<std::string> args;
bool printPath = getEnv("PRINT_PATH") == "1";
bool fromExpr = false;
- string attrPath;
+ std::string attrPath;
bool unpack = false;
bool executable = false;
std::optional<std::string> name;
@@ -147,7 +147,7 @@ static int main_nix_prefetch_url(int argc, char * * argv)
else if (*arg == "--version")
printVersion("nix-prefetch-url");
else if (*arg == "--type") {
- string s = getArg(*arg, arg, end);
+ auto s = getArg(*arg, arg, end);
ht = parseHashType(s);
}
else if (*arg == "--print-path")
@@ -186,7 +186,7 @@ static int main_nix_prefetch_url(int argc, char * * argv)
/* If -A is given, get the URL from the specified Nix
expression. */
- string url;
+ std::string url;
if (!fromExpr) {
if (args.empty())
throw UsageError("you must specify a URL");
diff --git a/src/nix/profile-list.md b/src/nix/profile-list.md
index 5c29c0b02..bdab9a208 100644
--- a/src/nix/profile-list.md
+++ b/src/nix/profile-list.md
@@ -8,7 +8,7 @@ R""(
# nix profile list
0 flake:nixpkgs#legacyPackages.x86_64-linux.spotify github:NixOS/nixpkgs/c23db78bbd474c4d0c5c3c551877523b4a50db06#legacyPackages.x86_64-linux.spotify /nix/store/akpdsid105phbbvknjsdh7hl4v3fhjkr-spotify-1.1.46.916.g416cacf1
1 flake:nixpkgs#legacyPackages.x86_64-linux.zoom-us github:NixOS/nixpkgs/c23db78bbd474c4d0c5c3c551877523b4a50db06#legacyPackages.x86_64-linux.zoom-us /nix/store/89pmjmbih5qpi7accgacd17ybpgp4xfm-zoom-us-5.4.53350.1027
- 2 flake:blender-bin#defaultPackage.x86_64-linux github:edolstra/nix-warez/d09d7eea893dcb162e89bc67f6dc1ced14abfc27?dir=blender#defaultPackage.x86_64-linux /nix/store/zfgralhqjnam662kqsgq6isjw8lhrflz-blender-bin-2.91.0
+ 2 flake:blender-bin#packages.x86_64-linux.default github:edolstra/nix-warez/d09d7eea893dcb162e89bc67f6dc1ced14abfc27?dir=blender#packages.x86_64-linux.default /nix/store/zfgralhqjnam662kqsgq6isjw8lhrflz-blender-bin-2.91.0
```
# Description
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 55b5ff736..a8ff9c78a 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -61,6 +61,27 @@ struct ProfileElement
{
return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths);
}
+
+ void updateStorePaths(ref<Store> evalStore, ref<Store> store, Installable & installable)
+ {
+ // FIXME: respect meta.outputsToInstall
+ storePaths.clear();
+ for (auto & buildable : getBuiltPaths(evalStore, store, installable.toDerivedPaths())) {
+ std::visit(overloaded {
+ [&](const BuiltPath::Opaque & bo) {
+ storePaths.insert(bo.path);
+ },
+ [&](const BuiltPath::Built & bfd) {
+ // TODO: Why are we querying if we know the output
+ // names already? Is it just to figure out what the
+ // default one is?
+ for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) {
+ storePaths.insert(output.second);
+ }
+ },
+ }, buildable.raw());
+ }
+ }
};
struct ProfileManifest
@@ -105,7 +126,7 @@ struct ProfileManifest
for (auto & drvInfo : drvInfos) {
ProfileElement element;
- element.storePaths = {state.store->parseStorePath(drvInfo.queryOutPath())};
+ element.storePaths = {drvInfo.queryOutPath()};
elements.emplace_back(std::move(element));
}
}
@@ -232,54 +253,26 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
{
ProfileManifest manifest(*getEvalState(), *profile);
- std::vector<DerivedPath> pathsToBuild;
+ auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
for (auto & installable : installables) {
+ ProfileElement element;
+
if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) {
+ // FIXME: make build() return this?
auto [attrPath, resolvedRef, drv] = installable2->toDerivation();
-
- ProfileElement element;
- if (!drv.outPath)
- throw UnimplementedError("CA derivations are not yet supported by 'nix profile'");
- element.storePaths = {*drv.outPath}; // FIXME
element.source = ProfileElementSource{
installable2->flakeRef,
resolvedRef,
attrPath,
};
+ }
- pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, StringSet{drv.outputName}});
+ element.updateStorePaths(getEvalStore(), store, *installable);
- manifest.elements.emplace_back(std::move(element));
- } else {
- auto buildables = build(getEvalStore(), store, Realise::Outputs, {installable}, bmNormal);
-
- for (auto & buildable : buildables) {
- ProfileElement element;
-
- std::visit(overloaded {
- [&](const BuiltPath::Opaque & bo) {
- pathsToBuild.push_back(bo);
- element.storePaths.insert(bo.path);
- },
- [&](const BuiltPath::Built & bfd) {
- // TODO: Why are we querying if we know the output
- // names already? Is it just to figure out what the
- // default one is?
- for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) {
- pathsToBuild.push_back(DerivedPath::Built{bfd.drvPath, {output.first}});
- element.storePaths.insert(output.second);
- }
- },
- }, buildable.raw());
-
- manifest.elements.emplace_back(std::move(element));
- }
- }
+ manifest.elements.push_back(std::move(element));
}
- store->buildPaths(pathsToBuild);
-
updateProfile(manifest.build(store));
}
};
@@ -373,15 +366,15 @@ struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElem
if (removedCount == 0) {
for (auto matcher: matchers) {
- if (const size_t* index = std::get_if<size_t>(&matcher)){
- warn("'%d' is not a valid index in profile", *index);
- } else if (const Path* path = std::get_if<Path>(&matcher)){
- warn("'%s' does not match any paths in profile", *path);
- } else if (const RegexPattern* regex = std::get_if<RegexPattern>(&matcher)){
- warn("'%s' does not match any packages in profile", regex->pattern);
+ if (const size_t * index = std::get_if<size_t>(&matcher)){
+ warn("'%d' is not a valid index", *index);
+ } else if (const Path * path = std::get_if<Path>(&matcher)){
+ warn("'%s' does not match any paths", *path);
+ } else if (const RegexPattern * regex = std::get_if<RegexPattern>(&matcher)){
+ warn("'%s' does not match any packages", regex->pattern);
}
}
- warn ("Try `nix profile list` to see the current profile.");
+ warn ("Use 'nix profile list' to see the current profile.");
}
updateProfile(newManifest.build(store));
}
@@ -407,48 +400,69 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
auto matchers = getMatchers(store);
- // FIXME: code duplication
- std::vector<DerivedPath> pathsToBuild;
+ std::vector<std::shared_ptr<Installable>> installables;
+ std::vector<size_t> indices;
+
+ auto upgradedCount = 0;
for (size_t i = 0; i < manifest.elements.size(); ++i) {
auto & element(manifest.elements[i]);
if (element.source
- && !element.source->originalRef.input.isImmutable()
+ && !element.source->originalRef.input.isLocked()
&& matches(*store, element, i, matchers))
{
+ upgradedCount++;
+
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking '%s' for updates", element.source->attrPath));
- InstallableFlake installable(
+ auto installable = std::make_shared<InstallableFlake>(
this,
getEvalState(),
FlakeRef(element.source->originalRef),
"",
- {element.source->attrPath},
- {},
+ Strings{element.source->attrPath},
+ Strings{},
lockFlags);
- auto [attrPath, resolvedRef, drv] = installable.toDerivation();
+ auto [attrPath, resolvedRef, drv] = installable->toDerivation();
if (element.source->resolvedRef == resolvedRef) continue;
printInfo("upgrading '%s' from flake '%s' to '%s'",
element.source->attrPath, element.source->resolvedRef, resolvedRef);
- if (!drv.outPath)
- throw UnimplementedError("CA derivations are not yet supported by 'nix profile'");
- element.storePaths = {*drv.outPath}; // FIXME
element.source = ProfileElementSource{
- installable.flakeRef,
+ installable->flakeRef,
resolvedRef,
attrPath,
};
- pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, {drv.outputName}});
+ installables.push_back(installable);
+ indices.push_back(i);
}
}
- store->buildPaths(pathsToBuild);
+ if (upgradedCount == 0) {
+ for (auto & matcher : matchers) {
+ if (const size_t * index = std::get_if<size_t>(&matcher)){
+ warn("'%d' is not a valid index", *index);
+ } else if (const Path * path = std::get_if<Path>(&matcher)){
+ warn("'%s' does not match any paths", *path);
+ } else if (const RegexPattern * regex = std::get_if<RegexPattern>(&matcher)){
+ warn("'%s' does not match any packages", regex->pattern);
+ }
+ }
+ warn ("Use 'nix profile list' to see the current profile.");
+ }
+
+ auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
+
+ for (size_t i = 0; i < installables.size(); ++i) {
+ auto & installable = installables.at(i);
+ auto & element = manifest.elements[indices.at(i)];
+ element.updateStorePaths(getEvalStore(), store, *installable);
+ }
updateProfile(manifest.build(store));
}
diff --git a/src/nix/profile.md b/src/nix/profile.md
index d3ddcd3d1..0a4ff2fa9 100644
--- a/src/nix/profile.md
+++ b/src/nix/profile.md
@@ -96,7 +96,7 @@ has the following fields:
user specified, but the one resulting from applying the default
attribute paths and prefixes; for instance, `hello` might resolve to
`packages.x86_64-linux.hello` and the empty string to
- `defaultPackage.x86_64-linux`.
+ `packages.x86_64-linux.default`.
* `storePath`: The paths in the Nix store containing the package.
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 2c39fac91..3a51a13e6 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -45,7 +45,7 @@ struct NixRepl
: gc
#endif
{
- string curDir;
+ std::string curDir;
std::unique_ptr<EvalState> state;
Bindings * autoArgs;
@@ -62,30 +62,30 @@ struct NixRepl
NixRepl(const Strings & searchPath, nix::ref<Store> store);
~NixRepl();
void mainLoop(const std::vector<std::string> & files);
- StringSet completePrefix(string prefix);
- bool getLine(string & input, const std::string &prompt);
+ StringSet completePrefix(const std::string & prefix);
+ bool getLine(std::string & input, const std::string &prompt);
StorePath getDerivationPath(Value & v);
- bool processLine(string line);
+ bool processLine(std::string line);
void loadFile(const Path & path);
void loadFlake(const std::string & flakeRef);
void initEnv();
void reloadFiles();
void addAttrsToScope(Value & attrs);
void addVarToScope(const Symbol & name, Value & v);
- Expr * parseString(string s);
- void evalString(string s, Value & v);
+ Expr * parseString(std::string s);
+ void evalString(std::string s, Value & v);
- typedef set<Value *> ValuesSeen;
+ typedef std::set<Value *> ValuesSeen;
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth);
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen);
};
-string removeWhitespace(string s)
+std::string removeWhitespace(std::string s)
{
s = chomp(s);
size_t n = s.find_first_not_of(" \n\r\t");
- if (n != string::npos) s = string(s, n);
+ if (n != std::string::npos) s = std::string(s, n);
return s;
}
@@ -104,7 +104,7 @@ NixRepl::~NixRepl()
write_history(historyFile.c_str());
}
-string runNix(Path program, const Strings & args,
+std::string runNix(Path program, const Strings & args,
const std::optional<std::string> & input = {})
{
auto subprocessEnv = getEnv();
@@ -198,7 +198,7 @@ namespace {
void NixRepl::mainLoop(const std::vector<std::string> & files)
{
- string error = ANSI_RED "error:" ANSI_NORMAL " ";
+ std::string error = ANSI_RED "error:" ANSI_NORMAL " ";
notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n");
for (auto & i : files)
@@ -252,7 +252,7 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
}
-bool NixRepl::getLine(string & input, const std::string &prompt)
+bool NixRepl::getLine(std::string & input, const std::string & prompt)
{
struct sigaction act, old;
sigset_t savedSignalMask, set;
@@ -297,7 +297,7 @@ bool NixRepl::getLine(string & input, const std::string &prompt)
}
-StringSet NixRepl::completePrefix(string prefix)
+StringSet NixRepl::completePrefix(const std::string & prefix)
{
StringSet completions;
@@ -313,7 +313,7 @@ StringSet NixRepl::completePrefix(string prefix)
size_t slash, dot;
- if ((slash = cur.rfind('/')) != string::npos) {
+ if ((slash = cur.rfind('/')) != std::string::npos) {
try {
auto dir = std::string(cur, 0, slash);
auto prefix2 = std::string(cur, slash + 1);
@@ -323,11 +323,11 @@ StringSet NixRepl::completePrefix(string prefix)
}
} catch (Error &) {
}
- } else if ((dot = cur.rfind('.')) == string::npos) {
+ } else if ((dot = cur.rfind('.')) == std::string::npos) {
/* This is a variable name; look it up in the current scope. */
StringSet::iterator i = varNames.lower_bound(cur);
while (i != varNames.end()) {
- if (string(*i, 0, cur.size()) != cur) break;
+ if (i->substr(0, cur.size()) != cur) break;
completions.insert(prev + *i);
i++;
}
@@ -336,8 +336,8 @@ StringSet NixRepl::completePrefix(string prefix)
/* This is an expression that should evaluate to an
attribute set. Evaluate it to get the names of the
attributes. */
- string expr(cur, 0, dot);
- string cur2 = string(cur, dot + 1);
+ auto expr = cur.substr(0, dot);
+ auto cur2 = cur.substr(dot + 1);
Expr * e = parseString(expr);
Value v;
@@ -345,8 +345,8 @@ StringSet NixRepl::completePrefix(string prefix)
state->forceAttrs(v, noPos);
for (auto & i : *v.attrs) {
- string name = i.name;
- if (string(name, 0, cur2.size()) != cur2) continue;
+ std::string name = i.name;
+ if (name.substr(0, cur2.size()) != cur2) continue;
completions.insert(prev + expr + "." + name);
}
@@ -365,7 +365,7 @@ StringSet NixRepl::completePrefix(string prefix)
}
-bool isVarName(const string & s)
+static bool isVarName(std::string_view s)
{
if (s.size() == 0) return false;
char c = s[0];
@@ -384,28 +384,27 @@ StorePath NixRepl::getDerivationPath(Value & v) {
auto drvInfo = getDerivation(*state, v, false);
if (!drvInfo)
throw Error("expression does not evaluate to a derivation, so I can't build it");
- Path drvPathRaw = drvInfo->queryDrvPath();
- if (drvPathRaw == "")
- throw Error("expression did not evaluate to a valid derivation (no drv path)");
- StorePath drvPath = state->store->parseStorePath(drvPathRaw);
- if (!state->store->isValidPath(drvPath))
- throw Error("expression did not evaluate to a valid derivation (invalid drv path)");
- return drvPath;
+ auto drvPath = drvInfo->queryDrvPath();
+ if (!drvPath)
+ throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)");
+ if (!state->store->isValidPath(*drvPath))
+ throw Error("expression evaluated to invalid derivation '%s'", state->store->printStorePath(*drvPath));
+ return *drvPath;
}
-bool NixRepl::processLine(string line)
+bool NixRepl::processLine(std::string line)
{
if (line == "") return true;
_isInterrupted = false;
- string command, arg;
+ std::string command, arg;
if (line[0] == ':') {
size_t p = line.find_first_of(" \n\r\t");
- command = string(line, 0, p);
- if (p != string::npos) arg = removeWhitespace(string(line, p));
+ command = line.substr(0, p);
+ if (p != std::string::npos) arg = removeWhitespace(line.substr(p));
} else {
arg = line;
}
@@ -590,13 +589,13 @@ bool NixRepl::processLine(string line)
else {
size_t p = line.find('=');
- string name;
- if (p != string::npos &&
+ std::string name;
+ if (p != std::string::npos &&
p < line.size() &&
line[p + 1] != '=' &&
- isVarName(name = removeWhitespace(string(line, 0, p))))
+ isVarName(name = removeWhitespace(line.substr(0, p))))
{
- Expr * e = parseString(string(line, p + 1));
+ Expr * e = parseString(line.substr(p + 1));
Value & v(*state->allocValue());
v.mkThunk(env, e);
addVarToScope(state->symbols.create(name), v);
@@ -627,8 +626,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)");
auto flakeRef = parseFlakeRef(flakeRefS, absPath("."), true);
- if (evalSettings.pureEval && !flakeRef.input.isImmutable())
- throw Error("cannot use ':load-flake' on mutable flake reference '%s' (use --impure to override)", flakeRefS);
+ if (evalSettings.pureEval && !flakeRef.input.isLocked())
+ throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS);
Value v;
@@ -683,7 +682,7 @@ void NixRepl::addAttrsToScope(Value & attrs)
for (auto & i : *attrs.attrs) {
staticEnv.vars.emplace_back(i.name, displ);
env->values[displ++] = i.value;
- varNames.insert((string) i.name);
+ varNames.insert((std::string) i.name);
}
staticEnv.sort();
staticEnv.deduplicate();
@@ -700,18 +699,18 @@ void NixRepl::addVarToScope(const Symbol & name, Value & v)
staticEnv.vars.emplace_back(name, displ);
staticEnv.sort();
env->values[displ++] = &v;
- varNames.insert((string) name);
+ varNames.insert((std::string) name);
}
-Expr * NixRepl::parseString(string s)
+Expr * NixRepl::parseString(std::string s)
{
Expr * e = state->parseExprFromString(std::move(s), curDir, staticEnv);
return e;
}
-void NixRepl::evalString(string s, Value & v)
+void NixRepl::evalString(std::string s, Value & v)
{
Expr * e = parseString(s);
e->eval(*state, *env, v);
@@ -780,14 +779,17 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
str << "«derivation ";
Bindings::iterator i = v.attrs->find(state->sDrvPath);
PathSet context;
- Path drvPath = i != v.attrs->end() ? state->coerceToPath(*i->pos, *i->value, context) : "???";
- str << drvPath << "»";
+ if (i != v.attrs->end())
+ str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context));
+ else
+ str << "???";
+ str << "»";
}
else if (maxDepth > 0) {
str << "{ ";
- typedef std::map<string, Value *> Sorted;
+ typedef std::map<std::string, Value *> Sorted;
Sorted sorted;
for (auto & i : *v.attrs)
sorted[i.name] = i.value;
@@ -798,7 +800,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
else
printStringValue(str, i.first.c_str());
str << " = ";
- if (seen.find(i.second) != seen.end())
+ if (seen.count(i.second))
str << "«repeated»";
else
try {
diff --git a/src/nix/run.cc b/src/nix/run.cc
index bae64ed39..033263c36 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -91,7 +91,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
void run(ref<Store> store) override
{
- auto outPaths = toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
+ auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
auto accessor = store->getFSAccessor();
@@ -158,7 +158,10 @@ struct CmdRun : InstallableCommand
Strings getDefaultFlakeAttrPaths() override
{
- Strings res{"defaultApp." + settings.thisSystem.get()};
+ Strings res{
+ "apps." + settings.thisSystem.get() + ".default",
+ "defaultApp." + settings.thisSystem.get(),
+ };
for (auto & s : SourceExprCommand::getDefaultFlakeAttrPaths())
res.push_back(s);
return res;
diff --git a/src/nix/run.md b/src/nix/run.md
index cd3b978c0..a0f362076 100644
--- a/src/nix/run.md
+++ b/src/nix/run.md
@@ -58,9 +58,9 @@ For instance, if `name` is set to `hello-1.10`, `nix run` will run
If no flake output attribute is given, `nix run` tries the following
flake output attributes:
-* `defaultApp.<system>`
+* `apps.<system>.default`
-* `defaultPackage.<system>`
+* `packages.<system>.default`
If an attribute *name* is given, `nix run` tries the following flake
output attributes:
@@ -74,7 +74,7 @@ output attributes:
# Apps
An app is specified by a flake output attribute named
-`apps.<system>.<name>` or `defaultApp.<system>`. It looks like this:
+`apps.<system>.<name>`. It looks like this:
```nix
apps.x86_64-linux.blender_2_79 = {
diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc
index c614be68d..61a02c9b3 100644
--- a/src/nix/show-derivation.cc
+++ b/src/nix/show-derivation.cc
@@ -40,7 +40,7 @@ struct CmdShowDerivation : InstallablesCommand
void run(ref<Store> store) override
{
- auto drvPaths = toDerivations(store, installables, true);
+ auto drvPaths = Installable::toDerivations(store, installables, true);
if (recursive) {
StorePathSet closure;
diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc
index e4a3cb554..aa7a8b12f 100644
--- a/src/nix/store-delete.cc
+++ b/src/nix/store-delete.cc
@@ -2,6 +2,7 @@
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
+#include "gc-store.hh"
using namespace nix;
@@ -32,12 +33,14 @@ struct CmdStoreDelete : StorePathsCommand
void run(ref<Store> store, std::vector<StorePath> && storePaths) override
{
+ auto & gcStore = requireGcStore(*store);
+
for (auto & path : storePaths)
options.pathsToDelete.insert(path);
GCResults results;
PrintFreed freed(true, results);
- store->collectGarbage(options, results);
+ gcStore.collectGarbage(options, results);
}
};
diff --git a/src/nix/store-gc.cc b/src/nix/store-gc.cc
index a2d74066e..21718dc0c 100644
--- a/src/nix/store-gc.cc
+++ b/src/nix/store-gc.cc
@@ -2,6 +2,7 @@
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
+#include "gc-store.hh"
using namespace nix;
@@ -33,10 +34,12 @@ struct CmdStoreGC : StoreCommand, MixDryRun
void run(ref<Store> store) override
{
+ auto & gcStore = requireGcStore(*store);
+
options.action = dryRun ? GCOptions::gcReturnDead : GCOptions::gcDeleteDead;
GCResults results;
PrintFreed freed(options.action == GCOptions::gcDeleteDead, results);
- store->collectGarbage(options, results);
+ gcStore.collectGarbage(options, results);
}
};
diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc
index 657df30d7..1d9ab28ba 100644
--- a/src/nix/why-depends.cc
+++ b/src/nix/why-depends.cc
@@ -82,9 +82,9 @@ struct CmdWhyDepends : SourceExprCommand
void run(ref<Store> store) override
{
auto package = parseInstallable(store, _package);
- auto packagePath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package);
+ auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package);
auto dependency = parseInstallable(store, _dependency);
- auto dependencyPath = toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency);
+ auto dependencyPath = Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency);
auto dependencyPathHash = dependencyPath.hashPart();
StorePathSet closure;
@@ -157,11 +157,11 @@ struct CmdWhyDepends : SourceExprCommand
closure (i.e., that have a non-infinite distance to
'dependency'). Print every edge on a path between `package`
and `dependency`. */
- std::function<void(Node &, const string &, const string &)> printNode;
+ std::function<void(Node &, const std::string &, const std::string &)> printNode;
struct BailOut { };
- printNode = [&](Node & node, const string & firstPad, const string & tailPad) {
+ printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) {
auto pathS = store->printStorePath(node.path);
assert(node.dist != inf);
@@ -171,12 +171,6 @@ struct CmdWhyDepends : SourceExprCommand
node.visited ? "\e[38;5;244m" : "",
firstPad != "" ? "→ " : "",
pathS);
- } else {
- logger->cout("%s%s%s%s" ANSI_NORMAL,
- firstPad,
- node.visited ? "\e[38;5;244m" : "",
- firstPad != "" ? treeLast : "",
- pathS);
}
if (node.path == dependencyPath && !all
@@ -184,7 +178,7 @@ struct CmdWhyDepends : SourceExprCommand
throw BailOut();
if (node.visited) return;
- node.visited = true;
+ if (precise) node.visited = true;
/* Sort the references by distance to `dependency` to
ensure that the shortest path is printed first. */
@@ -267,6 +261,16 @@ struct CmdWhyDepends : SourceExprCommand
if (!all) break;
}
+ if (!precise) {
+ auto pathS = store->printStorePath(ref.second->path);
+ logger->cout("%s%s%s%s" ANSI_NORMAL,
+ firstPad,
+ ref.second->visited ? "\e[38;5;244m" : "",
+ last ? treeLast : treeConn,
+ pathS);
+ node.visited = true;
+ }
+
printNode(*ref.second,
tailPad + (last ? treeNull : treeLine),
tailPad + (last ? treeNull : treeLine));
@@ -275,6 +279,9 @@ struct CmdWhyDepends : SourceExprCommand
RunPager pager;
try {
+ if (!precise) {
+ logger->cout("%s", store->printStorePath(graph.at(packagePath).path));
+ }
printNode(graph.at(packagePath), "", "");
} catch (BailOut & ) { }
}
diff --git a/src/resolve-system-dependencies/resolve-system-dependencies.cc b/src/resolve-system-dependencies/resolve-system-dependencies.cc
index 98c969437..4dd691981 100644
--- a/src/resolve-system-dependencies/resolve-system-dependencies.cc
+++ b/src/resolve-system-dependencies/resolve-system-dependencies.cc
@@ -23,9 +23,9 @@ Path resolveCacheFile(Path lib)
return cacheDir + "/" + lib;
}
-std::set<string> readCacheFile(const Path & file)
+std::set<std::string> readCacheFile(const Path & file)
{
- return tokenizeString<set<string>>(readFile(file), "\n");
+ return tokenizeString<std::set<std::string>>(readFile(file), "\n");
}
std::set<std::string> runResolver(const Path & filename)
@@ -81,7 +81,7 @@ std::set<std::string> runResolver(const Path & filename)
bool should_swap = magic == MH_CIGAM_64;
ptrdiff_t cmd_offset = mach64_offset + sizeof(mach_header_64);
- std::set<string> libs;
+ std::set<std::string> libs;
for (uint32_t i = 0; i < DO_SWAP(should_swap, m_header->ncmds); i++) {
load_command * cmd = (load_command *) (obj + cmd_offset);
switch(DO_SWAP(should_swap, cmd->cmd)) {
@@ -110,9 +110,9 @@ Path resolveSymlink(const Path & path)
: concatStrings(dirOf(path), "/", target);
}
-std::set<string> resolveTree(const Path & path, PathSet & deps)
+std::set<std::string> resolveTree(const Path & path, PathSet & deps)
{
- std::set<string> results;
+ std::set<std::string> results;
if (!deps.insert(path).second) return {};
for (auto & lib : runResolver(path)) {
results.insert(lib);
@@ -123,7 +123,7 @@ std::set<string> resolveTree(const Path & path, PathSet & deps)
return results;
}
-std::set<string> getPath(const Path & path)
+std::set<std::string> getPath(const Path & path)
{
if (hasPrefix(path, "/dev")) return {};
@@ -131,7 +131,7 @@ std::set<string> getPath(const Path & path)
if (pathExists(cacheFile))
return readCacheFile(cacheFile);
- std::set<string> deps, paths;
+ std::set<std::string> deps, paths;
paths.insert(path);
Path nextPath(path);
@@ -180,7 +180,7 @@ int main(int argc, char ** argv)
impurePaths.insert("/usr/lib/libSystem.dylib");
}
- std::set<string> allPaths;
+ std::set<std::string> allPaths;
for (auto & path : impurePaths)
for (auto & p : getPath(path))