From 073e134de6260de7d90b135b7e173157741d4853 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 8 Mar 2022 17:45:19 +0000 Subject: Rename `requireGcStore` to `GcStore::require` I should have done this to begin with. This will be nicer once more Store sub-interfaces exist too, to illustrate the pattern. --- src/nix/store-delete.cc | 2 +- src/nix/store-gc.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nix') diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc index aa7a8b12f..0de7efaba 100644 --- a/src/nix/store-delete.cc +++ b/src/nix/store-delete.cc @@ -33,7 +33,7 @@ struct CmdStoreDelete : StorePathsCommand void run(ref store, std::vector && storePaths) override { - auto & gcStore = requireGcStore(*store); + auto & gcStore = GcStore::require(*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..515f4ffdb 100644 --- a/src/nix/store-gc.cc +++ b/src/nix/store-gc.cc @@ -34,7 +34,7 @@ struct CmdStoreGC : StoreCommand, MixDryRun void run(ref store) override { - auto & gcStore = requireGcStore(*store); + auto & gcStore = GcStore::require(*store); options.action = dryRun ? GCOptions::gcReturnDead : GCOptions::gcDeleteDead; GCResults results; -- cgit v1.2.3 From 678d1c2aa0f499466c723d3461277dc197515f57 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 8 Mar 2022 18:20:39 +0000 Subject: Factor out a `LogStore` interface Continue progress on #5729. Just as I hoped, this uncovered an issue: the daemon protocol is missing a way to query build logs. This doesn't effect `unix://`, but does effect `ssh://`. A FIXME is left for this, so we come back to it later. --- src/nix/log.cc | 14 +++++++++++--- src/nix/repl.cc | 12 ++++++++++-- src/nix/store-copy-log.cc | 8 ++++++-- 3 files changed, 27 insertions(+), 7 deletions(-) (limited to 'src/nix') 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(&*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/repl.cc b/src/nix/repl.cc index 3a51a13e6..916353d8c 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" @@ -526,9 +527,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(&*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; diff --git a/src/nix/store-copy-log.cc b/src/nix/store-copy-log.cc index 079cd6b3e..22b3980c0 100644 --- a/src/nix/store-copy-log.cc +++ b/src/nix/store-copy-log.cc @@ -1,6 +1,7 @@ #include "command.hh" #include "shared.hh" #include "store-api.hh" +#include "log-store.hh" #include "sync.hh" #include "thread-pool.hh" @@ -26,7 +27,10 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand void run(ref srcStore) override { + auto & srcLogStore = LogStore::require(*srcStore); + auto dstStore = getDstStore(); + auto & dstLogStore = LogStore::require(*dstStore); StorePathSet drvPaths; @@ -35,8 +39,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)); } -- cgit v1.2.3 From a03b1fd7f60788304f358d5f4dc063c7c9e650a9 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 9 Mar 2022 15:27:48 +0000 Subject: Deduplicate the Store downcasting with a template --- src/nix/store-copy-log.cc | 5 +++-- src/nix/store-delete.cc | 3 ++- src/nix/store-gc.cc | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/nix') diff --git a/src/nix/store-copy-log.cc b/src/nix/store-copy-log.cc index 22b3980c0..2e288f743 100644 --- a/src/nix/store-copy-log.cc +++ b/src/nix/store-copy-log.cc @@ -1,6 +1,7 @@ #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" @@ -27,10 +28,10 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand void run(ref srcStore) override { - auto & srcLogStore = LogStore::require(*srcStore); + auto & srcLogStore = require(*srcStore); auto dstStore = getDstStore(); - auto & dstLogStore = LogStore::require(*dstStore); + auto & dstLogStore = require(*dstStore); StorePathSet drvPaths; diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc index 0de7efaba..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, std::vector && storePaths) override { - auto & gcStore = GcStore::require(*store); + auto & gcStore = require(*store); for (auto & path : storePaths) options.pathsToDelete.insert(path); diff --git a/src/nix/store-gc.cc b/src/nix/store-gc.cc index 515f4ffdb..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) override { - auto & gcStore = GcStore::require(*store); + auto & gcStore = require(*store); options.action = dryRun ? GCOptions::gcReturnDead : GCOptions::gcDeleteDead; GCResults results; -- cgit v1.2.3 From 2191dab65726012b057402e13132dd7a062d8440 Mon Sep 17 00:00:00 2001 From: Kevin Amado Date: Fri, 11 Mar 2022 08:57:28 -0500 Subject: nix-fmt: add command --- src/nix/flake.cc | 12 ++++++++++++ src/nix/fmt.cc | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/nix/fmt.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 src/nix/fmt.cc create mode 100644 src/nix/fmt.md (limited to 'src/nix') diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 47a380238..9830ce841 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -527,6 +527,16 @@ struct CmdFlakeCheck : FlakeCommand } } + else if (name == "formatter") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + 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) { @@ -1010,6 +1020,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" @@ -1059,6 +1070,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON else if ( (attrPath.size() == 2 && attrPath[0] == "defaultApp") || + (attrPath.size() == 2 && attrPath[0] == "formatter") || (attrPath.size() == 3 && attrPath[0] == "apps")) { auto aType = visitor.maybeGetAttr("type"); 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 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) { + 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("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. + +)"" -- cgit v1.2.3 From 0948b8e94dfbf87ed2a695c6c7d8dac250e2c293 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 1 Oct 2021 18:05:53 +0000 Subject: Reduce variants for derivation hash modulo This changes was taken from dynamic derivation (#4628). It` somewhat undoes the refactors I first did for floating CA derivations, as the benefit of hindsight + requirements of dynamic derivations made me reconsider some things. They aren't to consequential, but I figured they might be good to land first, before the more profound changes @thufschmitt has in the works. --- src/nix/develop.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nix') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 8af5da9d0..dafcafd79 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -206,7 +206,8 @@ static StorePath getDerivationEnvironment(ref store, ref evalStore output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } }; drv.env[output.first] = ""; } - Hash h = std::get<0>(hashDerivationModulo(*evalStore, drv, true)); + auto h0 = hashDerivationModulo(*evalStore, drv, true); + const Hash & h = h0.requireNoFixedNonDeferred(); for (auto & output : drv.outputs) { auto outPath = store->makeOutputPath(output.first, h, drv.name); -- cgit v1.2.3 From 3fc4c612fbde332d66b78dcc5b17b7d0d5235484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Thu, 17 Mar 2022 11:34:31 +0100 Subject: Fix `nix build --dry-run` with CA derivations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don’t try and assume that we know the output paths when we’ve just built with `--dry-run`. Instead make `--dry-run` follow a different code path that won’t assume the knowledge of the output paths at all. Fix #6275 --- src/nix/build.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'src/nix') diff --git a/src/nix/build.cc b/src/nix/build.cc index 680db1c60..840c7ca38 100644 --- a/src/nix/build.cc +++ b/src/nix/build.cc @@ -52,15 +52,26 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile void run(ref store) override { + if (dryRun) { + std::vector 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()) for (const auto & [_i, buildable] : enumerate(buildables)) { -- cgit v1.2.3 From 197feed51dd770929ba8f6f12aec50ed8597a747 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 17 Mar 2022 22:29:15 +0000 Subject: Clean up `DerivationOutput`, and headers 1. `DerivationOutput` now as the `std::variant` as a base class. And the variants are given hierarchical names under `DerivationOutput`. In 8e0d0689be797f9e42f9b43b06f50c1af7f20b4a @matthewbauer and I didn't know a better idiom, and so we made it a field. But this sort of "newtype" is anoying for literals downstream. Since then we leaned the base class, inherit the constructors trick, e.g. used in `DerivedPath`. Switching to use that makes this more ergonomic, and consistent. 2. `store-api.hh` and `derivations.hh` are now independent. In bcde5456cc3295061a0726881c3e441444dd6680 I swapped the dependency, but I now know it is better to just keep on using incomplete types as much as possible for faster compilation and good separation of concerns. --- src/nix/app.cc | 1 + src/nix/develop.cc | 12 +++++++----- src/nix/show-derivation.cc | 10 +++++----- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'src/nix') diff --git a/src/nix/app.cc b/src/nix/app.cc index 2563180fb..30e138a96 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 { diff --git a/src/nix/develop.cc b/src/nix/develop.cc index dafcafd79..6baf539c3 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -196,14 +196,14 @@ static StorePath getDerivationEnvironment(ref store, ref 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::InputAddressed { + .path = StorePath::dummy, + }; drv.env[output.first] = ""; } auto h0 = hashDerivationModulo(*evalStore, drv, true); @@ -211,7 +211,9 @@ static StorePath getDerivationEnvironment(ref store, ref evalStore for (auto & output : drv.outputs) { 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/show-derivation.cc b/src/nix/show-derivation.cc index 61a02c9b3..0d9655732 100644 --- a/src/nix/show-derivation.cc +++ b/src/nix/show-derivation.cc @@ -65,19 +65,19 @@ 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 &) {}, + }, output.raw()); } } -- cgit v1.2.3 From 8496be7defed3584c9fcd3b5d905fb84a9515d6f Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 18 Mar 2022 02:07:31 +0000 Subject: Use Deferred when building an input-addressed drv Easier than using dummy path with input addressed. --- src/nix/develop.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/nix') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 6baf539c3..d2f9b5a6a 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -201,9 +201,7 @@ static StorePath getDerivationEnvironment(ref store, ref evalStore } } else { for (auto & output : drv.outputs) { - output.second = DerivationOutput::InputAddressed { - .path = StorePath::dummy, - }; + output.second = DerivationOutput::Deferred { }; drv.env[output.first] = ""; } auto h0 = hashDerivationModulo(*evalStore, drv, true); -- cgit v1.2.3 From 4d6a3806d24b54f06ddc0cf234ac993db028cf29 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sat, 12 Mar 2022 00:28:00 +0000 Subject: Decode string context straight to using `StorePath`s I gather decoding happens on demand, so I hope don't think this should have any perf implications one way or the other. --- src/nix/app.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix') diff --git a/src/nix/app.cc b/src/nix/app.cc index 2563180fb..a4e0df06a 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -70,7 +70,7 @@ UnresolvedApp Installable::toApp(EvalState & state) std::vector 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), -- cgit v1.2.3 From 3b776cb0a7574bf11c20fe0a1d91ec1d21d8ebeb Mon Sep 17 00:00:00 2001 From: Hideaki Kawai Date: Tue, 22 Mar 2022 23:18:02 +0900 Subject: nix edit: support kakoune --- src/nix/edit.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nix') 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 `+`. +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 `+`. )"" -- cgit v1.2.3 From 4546a007a46fe12b77a49ae8753ab186d0b55fdd Mon Sep 17 00:00:00 2001 From: Rok Garbas Date: Thu, 24 Mar 2022 12:28:38 +0100 Subject: Fix flake profile use of originalUrl vs. originalUri Fixes #5872 --- src/nix/profile.cc | 5 +++-- src/nix/profile.md | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/nix') diff --git a/src/nix/profile.cc b/src/nix/profile.cc index a8ff9c78a..da990ddc8 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -107,8 +107,9 @@ struct ProfileManifest element.storePaths.insert(state.store->parseStorePath((std::string) p)); element.active = e["active"]; if (e.value("uri", "") != "") { + auto originalUrl = e.value("originalUrl", e["originalUri"]); element.source = ProfileElementSource{ - parseFlakeRef(e["originalUri"]), + parseFlakeRef(originalUrl), parseFlakeRef(e["uri"]), e["attrPath"] }; @@ -143,7 +144,7 @@ struct ProfileManifest obj["storePaths"] = paths; obj["active"] = element.active; if (element.source) { - obj["originalUri"] = element.source->originalRef.to_string(); + obj["originalUrl"] = element.source->originalRef.to_string(); obj["uri"] = element.source->resolvedRef.to_string(); obj["attrPath"] = element.source->attrPath; } 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 -- cgit v1.2.3 From 545c2d0d8cbac86c169a6dd049c1ed9c3913774d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 22 Mar 2022 21:14:58 +0100 Subject: fetchClosure: Allow a path to be rewritten to CA on the fly The advantage is that the resulting closure doesn't need to be signed, so you don't need to configure any binary cache keys on the client. --- src/nix/make-content-addressable.cc | 87 ++++++++----------------------------- 1 file changed, 19 insertions(+), 68 deletions(-) (limited to 'src/nix') diff --git a/src/nix/make-content-addressable.cc b/src/nix/make-content-addressable.cc index 2e75a3b61..a8579ea7c 100644 --- a/src/nix/make-content-addressable.cc +++ b/src/nix/make-content-addressable.cc @@ -1,6 +1,6 @@ #include "command.hh" #include "store-api.hh" -#include "references.hh" +#include "make-content-addressed.hh" #include "common-args.hh" #include "json.hh" @@ -27,74 +27,25 @@ struct CmdMakeContentAddressable : StorePathsCommand, MixJSON void run(ref store, StorePaths && storePaths) override { - auto paths = store->topoSortPaths(StorePathSet(storePaths.begin(), storePaths.end())); - - std::reverse(paths.begin(), paths.end()); - - std::map remappings; - - auto jsonRoot = json ? std::make_unique(std::cout) : nullptr; - auto jsonRewrites = json ? std::make_unique(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)); - } + auto remappings = makeContentAddressed(*store, *store, + 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(store->printStorePath(path), store->printStorePath(i->second)); + } + } else { + for (auto & path : storePaths) { + auto i = remappings.find(path); + assert(i != remappings.end()); + notice("rewrote '%s' to '%s'", + store->printStorePath(path), + store->printStorePath(i->second)); } - - 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)); } } }; -- cgit v1.2.3 From 5acaf13d3564f689e5461f29a9cc5958809d5e93 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 22 Mar 2022 21:54:49 +0100 Subject: Rename 'nix store make-content-addressable' to 'nix store make-content-addressed' --- src/nix/main.cc | 2 +- src/nix/make-content-addressable.cc | 53 --------------------------------- src/nix/make-content-addressable.md | 59 ------------------------------------- src/nix/make-content-addressed.cc | 53 +++++++++++++++++++++++++++++++++ src/nix/make-content-addressed.md | 59 +++++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 113 deletions(-) delete mode 100644 src/nix/make-content-addressable.cc delete mode 100644 src/nix/make-content-addressable.md create mode 100644 src/nix/make-content-addressed.cc create mode 100644 src/nix/make-content-addressed.md (limited to 'src/nix') diff --git a/src/nix/main.cc b/src/nix/main.cc index b923f2535..9bc6c15fa 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"}}, diff --git a/src/nix/make-content-addressable.cc b/src/nix/make-content-addressable.cc deleted file mode 100644 index a8579ea7c..000000000 --- a/src/nix/make-content-addressable.cc +++ /dev/null @@ -1,53 +0,0 @@ -#include "command.hh" -#include "store-api.hh" -#include "make-content-addressed.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, StorePaths && storePaths) override - { - auto remappings = makeContentAddressed(*store, *store, - 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(store->printStorePath(path), store->printStorePath(i->second)); - } - } else { - for (auto & path : storePaths) { - auto i = remappings.find(path); - assert(i != remappings.end()); - notice("rewrote '%s' to '%s'", - store->printStorePath(path), - store->printStorePath(i->second)); - } - } - } -}; - -static auto rCmdMakeContentAddressable = registerCommand2({"store", "make-content-addressable"}); diff --git a/src/nix/make-content-addressable.md b/src/nix/make-content-addressable.md deleted file mode 100644 index 3dd847edc..000000000 --- a/src/nix/make-content-addressable.md +++ /dev/null @@ -1,59 +0,0 @@ -R""( - -# Examples - -* Create a content-addressed representation of the closure of GNU Hello: - - ```console - # nix store make-content-addressable -r nixpkgs#hello - … - rewrote '/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10' to '/nix/store/5skmmcb9svys5lj3kbsrjg7vf2irid63-hello-2.10' - ``` - - Since the resulting paths are content-addressed, they are always - trusted and don't need signatures to copied to another store: - - ```console - # nix copy --to /tmp/nix --trusted-public-keys '' /nix/store/5skmmcb9svys5lj3kbsrjg7vf2irid63-hello-2.10 - ``` - - By contrast, the original closure is input-addressed, so it does - need signatures to be trusted: - - ```console - # nix copy --to /tmp/nix --trusted-public-keys '' nixpkgs#hello - cannot add path '/nix/store/zy9wbxwcygrwnh8n2w9qbbcr6zk87m26-libunistring-0.9.10' because it lacks a valid signature - ``` - -* Create a content-addressed representation of the current NixOS - system closure: - - ```console - # nix store make-content-addressable -r /run/current-system - ``` - -# Description - -This command converts the closure of the store paths specified by -*installables* to content-addressed form. Nix store paths are usually -*input-addressed*, meaning that the hash part of the store path is -computed from the contents of the derivation (i.e., the build-time -dependency graph). Input-addressed paths need to be signed by a -trusted key if you want to import them into a store, because we need -to trust that the contents of the path were actually built by the -derivation. - -By contrast, in a *content-addressed* path, the hash part is computed -from the contents of the path. This allows the contents of the path to -be verified without any additional information such as -signatures. This means that a command like - -```console -# nix store build /nix/store/5skmmcb9svys5lj3kbsrjg7vf2irid63-hello-2.10 \ - --substituters https://my-cache.example.org -``` - -will succeed even if the binary cache `https://my-cache.example.org` -doesn't present any signatures. - -)"" diff --git a/src/nix/make-content-addressed.cc b/src/nix/make-content-addressed.cc new file mode 100644 index 000000000..dc0447cb8 --- /dev/null +++ b/src/nix/make-content-addressed.cc @@ -0,0 +1,53 @@ +#include "command.hh" +#include "store-api.hh" +#include "make-content-addressed.hh" +#include "common-args.hh" +#include "json.hh" + +using namespace nix; + +struct CmdMakeContentAddressed : 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, StorePaths && storePaths) override + { + auto remappings = makeContentAddressed(*store, *store, + 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(store->printStorePath(path), store->printStorePath(i->second)); + } + } else { + for (auto & path : storePaths) { + auto i = remappings.find(path); + assert(i != remappings.end()); + notice("rewrote '%s' to '%s'", + store->printStorePath(path), + store->printStorePath(i->second)); + } + } + } +}; + +static auto rCmdMakeContentAddressed = registerCommand2({"store", "make-content-addressed"}); diff --git a/src/nix/make-content-addressed.md b/src/nix/make-content-addressed.md new file mode 100644 index 000000000..215683e6d --- /dev/null +++ b/src/nix/make-content-addressed.md @@ -0,0 +1,59 @@ +R""( + +# Examples + +* Create a content-addressed representation of the closure of GNU Hello: + + ```console + # nix store make-content-addressed nixpkgs#hello + … + rewrote '/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10' to '/nix/store/5skmmcb9svys5lj3kbsrjg7vf2irid63-hello-2.10' + ``` + + Since the resulting paths are content-addressed, they are always + trusted and don't need signatures to copied to another store: + + ```console + # nix copy --to /tmp/nix --trusted-public-keys '' /nix/store/5skmmcb9svys5lj3kbsrjg7vf2irid63-hello-2.10 + ``` + + By contrast, the original closure is input-addressed, so it does + need signatures to be trusted: + + ```console + # nix copy --to /tmp/nix --trusted-public-keys '' nixpkgs#hello + cannot add path '/nix/store/zy9wbxwcygrwnh8n2w9qbbcr6zk87m26-libunistring-0.9.10' because it lacks a valid signature + ``` + +* Create a content-addressed representation of the current NixOS + system closure: + + ```console + # nix store make-content-addressed /run/current-system + ``` + +# Description + +This command converts the closure of the store paths specified by +*installables* to content-addressed form. Nix store paths are usually +*input-addressed*, meaning that the hash part of the store path is +computed from the contents of the derivation (i.e., the build-time +dependency graph). Input-addressed paths need to be signed by a +trusted key if you want to import them into a store, because we need +to trust that the contents of the path were actually built by the +derivation. + +By contrast, in a *content-addressed* path, the hash part is computed +from the contents of the path. This allows the contents of the path to +be verified without any additional information such as +signatures. This means that a command like + +```console +# nix store build /nix/store/5skmmcb9svys5lj3kbsrjg7vf2irid63-hello-2.10 \ + --substituters https://my-cache.example.org +``` + +will succeed even if the binary cache `https://my-cache.example.org` +doesn't present any signatures. + +)"" -- cgit v1.2.3 From e5f7029ba49a486c1b0c8011be79b8b41be20935 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 22 Mar 2022 23:40:04 +0100 Subject: nix store make-content-addressed: Support --from / --to --- src/nix/make-content-addressed.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/nix') diff --git a/src/nix/make-content-addressed.cc b/src/nix/make-content-addressed.cc index dc0447cb8..34860c38f 100644 --- a/src/nix/make-content-addressed.cc +++ b/src/nix/make-content-addressed.cc @@ -6,7 +6,7 @@ using namespace nix; -struct CmdMakeContentAddressed : StorePathsCommand, MixJSON +struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, MixJSON { CmdMakeContentAddressed() { @@ -25,9 +25,11 @@ struct CmdMakeContentAddressed : StorePathsCommand, MixJSON ; } - void run(ref store, StorePaths && storePaths) override + void run(ref srcStore, StorePaths && storePaths) override { - auto remappings = makeContentAddressed(*store, *store, + auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri); + + auto remappings = makeContentAddressed(*srcStore, *dstStore, StorePathSet(storePaths.begin(), storePaths.end())); if (json) { @@ -36,15 +38,15 @@ struct CmdMakeContentAddressed : StorePathsCommand, MixJSON for (auto & path : storePaths) { auto i = remappings.find(path); assert(i != remappings.end()); - jsonRewrites.attr(store->printStorePath(path), store->printStorePath(i->second)); + 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'", - store->printStorePath(path), - store->printStorePath(i->second)); + srcStore->printStorePath(path), + srcStore->printStorePath(i->second)); } } } -- cgit v1.2.3 From cbcb69a39ce7ceb300d5a5588258b7f8c0c0664d Mon Sep 17 00:00:00 2001 From: polykernel <81340136+polykernel@users.noreply.github.com> Date: Sun, 20 Mar 2022 11:39:36 -0400 Subject: nix: allow whitespace characters before command in repl Before this change, processLine always uses the first character as the start of the line. This cause whitespaces to matter at the beginning of the line whereas it does not matter anywhere else. This commit trims leading white spaces of the string line so that subsequent operations can be performed on the string without explicitly tracking starting and ending indices of the string. --- src/nix/repl.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nix') diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 916353d8c..1f9d4fb4e 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -396,6 +396,7 @@ StorePath NixRepl::getDerivationPath(Value & v) { bool NixRepl::processLine(std::string line) { + line = trim(line); if (line == "") return true; _isInterrupted = false; -- cgit v1.2.3 From 86b05ccd54f2e98ac2b5cef3bcecb29ed6ec4fd8 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 25 Mar 2022 14:04:18 +0100 Subject: Only provide builtin.{getFlake,fetchClosure} is the corresponding experimental feature is enabled This allows writing fallback code like if builtins ? fetchClosure then builtins.fetchClose { ... } else builtins.storePath ... --- src/nix/main.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nix') diff --git a/src/nix/main.cc b/src/nix/main.cc index 9bc6c15fa..6198681e7 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -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(); -- cgit v1.2.3 From 16860a0328094c04c3e877089119a56f9ddfbcd6 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sat, 26 Mar 2022 11:32:38 +0100 Subject: nix eval: Add option `read-only` --- src/nix/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix') diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 8cd04d5fe..733b93661 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -16,7 +16,7 @@ struct CmdEval : MixJSON, InstallableCommand std::optional apply; std::optional writeTo; - CmdEval() + CmdEval() : InstallableCommand(true /* supportReadOnlyMode */) { addFlag({ .longName = "raw", -- cgit v1.2.3 From 057f9ee1900312f42efe6c5cebb02b07b4ff2131 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 28 Mar 2022 14:21:35 +0200 Subject: nix profile install: Don't use queryDerivationOutputMap() Instead get the outputs from Installable::build(). This will also allow 'nix profile install' to support impure derivations. Fixes #6286. --- src/nix/profile.cc | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'src/nix') diff --git a/src/nix/profile.cc b/src/nix/profile.cc index da990ddc8..f35947ddb 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 evalStore, ref store, Installable & installable) + void updateStorePaths( + ref evalStore, + ref 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()); } @@ -236,6 +235,16 @@ struct ProfileManifest } }; +static std::map +builtPathsPerInstallable( + const std::vector, BuiltPath>> & builtPaths) +{ + std::map res; + for (auto & [installable, builtPath] : builtPaths) + res[installable.get()].push_back(builtPath); + return res; +} + struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile { std::string description() override @@ -254,7 +263,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; @@ -269,7 +280,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile }; } - element.updateStorePaths(getEvalStore(), store, *installable); + element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]); manifest.elements.push_back(std::move(element)); } @@ -457,12 +468,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)); -- cgit v1.2.3 From b266fd53dda9c303c55ceb55752c2117011fce69 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 28 Mar 2022 14:58:38 +0200 Subject: nix {run,shell}: Print a better error message if the store is not local Closes #6317 --- src/nix/run.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/nix') diff --git a/src/nix/run.cc b/src/nix/run.cc index 033263c36..23e893fbf 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -38,9 +38,12 @@ void runProgramInStore(ref 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(); + auto store2 = store.dynamic_pointer_cast(); - 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); -- cgit v1.2.3 From 390269ed8784b1a73a3310e63eb96a4b62861654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Wed, 16 Mar 2022 14:21:09 +0100 Subject: Simplify the handling of the hash modulo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than having four different but very similar types of hashes, make only one, with a tag indicating whether it corresponds to a regular of deferred derivation. This implies a slight logical change: The original Nix+multiple-outputs model assumed only one hash-modulo per derivation. Adding multiple-outputs CA derivations changed this as these have one hash-modulo per output. This change is now treating each derivation as having one hash modulo per output. This obviously means that we internally loose the guaranty that all the outputs of input-addressed derivations have the same hash modulo. But it turns out that it doesn’t matter because there’s nothing in the code taking advantage of that fact (and it probably shouldn’t anyways). The upside is that it is now much easier to work with these hashes, and we can get rid of a lot of useless `std::visit{ overloaded`. Co-authored-by: John Ericson --- src/nix/develop.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nix') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index d2f9b5a6a..7fc74d34e 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -204,10 +204,10 @@ static StorePath getDerivationEnvironment(ref store, ref evalStore output.second = DerivationOutput::Deferred { }; drv.env[output.first] = ""; } - auto h0 = hashDerivationModulo(*evalStore, drv, true); - const Hash & h = h0.requireNoFixedNonDeferred(); + 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 = DerivationOutput::InputAddressed { .path = outPath, -- cgit v1.2.3 From d77823b502ebc358d33a7719375677fed92291c8 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Wed, 30 Mar 2022 16:10:42 -0400 Subject: bundler: update default bundler to support new bundler API --- src/nix/bundle.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix') diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc index 7ed558dee..81fb8464a 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 outLink; CmdBundle() -- cgit v1.2.3 From 50f9f335c92a88e8c9bd3421e6befbcd06cac4ec Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Wed, 30 Mar 2022 16:35:26 -0400 Subject: profile!: consistent use of url/uri. create new version --- src/nix/profile.cc | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'src/nix') diff --git a/src/nix/profile.cc b/src/nix/profile.cc index f35947ddb..b151e48d6 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -97,19 +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", "") != "") { - auto originalUrl = e.value("originalUrl", e["originalUri"]); + if (e.value(sUrl,"") != "") { element.source = ProfileElementSource{ - parseFlakeRef(originalUrl), - parseFlakeRef(e["uri"]), + parseFlakeRef(e[sOriginalUrl]), + parseFlakeRef(e[sUrl]), e["attrPath"] }; } @@ -144,13 +155,13 @@ struct ProfileManifest obj["active"] = element.active; if (element.source) { obj["originalUrl"] = element.source->originalRef.to_string(); - obj["uri"] = element.source->resolvedRef.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(); } -- cgit v1.2.3 From 5cd72598feaff3c4bbcc7304a4844768f64a1ee0 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 30 Mar 2022 16:31:01 +0200 Subject: Add support for impure derivations Impure derivations are derivations that can produce a different result every time they're built. Example: stdenv.mkDerivation { name = "impure"; __impure = true; # marks this derivation as impure outputHashAlgo = "sha256"; outputHashMode = "recursive"; buildCommand = "date > $out"; }; Some important characteristics: * This requires the 'impure-derivations' experimental feature. * Impure derivations are not "cached". Thus, running "nix-build" on the example above multiple times will cause a rebuild every time. * They are implemented similar to CA derivations, i.e. the output is moved to a content-addressed path in the store. The difference is that we don't register a realisation in the Nix database. * Pure derivations are not allowed to depend on impure derivations. In the future fixed-output derivations will be allowed to depend on impure derivations, thus forming an "impurity barrier" in the dependency graph. * When sandboxing is enabled, impure derivations can access the network in the same way as fixed-output derivations. In relaxed sandboxing mode, they can access the local filesystem. --- src/nix/show-derivation.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/nix') diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc index 0d9655732..fb46b4dbf 100644 --- a/src/nix/show-derivation.cc +++ b/src/nix/show-derivation.cc @@ -77,6 +77,10 @@ struct CmdShowDerivation : InstallablesCommand outputObj.attr("hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType)); }, [&](const DerivationOutput::Deferred &) {}, + [&](const DerivationOutput::Impure & doi) { + outputObj.attr("hashAlgo", makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)); + outputObj.attr("impure", true); + }, }, output.raw()); } } -- cgit v1.2.3 From c1e2ce4515c12ff0b4b1c3ab6d1e057507104979 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Thu, 31 Mar 2022 20:30:53 -0400 Subject: fix(run): set applyNixConfig lockFlag --- src/nix/run.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nix') diff --git a/src/nix/run.cc b/src/nix/run.cc index 23e893fbf..25a8fa8d3 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -182,6 +182,7 @@ struct CmdRun : InstallableCommand { auto state = getEvalState(); + lockFlags.applyNixConfig = true; auto app = installable->toApp(*state).resolve(getEvalStore(), store); Strings allArgs{app.program}; -- cgit v1.2.3 From 5abe3f4aa61f33ac2124a624763e067257541871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Tue, 5 Apr 2022 11:03:43 +0200 Subject: Allow `welcomeText` when checking a flake template Fix https://github.com/NixOS/nix/issues/6321 --- src/nix/flake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix') diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 47a380238..ce7dc101a 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -463,7 +463,7 @@ struct CmdFlakeCheck : FlakeCommand for (auto & attr : *v.attrs) { std::string name(attr.name); - if (name != "path" && name != "description") + if (name != "path" && name != "description" && name != "welcomeText") throw Error("template '%s' has unsupported attribute '%s'", attrPath, name); } } catch (Error & e) { -- cgit v1.2.3 From 9a640afc1e63bed28926cb44fe85137fb7d2d2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Tue, 5 Apr 2022 11:33:46 +0200 Subject: doctor: Always show the output Fix https://github.com/NixOS/nix/issues/6342 --- src/nix/doctor.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nix') 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; } -- cgit v1.2.3 From b9c969a86667a7b16a7efa1df0e3d090ef2ead72 Mon Sep 17 00:00:00 2001 From: Rehno Lindeque Date: Wed, 6 Apr 2022 12:20:39 -0400 Subject: nix flake check: Warn about deprecated nixosModule output --- src/nix/flake.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nix') diff --git a/src/nix/flake.cc b/src/nix/flake.cc index ce7dc101a..a876bb3af 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -508,6 +508,7 @@ struct CmdFlakeCheck : FlakeCommand name == "defaultBundler" ? "bundlers..default" : name == "overlay" ? "overlays.default" : name == "devShell" ? "devShells..default" : + name == "nixosModule" ? "nixosModules.default" : ""; if (replacement != "") warn("flake output attribute '%s' is deprecated; use '%s' instead", name, replacement); -- cgit v1.2.3 From d89840b103e57e81e5245c3fe9edfbf7c3477ad5 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 14 Apr 2022 14:04:19 +0200 Subject: Make InstallableFlake::toValue() and toDerivation() behave consistently In particular, this means that 'nix eval` (which uses toValue()) no longer auto-calls functions or functors (because AttrCursor::findAlongAttrPath() doesn't). Fixes #6152. Also use ref<> in a few places, and don't return attrpaths from getCursor() because cursors already have a getAttrPath() method. --- src/nix/app.cc | 4 ++-- src/nix/flake.cc | 2 +- src/nix/search.cc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nix') diff --git a/src/nix/app.cc b/src/nix/app.cc index 803d028f0..55efccdee 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -61,7 +61,7 @@ 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 type = cursor->getAttr("type")->getString(); @@ -101,7 +101,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/flake.cc b/src/nix/flake.cc index a876bb3af..66c315e5a 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -705,7 +705,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(); diff --git a/src/nix/search.cc b/src/nix/search.cc index e9307342c..e96a85ea2 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -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)!"); -- cgit v1.2.3 From 9b41239d8fdcc3fe50febe718c15833ebc224354 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 25 Mar 2022 13:36:41 -0400 Subject: fix: ensure apps are apps and packages are packages --- src/nix/app.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/nix') diff --git a/src/nix/app.cc b/src/nix/app.cc index 803d028f0..a43566496 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -65,6 +65,15 @@ UnresolvedApp Installable::toApp(EvalState & state) auto type = cursor->getAttr("type")->getString(); + std::string expected; + if (hasPrefix(attrPath,"apps.")) { + expected = "app"; + } else { + expected = "derivation"; + } + if (type != expected) { + throw Error("Attribute '%s' should have type '%s'.", attrPath, expected); + } if (type == "app") { auto [program, context] = cursor->getAttr("program")->getStringWithContext(); -- cgit v1.2.3 From 8b659eacce046326fa510f83b505b0ad326e60ef Mon Sep 17 00:00:00 2001 From: Robert Helgesson Date: Mon, 18 Apr 2022 17:14:15 +0200 Subject: Add .tgz as tarball extension in documentation Support for the `tgz` shorthand was added in 52f5fa948a4784b6a9b707770f4beee6a8674dee. --- src/nix/flake.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nix') 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: -- cgit v1.2.3 From 75b62e52600a44b42693944b50638bf580a2c86e Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 18 Jun 2020 17:54:16 +0000 Subject: Avoid `fmt` when constructor already does it There is a correctnes issue here, but #3724 will fix that. This is just a cleanup for brevity's sake. --- src/nix/repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix') diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 1f9d4fb4e..ec8a57a8e 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -119,7 +119,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; } -- cgit v1.2.3 From 2016b7142ad1282981ad1505085fff0ac9c7d66c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 19 Apr 2022 12:09:12 +0200 Subject: Fix compilation, style fixes --- src/nix/app.cc | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'src/nix') diff --git a/src/nix/app.cc b/src/nix/app.cc index bd6988066..6b6b31a12 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -62,22 +62,17 @@ std::string resolveString(Store & store, const std::string & toResolve, const Bu UnresolvedApp Installable::toApp(EvalState & state) { auto cursor = getCursor(state); + auto attrPath = cursor->getAttrPath(); auto type = cursor->getAttr("type")->getString(); - std::string expected; - if (hasPrefix(attrPath,"apps.")) { - expected = "app"; - } else { - expected = "derivation"; - } - if (type != expected) { - throw Error("Attribute '%s' should have type '%s'.", attrPath, expected); - } + 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 context2; for (auto & [path, name] : context) context2.push_back({path, {name}}); -- cgit v1.2.3 From c9e58aa5ff75351a5bb5af1258e019beef13721a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 19 Apr 2022 20:48:13 +0200 Subject: Require formatters to be packages Because of 9b41239d8fdcc3fe50febe718c15833ebc224354, a formatter can no longer be a package *or* an app. So let's require it to be a package for now. --- src/nix/app.cc | 4 ++-- src/nix/flake.cc | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src/nix') diff --git a/src/nix/app.cc b/src/nix/app.cc index 6b6b31a12..df7303e15 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -35,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) { @@ -51,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) { diff --git a/src/nix/flake.cc b/src/nix/flake.cc index dbd157248..04b23ed0f 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -1038,7 +1038,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")) ) { @@ -1071,7 +1071,6 @@ struct CmdFlakeShow : FlakeCommand, MixJSON else if ( (attrPath.size() == 2 && attrPath[0] == "defaultApp") || - (attrPath.size() == 2 && attrPath[0] == "formatter") || (attrPath.size() == 3 && attrPath[0] == "apps")) { auto aType = visitor.maybeGetAttr("type"); -- cgit v1.2.3 From 0e2b01b14e77dfb9a6f1748dec353273f91d1609 Mon Sep 17 00:00:00 2001 From: ckie Date: Mon, 18 Apr 2022 20:21:47 +0300 Subject: nix repl: make symlinks with the :bl command Requested by ppepino on the Matrix: https://matrix.to/#/!KqkRjyTEzAGRiZFBYT:nixos.org/$Tb32BS3rVE2BSULAX4sPm0h6CDewX2hClOTGzTC7gwM?via=nixos.org&via=matrix.org&via=nixos.dev This adds a new command, :bl, which works like :b but also creates a GC root symlink to the various derivation outputs. ckie@cookiemonster ~/git/nix -> ./outputs/out/bin/nix repl Welcome to Nix 2.6.0. Type :? for help. nix-repl> :l Added 16118 variables. nix-repl> :b runCommand "hello" {} "echo hi > $out" This derivation produced the following outputs: ./repl-result-out -> /nix/store/kidqq2acdpi05c4a9mlbg2baikmzik44-hello [1 built, 0.0 MiB DL] ckie@cookiemonster ~/git/nix -> cat ./repl-result-out hi --- src/nix/repl.cc | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'src/nix') diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 1f9d4fb4e..b055698b3 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -33,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 @@ -419,7 +420,8 @@ bool NixRepl::processLine(std::string line) << " Evaluate and print expression\n" << " = Bind expression to variable\n" << " :a Add attributes from resulting set to scope\n" - << " :b Build derivation\n" + << " :b Build a derivation\n" + << " :bl Build a derivation, creating GC roots in the working directory\n" << " :e Open package or function in $EDITOR\n" << " :i Build derivation, then install result into current profile\n" << " :l Load Nix expression and add it to scope\n" @@ -502,18 +504,26 @@ bool NixRepl::processLine(std::string line) 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(); + 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") { -- cgit v1.2.3 From 51cfea8bb05d3f284534b2486cc29bb0ebf17ade Mon Sep 17 00:00:00 2001 From: Artturin Date: Sat, 19 Mar 2022 20:16:05 +0200 Subject: nix build: add --print-out-paths flag has the same functionality as default nix-build $ nix-build . -A "bash" -A "bash.dev" -A "tinycc" /nix/store/4nmqxajzaf60yjribkgvj5j54x9yvr1r-bash-5.1-p12 /nix/store/c49i1ggnr5cc8gxmk9xm0cn961z104dn-bash-5.1-p12-dev /nix/store/dbapb08862ajgaax3621fz8hly9fdah3-tcc-0.9.27+date=2022-01-11 $ nix-build . -A "bash" /nix/store/4nmqxajzaf60yjribkgvj5j54x9yvr1r-bash-5.1-p12 $ $HOME/nixgits/nix/result/bin/nix build "nixpkgs#bash" "nixpkgs#bash.dev" "nixpkgs#tinycc" --print-out-paths /nix/store/4nmqxajzaf60yjribkgvj5j54x9yvr1r-bash-5.1-p12 /nix/store/c49i1ggnr5cc8gxmk9xm0cn961z104dn-bash-5.1-p12-dev /nix/store/dbapb08862ajgaax3621fz8hly9fdah3-tcc-0.9.27+date=2022-01-11 $ $HOME/nixgits/nix/result/bin/nix build "nixpkgs#bash" --print-out-paths /nix/store/4nmqxajzaf60yjribkgvj5j54x9yvr1r-bash-5.1-p12 --- src/nix/build.cc | 24 ++++++++++++++++++++++++ src/nix/build.md | 7 +++++++ 2 files changed, 31 insertions(+) (limited to 'src/nix') diff --git a/src/nix/build.cc b/src/nix/build.cc index 840c7ca38..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 @@ -12,6 +13,7 @@ using namespace nix; struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile { Path outLink = "result"; + bool printOutputPaths = false; BuildMode buildMode = bmNormal; CmdBuild() @@ -31,6 +33,12 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile .handler = {&outLink, Path("")}, }); + 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.", @@ -93,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 -- cgit v1.2.3 From f05e1f6fbb8a760f23a7af16b065078df6588acf Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 21 Apr 2022 11:58:40 +0200 Subject: Move hiliteMatches into a separate header This is mostly so that we don't #include everywhere (which adds quite a bit of compilation time). --- src/nix/search.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix') diff --git a/src/nix/search.cc b/src/nix/search.cc index e96a85ea2..e284de95c 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 #include -- cgit v1.2.3 From 38de79fcf7e00187107e638036c010911d1b675b Mon Sep 17 00:00:00 2001 From: pennae Date: Fri, 4 Mar 2022 19:47:32 +0100 Subject: remove Bindings::need a future commit will remove the ability to convert the symbol type used in bindings to strings. since we only have two users we can inline the error check. --- src/nix/bundle.cc | 6 ++++-- src/nix/prefetch.cc | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/nix') diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc index 81fb8464a..ee91e8ed0 100644 --- a/src/nix/bundle.cc +++ b/src/nix/bundle.cc @@ -110,8 +110,10 @@ struct CmdBundle : InstallableCommand 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/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")); -- cgit v1.2.3 From 39df15fb8e766c0a4fa2fda83784fb8a478a766c Mon Sep 17 00:00:00 2001 From: pennae Date: Fri, 4 Mar 2022 20:54:50 +0100 Subject: don't use full Pos for findPackageFilename/editorFor only file and line of the returned position were ever used, it wasn't actually used a position. as such we may as well use a path+int pair for only those two values and remove a use of Pos that would not work well with a position table. --- src/nix/edit.cc | 16 ++++++++-------- src/nix/repl.cc | 26 +++++++++++++------------- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'src/nix') diff --git a/src/nix/edit.cc b/src/nix/edit.cc index fc48db0d7..ffe79af89 100644 --- a/src/nix/edit.cc +++ b/src/nix/edit.cc @@ -30,17 +30,17 @@ struct CmdEdit : InstallableCommand 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()); + const auto [file, line] = [&] { + 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/repl.cc b/src/nix/repl.cc index 0eb037858..391255ce9 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -461,21 +461,21 @@ 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 { + if (v.type() == nPath || v.type() == nString) { + PathSet context; + auto filename = state->coerceToString(noPos, v, context); + return {state->symbols.create(*filename), 0}; + } else if (v.isLambda()) { + return {v.lambda.fun->pos.file, v.lambda.fun->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(); -- cgit v1.2.3 From 6526d1676ba5a645f65d751e7529ccd273579017 Mon Sep 17 00:00:00 2001 From: pennae Date: Fri, 4 Mar 2022 19:31:59 +0100 Subject: replace most Pos objects/ptrs with indexes into a position table Pos objects are somewhat wasteful as they duplicate the origin file name and input type for each object. on files that produce more than one Pos when parsed this a sizeable waste of memory (one pointer per Pos). the same goes for ptr on 64 bit machines: parsing enough source to require 8 bytes to locate a position would need at least 8GB of input and 64GB of expression memory. it's not likely that we'll hit that any time soon, so we can use a uint32_t index to locate positions instead. --- src/nix/bundle.cc | 6 +-- src/nix/edit.cc | 4 +- src/nix/eval.cc | 12 +++--- src/nix/flake.cc | 118 ++++++++++++++++++++++++++++-------------------------- src/nix/repl.cc | 9 +++-- 5 files changed, 79 insertions(+), 70 deletions(-) (limited to 'src/nix') diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc index ee91e8ed0..2421adf4e 100644 --- a/src/nix/bundle.cc +++ b/src/nix/bundle.cc @@ -97,13 +97,13 @@ 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 } }); @@ -113,7 +113,7 @@ struct CmdBundle : InstallableCommand auto * attr = vRes->attrs->get(evalState->sName); if (!attr) throw Error("attribute 'name' missing"); - outLink = evalState->forceStringNoCtx(*attr->value, *attr->pos); + outLink = evalState->forceStringNoCtx(*attr->value, attr->pos); } // TODO: will crash if not a localFSStore? diff --git a/src/nix/edit.cc b/src/nix/edit.cc index ffe79af89..76a134b1f 100644 --- a/src/nix/edit.cc +++ b/src/nix/edit.cc @@ -28,9 +28,9 @@ struct CmdEdit : InstallableCommand { auto state = getEvalState(); - auto [v, pos] = installable->toValue(*state); - const auto [file, line] = [&] { + auto [v, pos] = installable->toValue(*state); + try { return findPackageFilename(*state, *v, installable->what()); } catch (NoPositionInfo &) { diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 733b93661..81474c2d3 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -77,9 +77,9 @@ struct CmdEval : MixJSON, InstallableCommand if (pathExists(*writeTo)) throw Error("path '%s' already exists", *writeTo); - std::function recurse; + std::function 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) @@ -92,14 +92,16 @@ struct CmdEval : MixJSON, InstallableCommand try { if (attr.name == "." || attr.name == "..") throw Error("invalid file name '%s'", attr.name); - recurse(*attr.value, *attr.pos, path + "/" + std::string(attr.name)); + recurse(*attr.value, attr.pos, path + "/" + std::string(attr.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'", attr.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); diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 04b23ed0f..23e5cd24e 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 callback) + std::function 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(attr->name, *attr->value, attr->pos); for (auto & attr : *aOutputs->value->attrs) { if (attr.name != sHydraJobs) - callback(attr.name, *attr.value, *attr.pos); + callback(attr.name, *attr.value, attr.pos); } } @@ -315,13 +315,17 @@ 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 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 { + auto checkDerivation = [&](const std::string & attrPath, Value & v, const PosIdx pos) -> std::optional { 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 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'", 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 checkHydraJobs; + std::function 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); + state->forceAttrs(*attr.value, attr.pos); auto attrPath2 = attrPath + "." + (std::string) 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,7 +463,7 @@ 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); @@ -467,19 +473,19 @@ struct CmdFlakeCheck : FlakeCommand 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)); @@ -516,12 +522,12 @@ 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); + 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); + *attr2.value, attr2.pos); if (drvPath && (std::string) attr.name == settings.thisSystem.get()) drvPaths.push_back(DerivedPath::Built{*drvPath}); } @@ -531,61 +537,61 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "formatter") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, *attr.pos); + checkSystemName(attr.name, attr.pos); checkApp( fmt("%s.%s", name, attr.name), - *attr.value, *attr.pos); + *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); + 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); + *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); + 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); + *attr2.value, attr2.pos); } } else if (name == "defaultPackage" || name == "devShell") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, *attr.pos); + checkSystemName(attr.name, attr.pos); checkDerivation( fmt("%s.%s", name, attr.name), - *attr.value, *attr.pos); + *attr.value, attr.pos); } } else if (name == "defaultApp") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, *attr.pos); + checkSystemName(attr.name, attr.pos); checkApp( fmt("%s.%s", name, attr.name), - *attr.value, *attr.pos); + *attr.value, attr.pos); } } else if (name == "legacyPackages") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, *attr.pos); + checkSystemName(attr.name, attr.pos); // FIXME: do getDerivations? } } @@ -597,7 +603,7 @@ struct CmdFlakeCheck : FlakeCommand state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) checkOverlay(fmt("%s.%s", name, attr.name), - *attr.value, *attr.pos); + *attr.value, attr.pos); } else if (name == "nixosModule") @@ -607,14 +613,14 @@ struct CmdFlakeCheck : FlakeCommand state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) checkModule(fmt("%s.%s", name, attr.name), - *attr.value, *attr.pos); + *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); + *attr.value, attr.pos); } else if (name == "hydraJobs") @@ -627,28 +633,28 @@ struct CmdFlakeCheck : FlakeCommand state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) checkTemplate(fmt("%s.%s", name, attr.name), - *attr.value, *attr.pos); + *attr.value, attr.pos); } else if (name == "defaultBundler") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) { - checkSystemName(attr.name, *attr.pos); + checkSystemName(attr.name, attr.pos); checkBundler( fmt("%s.%s", name, attr.name), - *attr.value, *attr.pos); + *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); + 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); + *attr2.value, attr2.pos); } } } @@ -657,7 +663,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); } }); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 391255ce9..fd1b95afa 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -467,7 +467,8 @@ bool NixRepl::processLine(std::string line) auto filename = state->coerceToString(noPos, v, context); return {state->symbols.create(*filename), 0}; } else if (v.isLambda()) { - return {v.lambda.fun->pos.file, v.lambda.fun->pos.line}; + auto pos = state->positions[v.lambda.fun->pos]; + return {pos.file, pos.line}; } else { // assume it's a derivation return findPackageFilename(*state, v, arg); @@ -498,7 +499,7 @@ bool NixRepl::processLine(std::string line) Value v, f, result; evalString(arg, v); evalString("drv: (import {}).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)}); @@ -799,7 +800,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 << "»"; @@ -861,7 +862,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; -- cgit v1.2.3 From 8775be33931ec3b1cad97035ff3d5370a97178a1 Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 5 Mar 2022 14:40:24 +0100 Subject: store Symbols in a table as well, like positions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this slightly increases the amount of memory used for any given symbol, but this increase is more than made up for if the symbol is referenced more than once in the EvalState that holds it. on average every symbol should be referenced at least twice (once to introduce a binding, once to use it), so we expect no increase in memory on average. symbol tables are limited to 2³² entries like position tables, and similar arguments apply to why overflow is not likely: 2³² symbols would require as many string instances (at 24 bytes each) and map entries (at 24 bytes or more each, assuming that the map holds on average at most one item per bucket as the docs say). a full symbol table would require at least 192GB of memory just for symbols, which is well out of reach. (an ofborg eval of nixpks today creates less than a million symbols!) --- src/nix/app.cc | 6 ++--- src/nix/eval.cc | 14 +++++----- src/nix/flake.cc | 80 ++++++++++++++++++++++++++++++------------------------- src/nix/main.cc | 2 +- src/nix/repl.cc | 21 ++++++++------- src/nix/search.cc | 2 +- 6 files changed, 68 insertions(+), 57 deletions(-) (limited to 'src/nix') diff --git a/src/nix/app.cc b/src/nix/app.cc index df7303e15..95ac1cf5c 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -85,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; diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 81474c2d3..967dc8519 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -88,17 +88,19 @@ 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( state->positions[attr.pos], - hintfmt("while evaluating the attribute '%s'", attr.name)); + hintfmt("while evaluating the attribute '%s'", name)); throw; } + } } else throw TypeError("value at '%s' is not a string or an attribute set", state->positions[pos]); @@ -119,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 23e5cd24e..c8d8461e4 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -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; @@ -319,6 +311,14 @@ struct CmdFlakeCheck : FlakeCommand 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) @@ -390,7 +390,7 @@ struct CmdFlakeCheck : FlakeCommand } catch (Error & e) { e.addTrace( state->positions[attr.pos], - hintfmt("while evaluating the option '%s'", attr.name)); + hintfmt("while evaluating the option '%s'", state->symbols[attr.name])); throw; } } else @@ -414,7 +414,7 @@ struct CmdFlakeCheck : FlakeCommand for (auto & attr : *v.attrs) { state->forceAttrs(*attr.value, attr.pos); - auto attrPath2 = attrPath + "." + (std::string) attr.name; + auto attrPath2 = concatStrings(attrPath, ".", state->symbols[attr.name]); if (state->isDerivation(*attr.value)) { Activity act(*logger, lvlChatty, actUnknown, fmt("checking Hydra job '%s'", attrPath2)); @@ -468,7 +468,7 @@ struct CmdFlakeCheck : FlakeCommand throw Error("template '%s' lacks attribute 'description'", attrPath); for (auto & attr : *v.attrs) { - std::string name(attr.name); + 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); } @@ -522,13 +522,14 @@ struct CmdFlakeCheck : FlakeCommand if (name == "checks") { 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); state->forceAttrs(*attr.value, attr.pos); for (auto & attr2 : *attr.value->attrs) { auto drvPath = checkDerivation( - fmt("%s.%s.%s", name, attr.name, attr2.name), + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, attr2.pos); - if (drvPath && (std::string) attr.name == settings.thisSystem.get()) + if (drvPath && attr_name == settings.thisSystem.get()) drvPaths.push_back(DerivedPath::Built{*drvPath}); } } @@ -537,9 +538,10 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "formatter") { 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), + fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } } @@ -547,11 +549,12 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "packages" || name == "devShells") { 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); state->forceAttrs(*attr.value, attr.pos); for (auto & attr2 : *attr.value->attrs) checkDerivation( - fmt("%s.%s.%s", name, attr.name, attr2.name), + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, attr2.pos); } } @@ -559,11 +562,12 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "apps") { 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); state->forceAttrs(*attr.value, attr.pos); for (auto & attr2 : *attr.value->attrs) checkApp( - fmt("%s.%s.%s", name, attr.name, attr2.name), + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, attr2.pos); } } @@ -571,9 +575,10 @@ struct CmdFlakeCheck : FlakeCommand 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), + fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } } @@ -581,9 +586,10 @@ struct CmdFlakeCheck : FlakeCommand 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), + fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } } @@ -591,7 +597,7 @@ struct CmdFlakeCheck : FlakeCommand 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? } } @@ -602,7 +608,7 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "overlays") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) - checkOverlay(fmt("%s.%s", name, attr.name), + checkOverlay(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); } @@ -612,14 +618,14 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "nixosModules") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) - checkModule(fmt("%s.%s", name, attr.name), + 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), + checkNixOSConfiguration(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); } @@ -632,16 +638,17 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "templates") { state->forceAttrs(vOutput, pos); for (auto & attr : *vOutput.attrs) - checkTemplate(fmt("%s.%s", name, attr.name), + 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), + fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } } @@ -649,11 +656,12 @@ struct CmdFlakeCheck : FlakeCommand else if (name == "bundlers") { 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); state->forceAttrs(*attr.value, attr.pos); for (auto & attr2 : *attr.value->attrs) { checkBundler( - fmt("%s.%s.%s", name, attr.name, attr2.name), + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, attr2.pos); } } @@ -1000,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 description; if (auto aMeta = visitor.maybeGetAttr("meta")) { diff --git a/src/nix/main.cc b/src/nix/main.cc index 6198681e7..6d0f6ce6e 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -302,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/repl.cc b/src/nix/repl.cc index fd1b95afa..998ff7328 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -73,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); @@ -347,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) { @@ -464,8 +464,9 @@ bool NixRepl::processLine(std::string line) const auto [file, line] = [&] () -> std::pair { if (v.type() == nPath || v.type() == nString) { PathSet context; - auto filename = state->coerceToString(noPos, v, context); - return {state->symbols.create(*filename), 0}; + 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}; @@ -672,7 +673,7 @@ void NixRepl::initEnv() varNames.clear(); for (auto & i : state->staticBaseEnv.vars) - varNames.insert(i.first); + varNames.emplace(state->symbols[i.first]); } @@ -702,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(); @@ -710,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"); @@ -719,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]); } @@ -812,7 +813,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m typedef std::map 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)) diff --git a/src/nix/search.cc b/src/nix/search.cc index e284de95c..8b1e9ae6c 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -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(); } -- cgit v1.2.3