aboutsummaryrefslogtreecommitdiff
path: root/src/nix
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/app.cc23
-rw-r--r--src/nix/build.cc41
-rw-r--r--src/nix/build.md7
-rw-r--r--src/nix/bundle.cc12
-rw-r--r--src/nix/develop.cc13
-rw-r--r--src/nix/doctor.cc4
-rw-r--r--src/nix/edit.cc18
-rw-r--r--src/nix/edit.md6
-rw-r--r--src/nix/eval.cc24
-rw-r--r--src/nix/flake.cc186
-rw-r--r--src/nix/flake.md4
-rw-r--r--src/nix/fmt.cc53
-rw-r--r--src/nix/fmt.md53
-rw-r--r--src/nix/log.cc14
-rw-r--r--src/nix/main.cc5
-rw-r--r--src/nix/make-content-addressable.cc102
-rw-r--r--src/nix/make-content-addressed.cc55
-rw-r--r--src/nix/make-content-addressed.md (renamed from src/nix/make-content-addressable.md)4
-rw-r--r--src/nix/prefetch.cc10
-rw-r--r--src/nix/profile.cc63
-rw-r--r--src/nix/profile.md6
-rw-r--r--src/nix/repl.cc85
-rw-r--r--src/nix/run.cc8
-rw-r--r--src/nix/search.cc8
-rw-r--r--src/nix/show-derivation.cc14
-rw-r--r--src/nix/store-copy-log.cc9
-rw-r--r--src/nix/store-delete.cc3
-rw-r--r--src/nix/store-gc.cc3
28 files changed, 522 insertions, 311 deletions
diff --git a/src/nix/app.cc b/src/nix/app.cc
index 2563180fb..95ac1cf5c 100644
--- a/src/nix/app.cc
+++ b/src/nix/app.cc
@@ -4,6 +4,7 @@
#include "eval-cache.hh"
#include "names.hh"
#include "command.hh"
+#include "derivations.hh"
namespace nix {
@@ -34,7 +35,7 @@ struct InstallableDerivedPath : Installable
/**
* Return the rewrites that are needed to resolve a string whose context is
- * included in `dependencies`
+ * included in `dependencies`.
*/
StringPairs resolveRewrites(Store & store, const BuiltPaths dependencies)
{
@@ -50,7 +51,7 @@ StringPairs resolveRewrites(Store & store, const BuiltPaths dependencies)
}
/**
- * Resolve the given string assuming the given context
+ * Resolve the given string assuming the given context.
*/
std::string resolveString(Store & store, const std::string & toResolve, const BuiltPaths dependencies)
{
@@ -60,17 +61,21 @@ std::string resolveString(Store & store, const std::string & toResolve, const Bu
UnresolvedApp Installable::toApp(EvalState & state)
{
- auto [cursor, attrPath] = getCursor(state);
+ auto cursor = getCursor(state);
+ auto attrPath = cursor->getAttrPath();
auto type = cursor->getAttr("type")->getString();
+ std::string expected = !attrPath.empty() && attrPath[0] == "apps" ? "app" : "derivation";
+ if (type != expected)
+ throw Error("attribute '%s' should have type '%s'", cursor->getAttrPathStr(), expected);
+
if (type == "app") {
auto [program, context] = cursor->getAttr("program")->getStringWithContext();
-
std::vector<StorePathWithOutputs> context2;
for (auto & [path, name] : context)
- context2.push_back({state.store->parseStorePath(path), {name}});
+ context2.push_back({path, {name}});
return UnresolvedApp{App {
.context = std::move(context2),
@@ -80,9 +85,9 @@ UnresolvedApp Installable::toApp(EvalState & state)
else if (type == "derivation") {
auto drvPath = cursor->forceDerivation();
- auto outPath = cursor->getAttr(state.sOutPath)->getString();
- auto outputName = cursor->getAttr(state.sOutputName)->getString();
- auto name = cursor->getAttr(state.sName)->getString();
+ auto outPath = cursor->getAttr("outPath")->getString();
+ auto outputName = cursor->getAttr("outputName")->getString();
+ auto name = cursor->getAttr("name")->getString();
auto aPname = cursor->maybeGetAttr("pname");
auto aMeta = cursor->maybeGetAttr("meta");
auto aMainProgram = aMeta ? aMeta->maybeGetAttr("mainProgram") : nullptr;
@@ -100,7 +105,7 @@ UnresolvedApp Installable::toApp(EvalState & state)
}
else
- throw Error("attribute '%s' has unsupported type '%s'", attrPath, type);
+ throw Error("attribute '%s' has unsupported type '%s'", cursor->getAttrPathStr(), type);
}
// FIXME: move to libcmd
diff --git a/src/nix/build.cc b/src/nix/build.cc
index 680db1c60..9c648d28e 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -4,6 +4,7 @@
#include "shared.hh"
#include "store-api.hh"
#include "local-fs-store.hh"
+#include "progress-bar.hh"
#include <nlohmann/json.hpp>
@@ -12,6 +13,7 @@ using namespace nix;
struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
{
Path outLink = "result";
+ bool printOutputPaths = false;
BuildMode buildMode = bmNormal;
CmdBuild()
@@ -32,6 +34,12 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
});
addFlag({
+ .longName = "print-out-paths",
+ .description = "Print the resulting output paths",
+ .handler = {&printOutputPaths, true},
+ });
+
+ addFlag({
.longName = "rebuild",
.description = "Rebuild an already built package and compare the result to the existing store paths.",
.handler = {&buildMode, bmCheck},
@@ -52,15 +60,26 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
void run(ref<Store> store) override
{
+ if (dryRun) {
+ std::vector<DerivedPath> pathsToBuild;
+
+ for (auto & i : installables) {
+ auto b = i->toDerivedPaths();
+ pathsToBuild.insert(pathsToBuild.end(), b.begin(), b.end());
+ }
+ printMissing(store, pathsToBuild, lvlError);
+ if (json)
+ logger->cout("%s", derivedPathsToJSON(pathsToBuild, store).dump());
+ return;
+ }
+
auto buildables = Installable::build(
getEvalStore(), store,
- dryRun ? Realise::Derivation : Realise::Outputs,
+ Realise::Outputs,
installables, buildMode);
if (json) logger->cout("%s", derivedPathsWithHintsToJSON(buildables, store).dump());
- if (dryRun) return;
-
if (outLink != "")
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
for (const auto & [_i, buildable] : enumerate(buildables)) {
@@ -82,6 +101,22 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
}, buildable.raw());
}
+ if (printOutputPaths) {
+ stopProgressBar();
+ for (auto & buildable : buildables) {
+ std::visit(overloaded {
+ [&](const BuiltPath::Opaque & bo) {
+ std::cout << store->printStorePath(bo.path) << std::endl;
+ },
+ [&](const BuiltPath::Built & bfd) {
+ for (auto & output : bfd.outputs) {
+ std::cout << store->printStorePath(output.second) << std::endl;
+ }
+ },
+ }, buildable.raw());
+ }
+ }
+
updateProfile(buildables);
}
};
diff --git a/src/nix/build.md b/src/nix/build.md
index 20138b7e0..6a79f308c 100644
--- a/src/nix/build.md
+++ b/src/nix/build.md
@@ -25,6 +25,13 @@ R""(
lrwxrwxrwx 1 … result-1 -> /nix/store/rkfrm0z6x6jmi7d3gsmma4j53h15mg33-cowsay-3.03+dfsg2
```
+* Build GNU Hello and print the resulting store path.
+
+ ```console
+ # nix build nixpkgs#hello --print-out-paths
+ /nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10
+ ```
+
* Build a specific output:
```console
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index 7ed558dee..2421adf4e 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -9,7 +9,7 @@ using namespace nix;
struct CmdBundle : InstallableCommand
{
- std::string bundler = "github:matthewbauer/nix-bundle";
+ std::string bundler = "github:NixOS/bundlers";
std::optional<Path> outLink;
CmdBundle()
@@ -97,21 +97,23 @@ struct CmdBundle : InstallableCommand
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
PathSet context2;
- auto drvPath = evalState->coerceToStorePath(*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());
- auto outPath = evalState->coerceToStorePath(*attr2->pos, *attr2->value, context2);
+ auto outPath = evalState->coerceToStorePath(attr2->pos, *attr2->value, context2);
store->buildPaths({ DerivedPath::Built { drvPath } });
auto outPathS = store->printStorePath(outPath);
if (!outLink) {
- auto &attr = vRes->attrs->need(evalState->sName);
- outLink = evalState->forceStringNoCtx(*attr.value,*attr.pos);
+ auto * attr = vRes->attrs->get(evalState->sName);
+ if (!attr)
+ throw Error("attribute 'name' missing");
+ outLink = evalState->forceStringNoCtx(*attr->value, attr->pos);
}
// TODO: will crash if not a localFSStore?
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index 8af5da9d0..7fc74d34e 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -196,21 +196,22 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
drv.inputSrcs.insert(std::move(getEnvShPath));
if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
for (auto & output : drv.outputs) {
- output.second = {
- .output = DerivationOutputDeferred{},
- };
+ output.second = DerivationOutput::Deferred {},
drv.env[output.first] = hashPlaceholder(output.first);
}
} else {
for (auto & output : drv.outputs) {
- output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } };
+ output.second = DerivationOutput::Deferred { };
drv.env[output.first] = "";
}
- Hash h = std::get<0>(hashDerivationModulo(*evalStore, drv, true));
+ auto hashesModulo = hashDerivationModulo(*evalStore, drv, true);
for (auto & output : drv.outputs) {
+ Hash h = hashesModulo.hashes.at(output.first);
auto outPath = store->makeOutputPath(output.first, h, drv.name);
- output.second = { .output = DerivationOutputInputAddressed { .path = outPath } };
+ output.second = DerivationOutput::InputAddressed {
+ .path = outPath,
+ };
drv.env[output.first] = store->printStorePath(outPath);
}
}
diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc
index 4f3003448..ea87e3d87 100644
--- a/src/nix/doctor.cc
+++ b/src/nix/doctor.cc
@@ -24,12 +24,12 @@ std::string formatProtocol(unsigned int proto)
}
bool checkPass(const std::string & msg) {
- logger->log(ANSI_GREEN "[PASS] " ANSI_NORMAL + msg);
+ notice(ANSI_GREEN "[PASS] " ANSI_NORMAL + msg);
return true;
}
bool checkFail(const std::string & msg) {
- logger->log(ANSI_RED "[FAIL] " ANSI_NORMAL + msg);
+ notice(ANSI_RED "[FAIL] " ANSI_NORMAL + msg);
return false;
}
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
index fc48db0d7..76a134b1f 100644
--- a/src/nix/edit.cc
+++ b/src/nix/edit.cc
@@ -28,19 +28,19 @@ struct CmdEdit : InstallableCommand
{
auto state = getEvalState();
- auto [v, pos] = installable->toValue(*state);
+ const auto [file, line] = [&] {
+ auto [v, pos] = installable->toValue(*state);
- try {
- pos = findPackageFilename(*state, *v, installable->what());
- } catch (NoPositionInfo &) {
- }
-
- if (pos == noPos)
- throw Error("cannot find position information for '%s", installable->what());
+ try {
+ return findPackageFilename(*state, *v, installable->what());
+ } catch (NoPositionInfo &) {
+ throw Error("cannot find position information for '%s", installable->what());
+ }
+ }();
stopProgressBar();
- auto args = editorFor(pos);
+ auto args = editorFor(file, line);
restoreProcessContext();
diff --git a/src/nix/edit.md b/src/nix/edit.md
index 80563d06b..89bd09abf 100644
--- a/src/nix/edit.md
+++ b/src/nix/edit.md
@@ -24,8 +24,8 @@ this attribute to the location of the definition of the
`meta.description`, `version` or `name` derivation attributes.
The editor to invoke is specified by the `EDITOR` environment
-variable. It defaults to `cat`. If the editor is `emacs`, `nano` or
-`vim`, it is passed the line number of the derivation using the
-argument `+<lineno>`.
+variable. It defaults to `cat`. If the editor is `emacs`, `nano`,
+`vim` or `kak`, it is passed the line number of the derivation using
+the argument `+<lineno>`.
)""
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index 8cd04d5fe..967dc8519 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -16,7 +16,7 @@ struct CmdEval : MixJSON, InstallableCommand
std::optional<std::string> apply;
std::optional<Path> writeTo;
- CmdEval()
+ CmdEval() : InstallableCommand(true /* supportReadOnlyMode */)
{
addFlag({
.longName = "raw",
@@ -77,9 +77,9 @@ struct CmdEval : MixJSON, InstallableCommand
if (pathExists(*writeTo))
throw Error("path '%s' already exists", *writeTo);
- std::function<void(Value & v, const Pos & pos, const Path & path)> recurse;
+ std::function<void(Value & v, const PosIdx pos, const Path & path)> recurse;
- recurse = [&](Value & v, const Pos & pos, const Path & path)
+ recurse = [&](Value & v, const PosIdx pos, const Path & path)
{
state->forceValue(v, pos);
if (v.type() == nString)
@@ -88,18 +88,22 @@ struct CmdEval : MixJSON, InstallableCommand
else if (v.type() == nAttrs) {
if (mkdir(path.c_str(), 0777) == -1)
throw SysError("creating directory '%s'", path);
- for (auto & attr : *v.attrs)
+ for (auto & attr : *v.attrs) {
+ std::string_view name = state->symbols[attr.name];
try {
- if (attr.name == "." || attr.name == "..")
- throw Error("invalid file name '%s'", attr.name);
- recurse(*attr.value, *attr.pos, path + "/" + std::string(attr.name));
+ if (name == "." || name == "..")
+ throw Error("invalid file name '%s'", name);
+ recurse(*attr.value, attr.pos, concatStrings(path, "/", name));
} catch (Error & e) {
- e.addTrace(*attr.pos, hintfmt("while evaluating the attribute '%s'", attr.name));
+ e.addTrace(
+ state->positions[attr.pos],
+ hintfmt("while evaluating the attribute '%s'", name));
throw;
}
+ }
}
else
- throw TypeError("value at '%s' is not a string or an attribute set", pos);
+ throw TypeError("value at '%s' is not a string or an attribute set", state->positions[pos]);
};
recurse(*v, pos, *writeTo);
@@ -117,7 +121,7 @@ struct CmdEval : MixJSON, InstallableCommand
else {
state->forceValueDeep(*v);
- logger->cout("%s", *v);
+ logger->cout("%s", printValue(*state, *v));
}
}
};
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 47a380238..c8d8461e4 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -123,7 +123,7 @@ struct CmdFlakeLock : FlakeCommand
};
static void enumerateOutputs(EvalState & state, Value & vFlake,
- std::function<void(const std::string & name, Value & vProvide, const Pos & pos)> callback)
+ std::function<void(const std::string & name, Value & vProvide, const PosIdx pos)> callback)
{
auto pos = vFlake.determinePos(noPos);
state.forceAttrs(vFlake, pos);
@@ -139,11 +139,11 @@ static void enumerateOutputs(EvalState & state, Value & vFlake,
else. This way we can disable IFD for hydraJobs and then enable
it for other outputs. */
if (auto attr = aOutputs->value->attrs->get(sHydraJobs))
- callback(attr->name, *attr->value, *attr->pos);
+ callback(state.symbols[attr->name], *attr->value, attr->pos);
for (auto & attr : *aOutputs->value->attrs) {
if (attr.name != sHydraJobs)
- callback(attr.name, *attr.value, *attr.pos);
+ callback(state.symbols[attr.name], *attr.value, attr.pos);
}
}
@@ -254,14 +254,6 @@ struct CmdFlakeInfo : CmdFlakeMetadata
}
};
-static bool argHasName(std::string_view arg, std::string_view expected)
-{
- return
- arg == expected
- || arg == "_"
- || (hasPrefix(arg, "_") && arg.substr(1) == expected);
-}
-
struct CmdFlakeCheck : FlakeCommand
{
bool build = true;
@@ -315,13 +307,25 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME: rewrite to use EvalCache.
- auto checkSystemName = [&](const std::string & system, const Pos & pos) {
+ auto resolve = [&] (PosIdx p) {
+ return state->positions[p];
+ };
+
+ auto argHasName = [&] (SymbolIdx arg, std::string_view expected) {
+ std::string_view name = state->symbols[arg];
+ return
+ name == expected
+ || name == "_"
+ || (hasPrefix(name, "_") && name.substr(1) == expected);
+ };
+
+ auto checkSystemName = [&](const std::string & system, const PosIdx pos) {
// FIXME: what's the format of "system"?
if (system.find('-') == std::string::npos)
- reportError(Error("'%s' is not a valid system type, at %s", system, pos));
+ reportError(Error("'%s' is not a valid system type, at %s", system, resolve(pos)));
};
- auto checkDerivation = [&](const std::string & attrPath, Value & v, const Pos & pos) -> std::optional<StorePath> {
+ auto checkDerivation = [&](const std::string & attrPath, Value & v, const PosIdx pos) -> std::optional<StorePath> {
try {
auto drvInfo = getDerivation(*state, v, false);
if (!drvInfo)
@@ -329,7 +333,7 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME: check meta attributes
return drvInfo->queryDrvPath();
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the derivation '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the derivation '%s'", attrPath));
reportError(e);
}
return std::nullopt;
@@ -337,7 +341,7 @@ struct CmdFlakeCheck : FlakeCommand
std::vector<DerivedPath> drvPaths;
- auto checkApp = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkApp = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
#if 0
// FIXME
@@ -348,12 +352,12 @@ struct CmdFlakeCheck : FlakeCommand
}
#endif
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the app definition '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the app definition '%s'", attrPath));
reportError(e);
}
};
- auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkOverlay = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
if (!v.isLambda()
@@ -368,12 +372,12 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME: if we have a 'nixpkgs' input, use it to
// evaluate the overlay.
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the overlay '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the overlay '%s'", attrPath));
reportError(e);
}
};
- auto checkModule = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkModule = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
if (v.isLambda()) {
@@ -382,9 +386,11 @@ struct CmdFlakeCheck : FlakeCommand
} else if (v.type() == nAttrs) {
for (auto & attr : *v.attrs)
try {
- state->forceValue(*attr.value, *attr.pos);
+ state->forceValue(*attr.value, attr.pos);
} catch (Error & e) {
- e.addTrace(*attr.pos, hintfmt("while evaluating the option '%s'", attr.name));
+ e.addTrace(
+ state->positions[attr.pos],
+ hintfmt("while evaluating the option '%s'", state->symbols[attr.name]));
throw;
}
} else
@@ -392,14 +398,14 @@ struct CmdFlakeCheck : FlakeCommand
// FIXME: if we have a 'nixpkgs' input, use it to
// check the module.
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the NixOS module '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the NixOS module '%s'", attrPath));
reportError(e);
}
};
- std::function<void(const std::string & attrPath, Value & v, const Pos & pos)> checkHydraJobs;
+ std::function<void(const std::string & attrPath, Value & v, const PosIdx pos)> checkHydraJobs;
- checkHydraJobs = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ checkHydraJobs = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceAttrs(v, pos);
@@ -407,23 +413,23 @@ struct CmdFlakeCheck : FlakeCommand
throw Error("jobset should not be a derivation at top-level");
for (auto & attr : *v.attrs) {
- state->forceAttrs(*attr.value, *attr.pos);
- auto attrPath2 = attrPath + "." + (std::string) attr.name;
+ state->forceAttrs(*attr.value, attr.pos);
+ auto attrPath2 = concatStrings(attrPath, ".", state->symbols[attr.name]);
if (state->isDerivation(*attr.value)) {
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking Hydra job '%s'", attrPath2));
- checkDerivation(attrPath2, *attr.value, *attr.pos);
+ checkDerivation(attrPath2, *attr.value, attr.pos);
} else
- checkHydraJobs(attrPath2, *attr.value, *attr.pos);
+ checkHydraJobs(attrPath2, *attr.value, attr.pos);
}
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the Hydra jobset '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the Hydra jobset '%s'", attrPath));
reportError(e);
}
};
- auto checkNixOSConfiguration = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkNixOSConfiguration = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking NixOS configuration '%s'", attrPath));
@@ -433,12 +439,12 @@ struct CmdFlakeCheck : FlakeCommand
if (!state->isDerivation(*vToplevel))
throw Error("attribute 'config.system.build.toplevel' is not a derivation");
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the NixOS configuration '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the NixOS configuration '%s'", attrPath));
reportError(e);
}
};
- auto checkTemplate = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkTemplate = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking template '%s'", attrPath));
@@ -448,7 +454,7 @@ struct CmdFlakeCheck : FlakeCommand
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
if (attr->name == state->symbols.create("path")) {
PathSet context;
- auto path = state->coerceToPath(*attr->pos, *attr->value, context);
+ auto path = state->coerceToPath(attr->pos, *attr->value, context);
if (!store->isInStore(path))
throw Error("template '%s' has a bad 'path' attribute");
// TODO: recursively check the flake in 'path'.
@@ -457,29 +463,29 @@ struct CmdFlakeCheck : FlakeCommand
throw Error("template '%s' lacks attribute 'path'", attrPath);
if (auto attr = v.attrs->get(state->symbols.create("description")))
- state->forceStringNoCtx(*attr->value, *attr->pos);
+ state->forceStringNoCtx(*attr->value, attr->pos);
else
throw Error("template '%s' lacks attribute 'description'", attrPath);
for (auto & attr : *v.attrs) {
- std::string name(attr.name);
- if (name != "path" && name != "description")
+ std::string_view name(state->symbols[attr.name]);
+ if (name != "path" && name != "description" && name != "welcomeText")
throw Error("template '%s' has unsupported attribute '%s'", attrPath, name);
}
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the template '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the template '%s'", attrPath));
reportError(e);
}
};
- auto checkBundler = [&](const std::string & attrPath, Value & v, const Pos & pos) {
+ auto checkBundler = [&](const std::string & attrPath, Value & v, const PosIdx pos) {
try {
state->forceValue(v, pos);
if (!v.isLambda())
throw Error("bundler must be a function");
// TODO: check types of inputs/outputs?
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking the template '%s'", attrPath));
+ e.addTrace(resolve(pos), hintfmt("while checking the template '%s'", attrPath));
reportError(e);
}
};
@@ -492,7 +498,7 @@ struct CmdFlakeCheck : FlakeCommand
enumerateOutputs(*state,
*vFlake,
- [&](const std::string & name, Value & vOutput, const Pos & pos) {
+ [&](const std::string & name, Value & vOutput, const PosIdx pos) {
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking flake output '%s'", name));
@@ -508,6 +514,7 @@ struct CmdFlakeCheck : FlakeCommand
name == "defaultBundler" ? "bundlers.<system>.default" :
name == "overlay" ? "overlays.default" :
name == "devShell" ? "devShells.<system>.default" :
+ name == "nixosModule" ? "nixosModules.default" :
"";
if (replacement != "")
warn("flake output attribute '%s' is deprecated; use '%s' instead", name, replacement);
@@ -515,66 +522,82 @@ struct CmdFlakeCheck : FlakeCommand
if (name == "checks") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
- state->forceAttrs(*attr.value, *attr.pos);
+ const auto & attr_name = state->symbols[attr.name];
+ checkSystemName(attr_name, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos);
for (auto & attr2 : *attr.value->attrs) {
auto drvPath = checkDerivation(
- fmt("%s.%s.%s", name, attr.name, attr2.name),
- *attr2.value, *attr2.pos);
- if (drvPath && (std::string) attr.name == settings.thisSystem.get())
+ fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
+ *attr2.value, attr2.pos);
+ if (drvPath && attr_name == settings.thisSystem.get())
drvPaths.push_back(DerivedPath::Built{*drvPath});
}
}
}
+ else if (name == "formatter") {
+ state->forceAttrs(vOutput, pos);
+ for (auto & attr : *vOutput.attrs) {
+ const auto & attr_name = state->symbols[attr.name];
+ checkSystemName(attr_name, attr.pos);
+ checkApp(
+ fmt("%s.%s", name, attr_name),
+ *attr.value, attr.pos);
+ }
+ }
+
else if (name == "packages" || name == "devShells") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
- state->forceAttrs(*attr.value, *attr.pos);
+ const auto & attr_name = state->symbols[attr.name];
+ checkSystemName(attr_name, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos);
for (auto & attr2 : *attr.value->attrs)
checkDerivation(
- fmt("%s.%s.%s", name, attr.name, attr2.name),
- *attr2.value, *attr2.pos);
+ fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
+ *attr2.value, attr2.pos);
}
}
else if (name == "apps") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
- state->forceAttrs(*attr.value, *attr.pos);
+ const auto & attr_name = state->symbols[attr.name];
+ checkSystemName(attr_name, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos);
for (auto & attr2 : *attr.value->attrs)
checkApp(
- fmt("%s.%s.%s", name, attr.name, attr2.name),
- *attr2.value, *attr2.pos);
+ fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
+ *attr2.value, attr2.pos);
}
}
else if (name == "defaultPackage" || name == "devShell") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ const auto & attr_name = state->symbols[attr.name];
+ checkSystemName(attr_name, attr.pos);
checkDerivation(
- fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ fmt("%s.%s", name, attr_name),
+ *attr.value, attr.pos);
}
}
else if (name == "defaultApp") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ const auto & attr_name = state->symbols[attr.name];
+ checkSystemName(attr_name, attr.pos);
checkApp(
- fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ fmt("%s.%s", name, attr_name),
+ *attr.value, attr.pos);
}
}
else if (name == "legacyPackages") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ checkSystemName(state->symbols[attr.name], attr.pos);
// FIXME: do getDerivations?
}
}
@@ -585,8 +608,8 @@ struct CmdFlakeCheck : FlakeCommand
else if (name == "overlays") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
- checkOverlay(fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ checkOverlay(fmt("%s.%s", name, state->symbols[attr.name]),
+ *attr.value, attr.pos);
}
else if (name == "nixosModule")
@@ -595,15 +618,15 @@ struct CmdFlakeCheck : FlakeCommand
else if (name == "nixosModules") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
- checkModule(fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ checkModule(fmt("%s.%s", name, state->symbols[attr.name]),
+ *attr.value, attr.pos);
}
else if (name == "nixosConfigurations") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
- checkNixOSConfiguration(fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ checkNixOSConfiguration(fmt("%s.%s", name, state->symbols[attr.name]),
+ *attr.value, attr.pos);
}
else if (name == "hydraJobs")
@@ -615,29 +638,31 @@ struct CmdFlakeCheck : FlakeCommand
else if (name == "templates") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
- checkTemplate(fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ checkTemplate(fmt("%s.%s", name, state->symbols[attr.name]),
+ *attr.value, attr.pos);
}
else if (name == "defaultBundler") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
+ const auto & attr_name = state->symbols[attr.name];
+ checkSystemName(attr_name, attr.pos);
checkBundler(
- fmt("%s.%s", name, attr.name),
- *attr.value, *attr.pos);
+ fmt("%s.%s", name, attr_name),
+ *attr.value, attr.pos);
}
}
else if (name == "bundlers") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
- checkSystemName(attr.name, *attr.pos);
- state->forceAttrs(*attr.value, *attr.pos);
+ const auto & attr_name = state->symbols[attr.name];
+ checkSystemName(attr_name, attr.pos);
+ state->forceAttrs(*attr.value, attr.pos);
for (auto & attr2 : *attr.value->attrs) {
checkBundler(
- fmt("%s.%s.%s", name, attr.name, attr2.name),
- *attr2.value, *attr2.pos);
+ fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]),
+ *attr2.value, attr2.pos);
}
}
}
@@ -646,7 +671,7 @@ struct CmdFlakeCheck : FlakeCommand
warn("unknown flake output '%s'", name);
} catch (Error & e) {
- e.addTrace(pos, hintfmt("while checking flake output '%s'", name));
+ e.addTrace(resolve(pos), hintfmt("while checking flake output '%s'", name));
reportError(e);
}
});
@@ -704,7 +729,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
defaultTemplateAttrPathsPrefixes,
lockFlags);
- auto [cursor, attrPath] = installable.getCursor(*evalState);
+ auto cursor = installable.getCursor(*evalState);
auto templateDirAttr = cursor->getAttr("path");
auto templateDir = templateDirAttr->getString();
@@ -983,7 +1008,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
auto showDerivation = [&]()
{
- auto name = visitor.getAttr(state->sName)->getString();
+ auto name = visitor.getAttr("name")->getString();
if (json) {
std::optional<std::string> description;
if (auto aMeta = visitor.maybeGetAttr("meta")) {
@@ -1010,6 +1035,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
|| (attrPath.size() == 1 && (
attrPath[0] == "defaultPackage"
|| attrPath[0] == "devShell"
+ || attrPath[0] == "formatter"
|| attrPath[0] == "nixosConfigurations"
|| attrPath[0] == "nixosModules"
|| attrPath[0] == "defaultApp"
@@ -1026,7 +1052,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
}
else if (
- (attrPath.size() == 2 && (attrPath[0] == "defaultPackage" || attrPath[0] == "devShell"))
+ (attrPath.size() == 2 && (attrPath[0] == "defaultPackage" || attrPath[0] == "devShell" || attrPath[0] == "formatter"))
|| (attrPath.size() == 3 && (attrPath[0] == "checks" || attrPath[0] == "packages" || attrPath[0] == "devShells"))
)
{
diff --git a/src/nix/flake.md b/src/nix/flake.md
index d59915eeb..7d179a6c4 100644
--- a/src/nix/flake.md
+++ b/src/nix/flake.md
@@ -177,8 +177,8 @@ Currently the `type` attribute can be one of the following:
attribute `url`.
In URL form, the schema must be `http://`, `https://` or `file://`
- URLs and the extension must be `.zip`, `.tar`, `.tar.gz`, `.tar.xz`,
- `.tar.bz2` or `.tar.zst`.
+ URLs and the extension must be `.zip`, `.tar`, `.tgz`, `.tar.gz`,
+ `.tar.xz`, `.tar.bz2` or `.tar.zst`.
* `github`: A more efficient way to fetch repositories from
GitHub. The following attributes are required:
diff --git a/src/nix/fmt.cc b/src/nix/fmt.cc
new file mode 100644
index 000000000..e5d44bd38
--- /dev/null
+++ b/src/nix/fmt.cc
@@ -0,0 +1,53 @@
+#include "command.hh"
+#include "run.hh"
+
+using namespace nix;
+
+struct CmdFmt : SourceExprCommand {
+ std::vector<std::string> args;
+
+ CmdFmt() { expectArgs({.label = "args", .handler = {&args}}); }
+
+ std::string description() override {
+ return "reformat your code in the standard style";
+ }
+
+ std::string doc() override {
+ return
+ #include "fmt.md"
+ ;
+ }
+
+ Category category() override { return catSecondary; }
+
+ Strings getDefaultFlakeAttrPaths() override {
+ return Strings{"formatter." + settings.thisSystem.get()};
+ }
+
+ Strings getDefaultFlakeAttrPathPrefixes() override { return Strings{}; }
+
+ void run(ref<Store> store) {
+ auto evalState = getEvalState();
+ auto evalStore = getEvalStore();
+
+ auto installable = parseInstallable(store, ".");
+ auto app = installable->toApp(*evalState).resolve(evalStore, store);
+
+ Strings programArgs{app.program};
+
+ // Propagate arguments from the CLI
+ if (args.empty()) {
+ // Format the current flake out of the box
+ programArgs.push_back(".");
+ } else {
+ // User wants more power, let them decide which paths to include/exclude
+ for (auto &i : args) {
+ programArgs.push_back(i);
+ }
+ }
+
+ runProgramInStore(store, app.program, programArgs);
+ };
+};
+
+static auto r2 = registerCommand<CmdFmt>("fmt");
diff --git a/src/nix/fmt.md b/src/nix/fmt.md
new file mode 100644
index 000000000..1c78bb36f
--- /dev/null
+++ b/src/nix/fmt.md
@@ -0,0 +1,53 @@
+R""(
+
+# Examples
+
+With [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt):
+
+```nix
+# flake.nix
+{
+ outputs = { nixpkgs, self }: {
+ formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixpkgs-fmt;
+ };
+}
+```
+
+- Format the current flake: `$ nix fmt`
+
+- Format a specific folder or file: `$ nix fmt ./folder ./file.nix`
+
+With [nixfmt](https://github.com/serokell/nixfmt):
+
+```nix
+# flake.nix
+{
+ outputs = { nixpkgs, self }: {
+ formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt;
+ };
+}
+```
+
+- Format specific files: `$ nix fmt ./file1.nix ./file2.nix`
+
+With [Alejandra](https://github.com/kamadorueda/alejandra):
+
+```nix
+# flake.nix
+{
+ outputs = { nixpkgs, self }: {
+ formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.alejandra;
+ };
+}
+```
+
+- Format the current flake: `$ nix fmt`
+
+- Format a specific folder or file: `$ nix fmt ./folder ./file.nix`
+
+# Description
+
+`nix fmt` will rewrite all Nix files (\*.nix) to a canonical format
+using the formatter specified in your flake.
+
+)""
diff --git a/src/nix/log.cc b/src/nix/log.cc
index fd3c1d787..72d02ef11 100644
--- a/src/nix/log.cc
+++ b/src/nix/log.cc
@@ -2,6 +2,7 @@
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
+#include "log-store.hh"
#include "progress-bar.hh"
using namespace nix;
@@ -34,17 +35,24 @@ struct CmdLog : InstallableCommand
RunPager pager;
for (auto & sub : subs) {
+ auto * logSubP = dynamic_cast<LogStore *>(&*sub);
+ if (!logSubP) {
+ printInfo("Skipped '%s' which does not support retrieving build logs", sub->getUri());
+ continue;
+ }
+ auto & logSub = *logSubP;
+
auto log = std::visit(overloaded {
[&](const DerivedPath::Opaque & bo) {
- return sub->getBuildLog(bo.path);
+ return logSub.getBuildLog(bo.path);
},
[&](const DerivedPath::Built & bfd) {
- return sub->getBuildLog(bfd.drvPath);
+ return logSub.getBuildLog(bfd.drvPath);
},
}, b.raw());
if (!log) continue;
stopProgressBar();
- printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri());
+ printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
std::cout << *log;
return;
}
diff --git a/src/nix/main.cc b/src/nix/main.cc
index b923f2535..6d0f6ce6e 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -117,7 +117,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
{"hash-path", {"hash", "path"}},
{"ls-nar", {"nar", "ls"}},
{"ls-store", {"store", "ls"}},
- {"make-content-addressable", {"store", "make-content-addressable"}},
+ {"make-content-addressable", {"store", "make-content-addressed"}},
{"optimise-store", {"store", "optimise"}},
{"ping-store", {"store", "ping"}},
{"sign-paths", {"store", "sign"}},
@@ -289,6 +289,7 @@ void mainWrapped(int argc, char * * argv)
}
if (argc == 2 && std::string(argv[1]) == "__dump-builtins") {
+ settings.experimentalFeatures = {Xp::Flakes, Xp::FetchClosure};
evalSettings.pureEval = false;
EvalState state({}, openStore("dummy://"));
auto res = nlohmann::json::object();
@@ -301,7 +302,7 @@ void mainWrapped(int argc, char * * argv)
b["arity"] = primOp->arity;
b["args"] = primOp->args;
b["doc"] = trim(stripIndentation(primOp->doc));
- res[(std::string) builtin.name] = std::move(b);
+ res[state.symbols[builtin.name]] = std::move(b);
}
std::cout << res.dump() << "\n";
return;
diff --git a/src/nix/make-content-addressable.cc b/src/nix/make-content-addressable.cc
deleted file mode 100644
index 2e75a3b61..000000000
--- a/src/nix/make-content-addressable.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-#include "command.hh"
-#include "store-api.hh"
-#include "references.hh"
-#include "common-args.hh"
-#include "json.hh"
-
-using namespace nix;
-
-struct CmdMakeContentAddressable : StorePathsCommand, MixJSON
-{
- CmdMakeContentAddressable()
- {
- realiseMode = Realise::Outputs;
- }
-
- std::string description() override
- {
- return "rewrite a path or closure to content-addressed form";
- }
-
- std::string doc() override
- {
- return
- #include "make-content-addressable.md"
- ;
- }
-
- void run(ref<Store> store, StorePaths && storePaths) override
- {
- auto paths = store->topoSortPaths(StorePathSet(storePaths.begin(), storePaths.end()));
-
- std::reverse(paths.begin(), paths.end());
-
- std::map<StorePath, StorePath> remappings;
-
- auto jsonRoot = json ? std::make_unique<JSONObject>(std::cout) : nullptr;
- auto jsonRewrites = json ? std::make_unique<JSONObject>(jsonRoot->object("rewrites")) : nullptr;
-
- for (auto & path : paths) {
- auto pathS = store->printStorePath(path);
- auto oldInfo = store->queryPathInfo(path);
- std::string oldHashPart(path.hashPart());
-
- StringSink sink;
- store->narFromPath(path, sink);
-
- StringMap rewrites;
-
- StorePathSet references;
- bool hasSelfReference = false;
- for (auto & ref : oldInfo->references) {
- if (ref == path)
- hasSelfReference = true;
- else {
- auto i = remappings.find(ref);
- auto replacement = i != remappings.end() ? i->second : ref;
- // FIXME: warn about unremapped paths?
- if (replacement != ref)
- rewrites.insert_or_assign(store->printStorePath(ref), store->printStorePath(replacement));
- references.insert(std::move(replacement));
- }
- }
-
- sink.s = rewriteStrings(sink.s, rewrites);
-
- HashModuloSink hashModuloSink(htSHA256, oldHashPart);
- hashModuloSink(sink.s);
-
- auto narHash = hashModuloSink.finish().first;
-
- ValidPathInfo info {
- store->makeFixedOutputPath(FileIngestionMethod::Recursive, narHash, path.name(), references, hasSelfReference),
- narHash,
- };
- info.references = std::move(references);
- if (hasSelfReference) info.references.insert(info.path);
- info.narSize = sink.s.size();
- info.ca = FixedOutputHash {
- .method = FileIngestionMethod::Recursive,
- .hash = info.narHash,
- };
-
- if (!json)
- notice("rewrote '%s' to '%s'", pathS, store->printStorePath(info.path));
-
- auto source = sinkToSource([&](Sink & nextSink) {
- RewritingSink rsink2(oldHashPart, std::string(info.path.hashPart()), nextSink);
- rsink2(sink.s);
- rsink2.flush();
- });
-
- store->addToStore(info, *source);
-
- if (json)
- jsonRewrites->attr(store->printStorePath(path), store->printStorePath(info.path));
-
- remappings.insert_or_assign(std::move(path), std::move(info.path));
- }
- }
-};
-
-static auto rCmdMakeContentAddressable = registerCommand2<CmdMakeContentAddressable>({"store", "make-content-addressable"});
diff --git a/src/nix/make-content-addressed.cc b/src/nix/make-content-addressed.cc
new file mode 100644
index 000000000..34860c38f
--- /dev/null
+++ b/src/nix/make-content-addressed.cc
@@ -0,0 +1,55 @@
+#include "command.hh"
+#include "store-api.hh"
+#include "make-content-addressed.hh"
+#include "common-args.hh"
+#include "json.hh"
+
+using namespace nix;
+
+struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, MixJSON
+{
+ CmdMakeContentAddressed()
+ {
+ realiseMode = Realise::Outputs;
+ }
+
+ std::string description() override
+ {
+ return "rewrite a path or closure to content-addressed form";
+ }
+
+ std::string doc() override
+ {
+ return
+ #include "make-content-addressed.md"
+ ;
+ }
+
+ void run(ref<Store> srcStore, StorePaths && storePaths) override
+ {
+ auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
+
+ auto remappings = makeContentAddressed(*srcStore, *dstStore,
+ StorePathSet(storePaths.begin(), storePaths.end()));
+
+ if (json) {
+ JSONObject jsonRoot(std::cout);
+ JSONObject jsonRewrites(jsonRoot.object("rewrites"));
+ for (auto & path : storePaths) {
+ auto i = remappings.find(path);
+ assert(i != remappings.end());
+ jsonRewrites.attr(srcStore->printStorePath(path), srcStore->printStorePath(i->second));
+ }
+ } else {
+ for (auto & path : storePaths) {
+ auto i = remappings.find(path);
+ assert(i != remappings.end());
+ notice("rewrote '%s' to '%s'",
+ srcStore->printStorePath(path),
+ srcStore->printStorePath(i->second));
+ }
+ }
+ }
+};
+
+static auto rCmdMakeContentAddressed = registerCommand2<CmdMakeContentAddressed>({"store", "make-content-addressed"});
diff --git a/src/nix/make-content-addressable.md b/src/nix/make-content-addressed.md
index 3dd847edc..215683e6d 100644
--- a/src/nix/make-content-addressable.md
+++ b/src/nix/make-content-addressed.md
@@ -5,7 +5,7 @@ R""(
* Create a content-addressed representation of the closure of GNU Hello:
```console
- # nix store make-content-addressable -r nixpkgs#hello
+ # nix store make-content-addressed nixpkgs#hello
rewrote '/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10' to '/nix/store/5skmmcb9svys5lj3kbsrjg7vf2irid63-hello-2.10'
```
@@ -29,7 +29,7 @@ R""(
system closure:
```console
- # nix store make-content-addressable -r /run/current-system
+ # nix store make-content-addressed /run/current-system
```
# Description
diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc
index f2dd44ba4..ce3288dc1 100644
--- a/src/nix/prefetch.cc
+++ b/src/nix/prefetch.cc
@@ -199,11 +199,13 @@ static int main_nix_prefetch_url(int argc, char * * argv)
state->forceAttrs(v, noPos);
/* Extract the URL. */
- auto & attr = v.attrs->need(state->symbols.create("urls"));
- state->forceList(*attr.value, noPos);
- if (attr.value->listSize() < 1)
+ auto * attr = v.attrs->get(state->symbols.create("urls"));
+ if (!attr)
+ throw Error("attribute 'urls' missing");
+ state->forceList(*attr->value, noPos);
+ if (attr->value->listSize() < 1)
throw Error("'urls' list is empty");
- url = state->forceString(*attr.value->listElems()[0]);
+ url = state->forceString(*attr->value->listElems()[0]);
/* Extract the hash mode. */
auto attr2 = v.attrs->get(state->symbols.create("outputHashMode"));
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index a8ff9c78a..b151e48d6 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -62,22 +62,21 @@ struct ProfileElement
return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths);
}
- void updateStorePaths(ref<Store> evalStore, ref<Store> store, Installable & installable)
+ void updateStorePaths(
+ ref<Store> evalStore,
+ ref<Store> store,
+ const BuiltPaths & builtPaths)
{
// FIXME: respect meta.outputsToInstall
storePaths.clear();
- for (auto & buildable : getBuiltPaths(evalStore, store, installable.toDerivedPaths())) {
+ for (auto & buildable : builtPaths) {
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)) {
+ for (auto & output : bfd.outputs)
storePaths.insert(output.second);
- }
},
}, buildable.raw());
}
@@ -98,18 +97,30 @@ struct ProfileManifest
auto json = nlohmann::json::parse(readFile(manifestPath));
auto version = json.value("version", 0);
- if (version != 1)
- throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version);
+ std::string sUrl;
+ std::string sOriginalUrl;
+ switch(version){
+ case 1:
+ sUrl = "uri";
+ sOriginalUrl = "originalUri";
+ break;
+ case 2:
+ sUrl = "url";
+ sOriginalUrl = "originalUrl";
+ break;
+ default:
+ throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version);
+ }
for (auto & e : json["elements"]) {
ProfileElement element;
for (auto & p : e["storePaths"])
element.storePaths.insert(state.store->parseStorePath((std::string) p));
element.active = e["active"];
- if (e.value("uri", "") != "") {
+ if (e.value(sUrl,"") != "") {
element.source = ProfileElementSource{
- parseFlakeRef(e["originalUri"]),
- parseFlakeRef(e["uri"]),
+ parseFlakeRef(e[sOriginalUrl]),
+ parseFlakeRef(e[sUrl]),
e["attrPath"]
};
}
@@ -143,14 +154,14 @@ struct ProfileManifest
obj["storePaths"] = paths;
obj["active"] = element.active;
if (element.source) {
- obj["originalUri"] = element.source->originalRef.to_string();
- obj["uri"] = element.source->resolvedRef.to_string();
+ obj["originalUrl"] = element.source->originalRef.to_string();
+ obj["url"] = element.source->resolvedRef.to_string();
obj["attrPath"] = element.source->attrPath;
}
array.push_back(obj);
}
nlohmann::json json;
- json["version"] = 1;
+ json["version"] = 2;
json["elements"] = array;
return json.dump();
}
@@ -235,6 +246,16 @@ struct ProfileManifest
}
};
+static std::map<Installable *, BuiltPaths>
+builtPathsPerInstallable(
+ const std::vector<std::pair<std::shared_ptr<Installable>, BuiltPath>> & builtPaths)
+{
+ std::map<Installable *, BuiltPaths> res;
+ for (auto & [installable, builtPath] : builtPaths)
+ res[installable.get()].push_back(builtPath);
+ return res;
+}
+
struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
{
std::string description() override
@@ -253,7 +274,9 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
{
ProfileManifest manifest(*getEvalState(), *profile);
- auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
+ auto builtPaths = builtPathsPerInstallable(
+ Installable::build2(
+ getEvalStore(), store, Realise::Outputs, installables, bmNormal));
for (auto & installable : installables) {
ProfileElement element;
@@ -268,7 +291,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
};
}
- element.updateStorePaths(getEvalStore(), store, *installable);
+ element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]);
manifest.elements.push_back(std::move(element));
}
@@ -456,12 +479,14 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
warn ("Use 'nix profile list' to see the current profile.");
}
- auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
+ auto builtPaths = builtPathsPerInstallable(
+ Installable::build2(
+ 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);
+ element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]);
}
updateProfile(manifest.build(store));
diff --git a/src/nix/profile.md b/src/nix/profile.md
index 0a4ff2fa9..8dade051d 100644
--- a/src/nix/profile.md
+++ b/src/nix/profile.md
@@ -70,7 +70,7 @@ are installed in this version of the profile. It looks like this:
{
"active": true,
"attrPath": "legacyPackages.x86_64-linux.zoom-us",
- "originalUri": "flake:nixpkgs",
+ "originalUrl": "flake:nixpkgs",
"storePaths": [
"/nix/store/wbhg2ga8f3h87s9h5k0slxk0m81m4cxl-zoom-us-5.3.469451.0927"
],
@@ -84,11 +84,11 @@ are installed in this version of the profile. It looks like this:
Each object in the array `elements` denotes an installed package and
has the following fields:
-* `originalUri`: The [flake reference](./nix3-flake.md) specified by
+* `originalUrl`: The [flake reference](./nix3-flake.md) specified by
the user at the time of installation (e.g. `nixpkgs`). This is also
the flake reference that will be used by `nix profile upgrade`.
-* `uri`: The immutable flake reference to which `originalUri`
+* `uri`: The immutable flake reference to which `originalUrl`
resolved.
* `attrPath`: The flake output attribute that provided this
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 3a51a13e6..998ff7328 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -25,6 +25,7 @@ extern "C" {
#include "eval-inline.hh"
#include "attr-path.hh"
#include "store-api.hh"
+#include "log-store.hh"
#include "common-eval-args.hh"
#include "get-drvs.hh"
#include "derivations.hh"
@@ -32,6 +33,7 @@ extern "C" {
#include "command.hh"
#include "finally.hh"
#include "markdown.hh"
+#include "local-fs-store.hh"
#if HAVE_BOEHMGC
#define GC_INCLUDE_NEW
@@ -71,7 +73,7 @@ struct NixRepl
void initEnv();
void reloadFiles();
void addAttrsToScope(Value & attrs);
- void addVarToScope(const Symbol & name, Value & v);
+ void addVarToScope(const SymbolIdx name, Value & v);
Expr * parseString(std::string s);
void evalString(std::string s, Value & v);
@@ -118,7 +120,7 @@ std::string runNix(Path program, const Strings & args,
});
if (!statusOk(res.first))
- throw ExecError(res.first, fmt("program '%1%' %2%", program, statusToString(res.first)));
+ throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first));
return res.second;
}
@@ -345,9 +347,9 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
state->forceAttrs(v, noPos);
for (auto & i : *v.attrs) {
- std::string name = i.name;
+ std::string_view name = state->symbols[i.name];
if (name.substr(0, cur2.size()) != cur2) continue;
- completions.insert(prev + expr + "." + name);
+ completions.insert(concatStrings(prev, expr, ".", name));
}
} catch (ParseError & e) {
@@ -395,6 +397,7 @@ StorePath NixRepl::getDerivationPath(Value & v) {
bool NixRepl::processLine(std::string line)
{
+ line = trim(line);
if (line == "") return true;
_isInterrupted = false;
@@ -417,7 +420,8 @@ bool NixRepl::processLine(std::string line)
<< " <expr> Evaluate and print expression\n"
<< " <x> = <expr> Bind expression to variable\n"
<< " :a <expr> Add attributes from resulting set to scope\n"
- << " :b <expr> Build derivation\n"
+ << " :b <expr> Build a derivation\n"
+ << " :bl <expr> Build a derivation, creating GC roots in the working directory\n"
<< " :e <expr> Open package or function in $EDITOR\n"
<< " :i <expr> Build derivation, then install result into current profile\n"
<< " :l <path> Load Nix expression and add it to scope\n"
@@ -457,21 +461,23 @@ bool NixRepl::processLine(std::string line)
Value v;
evalString(arg, v);
- Pos pos;
-
- if (v.type() == nPath || v.type() == nString) {
- PathSet context;
- auto filename = state->coerceToString(noPos, v, context);
- pos.file = state->symbols.create(*filename);
- } else if (v.isLambda()) {
- pos = v.lambda.fun->pos;
- } else {
- // assume it's a derivation
- pos = findPackageFilename(*state, v, arg);
- }
+ const auto [file, line] = [&] () -> std::pair<std::string, uint32_t> {
+ if (v.type() == nPath || v.type() == nString) {
+ PathSet context;
+ auto filename = state->coerceToString(noPos, v, context).toOwned();
+ state->symbols.create(filename);
+ return {filename, 0};
+ } else if (v.isLambda()) {
+ auto pos = state->positions[v.lambda.fun->pos];
+ return {pos.file, pos.line};
+ } else {
+ // assume it's a derivation
+ return findPackageFilename(*state, v, arg);
+ }
+ }();
// Open in EDITOR
- auto args = editorFor(pos);
+ auto args = editorFor(file, line);
auto editor = args.front();
args.pop_front();
@@ -494,24 +500,32 @@ bool NixRepl::processLine(std::string line)
Value v, f, result;
evalString(arg, v);
evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f);
- state->callFunction(f, v, result, Pos());
+ state->callFunction(f, v, result, PosIdx());
StorePath drvPath = getDerivationPath(result);
runNix("nix-shell", {state->store->printStorePath(drvPath)});
}
- else if (command == ":b" || command == ":i" || command == ":s" || command == ":log") {
+ else if (command == ":b" || command == ":bl" || command == ":i" || command == ":s" || command == ":log") {
Value v;
evalString(arg, v);
StorePath drvPath = getDerivationPath(v);
Path drvPathRaw = state->store->printStorePath(drvPath);
- if (command == ":b") {
+ if (command == ":b" || command == ":bl") {
state->store->buildPaths({DerivedPath::Built{drvPath}});
auto drv = state->store->readDerivation(drvPath);
logger->cout("\nThis derivation produced the following outputs:");
- for (auto & [outputName, outputPath] : state->store->queryDerivationOutputMap(drvPath))
- logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
+ for (auto & [outputName, outputPath] : state->store->queryDerivationOutputMap(drvPath)) {
+ auto localStore = state->store.dynamic_pointer_cast<LocalFSStore>();
+ if (localStore && command == ":bl") {
+ std::string symlink = "repl-result-" + outputName;
+ localStore->addPermRoot(outputPath, absPath(symlink));
+ logger->cout(" ./%s -> %s", symlink, state->store->printStorePath(outputPath));
+ } else {
+ logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));
+ }
+ }
} else if (command == ":i") {
runNix("nix-env", {"-i", drvPathRaw});
} else if (command == ":log") {
@@ -526,9 +540,16 @@ bool NixRepl::processLine(std::string line)
bool foundLog = false;
RunPager pager;
for (auto & sub : subs) {
- auto log = sub->getBuildLog(drvPath);
+ auto * logSubP = dynamic_cast<LogStore *>(&*sub);
+ if (!logSubP) {
+ printInfo("Skipped '%s' which does not support retrieving build logs", sub->getUri());
+ continue;
+ }
+ auto & logSub = *logSubP;
+
+ auto log = logSub.getBuildLog(drvPath);
if (log) {
- printInfo("got build log for '%s' from '%s'", drvPathRaw, sub->getUri());
+ printInfo("got build log for '%s' from '%s'", drvPathRaw, logSub.getUri());
logger->writeToStdout(*log);
foundLog = true;
break;
@@ -652,7 +673,7 @@ void NixRepl::initEnv()
varNames.clear();
for (auto & i : state->staticBaseEnv.vars)
- varNames.insert(i.first);
+ varNames.emplace(state->symbols[i.first]);
}
@@ -682,7 +703,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((std::string) i.name);
+ varNames.emplace(state->symbols[i.name]);
}
staticEnv.sort();
staticEnv.deduplicate();
@@ -690,7 +711,7 @@ void NixRepl::addAttrsToScope(Value & attrs)
}
-void NixRepl::addVarToScope(const Symbol & name, Value & v)
+void NixRepl::addVarToScope(const SymbolIdx name, Value & v)
{
if (displ >= envSize)
throw Error("environment full; cannot add more variables");
@@ -699,7 +720,7 @@ void NixRepl::addVarToScope(const Symbol & name, Value & v)
staticEnv.vars.emplace_back(name, displ);
staticEnv.sort();
env->values[displ++] = &v;
- varNames.insert((std::string) name);
+ varNames.emplace(state->symbols[name]);
}
@@ -780,7 +801,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
Bindings::iterator i = v.attrs->find(state->sDrvPath);
PathSet context;
if (i != v.attrs->end())
- str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context));
+ str << state->store->printStorePath(state->coerceToStorePath(i->pos, *i->value, context));
else
str << "???";
str << "»";
@@ -792,7 +813,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
typedef std::map<std::string, Value *> Sorted;
Sorted sorted;
for (auto & i : *v.attrs)
- sorted[i.name] = i.value;
+ sorted.emplace(state->symbols[i.name], i.value);
for (auto & i : sorted) {
if (isVarName(i.first))
@@ -842,7 +863,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
case nFunction:
if (v.isLambda()) {
std::ostringstream s;
- s << v.lambda.fun->pos;
+ s << state->positions[v.lambda.fun->pos];
str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL;
} else if (v.isPrimOp()) {
str << ANSI_MAGENTA "«primop»" ANSI_NORMAL;
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 033263c36..25a8fa8d3 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -38,9 +38,12 @@ void runProgramInStore(ref<Store> store,
unshare(CLONE_NEWUSER) doesn't work in a multithreaded program
(which "nix" is), so we exec() a single-threaded helper program
(chrootHelper() below) to do the work. */
- auto store2 = store.dynamic_pointer_cast<LocalStore>();
+ auto store2 = store.dynamic_pointer_cast<LocalFSStore>();
- if (store2 && store->storeDir != store2->getRealStoreDir()) {
+ if (!store2)
+ throw Error("store '%s' is not a local store so it does not support command execution", store->getUri());
+
+ if (store->storeDir != store2->getRealStoreDir()) {
Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), program };
for (auto & arg : args) helperArgs.push_back(arg);
@@ -179,6 +182,7 @@ struct CmdRun : InstallableCommand
{
auto state = getEvalState();
+ lockFlags.applyNixConfig = true;
auto app = installable->toApp(*state).resolve(getEvalStore(), store);
Strings allArgs{app.program};
diff --git a/src/nix/search.cc b/src/nix/search.cc
index e9307342c..8b1e9ae6c 100644
--- a/src/nix/search.cc
+++ b/src/nix/search.cc
@@ -9,7 +9,7 @@
#include "shared.hh"
#include "eval-cache.hh"
#include "attr-path.hh"
-#include "fmt.hh"
+#include "hilite.hh"
#include <regex>
#include <fstream>
@@ -154,7 +154,7 @@ struct CmdSearch : InstallableCommand, MixJSON
recurse();
else if (attrPath[0] == "legacyPackages" && attrPath.size() > 2) {
- auto attr = cursor.maybeGetAttr(state->sRecurseForDerivations);
+ auto attr = cursor.maybeGetAttr("recurseForDerivations");
if (attr && attr->getBool())
recurse();
}
@@ -165,8 +165,8 @@ struct CmdSearch : InstallableCommand, MixJSON
}
};
- for (auto & [cursor, prefix] : installable->getCursors(*state))
- visit(*cursor, parseAttrPath(*state, prefix), true);
+ for (auto & cursor : installable->getCursors(*state))
+ visit(*cursor, cursor->getAttrPath(), true);
if (!json && !results)
throw Error("no results for the given search term(s)!");
diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc
index 61a02c9b3..fb46b4dbf 100644
--- a/src/nix/show-derivation.cc
+++ b/src/nix/show-derivation.cc
@@ -65,19 +65,23 @@ struct CmdShowDerivation : InstallablesCommand
auto & outputName = _outputName; // work around clang bug
auto outputObj { outputsObj.object(outputName) };
std::visit(overloaded {
- [&](const DerivationOutputInputAddressed & doi) {
+ [&](const DerivationOutput::InputAddressed & doi) {
outputObj.attr("path", store->printStorePath(doi.path));
},
- [&](const DerivationOutputCAFixed & dof) {
+ [&](const DerivationOutput::CAFixed & dof) {
outputObj.attr("path", store->printStorePath(dof.path(*store, drv.name, outputName)));
outputObj.attr("hashAlgo", dof.hash.printMethodAlgo());
outputObj.attr("hash", dof.hash.hash.to_string(Base16, false));
},
- [&](const DerivationOutputCAFloating & dof) {
+ [&](const DerivationOutput::CAFloating & dof) {
outputObj.attr("hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType));
},
- [&](const DerivationOutputDeferred &) {},
- }, output.output);
+ [&](const DerivationOutput::Deferred &) {},
+ [&](const DerivationOutput::Impure & doi) {
+ outputObj.attr("hashAlgo", makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType));
+ outputObj.attr("impure", true);
+ },
+ }, output.raw());
}
}
diff --git a/src/nix/store-copy-log.cc b/src/nix/store-copy-log.cc
index 079cd6b3e..2e288f743 100644
--- a/src/nix/store-copy-log.cc
+++ b/src/nix/store-copy-log.cc
@@ -1,6 +1,8 @@
#include "command.hh"
#include "shared.hh"
#include "store-api.hh"
+#include "store-cast.hh"
+#include "log-store.hh"
#include "sync.hh"
#include "thread-pool.hh"
@@ -26,7 +28,10 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand
void run(ref<Store> srcStore) override
{
+ auto & srcLogStore = require<LogStore>(*srcStore);
+
auto dstStore = getDstStore();
+ auto & dstLogStore = require<LogStore>(*dstStore);
StorePathSet drvPaths;
@@ -35,8 +40,8 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand
drvPaths.insert(drvPath);
for (auto & drvPath : drvPaths) {
- if (auto log = srcStore->getBuildLog(drvPath))
- dstStore->addBuildLog(drvPath, *log);
+ if (auto log = srcLogStore.getBuildLog(drvPath))
+ dstLogStore.addBuildLog(drvPath, *log);
else
throw Error("build log for '%s' is not available", srcStore->printStorePath(drvPath));
}
diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc
index aa7a8b12f..ca43f1530 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 "store-cast.hh"
#include "gc-store.hh"
using namespace nix;
@@ -33,7 +34,7 @@ struct CmdStoreDelete : StorePathsCommand
void run(ref<Store> store, std::vector<StorePath> && storePaths) override
{
- auto & gcStore = requireGcStore(*store);
+ auto & gcStore = require<GcStore>(*store);
for (auto & path : storePaths)
options.pathsToDelete.insert(path);
diff --git a/src/nix/store-gc.cc b/src/nix/store-gc.cc
index 21718dc0c..8b9b5d164 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 "store-cast.hh"
#include "gc-store.hh"
using namespace nix;
@@ -34,7 +35,7 @@ struct CmdStoreGC : StoreCommand, MixDryRun
void run(ref<Store> store) override
{
- auto & gcStore = requireGcStore(*store);
+ auto & gcStore = require<GcStore>(*store);
options.action = dryRun ? GCOptions::gcReturnDead : GCOptions::gcDeleteDead;
GCResults results;