From 98b85b2166736f08ae7e4a5e0014e92c8c79ebf7 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Thu, 30 May 2024 18:19:22 +0200 Subject: [PATCH 1/3] nix/main: Add AliasStatus::{Deprecated,AcceptedShorthand} --- src/nix/main.cc | 68 ++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/src/nix/main.cc b/src/nix/main.cc index 541d1a1b3..3602402ae 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -42,6 +42,19 @@ void chrootHelper(int argc, char * * argv); namespace nix { +enum struct AliasStatus { + /** Aliases that don't go away */ + AcceptedShorthand, + /** Aliases that will go away */ + Deprecated, +}; + +/** An alias, except for the original syntax, which is in the map key. */ +struct AliasInfo { + AliasStatus status; + std::vector replacement; +}; + /* Check if we have a non-loopback/link-local network interface. */ static bool haveInternet() { @@ -134,29 +147,29 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs }); } - std::map> aliases = { - {"add-to-store", {"store", "add-path"}}, - {"cat-nar", {"nar", "cat"}}, - {"cat-store", {"store", "cat"}}, - {"copy-sigs", {"store", "copy-sigs"}}, - {"dev-shell", {"develop"}}, - {"diff-closures", {"store", "diff-closures"}}, - {"dump-path", {"store", "dump-path"}}, - {"hash-file", {"hash", "file"}}, - {"hash-path", {"hash", "path"}}, - {"ls-nar", {"nar", "ls"}}, - {"ls-store", {"store", "ls"}}, - {"make-content-addressable", {"store", "make-content-addressed"}}, - {"optimise-store", {"store", "optimise"}}, - {"ping-store", {"store", "ping"}}, - {"sign-paths", {"store", "sign"}}, - {"show-derivation", {"derivation", "show"}}, - {"show-config", {"config", "show"}}, - {"to-base16", {"hash", "to-base16"}}, - {"to-base32", {"hash", "to-base32"}}, - {"to-base64", {"hash", "to-base64"}}, - {"verify", {"store", "verify"}}, - {"doctor", {"config", "check"}}, + std::map aliases = { + {"add-to-store", { AliasStatus::Deprecated, {"store", "add-path"}}}, + {"cat-nar", { AliasStatus::Deprecated, {"nar", "cat"}}}, + {"cat-store", { AliasStatus::Deprecated, {"store", "cat"}}}, + {"copy-sigs", { AliasStatus::Deprecated, {"store", "copy-sigs"}}}, + {"dev-shell", { AliasStatus::Deprecated, {"develop"}}}, + {"diff-closures", { AliasStatus::Deprecated, {"store", "diff-closures"}}}, + {"dump-path", { AliasStatus::Deprecated, {"store", "dump-path"}}}, + {"hash-file", { AliasStatus::Deprecated, {"hash", "file"}}}, + {"hash-path", { AliasStatus::Deprecated, {"hash", "path"}}}, + {"ls-nar", { AliasStatus::Deprecated, {"nar", "ls"}}}, + {"ls-store", { AliasStatus::Deprecated, {"store", "ls"}}}, + {"make-content-addressable", { AliasStatus::Deprecated, {"store", "make-content-addressed"}}}, + {"optimise-store", { AliasStatus::Deprecated, {"store", "optimise"}}}, + {"ping-store", { AliasStatus::Deprecated, {"store", "ping"}}}, + {"sign-paths", { AliasStatus::Deprecated, {"store", "sign"}}}, + {"show-derivation", { AliasStatus::Deprecated, {"derivation", "show"}}}, + {"show-config", { AliasStatus::Deprecated, {"config", "show"}}}, + {"to-base16", { AliasStatus::Deprecated, {"hash", "to-base16"}}}, + {"to-base32", { AliasStatus::Deprecated, {"hash", "to-base32"}}}, + {"to-base64", { AliasStatus::Deprecated, {"hash", "to-base64"}}}, + {"verify", { AliasStatus::Deprecated, {"store", "verify"}}}, + {"doctor", { AliasStatus::Deprecated, {"config", "check"}}}, }; bool aliasUsed = false; @@ -167,10 +180,13 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs auto arg = *pos; auto i = aliases.find(arg); if (i == aliases.end()) return pos; - warn("'%s' is a deprecated alias for '%s'", - arg, concatStringsSep(" ", i->second)); + auto & info = i->second; + if (info.status == AliasStatus::Deprecated) { + warn("'%s' is a deprecated alias for '%s'", + arg, concatStringsSep(" ", info.replacement)); + } pos = args.erase(pos); - for (auto j = i->second.rbegin(); j != i->second.rend(); ++j) + for (auto j = info.replacement.rbegin(); j != info.replacement.rend(); ++j) pos = args.insert(pos, *j); aliasUsed = true; return pos; From c692f6af132dc62f72edbb2c7a73bfa838398904 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Thu, 30 May 2024 18:22:11 +0200 Subject: [PATCH 2/3] nix env shell: Move from nix shell, add shorthand alias --- doc/manual/rl-next/nix-env-shell.md | 12 ++++ src/nix/env.cc | 98 +++++++++++++++++++++++++++++ src/nix/main.cc | 1 + src/nix/run.cc | 77 ----------------------- tests/functional/shell.sh | 3 + 5 files changed, 114 insertions(+), 77 deletions(-) create mode 100644 doc/manual/rl-next/nix-env-shell.md create mode 100644 src/nix/env.cc diff --git a/doc/manual/rl-next/nix-env-shell.md b/doc/manual/rl-next/nix-env-shell.md new file mode 100644 index 000000000..b2344417a --- /dev/null +++ b/doc/manual/rl-next/nix-env-shell.md @@ -0,0 +1,12 @@ +--- +synopsis: "`nix env shell` is the new `nix shell`, and `nix shell` remains an accepted alias" +issues: 10504 +prs: 10807 +--- + +This is part of an effort to bring more structure to the CLI subcommands. + +`nix env` will be about the process environment. +Future commands may include `nix env run` and `nix env print-env`. + +It is also somewhat analogous to the [planned](https://github.com/NixOS/nix/issues/10504) `nix dev shell` (currently `nix develop`), which is less about environment variables, and more about running a development shell, which is a more powerful command, but also requires more setup. diff --git a/src/nix/env.cc b/src/nix/env.cc new file mode 100644 index 000000000..47efdf308 --- /dev/null +++ b/src/nix/env.cc @@ -0,0 +1,98 @@ +#include "command.hh" +#include "run.hh" +#include + +using namespace nix; + +struct CmdEnv : NixMultiCommand +{ + CmdEnv() : NixMultiCommand("env", RegisterCommand::getCommandsFor({"env"})) + { } + + std::string description() override + { + return "manipulate the process environment"; + } + + Category category() override { return catUtility; } +}; + +static auto rCmdEnv = registerCommand("env"); + +struct CmdShell : InstallablesCommand, MixEnvironment +{ + + using InstallablesCommand::run; + + std::vector command = { getEnv("SHELL").value_or("bash") }; + + CmdShell() + { + addFlag({ + .longName = "command", + .shortName = 'c', + .description = "Command and arguments to be executed, defaulting to `$SHELL`", + .labels = {"command", "args"}, + .handler = {[&](std::vector ss) { + if (ss.empty()) throw UsageError("--command requires at least one argument"); + command = ss; + }} + }); + } + + std::string description() override + { + return "run a shell in which the specified packages are available"; + } + + std::string doc() override + { + return + #include "shell.md" + ; + } + + void run(ref store, Installables && installables) override + { + auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); + + auto accessor = store->getFSAccessor(); + + std::unordered_set done; + std::queue todo; + for (auto & path : outPaths) todo.push(path); + + setEnviron(); + + std::vector pathAdditions; + + while (!todo.empty()) { + auto path = todo.front(); + todo.pop(); + if (!done.insert(path).second) continue; + + if (true) + pathAdditions.push_back(store->printStorePath(path) + "/bin"); + + auto propPath = accessor->resolveSymlinks( + CanonPath(store->printStorePath(path)) / "nix-support" / "propagated-user-env-packages"); + if (auto st = accessor->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) { + for (auto & p : tokenizeString(accessor->readFile(propPath))) + todo.push(store->parseStorePath(p)); + } + } + + auto unixPath = tokenizeString(getEnv("PATH").value_or(""), ":"); + unixPath.insert(unixPath.begin(), pathAdditions.begin(), pathAdditions.end()); + auto unixPathString = concatStringsSep(":", unixPath); + setEnv("PATH", unixPathString.c_str()); + + Strings args; + for (auto & arg : command) args.push_back(arg); + + runProgramInStore(store, UseLookupPath::Use, *command.begin(), args); + } +}; + +static auto rCmdShell = registerCommand2({"env", "shell"}); + diff --git a/src/nix/main.cc b/src/nix/main.cc index 3602402ae..94fd05fba 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -163,6 +163,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs {"optimise-store", { AliasStatus::Deprecated, {"store", "optimise"}}}, {"ping-store", { AliasStatus::Deprecated, {"store", "ping"}}}, {"sign-paths", { AliasStatus::Deprecated, {"store", "sign"}}}, + {"shell", { AliasStatus::AcceptedShorthand, {"env", "shell"}}}, {"show-derivation", { AliasStatus::Deprecated, {"derivation", "show"}}}, {"show-config", { AliasStatus::Deprecated, {"config", "show"}}}, {"to-base16", { AliasStatus::Deprecated, {"hash", "to-base16"}}}, diff --git a/src/nix/run.cc b/src/nix/run.cc index cc999ddf4..7d3122470 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -71,83 +71,6 @@ void runProgramInStore(ref store, } -struct CmdShell : InstallablesCommand, MixEnvironment -{ - - using InstallablesCommand::run; - - std::vector command = { getEnv("SHELL").value_or("bash") }; - - CmdShell() - { - addFlag({ - .longName = "command", - .shortName = 'c', - .description = "Command and arguments to be executed, defaulting to `$SHELL`", - .labels = {"command", "args"}, - .handler = {[&](std::vector ss) { - if (ss.empty()) throw UsageError("--command requires at least one argument"); - command = ss; - }} - }); - } - - std::string description() override - { - return "run a shell in which the specified packages are available"; - } - - std::string doc() override - { - return - #include "shell.md" - ; - } - - void run(ref store, Installables && installables) override - { - auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); - - auto accessor = store->getFSAccessor(); - - std::unordered_set done; - std::queue todo; - for (auto & path : outPaths) todo.push(path); - - setEnviron(); - - std::vector pathAdditions; - - while (!todo.empty()) { - auto path = todo.front(); - todo.pop(); - if (!done.insert(path).second) continue; - - if (true) - pathAdditions.push_back(store->printStorePath(path) + "/bin"); - - auto propPath = accessor->resolveSymlinks( - CanonPath(store->printStorePath(path)) / "nix-support" / "propagated-user-env-packages"); - if (auto st = accessor->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) { - for (auto & p : tokenizeString(accessor->readFile(propPath))) - todo.push(store->parseStorePath(p)); - } - } - - auto unixPath = tokenizeString(getEnv("PATH").value_or(""), ":"); - unixPath.insert(unixPath.begin(), pathAdditions.begin(), pathAdditions.end()); - auto unixPathString = concatStringsSep(":", unixPath); - setEnv("PATH", unixPathString.c_str()); - - Strings args; - for (auto & arg : command) args.push_back(arg); - - runProgramInStore(store, UseLookupPath::Use, *command.begin(), args); - } -}; - -static auto rCmdShell = registerCommand("shell"); - struct CmdRun : InstallableValueCommand { using InstallableCommand::run; diff --git a/tests/functional/shell.sh b/tests/functional/shell.sh index e6bb4b161..1760eefff 100755 --- a/tests/functional/shell.sh +++ b/tests/functional/shell.sh @@ -5,6 +5,9 @@ source common.sh clearStore clearCache +# nix shell is an alias for nix env shell. We'll use the shorter form in the rest of the test. +nix env shell -f shell-hello.nix hello -c hello | grep 'Hello World' + nix shell -f shell-hello.nix hello -c hello | grep 'Hello World' nix shell -f shell-hello.nix hello -c hello NixOS | grep 'Hello NixOS' From d93cc11491f2ebba81ebb56ef8faa1b29bb7699a Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Thu, 30 May 2024 18:40:53 +0200 Subject: [PATCH 3/3] Format --- src/nix/env.cc | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/nix/env.cc b/src/nix/env.cc index 47efdf308..021c47cbb 100644 --- a/src/nix/env.cc +++ b/src/nix/env.cc @@ -6,15 +6,20 @@ using namespace nix; struct CmdEnv : NixMultiCommand { - CmdEnv() : NixMultiCommand("env", RegisterCommand::getCommandsFor({"env"})) - { } + CmdEnv() + : NixMultiCommand("env", RegisterCommand::getCommandsFor({"env"})) + { + } std::string description() override { return "manipulate the process environment"; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } }; static auto rCmdEnv = registerCommand("env"); @@ -24,20 +29,20 @@ struct CmdShell : InstallablesCommand, MixEnvironment using InstallablesCommand::run; - std::vector command = { getEnv("SHELL").value_or("bash") }; + std::vector command = {getEnv("SHELL").value_or("bash")}; CmdShell() { - addFlag({ - .longName = "command", - .shortName = 'c', - .description = "Command and arguments to be executed, defaulting to `$SHELL`", - .labels = {"command", "args"}, - .handler = {[&](std::vector ss) { - if (ss.empty()) throw UsageError("--command requires at least one argument"); - command = ss; - }} - }); + addFlag( + {.longName = "command", + .shortName = 'c', + .description = "Command and arguments to be executed, defaulting to `$SHELL`", + .labels = {"command", "args"}, + .handler = {[&](std::vector ss) { + if (ss.empty()) + throw UsageError("--command requires at least one argument"); + command = ss; + }}}); } std::string description() override @@ -48,19 +53,21 @@ struct CmdShell : InstallablesCommand, MixEnvironment std::string doc() override { return - #include "shell.md" - ; +#include "shell.md" + ; } void run(ref store, Installables && installables) override { - auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); + auto outPaths = + Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); auto accessor = store->getFSAccessor(); std::unordered_set done; std::queue todo; - for (auto & path : outPaths) todo.push(path); + for (auto & path : outPaths) + todo.push(path); setEnviron(); @@ -69,7 +76,8 @@ struct CmdShell : InstallablesCommand, MixEnvironment while (!todo.empty()) { auto path = todo.front(); todo.pop(); - if (!done.insert(path).second) continue; + if (!done.insert(path).second) + continue; if (true) pathAdditions.push_back(store->printStorePath(path) + "/bin"); @@ -88,11 +96,11 @@ struct CmdShell : InstallablesCommand, MixEnvironment setEnv("PATH", unixPathString.c_str()); Strings args; - for (auto & arg : command) args.push_back(arg); + for (auto & arg : command) + args.push_back(arg); runProgramInStore(store, UseLookupPath::Use, *command.begin(), args); } }; static auto rCmdShell = registerCommand2({"env", "shell"}); -