From 4a0b893d5e5d5cbf2f39e52d1651bcff8b4943a9 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 16 Jan 2023 23:01:18 -0500 Subject: [PATCH] Stuctured command stability Prior to this, there was an ad-hoc whitelist in `main.cc`. Now, every command states its stability. In a future PR, we will adjust the manual to take advantage of this new information in the JSON. (It will be easier to do that once we have some experimental feature docs to link too; see #5930 and #7798.) --- src/libutil/args.cc | 17 +++++++++++++++-- src/libutil/args.hh | 2 ++ src/nix/doctor.cc | 8 ++++++++ src/nix/main.cc | 6 ++---- src/nix/repl.cc | 8 ++++++++ src/nix/upgrade-nix.cc | 8 ++++++++ tests/experimental-features.sh | 11 ++++++++--- 7 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/libutil/args.cc b/src/libutil/args.cc index fc009592c..081dbeb28 100644 --- a/src/libutil/args.cc +++ b/src/libutil/args.cc @@ -236,8 +236,6 @@ nlohmann::json Args::toJSON() auto flags = nlohmann::json::object(); for (auto & [name, flag] : longFlags) { - /* Skip experimental flags when listing flags. */ - if (!experimentalFeatureSettings.isEnabled(flag->experimentalFeature)) continue; auto j = nlohmann::json::object(); if (flag->aliases.count(name)) continue; if (flag->shortName) @@ -249,6 +247,11 @@ nlohmann::json Args::toJSON() j["arity"] = flag->handler.arity; if (!flag->labels.empty()) j["labels"] = flag->labels; + // TODO With C++23 use `std::optional::tranform` + if (auto & xp = flag->experimentalFeature) + j["experimental-feature"] = showExperimentalFeature(*xp); + else + j["experimental-feature"] = nullptr; flags[name] = std::move(j); } @@ -345,6 +348,11 @@ Strings argvToStrings(int argc, char * * argv) return args; } +std::optional Command::experimentalFeature () +{ + return { Xp::NixCommand }; +} + MultiCommand::MultiCommand(const Commands & commands_) : commands(commands_) { @@ -408,6 +416,11 @@ nlohmann::json MultiCommand::toJSON() cat["id"] = command->category(); cat["description"] = trim(categories[command->category()]); j["category"] = std::move(cat); + // TODO With C++23 use `std::optional::tranform` + if (auto xp = command->experimentalFeature()) + cat["experimental-feature"] = showExperimentalFeature(*xp); + else + cat["experimental-feature"] = nullptr; cmds[name] = std::move(j); } diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 07d0d8eae..d90129796 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -236,6 +236,8 @@ struct Command : virtual public Args static constexpr Category catDefault = 0; + virtual std::optional experimentalFeature (); + virtual Category category() { return catDefault; } }; diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc index 7da4549a1..354b03cf6 100644 --- a/src/nix/doctor.cc +++ b/src/nix/doctor.cc @@ -39,6 +39,14 @@ struct CmdDoctor : StoreCommand { bool success = true; + /** + * This command is stable before the others + */ + std::optional experimentalFeature() override + { + return std::nullopt; + } + std::string description() override { return "check your system for potential problems and print a PASS or FAIL for each check"; diff --git a/src/nix/main.cc b/src/nix/main.cc index c2e1dda74..4d4164333 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -423,10 +423,8 @@ void mainWrapped(int argc, char * * argv) if (!args.command) throw UsageError("no subcommand specified"); - if (args.command->first != "repl" - && args.command->first != "doctor" - && args.command->first != "upgrade-nix") - experimentalFeatureSettings.require(Xp::NixCommand); + experimentalFeatureSettings.require( + args.command->second->experimentalFeature()); if (args.useNet && !haveInternet()) { warn("you don't have Internet access; disabling some network-dependent features"); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 7aa8774e9..bb14f3f99 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -12,6 +12,14 @@ struct CmdRepl : RawInstallablesCommand evalSettings.pureEval = false; } + /** + * This command is stable before the others + */ + std::optional experimentalFeature() override + { + return std::nullopt; + } + std::vector files; Strings getDefaultFlakeAttrPaths() override diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc index 17796d6b8..2295d86d0 100644 --- a/src/nix/upgrade-nix.cc +++ b/src/nix/upgrade-nix.cc @@ -32,6 +32,14 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand }); } + /** + * This command is stable before the others + */ + std::optional experimentalFeature() override + { + return std::nullopt; + } + std::string description() override { return "upgrade Nix to the stable version declared in Nixpkgs"; diff --git a/tests/experimental-features.sh b/tests/experimental-features.sh index f718585f3..a4d55f5f4 100644 --- a/tests/experimental-features.sh +++ b/tests/experimental-features.sh @@ -15,15 +15,20 @@ function both_ways { # Simple case, the configuration effects the running command both_ways show-config -# Complicated case, earlier args effect later args +# Skipping for now, because we actually *do* want these to show up in +# the manual, just be marked experimental. Will reenable once the manual +# generation takes advantage of the JSON metadata on this. -both_ways store gc --help +# both_ways store gc --help expect 1 nix --experimental-features 'nix-command' show-config --flake-registry 'https://no' nix --experimental-features 'nix-command flakes' show-config --flake-registry 'https://no' -# Double check this is stable +# Double check these are stable nix --experimental-features '' --help +nix --experimental-features '' doctor --help +nix --experimental-features '' repl --help +nix --experimental-features '' upgrade-nix --help # These 3 arguments are currently given to all commands, which is wrong (as not # all care). To deal with fixing later, we simply make them require the