From 6cd2b4e169696410ed3959c13c2c041b51db9c21 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 10 Apr 2025 18:40:27 +0200 Subject: [PATCH 1/2] Move alias support from NixArgs to MultiCommand This allows subcommands to declare aliases, e.g. `nix store ping` is now a proper alias of `nix store info`. --- doc/manual/meson.build | 1 - src/libutil/args.cc | 21 +++++++ src/libutil/include/nix/util/args.hh | 22 ++++++++ src/nix/main.cc | 83 +++++++++------------------- src/nix/store-info.cc | 15 +---- src/nix/store.cc | 6 +- 6 files changed, 75 insertions(+), 73 deletions(-) diff --git a/doc/manual/meson.build b/doc/manual/meson.build index 8796cee63..1d6687910 100644 --- a/doc/manual/meson.build +++ b/doc/manual/meson.build @@ -281,7 +281,6 @@ nix3_manpages = [ 'nix3-store', 'nix3-store-optimise', 'nix3-store-path-from-hash-part', - 'nix3-store-ping', 'nix3-store-prefetch-file', 'nix3-store-repair', 'nix3-store-sign', diff --git a/src/libutil/args.cc b/src/libutil/args.cc index b4177bf93..fb9d7163c 100644 --- a/src/libutil/args.cc +++ b/src/libutil/args.cc @@ -647,4 +647,25 @@ nlohmann::json MultiCommand::toJSON() return res; } +Strings::iterator MultiCommand::rewriteArgs(Strings & args, Strings::iterator pos) +{ + if (command) + return command->second->rewriteArgs(args, pos); + + if (aliasUsed || pos == args.end()) return pos; + auto arg = *pos; + auto i = aliases.find(arg); + if (i == aliases.end()) return pos; + 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 = info.replacement.rbegin(); j != info.replacement.rend(); ++j) + pos = args.insert(pos, *j); + aliasUsed = true; + return pos; +} + } diff --git a/src/libutil/include/nix/util/args.hh b/src/libutil/include/nix/util/args.hh index 77c4fb5b6..463270374 100644 --- a/src/libutil/include/nix/util/args.hh +++ b/src/libutil/include/nix/util/args.hh @@ -393,8 +393,30 @@ public: nlohmann::json toJSON() override; + 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; + }; + + /** + * A list of aliases (remapping a deprecated/shorthand subcommand + * to something else). + */ + std::map aliases; + + Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override; + protected: std::string commandName = ""; + bool aliasUsed = false; }; Strings argvToStrings(int argc, char * * argv); diff --git a/src/nix/main.cc b/src/nix/main.cc index a2c9dcf68..f229ba2a4 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -50,19 +50,6 @@ 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() { @@ -153,54 +140,34 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs .handler = {[&]() { refresh = true; }}, .experimentalFeature = Xp::NixCommand, }); - } - 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", "info"}}}, - {"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"}}}, - {"to-base32", { AliasStatus::Deprecated, {"hash", "to-base32"}}}, - {"to-base64", { AliasStatus::Deprecated, {"hash", "to-base64"}}}, - {"verify", { AliasStatus::Deprecated, {"store", "verify"}}}, - {"doctor", { AliasStatus::Deprecated, {"config", "check"}}}, + 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", "info"}}}, + {"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"}}}, + {"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; - - Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override - { - if (aliasUsed || command || pos == args.end()) return pos; - auto arg = *pos; - auto i = aliases.find(arg); - if (i == aliases.end()) return pos; - 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 = info.replacement.rbegin(); j != info.replacement.rend(); ++j) - pos = args.insert(pos, *j); - aliasUsed = true; - return pos; - } - std::string description() override { return "a tool for reproducible and declarative configuration management"; diff --git a/src/nix/store-info.cc b/src/nix/store-info.cc index 323dfeee4..c4c63ae3a 100644 --- a/src/nix/store-info.cc +++ b/src/nix/store-info.cc @@ -7,7 +7,7 @@ using namespace nix; -struct CmdPingStore : StoreCommand, MixJSON +struct CmdInfoStore : StoreCommand, MixJSON { std::string description() override { @@ -46,15 +46,4 @@ struct CmdPingStore : StoreCommand, MixJSON } }; -struct CmdInfoStore : CmdPingStore -{ - void run(nix::ref store) override - { - warn("'nix store ping' is a deprecated alias for 'nix store info'"); - CmdPingStore::run(store); - } -}; - - -static auto rCmdPingStore = registerCommand2({"store", "info"}); -static auto rCmdInfoStore = registerCommand2({"store", "ping"}); +static auto rCmdInfoStore = registerCommand2({"store", "info"}); diff --git a/src/nix/store.cc b/src/nix/store.cc index b40b6d068..80f9363ca 100644 --- a/src/nix/store.cc +++ b/src/nix/store.cc @@ -5,7 +5,11 @@ using namespace nix; struct CmdStore : NixMultiCommand { CmdStore() : NixMultiCommand("store", RegisterCommand::getCommandsFor({"store"})) - { } + { + aliases = { + {"ping", { AliasStatus::Deprecated, {"info"}}}, + }; + } std::string description() override { From b1b75e1d7a8bb8a1ec978e2a6ef340a85515953e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Sat, 12 Apr 2025 10:20:30 +0200 Subject: [PATCH 2/2] tests/functional: add test for alias commands --- tests/functional/store-info.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/functional/store-info.sh b/tests/functional/store-info.sh index beecc2dd9..b1e0772b5 100755 --- a/tests/functional/store-info.sh +++ b/tests/functional/store-info.sh @@ -3,9 +3,11 @@ source common.sh STORE_INFO=$(nix store info 2>&1) +LEGACY_STORE_INFO=$(nix store ping 2>&1) # alias to nix store info STORE_INFO_JSON=$(nix store info --json) echo "$STORE_INFO" | grep "Store URL: ${NIX_REMOTE}" +echo "$LEGACY_STORE_INFO" | grep "Store URL: ${NIX_REMOTE}" if [[ -v NIX_DAEMON_PACKAGE ]] && isDaemonNewer "2.7.0pre20220126"; then DAEMON_VERSION=$("$NIX_DAEMON_PACKAGE"/bin/nix daemon --version | cut -d' ' -f3) @@ -13,6 +15,7 @@ if [[ -v NIX_DAEMON_PACKAGE ]] && isDaemonNewer "2.7.0pre20220126"; then [[ "$(echo "$STORE_INFO_JSON" | jq -r ".version")" == "$DAEMON_VERSION" ]] fi + expect 127 NIX_REMOTE=unix:"$PWD"/store nix store info || \ fail "nix store info on a non-existent store should fail"