From 452ffe5464f20ac44a01c536349895d138150a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= <7226587+thufschmitt@users.noreply.github.com> Date: Wed, 18 May 2022 16:46:13 +0200 Subject: [PATCH 01/57] Hint at the source file on conflict in `flake new` Add a pointer to the source file (from the template) when `nix flake new` (or `init`) encounters an already existing file Fix #6542 --- src/nix/flake.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 1938ce4e6..a1edb5dbf 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -758,7 +758,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand if (pathExists(to2)) { auto contents2 = readFile(to2); if (contents != contents2) - throw Error("refusing to overwrite existing file '%s'", to2); + throw Error("refusing to overwrite existing file '%s' - please merge manually with '%s'", to2, from2); } else writeFile(to2, contents); } @@ -766,7 +766,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand auto target = readLink(from2); if (pathExists(to2)) { if (readLink(to2) != target) - throw Error("refusing to overwrite existing symlink '%s'", to2); + throw Error("refusing to overwrite existing symlink '%s' - please merge manually with '%s'", to2, from2); } else createSymlink(target, to2); } From 06d57ce7597fc1b49ce1cdc721edc64eaafe38fb Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Wed, 22 Dec 2021 15:36:08 -0700 Subject: [PATCH 02/57] nix repl: load flakes from cli args If experimental feature "flakes" is enabled, args passed to `nix repl` will now be considered flake refs and imported using the existing `:load-flake` machinery. In addition, `:load-flake` now supports loading flake fragments. --- src/nix/repl.cc | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 2967632ed..d20eb0929 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -646,11 +646,11 @@ void NixRepl::loadFlake(const std::string & flakeRefS) if (flakeRefS.empty()) throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)"); - auto flakeRef = parseFlakeRef(flakeRefS, absPath("."), true); + auto [flakeRef, fragment] = parseFlakeRefWithFragment(flakeRefS, absPath("."), true); if (evalSettings.pureEval && !flakeRef.input.isLocked()) throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS); - Value v; + auto v = state->allocValue(); flake::callFlake(*state, flake::lockFlake(*state, flakeRef, @@ -659,8 +659,17 @@ void NixRepl::loadFlake(const std::string & flakeRefS) .useRegistries = !evalSettings.pureEval, .allowMutable = !evalSettings.pureEval, }), - v); - addAttrsToScope(v); + *v); + + auto f = v->attrs->get(state->symbols.create(fragment)); + + if (f == 0) { + warn("no attribute %s, nothing loaded", fragment); + return; + }; + + fragment != "" ? addAttrsToScope(*f->value) : addAttrsToScope(*v); + } @@ -689,7 +698,10 @@ void NixRepl::reloadFiles() if (!first) notice(""); first = false; notice("Loading '%1%'...", i); - loadFile(i); + + settings.isExperimentalFeatureEnabled(Xp::Flakes) + ? loadFlake(i) + : loadFile(i); } } From 81567a096258026148b42f3048be9b2ba295b41a Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 18 Feb 2022 18:33:03 -0500 Subject: [PATCH 03/57] repl: allow loading installables from CLI repl: search installable with findAlongAttrPath repl: refactor handling of args repl: temp --- src/libcmd/command.hh | 1 + src/libcmd/installables.cc | 5 ++- src/nix/repl.cc | 87 ++++++++++++++++++++++---------------- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 078e2a2ce..65626e33f 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -132,6 +132,7 @@ struct InstallableCommand : virtual Args, SourceExprCommand InstallableCommand(bool supportReadOnlyMode = false); void prepare() override; + std::shared_ptr load(); std::optional getFlakeRefForCompletion() override { diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 635ce19b6..7d2ff0f68 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -1054,10 +1054,13 @@ InstallableCommand::InstallableCommand(bool supportReadOnlyMode) }} }); } +std::shared_ptr InstallableCommand::load() { + return parseInstallable(getStore(), _installable); +} void InstallableCommand::prepare() { - installable = parseInstallable(getStore(), _installable); + installable = load(); } } diff --git a/src/nix/repl.cc b/src/nix/repl.cc index d20eb0929..df921ef06 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -22,6 +22,7 @@ extern "C" { #include "ansicolor.hh" #include "shared.hh" #include "eval.hh" +#include "eval-cache.hh" #include "eval-inline.hh" #include "attr-path.hh" #include "store-api.hh" @@ -42,16 +43,20 @@ extern "C" { namespace nix { +typedef std::vector> Installables; + struct NixRepl #if HAVE_BOEHMGC : gc #endif { std::string curDir; - std::unique_ptr state; + ref state; Bindings * autoArgs; Strings loadedFiles; + typedef std::vector> AnnotatedValues; + std::function getValues; const static int envSize = 32768; StaticEnv staticEnv; @@ -61,13 +66,16 @@ struct NixRepl const Path historyFile; - NixRepl(const Strings & searchPath, nix::ref store); + NixRepl(const Strings & searchPath, nix::ref store,ref state, + std::function getValues); ~NixRepl(); - void mainLoop(const std::vector & files); + void mainLoop(); StringSet completePrefix(const std::string & prefix); bool getLine(std::string & input, const std::string &prompt); StorePath getDerivationPath(Value & v); bool processLine(std::string line); + + void loadInstallable(Installable & installable); void loadFile(const Path & path); void loadFlake(const std::string & flakeRef); void initEnv(); @@ -92,8 +100,10 @@ std::string removeWhitespace(std::string s) } -NixRepl::NixRepl(const Strings & searchPath, nix::ref store) - : state(std::make_unique(searchPath, store)) +NixRepl::NixRepl(const Strings & searchPath, nix::ref store,ref state, + std::function getValues) + : state(state) + , getValues(getValues) , staticEnv(false, &state->staticBaseEnv) , historyFile(getDataDir() + "/nix/repl-history") { @@ -198,16 +208,12 @@ namespace { } } -void NixRepl::mainLoop(const std::vector & files) +void NixRepl::mainLoop() { std::string error = ANSI_RED "error:" ANSI_NORMAL " "; notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n"); - for (auto & i : files) - loadedFiles.push_back(i); - reloadFiles(); - if (!loadedFiles.empty()) notice(""); // Allow nix-repl specific settings in .inputrc rl_readline_name = "nix-repl"; @@ -630,6 +636,11 @@ bool NixRepl::processLine(std::string line) return true; } +void NixRepl::loadInstallable(Installable & installable) +{ + auto [val, pos] = installable.toValue(*state); + addAttrsToScope(*val); +} void NixRepl::loadFile(const Path & path) { @@ -646,11 +657,11 @@ void NixRepl::loadFlake(const std::string & flakeRefS) if (flakeRefS.empty()) throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)"); - auto [flakeRef, fragment] = parseFlakeRefWithFragment(flakeRefS, absPath("."), true); + auto flakeRef = parseFlakeRef(flakeRefS, absPath("."), true); if (evalSettings.pureEval && !flakeRef.input.isLocked()) throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS); - auto v = state->allocValue(); + Value v; flake::callFlake(*state, flake::lockFlake(*state, flakeRef, @@ -659,17 +670,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS) .useRegistries = !evalSettings.pureEval, .allowMutable = !evalSettings.pureEval, }), - *v); - - auto f = v->attrs->get(state->symbols.create(fragment)); - - if (f == 0) { - warn("no attribute %s, nothing loaded", fragment); - return; - }; - - fragment != "" ? addAttrsToScope(*f->value) : addAttrsToScope(*v); - + v); + addAttrsToScope(v); } @@ -693,15 +695,14 @@ void NixRepl::reloadFiles() Strings old = loadedFiles; loadedFiles.clear(); - bool first = true; for (auto & i : old) { - if (!first) notice(""); - first = false; notice("Loading '%1%'...", i); + loadFile(i); + } - settings.isExperimentalFeatureEnabled(Xp::Flakes) - ? loadFlake(i) - : loadFile(i); + for (auto & [i,what] : getValues()) { + notice("Loading Installable '%1%'...", what); + addAttrsToScope(*i); } } @@ -898,17 +899,20 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m return str; } -struct CmdRepl : StoreCommand, MixEvalArgs +struct CmdRepl : InstallableCommand { std::vector files; + Strings getDefaultFlakeAttrPathPrefixes() + override { + return {}; + } + Strings getDefaultFlakeAttrPaths() + override { + return {""}; + } CmdRepl() { - expectArgs({ - .label = "files", - .handler = {&files}, - .completer = completePath - }); } std::string description() override @@ -925,10 +929,19 @@ struct CmdRepl : StoreCommand, MixEvalArgs void run(ref store) override { + evalSettings.pureEval = false; - auto repl = std::make_unique(searchPath, openStore()); + auto state = getEvalState(); + auto repl = std::make_unique(searchPath, openStore(),state + ,[&]()->NixRepl::AnnotatedValues{ + auto installable = load(); + auto [val, pos] = installable->toValue(*state); + auto what = installable->what(); + return { {val,what} }; + } + ); repl->autoArgs = getAutoArgs(*repl->state); - repl->mainLoop(files); + repl->mainLoop(); } }; From 5640b528349c43717aa501797a4f337373ebf3e4 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 11 Mar 2022 13:26:08 -0500 Subject: [PATCH 04/57] repl: use installables --- src/libcmd/command.hh | 2 +- src/libcmd/installables.cc | 12 +++++++----- src/libcmd/installables.hh | 1 + src/nix/repl.cc | 23 ++++++++++++----------- src/nix/repl.md | 30 +++++++++++++++++++++++++++--- 5 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 65626e33f..65eb0c4a0 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -114,6 +114,7 @@ struct InstallablesCommand : virtual Args, SourceExprCommand InstallablesCommand(); void prepare() override; + Installables load(); virtual bool useDefaultInstallables() { return true; } @@ -132,7 +133,6 @@ struct InstallableCommand : virtual Args, SourceExprCommand InstallableCommand(bool supportReadOnlyMode = false); void prepare() override; - std::shared_ptr load(); std::optional getFlakeRefForCompletion() override { diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 7d2ff0f68..c29fbeec9 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -1025,11 +1025,16 @@ InstallablesCommand::InstallablesCommand() void InstallablesCommand::prepare() { + installables = load(); +} + +Installables InstallablesCommand::load() { + Installables installables; if (_installables.empty() && useDefaultInstallables()) // FIXME: commands like "nix profile install" should not have a // default, probably. _installables.push_back("."); - installables = parseInstallables(getStore(), _installables); + return parseInstallables(getStore(), _installables); } std::optional InstallablesCommand::getFlakeRefForCompletion() @@ -1054,13 +1059,10 @@ InstallableCommand::InstallableCommand(bool supportReadOnlyMode) }} }); } -std::shared_ptr InstallableCommand::load() { - return parseInstallable(getStore(), _installable); -} void InstallableCommand::prepare() { - installable = load(); + installable = parseInstallable(getStore(), _installable); } } diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh index 5d715210e..b97888db6 100644 --- a/src/libcmd/installables.hh +++ b/src/libcmd/installables.hh @@ -131,6 +131,7 @@ struct Installable OperateOn operateOn, const std::vector> & installables); }; +typedef std::vector> Installables; struct InstallableValue : Installable { diff --git a/src/nix/repl.cc b/src/nix/repl.cc index df921ef06..b5ecc8ad0 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -43,8 +43,6 @@ extern "C" { namespace nix { -typedef std::vector> Installables; - struct NixRepl #if HAVE_BOEHMGC : gc @@ -899,17 +897,16 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m return str; } -struct CmdRepl : InstallableCommand +struct CmdRepl : InstallablesCommand { std::vector files; - Strings getDefaultFlakeAttrPathPrefixes() - override { - return {}; - } Strings getDefaultFlakeAttrPaths() override { return {""}; } + virtual bool useDefaultInstallables() { + return file.has_value() or expr.has_value(); + } CmdRepl() { @@ -934,10 +931,14 @@ struct CmdRepl : InstallableCommand auto state = getEvalState(); auto repl = std::make_unique(searchPath, openStore(),state ,[&]()->NixRepl::AnnotatedValues{ - auto installable = load(); - auto [val, pos] = installable->toValue(*state); - auto what = installable->what(); - return { {val,what} }; + auto installables = load(); + NixRepl::AnnotatedValues values; + for (auto & installable: installables){ + auto [val, pos] = installable->toValue(*state); + auto what = installable->what(); + values.push_back( {val,what} ); + } + return values; } ); repl->autoArgs = getAutoArgs(*repl->state); diff --git a/src/nix/repl.md b/src/nix/repl.md index 9b6f2bee3..be1498e5b 100644 --- a/src/nix/repl.md +++ b/src/nix/repl.md @@ -24,10 +24,34 @@ R""( * Interact with Nixpkgs in the REPL: ```console - # nix repl '' + # nix repl --file example.nix + Loading Installable ''... + Added 3 variables. - Loading ''... - Added 12428 variables. + # nix repl --expr '{a={b=3;c=4;};}' + Loading Installable ''... + Added 1 variables. + + # nix repl --expr '{a={b=3;c=4;};}' a + Loading Installable ''... + Added 1 variables. + + # nix repl nixpkgs + Loading Installable 'flake:nixpkgs#'... + Added 5 variables. + + nix-repl> legacyPackages.x86_64-linux.emacs.name + "emacs-27.1" + + nix-repl> legacyPackages.x86_64-linux.emacs.name + "emacs-27.1" + + nix-repl> :q + + # nix repl --expr 'import {}' --impure + + Loading Installable ''... + Added 12439 variables. nix-repl> emacs.name "emacs-27.1" From 1ca3f6035da4e82647382405c774e43e02de3fa1 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 11 Mar 2022 13:52:08 -0500 Subject: [PATCH 05/57] repl: update docs with installables --- doc/manual/src/release-notes/rl-next.md | 5 +++++ src/nix/repl.cc | 16 +++------------- src/nix/repl.md | 2 +- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index efd893662..096499bc3 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -24,3 +24,8 @@ Selecting derivation outputs using the attribute selection syntax (e.g. `nixpkgs#glibc.dev`) no longer works. + +* `nix repl` now takes installables on the command line, unifying the usage + with other commands that use `--file` and `--expr`. Primary breaking change + is for the common usage of `nix repl ''` which can be recovered with + `nix repl nixpkgs` or `nix repl --expr 'import {}'` diff --git a/src/nix/repl.cc b/src/nix/repl.cc index b5ecc8ad0..ac0f1f4d7 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -73,7 +73,6 @@ struct NixRepl StorePath getDerivationPath(Value & v); bool processLine(std::string line); - void loadInstallable(Installable & installable); void loadFile(const Path & path); void loadFlake(const std::string & flakeRef); void initEnv(); @@ -634,12 +633,6 @@ bool NixRepl::processLine(std::string line) return true; } -void NixRepl::loadInstallable(Installable & installable) -{ - auto [val, pos] = installable.toValue(*state); - addAttrsToScope(*val); -} - void NixRepl::loadFile(const Path & path) { loadedFiles.remove(path); @@ -899,6 +892,9 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m struct CmdRepl : InstallablesCommand { + CmdRepl(){ + evalSettings.pureEval = false; + } std::vector files; Strings getDefaultFlakeAttrPaths() override { @@ -908,10 +904,6 @@ struct CmdRepl : InstallablesCommand return file.has_value() or expr.has_value(); } - CmdRepl() - { - } - std::string description() override { return "start an interactive environment for evaluating Nix expressions"; @@ -926,8 +918,6 @@ struct CmdRepl : InstallablesCommand void run(ref store) override { - - evalSettings.pureEval = false; auto state = getEvalState(); auto repl = std::make_unique(searchPath, openStore(),state ,[&]()->NixRepl::AnnotatedValues{ diff --git a/src/nix/repl.md b/src/nix/repl.md index be1498e5b..6a526f7d0 100644 --- a/src/nix/repl.md +++ b/src/nix/repl.md @@ -48,7 +48,7 @@ R""( nix-repl> :q - # nix repl --expr 'import {}' --impure + # nix repl --expr 'import {}' Loading Installable ''... Added 12439 variables. From 9f8c1183fa10aa9d95bce0ca2f3337532ad7981b Mon Sep 17 00:00:00 2001 From: tomberek Date: Wed, 18 May 2022 21:18:07 -0400 Subject: [PATCH 06/57] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com> --- src/nix/repl.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nix/repl.cc b/src/nix/repl.cc index ac0f1f4d7..a1b42b760 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -896,11 +896,12 @@ struct CmdRepl : InstallablesCommand evalSettings.pureEval = false; } std::vector files; - Strings getDefaultFlakeAttrPaths() - override { + Strings getDefaultFlakeAttrPaths() override + { return {""}; } - virtual bool useDefaultInstallables() { + virtual bool useDefaultInstallables() override + { return file.has_value() or expr.has_value(); } From 7534798eedb696226101f2c8793ba9ace049f5e4 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Wed, 18 May 2022 21:33:41 -0400 Subject: [PATCH 07/57] refactor: factor out getValue --- src/nix/repl.cc | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/nix/repl.cc b/src/nix/repl.cc index a1b42b760..cae76bb5d 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -920,18 +920,22 @@ struct CmdRepl : InstallablesCommand void run(ref store) override { auto state = getEvalState(); - auto repl = std::make_unique(searchPath, openStore(),state - ,[&]()->NixRepl::AnnotatedValues{ - auto installables = load(); - NixRepl::AnnotatedValues values; - for (auto & installable: installables){ - auto [val, pos] = installable->toValue(*state); - auto what = installable->what(); - values.push_back( {val,what} ); - } - return values; - } - ); + auto getValues = [&]()->NixRepl::AnnotatedValues{ + auto installables = load(); + NixRepl::AnnotatedValues values; + for (auto & installable: installables){ + auto [val, pos] = installable->toValue(*state); + auto what = installable->what(); + values.push_back( {val,what} ); + } + return values; + }; + auto repl = std::make_unique( + searchPath, + openStore(), + state, + getValues + ); repl->autoArgs = getAutoArgs(*repl->state); repl->mainLoop(); } From e1f308a1ec3c395cd4978b45400f7a45adcea0dc Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Wed, 18 May 2022 22:28:15 -0400 Subject: [PATCH 08/57] repl: provide backward compat with legacy usage --- src/libcmd/command.hh | 2 +- src/nix/repl.cc | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 65eb0c4a0..2c88e1526 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -120,7 +120,7 @@ struct InstallablesCommand : virtual Args, SourceExprCommand std::optional getFlakeRefForCompletion() override; -private: +protected: std::vector _installables; }; diff --git a/src/nix/repl.cc b/src/nix/repl.cc index cae76bb5d..d4079816f 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -895,6 +895,22 @@ struct CmdRepl : InstallablesCommand CmdRepl(){ evalSettings.pureEval = false; } + void prepare() + { + if (!settings.isExperimentalFeatureEnabled(Xp::Flakes) && !(file)) { + warn("future versions of Nix will require using `--file` to load a file"); + if (this->_installables.size() > 1) { + warn("more than one input file is not currently supported"); + } + if (this->_installables.size() >= 1) { + file = std::optional( + this->_installables[0].data() + ); + } + _installables.clear(); + } + installables = InstallablesCommand::load(); + } std::vector files; Strings getDefaultFlakeAttrPaths() override { From f21dec5befc9ee273a5210dec322d30c3c3be595 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Thu, 19 May 2022 01:01:45 -0400 Subject: [PATCH 09/57] repl: hide flake behavior behind flag and provide warning --- src/nix/repl.cc | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/nix/repl.cc b/src/nix/repl.cc index d4079816f..18cdb3580 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -897,17 +897,14 @@ struct CmdRepl : InstallablesCommand } void prepare() { - if (!settings.isExperimentalFeatureEnabled(Xp::Flakes) && !(file)) { + if (!settings.isExperimentalFeatureEnabled(Xp::Flakes) && !(file) && this->_installables.size() >= 1) { warn("future versions of Nix will require using `--file` to load a file"); - if (this->_installables.size() > 1) { + if (this->_installables.size() > 1) warn("more than one input file is not currently supported"); - } - if (this->_installables.size() >= 1) { - file = std::optional( - this->_installables[0].data() - ); - } - _installables.clear(); + auto filePath = this->_installables[0].data(); + file = std::optional(filePath); + _installables.front() = _installables.back(); + _installables.pop_back(); } installables = InstallablesCommand::load(); } @@ -940,9 +937,20 @@ struct CmdRepl : InstallablesCommand auto installables = load(); NixRepl::AnnotatedValues values; for (auto & installable: installables){ - auto [val, pos] = installable->toValue(*state); auto what = installable->what(); - values.push_back( {val,what} ); + if (!settings.isExperimentalFeatureEnabled(Xp::Flakes) && file){ + auto [val, pos] = installable->toValue(*state); + auto what = installable->what(); + state->forceValue(*val, pos); + auto autoArgs = getAutoArgs(*state); + Value *valPost = state->allocValue(); + state->autoCallFunction(*autoArgs, *val, *valPost); + state->forceValue(*valPost, pos); + values.push_back( {valPost, what }); + } else { + auto [val, pos] = installable->toValue(*state); + values.push_back( {val,what} ); + } } return values; }; From 7d7e00272a2f47f68b3809296992db84ae871e09 Mon Sep 17 00:00:00 2001 From: tomberek Date: Fri, 20 May 2022 01:28:20 -0400 Subject: [PATCH 10/57] Apply suggestions from code review Style fixes from @edolstra Co-authored-by: Eelco Dolstra --- src/nix/repl.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 18cdb3580..6c05daa11 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -97,7 +97,7 @@ std::string removeWhitespace(std::string s) } -NixRepl::NixRepl(const Strings & searchPath, nix::ref store,ref state, +NixRepl::NixRepl(const Strings & searchPath, nix::ref store, ref state, std::function getValues) : state(state) , getValues(getValues) @@ -691,8 +691,8 @@ void NixRepl::reloadFiles() loadFile(i); } - for (auto & [i,what] : getValues()) { - notice("Loading Installable '%1%'...", what); + for (auto & [i, what] : getValues()) { + notice("Loading installable '%1%'...", what); addAttrsToScope(*i); } } @@ -943,13 +943,13 @@ struct CmdRepl : InstallablesCommand auto what = installable->what(); state->forceValue(*val, pos); auto autoArgs = getAutoArgs(*state); - Value *valPost = state->allocValue(); + auto valPost = state->allocValue(); state->autoCallFunction(*autoArgs, *val, *valPost); state->forceValue(*valPost, pos); values.push_back( {valPost, what }); } else { auto [val, pos] = installable->toValue(*state); - values.push_back( {val,what} ); + values.push_back( {val, what} ); } } return values; From db613a85fb7fb8c8a0f476f83db92523cce327f7 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 20 May 2022 01:35:06 -0400 Subject: [PATCH 11/57] repl: allow --file to always utilize autoargs --- src/nix/repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 6c05daa11..e9898c08c 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -938,7 +938,7 @@ struct CmdRepl : InstallablesCommand NixRepl::AnnotatedValues values; for (auto & installable: installables){ auto what = installable->what(); - if (!settings.isExperimentalFeatureEnabled(Xp::Flakes) && file){ + if (file){ auto [val, pos] = installable->toValue(*state); auto what = installable->what(); state->forceValue(*val, pos); From 542e36c6e7ed5efa3d60e5adfc37ff7bb7e90a41 Mon Sep 17 00:00:00 2001 From: tomberek Date: Fri, 20 May 2022 01:48:24 -0400 Subject: [PATCH 12/57] Apply suggestions from code review Co-authored-by: Eelco Dolstra --- src/libcmd/installables.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh index b97888db6..948f78919 100644 --- a/src/libcmd/installables.hh +++ b/src/libcmd/installables.hh @@ -131,6 +131,7 @@ struct Installable OperateOn operateOn, const std::vector> & installables); }; + typedef std::vector> Installables; struct InstallableValue : Installable From 82c4af41e3348a87ebc9fb583df09070beadc019 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 20 May 2022 01:49:49 -0400 Subject: [PATCH 13/57] repl: clarify change and usage of --- doc/manual/src/release-notes/rl-next.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index 096499bc3..6dbf6adae 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -28,4 +28,4 @@ * `nix repl` now takes installables on the command line, unifying the usage with other commands that use `--file` and `--expr`. Primary breaking change is for the common usage of `nix repl ''` which can be recovered with - `nix repl nixpkgs` or `nix repl --expr 'import {}'` + `nix repl --file ''` or `nix repl --expr 'import {}'` From 938150472d8373395f6f09cd76d4b0bde271ffda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Fri, 20 May 2022 08:12:02 +0200 Subject: [PATCH 14/57] Add some tests for the new REPL cli - Test that without the XP feature things work as before - Test that with or without the XP feature `--file file` works - Test that with XP feature passing a flakeref works - Test `:reload` with a flake --- tests/repl.sh | 55 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/tests/repl.sh b/tests/repl.sh index b6937b9e9..e879319fa 100644 --- a/tests/repl.sh +++ b/tests/repl.sh @@ -50,15 +50,17 @@ testRepl testRepl --store "$TEST_ROOT/store?real=$NIX_STORE_DIR" testReplResponse () { - local response="$(nix repl <<< "$1")" - echo "$response" | grep -qs "$2" \ + local commands="$1"; shift + local expectedResponse="$1"; shift + local response="$(nix repl "$@" <<< "$commands")" + echo "$response" | grep -qs "$expectedResponse" \ || fail "repl command set: -$1 +$commands does not respond with: -$2 +$expectedResponse but with: @@ -71,3 +73,48 @@ testReplResponse ' :a { a = "2"; } "result: ${a}" ' "result: 2" + +testReplResponse ' +drvPath +' '"/tmp/nix-test/default/store/qlksh7k4a72107vc054ilywq4rcmy9if-simple.drv"' \ +$testDir/simple.nix --experimental-features '' + +testReplResponse ' +drvPath +' '"/tmp/nix-test/default/store/qlksh7k4a72107vc054ilywq4rcmy9if-simple.drv"' \ +--file $testDir/simple.nix --experimental-features '' + +testReplResponse ' +drvPath +' '"/tmp/nix-test/default/store/qlksh7k4a72107vc054ilywq4rcmy9if-simple.drv"' \ +--file $testDir/simple.nix --experimental-features 'flakes' + +mkdir -p flake && cat < flake/flake.nix +{ + outputs = { self }: { + foo = 1; + bar.baz = 2; + + changingThing = "beforeChange"; + }; +} +EOF +testReplResponse ' +foo + baz +' "3" \ + ./flake ./flake\#bar + +# Test the `:reload` mechansim with flakes: +# - Eval `./flake#changingThing` +# - Modify the flake +# - Re-eval it +# - Check that the result has changed +replResult=$( ( +echo "changingThing" +sleep 1 # Leave the repl the time to eval 'foo' +sed -i 's/beforeChange/afterChange/' flake/flake.nix +echo ":reload" +echo "changingThing" +) | nix repl ./flake) +echo "$replResult" | grep -qs beforeChange +echo "$replResult" | grep -qs afterChange From 0053dab43f9ca350c27235f8a58b5d550bfffd38 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 20 May 2022 08:03:41 -0400 Subject: [PATCH 15/57] repl: fix tests to run on any testing store --- tests/repl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/repl.sh b/tests/repl.sh index e879319fa..07f647585 100644 --- a/tests/repl.sh +++ b/tests/repl.sh @@ -76,17 +76,17 @@ testReplResponse ' testReplResponse ' drvPath -' '"/tmp/nix-test/default/store/qlksh7k4a72107vc054ilywq4rcmy9if-simple.drv"' \ +' '".*-simple.drv"' \ $testDir/simple.nix --experimental-features '' testReplResponse ' drvPath -' '"/tmp/nix-test/default/store/qlksh7k4a72107vc054ilywq4rcmy9if-simple.drv"' \ +' '".*-simple.drv"' \ --file $testDir/simple.nix --experimental-features '' testReplResponse ' drvPath -' '"/tmp/nix-test/default/store/qlksh7k4a72107vc054ilywq4rcmy9if-simple.drv"' \ +' '".*-simple.drv"' \ --file $testDir/simple.nix --experimental-features 'flakes' mkdir -p flake && cat < flake/flake.nix From 7a04fb1c56ca60652c2a44019b31fe8cf2e2bc46 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 20 May 2022 08:20:00 -0400 Subject: [PATCH 16/57] repl: add repl-flake experimental feature for gating --- src/libutil/experimental-features.cc | 1 + src/libutil/experimental-features.hh | 1 + src/nix/repl.cc | 2 +- tests/repl.sh | 6 +++--- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 315de64a4..fa79cca6b 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -13,6 +13,7 @@ std::map stringifiedXpFeatures = { { Xp::RecursiveNix, "recursive-nix" }, { Xp::NoUrlLiterals, "no-url-literals" }, { Xp::FetchClosure, "fetch-closure" }, + { Xp::ReplFlake, "repl-flake" }, }; const std::optional parseExperimentalFeature(const std::string_view & name) diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index 57512830c..d09ab025c 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -22,6 +22,7 @@ enum struct ExperimentalFeature RecursiveNix, NoUrlLiterals, FetchClosure, + ReplFlake, }; /** diff --git a/src/nix/repl.cc b/src/nix/repl.cc index e9898c08c..b12f05c15 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -897,7 +897,7 @@ struct CmdRepl : InstallablesCommand } void prepare() { - if (!settings.isExperimentalFeatureEnabled(Xp::Flakes) && !(file) && this->_installables.size() >= 1) { + if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) { warn("future versions of Nix will require using `--file` to load a file"); if (this->_installables.size() > 1) warn("more than one input file is not currently supported"); diff --git a/tests/repl.sh b/tests/repl.sh index 07f647585..5caf0a58a 100644 --- a/tests/repl.sh +++ b/tests/repl.sh @@ -87,7 +87,7 @@ drvPath testReplResponse ' drvPath ' '".*-simple.drv"' \ ---file $testDir/simple.nix --experimental-features 'flakes' +--file $testDir/simple.nix --experimental-features 'repl-flake' mkdir -p flake && cat < flake/flake.nix { @@ -102,7 +102,7 @@ EOF testReplResponse ' foo + baz ' "3" \ - ./flake ./flake\#bar + ./flake ./flake\#bar --experimental-features 'flakes repl-flake' # Test the `:reload` mechansim with flakes: # - Eval `./flake#changingThing` @@ -115,6 +115,6 @@ sleep 1 # Leave the repl the time to eval 'foo' sed -i 's/beforeChange/afterChange/' flake/flake.nix echo ":reload" echo "changingThing" -) | nix repl ./flake) +) | nix repl ./flake --experimental-features 'flakes repl-flake') echo "$replResult" | grep -qs beforeChange echo "$replResult" | grep -qs afterChange From 8c3939af14106c753bbb963663ad1cfb4fa6de80 Mon Sep 17 00:00:00 2001 From: tomberek Date: Fri, 20 May 2022 12:09:41 -0400 Subject: [PATCH 17/57] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com> --- tests/repl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/repl.sh b/tests/repl.sh index 5caf0a58a..e9e41558a 100644 --- a/tests/repl.sh +++ b/tests/repl.sh @@ -77,7 +77,7 @@ testReplResponse ' testReplResponse ' drvPath ' '".*-simple.drv"' \ -$testDir/simple.nix --experimental-features '' +$testDir/simple.nix testReplResponse ' drvPath @@ -87,7 +87,7 @@ drvPath testReplResponse ' drvPath ' '".*-simple.drv"' \ ---file $testDir/simple.nix --experimental-features 'repl-flake' +--file $testDir/simple.nix --extra-experimental-features 'repl-flake' mkdir -p flake && cat < flake/flake.nix { From 9151dbff88fa765496e970aee2db5a8ce640b3a4 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 10:26:46 -0600 Subject: [PATCH 18/57] ignore-try flag --- src/libcmd/command.cc | 11 ++++++++++- src/libcmd/command.hh | 1 + src/libexpr/eval.cc | 1 + src/libexpr/eval.hh | 1 + src/libexpr/primops.cc | 14 ++++++++++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 7f8072d75..940fd5b23 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -91,6 +91,12 @@ EvalCommand::EvalCommand() .description = "start an interactive environment if evaluation fails", .handler = {&startReplOnEvalErrors, true}, }); + + addFlag({ + .longName = "ignore-try", + .description = "ignore exceptions in try clauses during debug", + .handler = {&ignoreExceptionsDuringTry, true}, + }); } EvalCommand::~EvalCommand() @@ -120,7 +126,10 @@ ref EvalCommand::getEvalState() ; if (startReplOnEvalErrors) { - evalState->debugRepl = &runRepl; + evalState->debugRepl = &runRepl; + }; + if (ignoreExceptionsDuringTry) { + evalState->ignoreTry = ignoreExceptionsDuringTry; }; } return ref(evalState); diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 8982f21d0..2c930dcb7 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -58,6 +58,7 @@ struct CopyCommand : virtual StoreCommand struct EvalCommand : virtual StoreCommand, MixEvalArgs { bool startReplOnEvalErrors = false; + bool ignoreExceptionsDuringTry = false; EvalCommand(); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 40462afdf..c35527992 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -467,6 +467,7 @@ EvalState::EvalState( , debugRepl(0) , debugStop(false) , debugQuit(false) + , ignoreTry(false) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC , valueAllocCache(std::allocate_shared(traceable_allocator(), nullptr)) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 7b8732169..3c3dddd1e 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -130,6 +130,7 @@ public: void (* debugRepl)(ref es, const ValMap & extraEnv); bool debugStop; bool debugQuit; + bool ignoreTry; std::list debugTraces; std::map> exprEnvs; const std::shared_ptr getStaticEnv(const Expr & expr) const diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index eea274301..772898932 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -851,6 +851,15 @@ static RegisterPrimOp primop_floor({ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { auto attrs = state.buildBindings(2); + + void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; + if (state.debugRepl && state.ignoreTry) + { + // to prevent starting the repl from exceptions withing a tryEval, null it. + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; + } + try { state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); @@ -859,6 +868,11 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); } + + // restore the debugRepl pointer if we saved it earlier. + if (savedDebugRepl) + state.debugRepl = savedDebugRepl; + v.mkAttrs(attrs); } From bc0d41e9baa19c10977dd38f4bb255c14bd6554d Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 12:17:28 -0600 Subject: [PATCH 19/57] print message with exceptions in a try clause --- src/libexpr/eval.cc | 12 ++++++++++-- src/libexpr/eval.hh | 1 + src/libexpr/primops.cc | 15 +++++++++++---- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c35527992..60214453a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -464,10 +464,11 @@ EvalState::EvalState( , emptyBindings(0) , store(store) , buildStore(buildStore ? buildStore : store) - , debugRepl(0) + , debugRepl(nullptr) , debugStop(false) , debugQuit(false) , ignoreTry(false) + , trylevel(0) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC , valueAllocCache(std::allocate_shared(traceable_allocator(), nullptr)) @@ -833,7 +834,14 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & : nullptr; if (error) - printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + { + printError("%s\n\n", error->what()); + + if (trylevel > 0 && error->info().level != lvlInfo) + printError("This exception occurred in a try clause. use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); + + printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + } auto se = getStaticEnv(expr); if (se) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 3c3dddd1e..9aff77042 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -131,6 +131,7 @@ public: bool debugStop; bool debugQuit; bool ignoreTry; + int trylevel; std::list debugTraces; std::map> exprEnvs; const std::shared_ptr getStaticEnv(const Expr & expr) const diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 772898932..e4fd8f650 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -853,11 +853,15 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va auto attrs = state.buildBindings(2); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl && state.ignoreTry) + if (state.debugRepl) { - // to prevent starting the repl from exceptions withing a tryEval, null it. - savedDebugRepl = state.debugRepl; - state.debugRepl = nullptr; + state.trylevel++; + if (state.ignoreTry) + { + // to prevent starting the repl from exceptions withing a tryEval, null it. + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; + } } try { @@ -873,6 +877,9 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va if (savedDebugRepl) state.debugRepl = savedDebugRepl; + if (state.debugRepl) + state.trylevel--; + v.mkAttrs(attrs); } From 8cf6ae86648336bd67a1555302b21576b790c368 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 12:29:38 -0600 Subject: [PATCH 20/57] use Counter class to count tryEval levels --- src/libexpr/primops.cc | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e4fd8f650..ecc1c136a 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -846,22 +846,30 @@ static RegisterPrimOp primop_floor({ .fun = prim_floor, }); +class Counter +{ + private: + int &counter; + public: + Counter(int &counter) :counter(counter) { counter++; } + ~Counter() { counter--; } +}; + /* Try evaluating the argument. Success => {success=true; value=something;}, * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { auto attrs = state.buildBindings(2); + /* increment state.trylevel, and decrement it when this function returns. */ + Counter trylevel(state.trylevel); + void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl) + if (state.debugRepl && state.ignoreTry) { - state.trylevel++; - if (state.ignoreTry) - { - // to prevent starting the repl from exceptions withing a tryEval, null it. - savedDebugRepl = state.debugRepl; - state.debugRepl = nullptr; - } + /* to prevent starting the repl from exceptions withing a tryEval, null it. */ + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; } try { @@ -877,9 +885,6 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va if (savedDebugRepl) state.debugRepl = savedDebugRepl; - if (state.debugRepl) - state.trylevel--; - v.mkAttrs(attrs); } From 49ff4ef6373f4aaeb6194fb4a195d3037c74312e Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 10 Jun 2022 12:22:36 -0600 Subject: [PATCH 21/57] remove unused parameter --- src/libexpr/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 60214453a..28256ec5c 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -840,7 +840,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & if (trylevel > 0 && error->info().level != lvlInfo) printError("This exception occurred in a try clause. use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); - printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL); } auto se = getStaticEnv(expr); From 98946e2d9c93e3558f19ee3d49deef67a98706d8 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Mon, 13 Jun 2022 23:01:13 +0200 Subject: [PATCH 22/57] nix-shell: restore backwards-compat with old nixpkgs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Basically an attempt to resume fixing #5543 for a breakage introduced earlier[1]. Basically, when evaluating an older `nixpkgs` with `nix-shell` the following error occurs: λ ma27 [~] → nix-shell -I nixpkgs=channel:nixos-18.03 -p nix error: anonymous function at /nix/store/zakqwc529rb6xcj8pwixjsxscvlx9fbi-source/pkgs/top-level/default.nix:20:1 called with unexpected argument 'inNixShell' at /nix/store/zakqwc529rb6xcj8pwixjsxscvlx9fbi-source/pkgs/top-level/impure.nix:82:1: 81| 82| import ./. (builtins.removeAttrs args [ "system" "platform" ] // { | ^ 83| inherit config overlays crossSystem; This is a problem because one of the main selling points of Nix is that you can evaluate any old Nix expression and still get the same result (which also means that it *still evaluates*). In fact we're deprecating, but not removing a lot of stuff for that reason such as unquoted URLs[2] or `builtins.toPath`. However this property was essentially thrown away here. The change is rather simple: check if `inNixShell` is specified in the formals of an auto-called function. This means that { inNixShell ? false }: builtins.trace inNixShell (with import { }; makeShell { name = "foo"; }) will show `trace: true` while args@{ ... }: builtins.trace args.inNixShell (with import { }; makeShell { name = "foo"; }) will throw the following error: error: attribute 'inNixShell' missing This is explicitly needed because the function in `pkgs/top-level/impure.nix` of e.g. NixOS 18.03 has an ellipsis[3], but passes the attribute-set on to another lambda with formals that doesn't have an ellipsis anymore (hence the error from above). This was perhaps a mistake, but we can't fix it anymore. This also means that there's AFAICS no proper way to check if the attr-set that's passed to the Nix code via `EvalState::autoCallFunction` is eventually passed to a lambda with formals where `inNixShell` is missing. However, this fix comes with a certain price. Essentially every `shell.nix` that assumes `inNixShell` to be passed to the formals even without explicitly specifying it would break with this[4]. However I think that this is ugly, but preferable: * Nix 2.3 was declared stable by NixOS up until recently (well, it still is as long as 21.11 is alive), so most people might not have even noticed that feature. * We're talking about a way shorter time-span with this change being in the wild, so the fallout should be smaller IMHO. [1] https://github.com/NixOS/nix/commit/9d612c393abc3a73590650d24bcfe2ee57792872 [2] https://github.com/NixOS/rfcs/pull/45#issuecomment-488232537 [3] https://github.com/NixOS/nixpkgs/blob/release-18.03/pkgs/top-level/impure.nix#L75 [4] See e.g. the second expression in this commit-message or the changes for `tests/ca/nix-shell.sh`. --- src/nix-build/nix-build.cc | 38 ++++++++++++++++++++++++++++++++++---- tests/ca-shell.nix | 2 +- tests/nix-shell.sh | 7 +++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 519855ea3..7eb8c8f6a 100644 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -257,11 +257,12 @@ static void main_nix_build(int argc, char * * argv) auto autoArgs = myArgs.getAutoArgs(*state); + auto autoArgsWithInNixShell = autoArgs; if (runEnv) { - auto newArgs = state->buildBindings(autoArgs->size() + 1); + auto newArgs = state->buildBindings(autoArgsWithInNixShell->size() + 1); newArgs.alloc("inNixShell").mkBool(true); for (auto & i : *autoArgs) newArgs.insert(i); - autoArgs = newArgs.finish(); + autoArgsWithInNixShell = newArgs.finish(); } if (packages) { @@ -316,10 +317,39 @@ static void main_nix_build(int argc, char * * argv) Value vRoot; state->eval(e, vRoot); + std::function takesNixShellAttr; + takesNixShellAttr = [&](const Value & v) { + if (!runEnv) { + return false; + } + bool add = false; + if (v.type() == nFunction && v.lambda.fun->hasFormals()) { + for (auto & i : v.lambda.fun->formals->formals) { + if (state->symbols[i.name] == "inNixShell") { + add = true; + break; + } + } + } + return add; + }; + for (auto & i : attrPaths) { - Value & v(*findAlongAttrPath(*state, i, *autoArgs, vRoot).first); + Value & v(*findAlongAttrPath( + *state, + i, + takesNixShellAttr(vRoot) ? *autoArgsWithInNixShell : *autoArgs, + vRoot + ).first); state->forceValue(v, [&]() { return v.determinePos(noPos); }); - getDerivations(*state, v, "", *autoArgs, drvs, false); + getDerivations( + *state, + v, + "", + takesNixShellAttr(v) ? *autoArgsWithInNixShell : *autoArgs, + drvs, + false + ); } } diff --git a/tests/ca-shell.nix b/tests/ca-shell.nix index ad2ab6aff..36e1d1526 100644 --- a/tests/ca-shell.nix +++ b/tests/ca-shell.nix @@ -1 +1 @@ -{ ... }@args: import ./shell.nix (args // { contentAddressed = true; }) +{ inNixShell ? false, ... }@args: import ./shell.nix (args // { contentAddressed = true; }) diff --git a/tests/nix-shell.sh b/tests/nix-shell.sh index 3241d7a0f..0dc1999d8 100644 --- a/tests/nix-shell.sh +++ b/tests/nix-shell.sh @@ -102,3 +102,10 @@ source <(nix print-dev-env -f "$shellDotNix" shellDrv) [[ ${arr2[1]} = $'\n' ]] [[ ${arr2[2]} = $'x\ny' ]] [[ $(fun) = blabla ]] + +# Test nix-shell with ellipsis and no `inNixShell` argument (for backwards compat with old nixpkgs) +cat >$TEST_ROOT/shell-ellipsis.nix < Date: Wed, 15 Jun 2022 09:02:36 -0400 Subject: [PATCH 23/57] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com> --- doc/manual/src/release-notes/rl-next.md | 2 ++ src/nix/repl.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index 5749f3924..9684a70d4 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -7,3 +7,5 @@ with other commands that use `--file` and `--expr`. Primary breaking change is for the common usage of `nix repl ''` which can be recovered with `nix repl --file ''` or `nix repl --expr 'import {}'` + + This is currently guarded by the 'repl-flake' experimental feature diff --git a/src/nix/repl.md b/src/nix/repl.md index 6a526f7d0..23ef0f4e6 100644 --- a/src/nix/repl.md +++ b/src/nix/repl.md @@ -36,7 +36,7 @@ R""( Loading Installable ''... Added 1 variables. - # nix repl nixpkgs + # nix repl --extra_experimental_features 'flakes repl-flake' nixpkgs Loading Installable 'flake:nixpkgs#'... Added 5 variables. From d6d0e781bbade76f6ea3f310cb36973f4013826d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Na=C3=AFm=20Favier?= Date: Sun, 19 Jun 2022 17:54:27 +0200 Subject: [PATCH 24/57] Complete flake inputs for all given flakes Allow `nix build flake1 flake2 --update-input ` to complete the inputs of both flakes. Also do tilde expansion so that `nix build ~/flake --update-input ` works. --- src/libcmd/command.hh | 10 ++++++---- src/libcmd/installables.cc | 34 ++++++++++++++++------------------ src/nix/flake.cc | 4 ++-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 8982f21d0..cab379b84 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -79,8 +79,10 @@ struct MixFlakeOptions : virtual Args, EvalCommand MixFlakeOptions(); - virtual std::optional getFlakeRefForCompletion() + virtual std::vector getFlakesForCompletion() { return {}; } + + void completeFlakeInput(std::string_view prefix); }; struct SourceExprCommand : virtual Args, MixFlakeOptions @@ -119,7 +121,7 @@ struct InstallablesCommand : virtual Args, SourceExprCommand virtual bool useDefaultInstallables() { return true; } - std::optional getFlakeRefForCompletion() override; + std::vector getFlakesForCompletion() override; private: @@ -135,9 +137,9 @@ struct InstallableCommand : virtual Args, SourceExprCommand void prepare() override; - std::optional getFlakeRefForCompletion() override + std::vector getFlakesForCompletion() override { - return parseFlakeRefWithFragment(_installable, absPath(".")).first; + return {_installable}; } private: diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index ffc25135e..1bcef4172 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -23,15 +23,16 @@ namespace nix { -void completeFlakeInputPath( - ref evalState, - const FlakeRef & flakeRef, - std::string_view prefix) +void MixFlakeOptions::completeFlakeInput(std::string_view prefix) { - auto flake = flake::getFlake(*evalState, flakeRef, true); - for (auto & input : flake.inputs) - if (hasPrefix(input.first, prefix)) - completions->add(input.first); + auto evalState = getEvalState(); + for (auto & flakeRefS : getFlakesForCompletion()) { + auto flakeRef = parseFlakeRefWithFragment(expandTilde(flakeRefS), absPath(".")).first; + auto flake = flake::getFlake(*evalState, flakeRef, true); + for (auto & input : flake.inputs) + if (hasPrefix(input.first, prefix)) + completions->add(input.first); + } } MixFlakeOptions::MixFlakeOptions() @@ -86,8 +87,7 @@ MixFlakeOptions::MixFlakeOptions() lockFlags.inputUpdates.insert(flake::parseInputPath(s)); }}, .completer = {[&](size_t, std::string_view prefix) { - if (auto flakeRef = getFlakeRefForCompletion()) - completeFlakeInputPath(getEvalState(), *flakeRef, prefix); + completeFlakeInput(prefix); }} }); @@ -103,12 +103,10 @@ MixFlakeOptions::MixFlakeOptions() parseFlakeRef(flakeRef, absPath("."), true)); }}, .completer = {[&](size_t n, std::string_view prefix) { - if (n == 0) { - if (auto flakeRef = getFlakeRefForCompletion()) - completeFlakeInputPath(getEvalState(), *flakeRef, prefix); - } else if (n == 1) { + if (n == 0) + completeFlakeInput(prefix); + else if (n == 1) completeFlakeRef(getEvalState()->store, prefix); - } }} }); @@ -1043,14 +1041,14 @@ void InstallablesCommand::prepare() installables = parseInstallables(getStore(), _installables); } -std::optional InstallablesCommand::getFlakeRefForCompletion() +std::vector InstallablesCommand::getFlakesForCompletion() { if (_installables.empty()) { if (useDefaultInstallables()) - return parseFlakeRefWithFragment(".", absPath(".")).first; + return {"."}; return {}; } - return parseFlakeRefWithFragment(_installables.front(), absPath(".")).first; + return _installables; } InstallableCommand::InstallableCommand(bool supportReadOnlyMode) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 8370b8dcf..439eb53ba 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -50,9 +50,9 @@ public: return flake::lockFlake(*getEvalState(), getFlakeRef(), lockFlags); } - std::optional getFlakeRefForCompletion() override + std::vector getFlakesForCompletion() override { - return getFlakeRef(); + return {flakeUrl}; } }; From 3a85fd077cf8a404e0b7c727e47b8fcee85280a5 Mon Sep 17 00:00:00 2001 From: "Manu [tennox]" <2084639+tennox@users.noreply.github.com> Date: Tue, 21 Jun 2022 17:26:32 +0100 Subject: [PATCH 25/57] #6542 Apply flake templates partially on conflicts Will still exit with non-zero exit code and clearly prompt which files to merge: ``` nixx flake init -t github:numtide/devshell wrote: /home/manu/dev/stuff/gopassbridge/.envrc refusing to overwrite existing file '/home/manu/dev/stuff/gopassbridge/.gitignore' -> merge manually with '/nix/store/ksmwhyghjwb4d9dw6hcpbvng1msdvjim-source/template/.gitignore' wrote: /home/manu/dev/stuff/gopassbridge/devshell.toml wrote: /home/manu/dev/stuff/gopassbridge/flake.nix error: Encountered 1 conflicts - please merge manually ``` --- src/nix/flake.cc | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index a1edb5dbf..24255c247 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -740,7 +740,9 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand "If you've set '%s' to a string, try using a path instead.", templateDir, templateDirAttr->getAttrPathStr()); - std::vector files; + std::vector changedFiles; + std::vector conflictedFiles; + auto success = false; std::function copyDir; copyDir = [&](const Path & from, const Path & to) @@ -757,22 +759,33 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand auto contents = readFile(from2); if (pathExists(to2)) { auto contents2 = readFile(to2); - if (contents != contents2) - throw Error("refusing to overwrite existing file '%s' - please merge manually with '%s'", to2, from2); + if (contents != contents2) { + printError("refusing to overwrite existing file '%s'\n-> merge manually with '%s'", to2, from2); + success = false; + conflictedFiles.push_back(to2); + } else { + notice("skipping identical file: %s", from2); + } + continue; } else writeFile(to2, contents); } else if (S_ISLNK(st.st_mode)) { auto target = readLink(from2); if (pathExists(to2)) { - if (readLink(to2) != target) - throw Error("refusing to overwrite existing symlink '%s' - please merge manually with '%s'", to2, from2); + if (readLink(to2) != target) { + printError("refusing to overwrite existing file '%s' - please merge manually with '%s'", to2, from2); + success = false; + conflictedFiles.push_back(to2); + } else { + notice("skipping identical file: %s", from2); + } } else createSymlink(target, to2); } else throw Error("file '%s' has unsupported type", from2); - files.push_back(to2); + changedFiles.push_back(to2); notice("wrote: %s", to2); } }; @@ -781,7 +794,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand if (pathExists(flakeDir + "/.git")) { Strings args = { "-C", flakeDir, "add", "--intent-to-add", "--force", "--" }; - for (auto & s : files) args.push_back(s); + for (auto & s : changedFiles) args.push_back(s); runProgram("git", true, args); } auto welcomeText = cursor->maybeGetAttr("welcomeText"); @@ -789,6 +802,9 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand notice("\n"); notice(renderMarkdownToTerminal(welcomeText->getString())); } + + if (!success) + throw Error("Encountered %d conflicts - please merge manually", conflictedFiles.size()); } }; From e94aa1f6473196f04c339f8661ee4df7b5a0d3be Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Wed, 22 Jun 2022 22:35:48 +0200 Subject: [PATCH 26/57] tests/nix-shell: more meaningful testcase --- tests/nix-shell.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/nix-shell.sh b/tests/nix-shell.sh index 0dc1999d8..f291c6f79 100644 --- a/tests/nix-shell.sh +++ b/tests/nix-shell.sh @@ -105,7 +105,8 @@ source <(nix print-dev-env -f "$shellDotNix" shellDrv) # Test nix-shell with ellipsis and no `inNixShell` argument (for backwards compat with old nixpkgs) cat >$TEST_ROOT/shell-ellipsis.nix < Date: Wed, 22 Jun 2022 11:24:20 +0200 Subject: [PATCH 27/57] nix develop: save XDG_DATA_DIRS for loadable completion --- src/nix/develop.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 2a3fc0213..6d9ad9942 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -276,15 +276,25 @@ struct Common : InstallableCommand, MixProfile const BuildEnvironment & buildEnvironment, const Path & outputsDir = absPath(".") + "/outputs") { + // A list of colon-separated environment variables that should be + // prepended to, rather than overwritten, in order to keep the shell usable. + // Please keep this list minimal in order to avoid impurities. + static const char * const savedVars[] = { + "PATH", // for commands + "XDG_DATA_DIRS", // for loadable completion + }; + std::ostringstream out; out << "unset shellHook\n"; - out << "nix_saved_PATH=\"$PATH\"\n"; + for (auto & var : savedVars) + out << fmt("nix_saved_%s=\"$%s\"\n", var, var); buildEnvironment.toBash(out, ignoreVars); - out << "PATH=\"$PATH:$nix_saved_PATH\"\n"; + for (auto & var : savedVars) + out << fmt("%s=\"$%s:$nix_saved_%s\"\n", var, var, var); out << "export NIX_BUILD_TOP=\"$(mktemp -d -t nix-shell.XXXXXX)\"\n"; for (auto & i : {"TMP", "TMPDIR", "TEMP", "TEMPDIR"}) From c6f7726f48e83230246f9328115368547fe29f5f Mon Sep 17 00:00:00 2001 From: Dave Nicponski Date: Wed, 15 Jun 2022 12:49:12 -0400 Subject: [PATCH 28/57] Don't capture stdout when launching subshells in `nix repl` --- src/libcmd/repl.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 3c89a8ea3..588115a48 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -111,23 +111,20 @@ NixRepl::~NixRepl() write_history(historyFile.c_str()); } -std::string runNix(Path program, const Strings & args, +void runNix(Path program, const Strings & args, const std::optional & input = {}) { auto subprocessEnv = getEnv(); subprocessEnv["NIX_CONFIG"] = globalConfig.toKeyValue(); - auto res = runProgram(RunOptions { + runProgram2(RunOptions { .program = settings.nixBinDir+ "/" + program, .args = args, .environment = subprocessEnv, .input = input, }); - if (!statusOk(res.first)) - throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first)); - - return res.second; + return; } static NixRepl * curRepl; // ugly From f801d70ba70c130a26747aa5b60d233f37d34bfa Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Fri, 24 Jun 2022 11:17:29 -0400 Subject: [PATCH 29/57] tests: enable ca-derivations for simple.nix in repl tests --- tests/repl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/repl.sh b/tests/repl.sh index 30921af04..c555560cc 100644 --- a/tests/repl.sh +++ b/tests/repl.sh @@ -87,12 +87,12 @@ $testDir/simple.nix testReplResponse ' drvPath ' '".*-simple.drv"' \ ---file $testDir/simple.nix --experimental-features '' +--file $testDir/simple.nix --experimental-features 'ca-derivations' testReplResponse ' drvPath ' '".*-simple.drv"' \ ---file $testDir/simple.nix --extra-experimental-features 'repl-flake' +--file $testDir/simple.nix --extra-experimental-features 'repl-flake ca-derivations' mkdir -p flake && cat < flake/flake.nix { From 117baee1b78f662291e980075668720179c1c455 Mon Sep 17 00:00:00 2001 From: Manuel <2084639+tennox@users.noreply.github.com> Date: Sun, 26 Jun 2022 18:00:34 +0100 Subject: [PATCH 30/57] Update src/nix/flake.cc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/NixOS/nix/pull/6699#discussion_r904096906 Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com> --- src/nix/flake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 24255c247..fdb373f24 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -760,7 +760,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand if (pathExists(to2)) { auto contents2 = readFile(to2); if (contents != contents2) { - printError("refusing to overwrite existing file '%s'\n-> merge manually with '%s'", to2, from2); + printError("refusing to overwrite existing file '%s'\n please merge it manually with '%s'", to2, from2); success = false; conflictedFiles.push_back(to2); } else { From 58cbbdc5e78b952bfaf8ff36e9c94ccbd08469b7 Mon Sep 17 00:00:00 2001 From: Manuel <2084639+tennox@users.noreply.github.com> Date: Sun, 26 Jun 2022 18:00:57 +0100 Subject: [PATCH 31/57] Update src/nix/flake.cc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/NixOS/nix/pull/6699#discussion_r904097147 Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com> --- src/nix/flake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index fdb373f24..10bbcaf43 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -774,7 +774,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand auto target = readLink(from2); if (pathExists(to2)) { if (readLink(to2) != target) { - printError("refusing to overwrite existing file '%s' - please merge manually with '%s'", to2, from2); + printError("refusing to overwrite existing file '%s'\n please merge it manually with '%s'", to2, from2); success = false; conflictedFiles.push_back(to2); } else { From 4374e3ec67a6c3ed8342908a5229437424926bf5 Mon Sep 17 00:00:00 2001 From: "Manu [tennox]" <2084639+tennox@users.noreply.github.com> Date: Sun, 26 Jun 2022 18:12:30 +0100 Subject: [PATCH 32/57] #6699 flake init: Apply suggestions of @thufschmitt --- src/nix/flake.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 10bbcaf43..1140548e7 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -742,7 +742,6 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand std::vector changedFiles; std::vector conflictedFiles; - auto success = false; std::function copyDir; copyDir = [&](const Path & from, const Path & to) @@ -761,7 +760,6 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand auto contents2 = readFile(to2); if (contents != contents2) { printError("refusing to overwrite existing file '%s'\n please merge it manually with '%s'", to2, from2); - success = false; conflictedFiles.push_back(to2); } else { notice("skipping identical file: %s", from2); @@ -775,7 +773,6 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand if (pathExists(to2)) { if (readLink(to2) != target) { printError("refusing to overwrite existing file '%s'\n please merge it manually with '%s'", to2, from2); - success = false; conflictedFiles.push_back(to2); } else { notice("skipping identical file: %s", from2); @@ -803,8 +800,8 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand notice(renderMarkdownToTerminal(welcomeText->getString())); } - if (!success) - throw Error("Encountered %d conflicts - please merge manually", conflictedFiles.size()); + if (!conflictedFiles.empty()) + throw Error("Encountered %d conflicts - see above", conflictedFiles.size()); } }; From ae4c9ef8e284eabf3624d9e9ad0f0b432e06da41 Mon Sep 17 00:00:00 2001 From: "Manu [tennox]" <2084639+tennox@users.noreply.github.com> Date: Sun, 26 Jun 2022 21:29:45 +0100 Subject: [PATCH 33/57] #6699 flake init: fix trying to add unchanged file After skipping because of being of identical content it tried to git add it. --- src/nix/flake.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 1140548e7..895a7de76 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -777,6 +777,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand } else { notice("skipping identical file: %s", from2); } + continue; } else createSymlink(target, to2); } @@ -789,7 +790,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand copyDir(templateDir, flakeDir); - if (pathExists(flakeDir + "/.git")) { + if (!changedFiles.empty() && pathExists(flakeDir + "/.git")) { Strings args = { "-C", flakeDir, "add", "--intent-to-add", "--force", "--" }; for (auto & s : changedFiles) args.push_back(s); runProgram("git", true, args); From 6cab5284614991ea3622492eacdceb3caf52ccff Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 29 Jun 2022 12:16:51 +0200 Subject: [PATCH 34/57] Don't fail if we can't create ~/.local/share/nix/root https://hydra.nixos.org/build/182135943 --- src/libstore/store-api.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 53b1a8777..05353bce2 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -1326,9 +1326,14 @@ std::shared_ptr openFromNonUri(const std::string & uri, const Store::Para we're not root, then automatically set up a chroot store in ~/.local/share/nix/root. */ auto chrootStore = getDataDir() + "/nix/root"; - if (!pathExists(chrootStore)) + if (!pathExists(chrootStore)) { + try { + createDirs(chrootStore); + } catch (Error & e) { + return std::make_shared(params); + } warn("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore); - else + } else debug("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore); Store::Params params2; params2["root"] = chrootStore; From 83f96e61a43b77677e14cdf415f1a30d37b17f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Wed, 29 Jun 2022 16:28:46 +0200 Subject: [PATCH 35/57] Add some test for `nix flake init` with conflicts --- tests/flakes.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/flakes.sh b/tests/flakes.sh index 36bffcf3b..35cf4d8e7 100644 --- a/tests/flakes.sh +++ b/tests/flakes.sh @@ -408,8 +408,10 @@ cat > $templatesDir/trivial/flake.nix < $templatesDir/trivial/a +echo b > $templatesDir/trivial/b -git -C $templatesDir add flake.nix trivial/flake.nix +git -C $templatesDir add flake.nix trivial/ git -C $templatesDir commit -m 'Initial' nix flake check templates @@ -424,6 +426,18 @@ nix flake show $flake7Dir nix flake show $flake7Dir --json | jq git -C $flake7Dir commit -a -m 'Initial' +# Test 'nix flake init' with benign conflicts +rm -rf $flake7Dir && mkdir $flake7Dir && git -C $flake7Dir init +echo a > $flake7Dir/a +(cd $flake7Dir && nix flake init) # check idempotence + +# Test 'nix flake init' with conflicts +rm -rf $flake7Dir && mkdir $flake7Dir && git -C $flake7Dir init +echo b > $flake7Dir/a +pushd $flake7Dir +(! nix flake init) |& grep "refusing to overwrite existing file '$flake7Dir/a'" +popd + # Test 'nix flake new'. rm -rf $flake6Dir nix flake new -t templates#trivial $flake6Dir From d31c520f40101326179fe27bad7ccc2045c73156 Mon Sep 17 00:00:00 2001 From: naveen <172697+naveensrinivasan@users.noreply.github.com> Date: Fri, 1 Jul 2022 00:29:30 +0000 Subject: [PATCH 36/57] chore: Set permissions for GitHub actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much. - Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> --- .github/workflows/ci.yml | 2 ++ .github/workflows/hydra_status.yml | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc6531ea5..1a317f267 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,8 @@ jobs: - run: nix --experimental-features 'nix-command flakes' flake check -L check_cachix: + permissions: + contents: none name: Cachix secret present for installer tests runs-on: ubuntu-latest outputs: diff --git a/.github/workflows/hydra_status.yml b/.github/workflows/hydra_status.yml index 53e69cb2d..d85999256 100644 --- a/.github/workflows/hydra_status.yml +++ b/.github/workflows/hydra_status.yml @@ -3,6 +3,9 @@ on: schedule: - cron: "12,42 * * * *" workflow_dispatch: +permissions: + contents: read + jobs: check_hydra_status: name: Check Hydra status From 07416a6005fe035baa8646c6827904afb5226f95 Mon Sep 17 00:00:00 2001 From: Alex Wied Date: Tue, 28 Jun 2022 16:38:19 -0400 Subject: [PATCH 37/57] Allow specification of extra packages, maxLayers in Docker image --- docker.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docker.nix b/docker.nix index 0cd64856f..ddf6feff5 100644 --- a/docker.nix +++ b/docker.nix @@ -4,6 +4,8 @@ , tag ? "latest" , channelName ? "nixpkgs" , channelURL ? "https://nixos.org/channels/nixpkgs-unstable" +, extraPkgs ? [] +, maxLayers ? 100 }: let defaultPkgs = with pkgs; [ @@ -23,7 +25,7 @@ let iana-etc git openssh - ]; + ] ++ extraPkgs; users = { @@ -229,7 +231,7 @@ let in pkgs.dockerTools.buildLayeredImageWithNixDb { - inherit name tag; + inherit name tag maxLayers; contents = [ baseSystem ]; From 70083218b3727bd1279026cbe4d4179d0c7182c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Tue, 5 Jul 2022 12:06:58 +0200 Subject: [PATCH 38/57] Restrict the permissions of the CI --- .github/workflows/ci.yml | 2 ++ .github/workflows/hydra_status.yml | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a317f267..956f81684 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,8 @@ on: pull_request: push: +permissions: read-all + jobs: tests: diff --git a/.github/workflows/hydra_status.yml b/.github/workflows/hydra_status.yml index d85999256..7766e4f8e 100644 --- a/.github/workflows/hydra_status.yml +++ b/.github/workflows/hydra_status.yml @@ -1,4 +1,7 @@ name: Hydra status + +permissions: read-all + on: schedule: - cron: "12,42 * * * *" From 541e10496a242d7c32b4e3f3ce9b4caacc04eb14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Tue, 5 Jul 2022 16:28:39 +0200 Subject: [PATCH 39/57] Fix the hydra_status CI job --- .github/workflows/hydra_status.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/hydra_status.yml b/.github/workflows/hydra_status.yml index 7766e4f8e..38a9c0877 100644 --- a/.github/workflows/hydra_status.yml +++ b/.github/workflows/hydra_status.yml @@ -6,8 +6,6 @@ on: schedule: - cron: "12,42 * * * *" workflow_dispatch: -permissions: - contents: read jobs: check_hydra_status: From ba1fe85b65e4e6408971bb36c40e0aad684cfc74 Mon Sep 17 00:00:00 2001 From: Gytis Ivaskevicius Date: Mon, 13 Dec 2021 09:24:24 +0200 Subject: [PATCH 40/57] Add builtins.traceVerbose Co-Authored-By: Silvan Mosberger Add builtins.traceVerbose tests --- src/libexpr/eval.hh | 3 +++ src/libexpr/primops.cc | 21 +++++++++++++++++++++ tests/lang.sh | 2 ++ 3 files changed, 26 insertions(+) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 4eaa3c9b0..7db954bf4 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -646,6 +646,9 @@ struct EvalSettings : Config Setting useEvalCache{this, true, "eval-cache", "Whether to use the flake evaluation cache."}; + + Setting traceVerbose{this, false, "trace-verbose", + "Whether `builtins.traceVerbose` should trace its first argument when evaluated."}; }; extern EvalSettings evalSettings; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index eea274301..ac84e26c3 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -970,6 +970,15 @@ static RegisterPrimOp primop_trace({ }); +/* Takes two arguments and evaluates to the second one. Used as the + * builtins.traceVerbose implementation when --trace-verbose is not enabled + */ +static void prim_second(EvalState & state, const Pos & pos, Value * * args, Value & v) +{ + state.forceValue(*args[1], pos); + v = *args[1]; +} + /************************************************************* * Derivations *************************************************************/ @@ -3926,6 +3935,18 @@ void EvalState::createBaseEnv() addPrimOp("__exec", 1, prim_exec); } + addPrimOp({ + .fun = evalSettings.traceVerbose ? prim_trace : prim_second, + .arity = 2, + .name = symbols.create("__traceVerbose"), + .args = { "e1", "e2" }, + .doc = R"( + Evaluate *e1* and print its abstract syntax representation on standard + error if `--trace-verbose` is enabled. Then return *e2*. This function + is useful for debugging. + )", + }); + /* Add a value containing the current Nix expression search path. */ mkList(v, searchPath.size()); int n = 0; diff --git a/tests/lang.sh b/tests/lang.sh index f09eaeb31..c0b0fc58c 100644 --- a/tests/lang.sh +++ b/tests/lang.sh @@ -5,6 +5,8 @@ export NIX_REMOTE=dummy:// nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>&1 | grep -q Hello nix-instantiate --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 +nix-instantiate --trace-verbose --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grep -q Hello +(! nix-instantiate --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grep -q Hello) (! nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grep -q Hello) nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' 2>&1 | grep -q Hello From b2703c73a4e28a2456a599a122cc2b4ab0d33430 Mon Sep 17 00:00:00 2001 From: Gytis Ivaskevicius Date: Tue, 5 Jul 2022 19:56:39 +0300 Subject: [PATCH 41/57] builtins.traceVerbose: Post rebase fixes --- src/libexpr/primops.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ac84e26c3..5fda9af75 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -973,7 +973,7 @@ static RegisterPrimOp primop_trace({ /* Takes two arguments and evaluates to the second one. Used as the * builtins.traceVerbose implementation when --trace-verbose is not enabled */ -static void prim_second(EvalState & state, const Pos & pos, Value * * args, Value & v) +static void prim_second(EvalState & state, const PosIdx pos, Value * * args, Value & v) { state.forceValue(*args[1], pos); v = *args[1]; @@ -3938,7 +3938,7 @@ void EvalState::createBaseEnv() addPrimOp({ .fun = evalSettings.traceVerbose ? prim_trace : prim_second, .arity = 2, - .name = symbols.create("__traceVerbose"), + .name = "__traceVerbose", .args = { "e1", "e2" }, .doc = R"( Evaluate *e1* and print its abstract syntax representation on standard From 6fa95c35c7f9d88ad7685614d275d06373394c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= <7226587+thufschmitt@users.noreply.github.com> Date: Wed, 6 Jul 2022 06:46:54 +0200 Subject: [PATCH 42/57] Add a release notes entry for #4914 cc @gytis-ivaskevicius --- doc/manual/src/release-notes/rl-next.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index 9684a70d4..f6a45184f 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -9,3 +9,6 @@ `nix repl --file ''` or `nix repl --expr 'import {}'` This is currently guarded by the 'repl-flake' experimental feature + +* A new primop `builtins.traceVerbose` is available. It is similar to `builtins.trace` + if the `trace-verbose` setting is set to true, and it is a no-op otherwise. From eac211a171fa6253b5ae6fdcf56fc5d0aced0201 Mon Sep 17 00:00:00 2001 From: laalsaas Date: Sun, 10 Jul 2022 12:09:44 +0200 Subject: [PATCH 43/57] Fix logical and typographical errors in nix-env man page --- doc/manual/src/command-ref/nix-env.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/src/command-ref/nix-env.md b/doc/manual/src/command-ref/nix-env.md index 8d6abaf52..a372c5eae 100644 --- a/doc/manual/src/command-ref/nix-env.md +++ b/doc/manual/src/command-ref/nix-env.md @@ -31,7 +31,7 @@ subcommand to be performed. These are documented below. Several commands, such as `nix-env -q` and `nix-env -i`, take a list of arguments that specify the packages on which to operate. These are extended regular expressions that must match the entire name of the -package. (For details on regular expressions, see regex7.) The match is +package. (For details on regular expressions, see **regex**(7).) The match is case-sensitive. The regular expression can optionally be followed by a dash and a version number; if omitted, any version of the package will match. Here are some examples: @@ -412,7 +412,7 @@ The upgrade operation determines whether a derivation `y` is an upgrade of a derivation `x` by looking at their respective `name` attributes. The names (e.g., `gcc-3.3.1` are split into two parts: the package name (`gcc`), and the version (`3.3.1`). The version part starts after the -first dash not followed by a letter. `x` is considered an upgrade of `y` +first dash not followed by a letter. `y` is considered an upgrade of `x` if their package names match, and the version of `y` is higher than that of `x`. From 5022a713051c67d503856dab4cb088827d9f222e Mon Sep 17 00:00:00 2001 From: Ryan Mulligan Date: Sun, 10 Jul 2022 16:50:49 -0700 Subject: [PATCH 44/57] update stale bot per RFC 0124 --- .github/stale.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index fe24942f4..ee831135a 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,10 +1,9 @@ # Configuration for probot-stale - https://github.com/probot/stale daysUntilStale: 180 -daysUntilClose: 365 +daysUntilClose: false exemptLabels: - "critical" + - "never-stale" staleLabel: "stale" -markComment: | - I marked this as stale due to inactivity. → [More info](https://github.com/NixOS/nix/blob/master/.github/STALE-BOT.md) -closeComment: | - I closed this issue due to inactivity. → [More info](https://github.com/NixOS/nix/blob/master/.github/STALE-BOT.md) +markComment: false +closeComment: false From 517ce38dadc2c8d6282b6865ec0c620b7e26df3a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 11 Jul 2022 11:17:19 +0200 Subject: [PATCH 45/57] Update release notes --- doc/manual/src/release-notes/rl-next.md | 33 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index f6a45184f..bbaa68d4f 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -1,14 +1,31 @@ # Release X.Y (202?-??-??) -* Nix can now be built with LTO by passing `--enable-lto` to `configure`. - LTO is currently only supported when building with GCC. - * `nix repl` now takes installables on the command line, unifying the usage with other commands that use `--file` and `--expr`. Primary breaking change is for the common usage of `nix repl ''` which can be recovered with - `nix repl --file ''` or `nix repl --expr 'import {}'` - - This is currently guarded by the 'repl-flake' experimental feature + `nix repl --file ''` or `nix repl --expr 'import {}'`. -* A new primop `builtins.traceVerbose` is available. It is similar to `builtins.trace` - if the `trace-verbose` setting is set to true, and it is a no-op otherwise. + This is currently guarded by the `repl-flake` experimental feature. + +* A new function `builtins.traceVerbose` is available. It is similar + to `builtins.trace` if the `trace-verbose` setting is set to true, + and it is a no-op otherwise. + +* `nix search` has a new flag `--exclude` to filter out packages. + +* On Linux, if `/nix` doesn't exist and cannot be created and you're + not running as root, Nix will automatically use + `~/.local/share/nix/root` as a chroot store. This enables non-root + users to download the statically linked Nix binary and have it work + out of the box, e.g. + + ``` + # ~/nix run nixpkgs#hello + warning: '/nix' does not exists, so Nix will use '/home/ubuntu/.local/share/nix/root' as a chroot store + Hello, world! + ``` + +* `flake-registry.json` is now fetched from `channels.nixos.org`. + +* Nix can now be built with LTO by passing `--enable-lto` to `configure`. + LTO is currently only supported when building with GCC. From 711b2e1f48316d80853635408c518e3562a1fa37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Na=C3=AFm=20Favier?= Date: Mon, 20 Jun 2022 04:15:38 +0200 Subject: [PATCH 46/57] Fix flake input completion for `InstallablesCommand`s Defers completion of flake inputs until the whole command line is parsed so that we know what flakes we need to complete the inputs of. Previously, `nix build flake --update-input ` always behaved like `nix build . --update-input `. --- src/libcmd/command.hh | 4 ++++ src/libcmd/installables.cc | 34 ++++++++++++++++++++-------------- src/libutil/args.cc | 10 +++++++++- src/libutil/args.hh | 7 +++++++ src/nix/main.cc | 5 ++++- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index cab379b84..ffa8e784f 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -77,12 +77,16 @@ struct MixFlakeOptions : virtual Args, EvalCommand { flake::LockFlags lockFlags; + std::optional needsFlakeInputCompletion = {}; + MixFlakeOptions(); virtual std::vector getFlakesForCompletion() { return {}; } void completeFlakeInput(std::string_view prefix); + + void completionHook() override; }; struct SourceExprCommand : virtual Args, MixFlakeOptions diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 1bcef4172..81c8dd062 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -23,18 +23,6 @@ namespace nix { -void MixFlakeOptions::completeFlakeInput(std::string_view prefix) -{ - auto evalState = getEvalState(); - for (auto & flakeRefS : getFlakesForCompletion()) { - auto flakeRef = parseFlakeRefWithFragment(expandTilde(flakeRefS), absPath(".")).first; - auto flake = flake::getFlake(*evalState, flakeRef, true); - for (auto & input : flake.inputs) - if (hasPrefix(input.first, prefix)) - completions->add(input.first); - } -} - MixFlakeOptions::MixFlakeOptions() { auto category = "Common flake-related options"; @@ -87,7 +75,7 @@ MixFlakeOptions::MixFlakeOptions() lockFlags.inputUpdates.insert(flake::parseInputPath(s)); }}, .completer = {[&](size_t, std::string_view prefix) { - completeFlakeInput(prefix); + needsFlakeInputCompletion = {std::string(prefix)}; }} }); @@ -104,7 +92,7 @@ MixFlakeOptions::MixFlakeOptions() }}, .completer = {[&](size_t n, std::string_view prefix) { if (n == 0) - completeFlakeInput(prefix); + needsFlakeInputCompletion = {std::string(prefix)}; else if (n == 1) completeFlakeRef(getEvalState()->store, prefix); }} @@ -137,6 +125,24 @@ MixFlakeOptions::MixFlakeOptions() }); } +void MixFlakeOptions::completeFlakeInput(std::string_view prefix) +{ + auto evalState = getEvalState(); + for (auto & flakeRefS : getFlakesForCompletion()) { + auto flakeRef = parseFlakeRefWithFragment(expandTilde(flakeRefS), absPath(".")).first; + auto flake = flake::getFlake(*evalState, flakeRef, true); + for (auto & input : flake.inputs) + if (hasPrefix(input.first, prefix)) + completions->add(input.first); + } +} + +void MixFlakeOptions::completionHook() +{ + if (auto & prefix = needsFlakeInputCompletion) + completeFlakeInput(*prefix); +} + SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode) { addFlag({ diff --git a/src/libutil/args.cc b/src/libutil/args.cc index 4b8c55686..44b63f0f6 100644 --- a/src/libutil/args.cc +++ b/src/libutil/args.cc @@ -124,7 +124,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end) bool anyCompleted = false; for (size_t n = 0 ; n < flag.handler.arity; ++n) { if (pos == end) { - if (flag.handler.arity == ArityAny) break; + if (flag.handler.arity == ArityAny || anyCompleted) break; throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity); } if (auto prefix = needsCompletion(*pos)) { @@ -362,6 +362,14 @@ bool MultiCommand::processArgs(const Strings & args, bool finish) return Args::processArgs(args, finish); } +void MultiCommand::completionHook() +{ + if (command) + return command->second->completionHook(); + else + return Args::completionHook(); +} + nlohmann::json MultiCommand::toJSON() { auto cmds = nlohmann::json::object(); diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 07c017719..84866f12b 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -148,6 +148,11 @@ protected: argument (if any) have been processed. */ virtual void initialFlagsProcessed() {} + /* Called after the command line has been processed if we need to generate + completions. Useful for commands that need to know the whole command line + in order to know what completions to generate. */ + virtual void completionHook() { } + public: void addFlag(Flag && flag); @@ -223,6 +228,8 @@ public: bool processArgs(const Strings & args, bool finish) override; + void completionHook() override; + nlohmann::json toJSON() override; }; diff --git a/src/nix/main.cc b/src/nix/main.cc index f398e3118..f6138cbe6 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -342,7 +342,10 @@ void mainWrapped(int argc, char * * argv) if (!completions) throw; } - if (completions) return; + if (completions) { + args.completionHook(); + return; + } if (args.showVersion) { printVersion(programName); From 69ea265fd26e6b503bb52566ce6f5f12e0a75661 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:21:12 -0600 Subject: [PATCH 47/57] 'tryEval' not 'try clause' --- src/libexpr/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 28256ec5c..956c4b474 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -838,7 +838,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & printError("%s\n\n", error->what()); if (trylevel > 0 && error->info().level != lvlInfo) - printError("This exception occurred in a try clause. use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); + printError("This exception occurred in a 'tryEval' call. Use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL); } From 6ac8200ff5d21d7c4464b4b3a2d3716fa4b942fd Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:21:40 -0600 Subject: [PATCH 48/57] use util.hh class instead of local --- src/libexpr/primops.cc | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ecc1c136a..3a07e43a7 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -846,15 +846,6 @@ static RegisterPrimOp primop_floor({ .fun = prim_floor, }); -class Counter -{ - private: - int &counter; - public: - Counter(int &counter) :counter(counter) { counter++; } - ~Counter() { counter--; } -}; - /* Try evaluating the argument. Success => {success=true; value=something;}, * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) @@ -862,7 +853,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va auto attrs = state.buildBindings(2); /* increment state.trylevel, and decrement it when this function returns. */ - Counter trylevel(state.trylevel); + MaintainCount trylevel(state.trylevel); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; if (state.debugRepl && state.ignoreTry) From a3629ab0ccd40a4492ac99424d84b3649df8b057 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:47:09 -0600 Subject: [PATCH 49/57] move ignore-try to EvalSettings --- src/libcmd/command.cc | 9 --------- src/libexpr/eval.cc | 1 - src/libexpr/eval.hh | 8 +++++++- src/libexpr/primops.cc | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 940fd5b23..14bb27936 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -91,12 +91,6 @@ EvalCommand::EvalCommand() .description = "start an interactive environment if evaluation fails", .handler = {&startReplOnEvalErrors, true}, }); - - addFlag({ - .longName = "ignore-try", - .description = "ignore exceptions in try clauses during debug", - .handler = {&ignoreExceptionsDuringTry, true}, - }); } EvalCommand::~EvalCommand() @@ -128,9 +122,6 @@ ref EvalCommand::getEvalState() if (startReplOnEvalErrors) { evalState->debugRepl = &runRepl; }; - if (ignoreExceptionsDuringTry) { - evalState->ignoreTry = ignoreExceptionsDuringTry; - }; } return ref(evalState); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 956c4b474..f485e2fed 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -467,7 +467,6 @@ EvalState::EvalState( , debugRepl(nullptr) , debugStop(false) , debugQuit(false) - , ignoreTry(false) , trylevel(0) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 9aff77042..b8903c06c 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -130,7 +130,6 @@ public: void (* debugRepl)(ref es, const ValMap & extraEnv); bool debugStop; bool debugQuit; - bool ignoreTry; int trylevel; std::list debugTraces; std::map> exprEnvs; @@ -648,6 +647,13 @@ struct EvalSettings : Config Setting useEvalCache{this, true, "eval-cache", "Whether to use the flake evaluation cache."}; + + Setting ignoreExceptionsDuringTry{this, false, "ignore-try", + R"( + If set to true, ignore exceptions inside 'tryEval' calls when evaluating nix expressions in + debug mode (using the --debugger flag). By default the debugger will pause on all exceptions. + )"}; + }; extern EvalSettings evalSettings; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 3a07e43a7..2201ca0c4 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -856,7 +856,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va MaintainCount trylevel(state.trylevel); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl && state.ignoreTry) + if (state.debugRepl && evalSettings.ignoreExceptionsDuringTry) { /* to prevent starting the repl from exceptions withing a tryEval, null it. */ savedDebugRepl = state.debugRepl; From c364e0b098e1abc5bb06e0e86b3525c7bef33e15 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 11 Jul 2022 20:56:19 +0200 Subject: [PATCH 50/57] Fix buildStatic.aarch64-linux Commit 925b97522497e9c0f7a385c904410e560796208f accidentally enabled use of the gold linker on aarch64-linux, which apparently doesn't work. https://hydra.nixos.org/build/183500621 --- flake.nix | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/flake.nix b/flake.nix index 22367df71..1ee040441 100644 --- a/flake.nix +++ b/flake.nix @@ -54,7 +54,7 @@ # we want most of the time and for backwards compatibility forAllSystems (system: stdenvsPackages.${system} // stdenvsPackages.${system}.stdenvPackages); - commonDeps = pkgs: with pkgs; rec { + commonDeps = { pkgs, isStatic ? false }: with pkgs; rec { # Use "busybox-sandbox-shell" if present, # if not (legacy) fallback and hope it's sufficient. sh = pkgs.busybox-sandbox-shell or (busybox.override { @@ -85,6 +85,8 @@ lib.optionals stdenv.isLinux [ "--with-boost=${boost}/lib" "--with-sandbox-shell=${sh}/bin/busybox" + ] + ++ lib.optionals (stdenv.isLinux && !(isStatic && stdenv.system == "aarch64-linux")) [ "LDFLAGS=-fuse-ld=gold" ]; @@ -170,7 +172,7 @@ echo "file installer $out/install" >> $out/nix-support/hydra-build-products ''; - testNixVersions = pkgs: client: daemon: with commonDeps pkgs; with pkgs.lib; pkgs.stdenv.mkDerivation { + testNixVersions = pkgs: client: daemon: with commonDeps { inherit pkgs; }; with pkgs.lib; pkgs.stdenv.mkDerivation { NIX_DAEMON_PACKAGE = daemon; NIX_CLIENT_PACKAGE = client; name = @@ -281,7 +283,7 @@ # Forward from the previous stage as we don’t want it to pick the lowdown override nixUnstable = prev.nixUnstable; - nix = with final; with commonDeps pkgs; currentStdenv.mkDerivation { + nix = with final; with commonDeps { inherit pkgs; }; currentStdenv.mkDerivation { name = "nix-${version}"; inherit version; @@ -448,7 +450,7 @@ # Line coverage analysis. coverage = with nixpkgsFor.x86_64-linux; - with commonDeps pkgs; + with commonDeps { inherit pkgs; }; releaseTools.coverageAnalysis { name = "nix-coverage-${version}"; @@ -559,7 +561,7 @@ } // (nixpkgs.lib.optionalAttrs (builtins.elem system linux64BitSystems) { nix-static = let nixpkgs = nixpkgsFor.${system}.pkgsStatic; - in with commonDeps nixpkgs; nixpkgs.stdenv.mkDerivation { + in with commonDeps { pkgs = nixpkgs; isStatic = true; }; nixpkgs.stdenv.mkDerivation { name = "nix-${version}"; src = self; @@ -630,7 +632,7 @@ inherit system crossSystem; overlays = [ self.overlays.default ]; }; - in with commonDeps nixpkgsCross; nixpkgsCross.stdenv.mkDerivation { + in with commonDeps { pkgs = nixpkgsCross; }; nixpkgsCross.stdenv.mkDerivation { name = "nix-${version}"; src = self; @@ -673,7 +675,7 @@ devShells = forAllSystems (system: forAllStdenvs (stdenv: with nixpkgsFor.${system}; - with commonDeps pkgs; + with commonDeps { inherit pkgs; }; nixpkgsFor.${system}.${stdenv}.mkDerivation { name = "nix"; From 28e913c605d36711546706b7ddbdb8ad711a2486 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 11 Jul 2022 21:10:23 +0200 Subject: [PATCH 51/57] Branch 2.10 release notes --- doc/manual/src/SUMMARY.md.in | 1 + doc/manual/src/release-notes/rl-2.10.md | 31 +++++++++++++++++++++++++ doc/manual/src/release-notes/rl-next.md | 29 ----------------------- 3 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 doc/manual/src/release-notes/rl-2.10.md diff --git a/doc/manual/src/SUMMARY.md.in b/doc/manual/src/SUMMARY.md.in index 825a8b4c0..9728728aa 100644 --- a/doc/manual/src/SUMMARY.md.in +++ b/doc/manual/src/SUMMARY.md.in @@ -72,6 +72,7 @@ - [CLI guideline](contributing/cli-guideline.md) - [Release Notes](release-notes/release-notes.md) - [Release X.Y (202?-??-??)](release-notes/rl-next.md) + - [Release 2.10 (2022-07-11)](release-notes/rl-2.10.md) - [Release 2.9 (2022-05-30)](release-notes/rl-2.9.md) - [Release 2.8 (2022-04-19)](release-notes/rl-2.8.md) - [Release 2.7 (2022-03-07)](release-notes/rl-2.7.md) diff --git a/doc/manual/src/release-notes/rl-2.10.md b/doc/manual/src/release-notes/rl-2.10.md new file mode 100644 index 000000000..b99dbeef0 --- /dev/null +++ b/doc/manual/src/release-notes/rl-2.10.md @@ -0,0 +1,31 @@ +# Release 2.10 (2022-07-11) + +* `nix repl` now takes installables on the command line, unifying the usage + with other commands that use `--file` and `--expr`. Primary breaking change + is for the common usage of `nix repl ''` which can be recovered with + `nix repl --file ''` or `nix repl --expr 'import {}'`. + + This is currently guarded by the `repl-flake` experimental feature. + +* A new function `builtins.traceVerbose` is available. It is similar + to `builtins.trace` if the `trace-verbose` setting is set to true, + and it is a no-op otherwise. + +* `nix search` has a new flag `--exclude` to filter out packages. + +* On Linux, if `/nix` doesn't exist and cannot be created and you're + not running as root, Nix will automatically use + `~/.local/share/nix/root` as a chroot store. This enables non-root + users to download the statically linked Nix binary and have it work + out of the box, e.g. + + ``` + # ~/nix run nixpkgs#hello + warning: '/nix' does not exists, so Nix will use '/home/ubuntu/.local/share/nix/root' as a chroot store + Hello, world! + ``` + +* `flake-registry.json` is now fetched from `channels.nixos.org`. + +* Nix can now be built with LTO by passing `--enable-lto` to `configure`. + LTO is currently only supported when building with GCC. diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index bbaa68d4f..78ae99f4b 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -1,31 +1,2 @@ # Release X.Y (202?-??-??) -* `nix repl` now takes installables on the command line, unifying the usage - with other commands that use `--file` and `--expr`. Primary breaking change - is for the common usage of `nix repl ''` which can be recovered with - `nix repl --file ''` or `nix repl --expr 'import {}'`. - - This is currently guarded by the `repl-flake` experimental feature. - -* A new function `builtins.traceVerbose` is available. It is similar - to `builtins.trace` if the `trace-verbose` setting is set to true, - and it is a no-op otherwise. - -* `nix search` has a new flag `--exclude` to filter out packages. - -* On Linux, if `/nix` doesn't exist and cannot be created and you're - not running as root, Nix will automatically use - `~/.local/share/nix/root` as a chroot store. This enables non-root - users to download the statically linked Nix binary and have it work - out of the box, e.g. - - ``` - # ~/nix run nixpkgs#hello - warning: '/nix' does not exists, so Nix will use '/home/ubuntu/.local/share/nix/root' as a chroot store - Hello, world! - ``` - -* `flake-registry.json` is now fetched from `channels.nixos.org`. - -* Nix can now be built with LTO by passing `--enable-lto` to `configure`. - LTO is currently only supported when building with GCC. From c1c37f32002e2e2ad167bcac2e5d76a3a3ad6a35 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Mon, 13 Jun 2022 20:39:09 +0200 Subject: [PATCH 52/57] flakes: throw an error if `follows`-declaration for an input is invalid I recently got fairly confused why the following expression didn't have any effect { description = "Foobar"; inputs.sops-nix = { url = github:mic92/sops-nix; inputs.nixpkgs_22_05.follows = "nixpkgs"; }; } until I found out that the input was called `nixpkgs-22_05` (please note the dash vs. underscore). IMHO it's not a good idea to not throw an error in that case and probably leave end-users rather confused, so I implemented a small check for that which basically checks whether `follows`-declaration from overrides actually have corresponding inputs in the transitive flake. In fact this was done by accident already in our own test-suite where the removal of a `follows` was apparently forgotten[1]. Since the key of the `std::map` that holds the `overrides` is a vector and we have to find the last element of each vector (i.e. the override) this has to be done with a for loop in O(n) complexity with `n` being the total amount of overrides (which shouldn't be that large though). Please note that this doesn't work with nested expressions, i.e. inputs.fenix.inputs.nixpkgs.follows = "..."; which is a known problem[2]. For the expression demonstrated above, an error like this will be thrown: error: sops-nix has a `follows'-declaration for a non-existant input nixpkgs_22_05! [1] 2664a216e57169ec57d7f51be1b8383c1be83fd5 [2] https://github.com/NixOS/nix/issues/5790 --- src/libexpr/flake/flake.cc | 23 +++++++++++++++++++++++ tests/flakes.sh | 21 ++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 920726b73..b97780a9c 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -373,6 +373,29 @@ LockedFlake lockFlake( { debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); + auto overrides2 = overrides; + for (auto & [inputPath, inputOverride] : overrides2) { + auto inputPath2(inputPath); + auto follow = inputPath2.back(); + inputPath2.pop_back(); + if (inputPath2 == inputPathPrefix + && flakeInputs.find(follow) == flakeInputs.end() + ) { + std::string root; + for (auto & element : inputPath2) { + root.append(element); + if (element != inputPath2.back()) { + root.append(".inputs."); + } + } + throw Error( + "%s has a `follows'-declaration for a non-existant input %s!", + root, + follow + ); + } + } + /* Get the overrides (i.e. attributes of the form 'inputs.nixops.inputs.nixpkgs.url = ...'). */ for (auto & [id, input] : flakeInputs) { diff --git a/tests/flakes.sh b/tests/flakes.sh index 35cf4d8e7..868c410f4 100644 --- a/tests/flakes.sh +++ b/tests/flakes.sh @@ -801,6 +801,8 @@ nix flake metadata $flakeFollowsA nix flake update $flakeFollowsA +nix flake lock $flakeFollowsA + oldLock="$(cat "$flakeFollowsA/flake.lock")" # Ensure that locking twice doesn't change anything @@ -823,7 +825,6 @@ cat > $flakeFollowsA/flake.nix <$flakeFollowsA/flake.nix <&1 | grep "error: B has a \`follows'-declaration for a non-existant input invalid!" From 411111a3bc0e47520797106e1697aaa11631a101 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Tue, 12 Jul 2022 11:22:35 +0200 Subject: [PATCH 53/57] Turn error for non-existant follows into a warning --- src/libexpr/flake/flake.cc | 5 ++--- tests/flakes.sh | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index b97780a9c..c59a42d56 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -373,8 +373,7 @@ LockedFlake lockFlake( { debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); - auto overrides2 = overrides; - for (auto & [inputPath, inputOverride] : overrides2) { + for (auto [inputPath, inputOverride] : overrides) { auto inputPath2(inputPath); auto follow = inputPath2.back(); inputPath2.pop_back(); @@ -388,7 +387,7 @@ LockedFlake lockFlake( root.append(".inputs."); } } - throw Error( + warn( "%s has a `follows'-declaration for a non-existant input %s!", root, follow diff --git a/tests/flakes.sh b/tests/flakes.sh index 868c410f4..9087e1978 100644 --- a/tests/flakes.sh +++ b/tests/flakes.sh @@ -877,4 +877,4 @@ EOF git -C $flakeFollowsA add flake.nix -nix flake lock $flakeFollowsA 2>&1 | grep "error: B has a \`follows'-declaration for a non-existant input invalid!" +nix flake lock $flakeFollowsA 2>&1 | grep "warning: B has a \`follows'-declaration for a non-existant input invalid!" From 1f771065f1353ba462d73641b047b4fb2f02f482 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Tue, 12 Jul 2022 11:25:33 +0200 Subject: [PATCH 54/57] Move follows-check into its own function --- src/libexpr/flake/flake.cc | 47 ++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index c59a42d56..906e11251 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -353,26 +353,15 @@ LockedFlake lockFlake( std::vector parents; std::function node, const InputPath & inputPathPrefix, - std::shared_ptr oldNode, - const InputPath & lockRootPath, - const Path & parentPath, - bool trustLock)> - computeLocks; + const FlakeInputs & flakeInputs + )> + checkFollowsDeclarations; - computeLocks = [&]( - const FlakeInputs & flakeInputs, - std::shared_ptr node, + checkFollowsDeclarations = [&]( const InputPath & inputPathPrefix, - std::shared_ptr oldNode, - const InputPath & lockRootPath, - const Path & parentPath, - bool trustLock) - { - debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); - + const FlakeInputs & flakeInputs + ) { for (auto [inputPath, inputOverride] : overrides) { auto inputPath2(inputPath); auto follow = inputPath2.back(); @@ -394,6 +383,30 @@ LockedFlake lockFlake( ); } } + }; + + std::function node, + const InputPath & inputPathPrefix, + std::shared_ptr oldNode, + const InputPath & lockRootPath, + const Path & parentPath, + bool trustLock)> + computeLocks; + + computeLocks = [&]( + const FlakeInputs & flakeInputs, + std::shared_ptr node, + const InputPath & inputPathPrefix, + std::shared_ptr oldNode, + const InputPath & lockRootPath, + const Path & parentPath, + bool trustLock) + { + debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); + + checkFollowsDeclarations(inputPathPrefix, flakeInputs); /* Get the overrides (i.e. attributes of the form 'inputs.nixops.inputs.nixpkgs.url = ...'). */ From f6a434c8a4d76973a26e8cbd938be2beb29696de Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 12 Jul 2022 11:53:24 +0200 Subject: [PATCH 55/57] Fix debug message --- src/libexpr/eval-cache.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index dbfd8e70b..0d83b6cfe 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -486,7 +486,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro return nullptr; else if (std::get_if(&attr->second)) { if (forceErrors) - debug("reevaluating failed cached attribute '%s'"); + debug("reevaluating failed cached attribute '%s'", getAttrPathStr(name)); else throw CachedEvalError("cached failure of attribute '%s'", getAttrPathStr(name)); } else From c9d406ba04b81c21f187348fe52fa6e1f95ad78c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 12 Jul 2022 16:09:25 +0200 Subject: [PATCH 56/57] Fix --no-daemon installation It was accidentally triggering the auto-chroot code path because /nix/var/nix didn't exist. Fixes #6790. --- scripts/install-nix-from-closure.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/install-nix-from-closure.sh b/scripts/install-nix-from-closure.sh index d543b4463..cd3cf6670 100644 --- a/scripts/install-nix-from-closure.sh +++ b/scripts/install-nix-from-closure.sh @@ -148,7 +148,9 @@ if ! [ -w "$dest" ]; then exit 1 fi -mkdir -p "$dest/store" +# The auto-chroot code in openFromNonUri() checks for the +# non-existence of /nix/var/nix, so we need to create it here. +mkdir -p "$dest/store" "$dest/var/nix" printf "copying Nix to %s..." "${dest}/store" >&2 # Insert a newline if no progress is shown. From 694a9dc282dd9f07e9f8f1bc7362bef50588389c Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Wed, 13 Jul 2022 01:10:32 +0900 Subject: [PATCH 57/57] Fix typo in flake.cc non-existant -> non-existent --- src/libexpr/flake/flake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 906e11251..233e52407 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -377,7 +377,7 @@ LockedFlake lockFlake( } } warn( - "%s has a `follows'-declaration for a non-existant input %s!", + "%s has a `follows'-declaration for a non-existent input %s!", root, follow );