forked from lix-project/lix
nix --help: Group commands
This commit is contained in:
parent
a721a0b114
commit
f132d82a79
|
@ -1,13 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
namespace nix
|
||||
{
|
||||
namespace nix {
|
||||
|
||||
/* Some ANSI escape sequences. */
|
||||
#define ANSI_NORMAL "\e[0m"
|
||||
#define ANSI_BOLD "\e[1m"
|
||||
#define ANSI_FAINT "\e[2m"
|
||||
#define ANSI_ITALIC "\e[3m"
|
||||
#define ANSI_RED "\e[31;1m"
|
||||
#define ANSI_GREEN "\e[32;1m"
|
||||
#define ANSI_YELLOW "\e[33;1m"
|
||||
#define ANSI_BLUE "\e[34;1m"
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ void Args::parseCmdline(const Strings & _cmdline)
|
|||
|
||||
void Args::printHelp(const string & programName, std::ostream & out)
|
||||
{
|
||||
std::cout << "Usage: " << programName << " <FLAGS>...";
|
||||
std::cout << fmt(ANSI_BOLD "Usage:" ANSI_NORMAL " %s " ANSI_ITALIC "FLAGS..." ANSI_NORMAL, programName);
|
||||
for (auto & exp : expectedArgs) {
|
||||
std::cout << renderLabels({exp.label});
|
||||
// FIXME: handle arity > 1
|
||||
|
@ -70,11 +70,11 @@ void Args::printHelp(const string & programName, std::ostream & out)
|
|||
|
||||
auto s = description();
|
||||
if (s != "")
|
||||
std::cout << "\nSummary: " << s << ".\n";
|
||||
std::cout << "\n" ANSI_BOLD "Summary:" ANSI_NORMAL " " << s << ".\n";
|
||||
|
||||
if (longFlags.size()) {
|
||||
std::cout << "\n";
|
||||
std::cout << "Flags:\n";
|
||||
std::cout << ANSI_BOLD "Flags:" ANSI_NORMAL "\n";
|
||||
printFlags(out);
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ std::string renderLabels(const Strings & labels)
|
|||
std::string res;
|
||||
for (auto label : labels) {
|
||||
for (auto & c : label) c = std::toupper(c);
|
||||
res += " <" + label + ">";
|
||||
res += " " ANSI_ITALIC + label + ANSI_NORMAL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -190,10 +190,10 @@ void printTable(std::ostream & out, const Table2 & table)
|
|||
{
|
||||
size_t max = 0;
|
||||
for (auto & row : table)
|
||||
max = std::max(max, row.first.size());
|
||||
max = std::max(max, filterANSIEscapes(row.first, true).size());
|
||||
for (auto & row : table) {
|
||||
out << " " << row.first
|
||||
<< std::string(max - row.first.size() + 2, ' ')
|
||||
<< std::string(max - filterANSIEscapes(row.first, true).size() + 2, ' ')
|
||||
<< row.second << "\n";
|
||||
}
|
||||
}
|
||||
|
@ -204,8 +204,7 @@ void Command::printHelp(const string & programName, std::ostream & out)
|
|||
|
||||
auto exs = examples();
|
||||
if (!exs.empty()) {
|
||||
out << "\n";
|
||||
out << "Examples:\n";
|
||||
out << "\n" ANSI_BOLD "Examples:" ANSI_NORMAL "\n";
|
||||
for (auto & ex : exs)
|
||||
out << "\n"
|
||||
<< " " << ex.description << "\n" // FIXME: wrap
|
||||
|
@ -221,49 +220,55 @@ MultiCommand::MultiCommand(const Commands & commands)
|
|||
auto i = commands.find(ss[0]);
|
||||
if (i == commands.end())
|
||||
throw UsageError("'%s' is not a recognised command", ss[0]);
|
||||
command = i->second();
|
||||
command->_name = ss[0];
|
||||
command = {ss[0], i->second()};
|
||||
}});
|
||||
|
||||
categories[Command::catDefault] = "Available commands";
|
||||
}
|
||||
|
||||
void MultiCommand::printHelp(const string & programName, std::ostream & out)
|
||||
{
|
||||
if (command) {
|
||||
command->printHelp(programName + " " + command->name(), out);
|
||||
command->second->printHelp(programName + " " + command->first, out);
|
||||
return;
|
||||
}
|
||||
|
||||
out << "Usage: " << programName << " <COMMAND> <FLAGS>... <ARGS>...\n";
|
||||
out << fmt(ANSI_BOLD "Usage:" ANSI_NORMAL " %s " ANSI_ITALIC "COMMAND FLAGS... ARGS..." ANSI_NORMAL "\n", programName);
|
||||
|
||||
out << "\n";
|
||||
out << "Common flags:\n";
|
||||
out << "\n" ANSI_BOLD "Common flags:" ANSI_NORMAL "\n";
|
||||
printFlags(out);
|
||||
|
||||
out << "\n";
|
||||
out << "Available commands:\n";
|
||||
std::map<Command::Category, std::map<std::string, ref<Command>>> commandsByCategory;
|
||||
|
||||
for (auto & [name, commandFun] : commands) {
|
||||
auto command = commandFun();
|
||||
commandsByCategory[command->category()].insert_or_assign(name, command);
|
||||
}
|
||||
|
||||
for (auto & [category, commands] : commandsByCategory) {
|
||||
out << fmt("\n" ANSI_BOLD "%s:" ANSI_NORMAL "\n", categories[category]);
|
||||
|
||||
Table2 table;
|
||||
for (auto & i : commands) {
|
||||
auto command = i.second();
|
||||
command->_name = i.first;
|
||||
for (auto & [name, command] : commands) {
|
||||
auto descr = command->description();
|
||||
if (!descr.empty())
|
||||
table.push_back(std::make_pair(command->name(), descr));
|
||||
table.push_back(std::make_pair(name, descr));
|
||||
}
|
||||
printTable(out, table);
|
||||
}
|
||||
}
|
||||
|
||||
bool MultiCommand::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||
{
|
||||
if (Args::processFlag(pos, end)) return true;
|
||||
if (command && command->processFlag(pos, end)) return true;
|
||||
if (command && command->second->processFlag(pos, end)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MultiCommand::processArgs(const Strings & args, bool finish)
|
||||
{
|
||||
if (command)
|
||||
return command->processArgs(args, finish);
|
||||
return command->second->processArgs(args, finish);
|
||||
else
|
||||
return Args::processArgs(args, finish);
|
||||
}
|
||||
|
|
|
@ -197,17 +197,10 @@ public:
|
|||
run() method. */
|
||||
struct Command : virtual Args
|
||||
{
|
||||
private:
|
||||
std::string _name;
|
||||
|
||||
friend class MultiCommand;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Command() { }
|
||||
|
||||
std::string name() { return _name; }
|
||||
|
||||
virtual void prepare() { };
|
||||
virtual void run() = 0;
|
||||
|
||||
|
@ -221,6 +214,12 @@ public:
|
|||
|
||||
virtual Examples examples() { return Examples(); }
|
||||
|
||||
typedef int Category;
|
||||
|
||||
static constexpr Category catDefault = 0;
|
||||
|
||||
virtual Category category() { return catDefault; }
|
||||
|
||||
void printHelp(const string & programName, std::ostream & out) override;
|
||||
};
|
||||
|
||||
|
@ -233,7 +232,10 @@ class MultiCommand : virtual Args
|
|||
public:
|
||||
Commands commands;
|
||||
|
||||
std::shared_ptr<Command> command;
|
||||
std::map<Command::Category, std::string> categories;
|
||||
|
||||
// Selected command, if any.
|
||||
std::optional<std::pair<std::string, ref<Command>>> command;
|
||||
|
||||
MultiCommand(const Commands & commands);
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ struct CmdAddToStore : MixDryRun, StoreCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
if (!namePart) namePart = baseNameOf(path);
|
||||
|
|
|
@ -30,9 +30,11 @@ struct CmdCatStore : StoreCommand, MixCat
|
|||
|
||||
std::string description() override
|
||||
{
|
||||
return "print the contents of a store file on stdout";
|
||||
return "print the contents of a file in the Nix store on stdout";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
cat(store->getFSAccessor());
|
||||
|
@ -51,9 +53,11 @@ struct CmdCatNar : StoreCommand, MixCat
|
|||
|
||||
std::string description() override
|
||||
{
|
||||
return "print the contents of a file inside a NAR file";
|
||||
return "print the contents of a file inside a NAR file on stdout";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
cat(makeNarAccessor(make_ref<std::string>(readFile(narPath))));
|
||||
|
|
|
@ -10,6 +10,10 @@ namespace nix {
|
|||
|
||||
extern std::string programPath;
|
||||
|
||||
static constexpr Command::Category catSecondary = 100;
|
||||
static constexpr Command::Category catUtility = 101;
|
||||
static constexpr Command::Category catNixInstallation = 102;
|
||||
|
||||
/* A command that requires a Nix store. */
|
||||
struct StoreCommand : virtual Command
|
||||
{
|
||||
|
|
|
@ -80,6 +80,8 @@ struct CmdCopy : StorePathsCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catSecondary; }
|
||||
|
||||
ref<Store> createStore() override
|
||||
{
|
||||
return srcUri.empty() ? StoreCommand::createStore() : openStore(srcUri);
|
||||
|
|
|
@ -328,6 +328,8 @@ struct CmdPrintDevEnv : Common
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
auto buildEnvironment = getBuildEnvironment(store).first;
|
||||
|
|
|
@ -43,6 +43,8 @@ struct CmdDoctor : StoreCommand
|
|||
return "check your system for potential problems and print a PASS or FAIL for each check.";
|
||||
}
|
||||
|
||||
Category category() override { return catNixInstallation; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
logger->log("Running checks against store uri: " + store->getUri());
|
||||
|
|
|
@ -20,6 +20,8 @@ struct CmdDumpPath : StorePathCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store, const StorePath & storePath) override
|
||||
{
|
||||
FdSink sink(STDOUT_FILENO);
|
||||
|
|
|
@ -25,6 +25,8 @@ struct CmdEdit : InstallableCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catSecondary; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
auto state = getEvalState();
|
||||
|
|
|
@ -45,6 +45,8 @@ struct CmdEval : MixJSON, InstallableCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catSecondary; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
if (raw && json)
|
||||
|
|
|
@ -41,6 +41,8 @@ struct CmdHash : Command
|
|||
: "print cryptographic hash of the NAR serialisation of a path";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run() override
|
||||
{
|
||||
for (auto path : paths) {
|
||||
|
@ -87,6 +89,8 @@ struct CmdToBase : Command
|
|||
"SRI");
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run() override
|
||||
{
|
||||
for (auto s : args)
|
||||
|
|
|
@ -31,6 +31,8 @@ struct CmdLog : InstallableCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catSecondary; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
settings.readOnlyMode = true;
|
||||
|
|
|
@ -100,9 +100,11 @@ struct CmdLsStore : StoreCommand, MixLs
|
|||
|
||||
std::string description() override
|
||||
{
|
||||
return "show information about a store path";
|
||||
return "show information about a path in the Nix store";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
list(store->getFSAccessor());
|
||||
|
@ -131,9 +133,11 @@ struct CmdLsNar : Command, MixLs
|
|||
|
||||
std::string description() override
|
||||
{
|
||||
return "show information about the contents of a NAR file";
|
||||
return "show information about a path inside a NAR file";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run() override
|
||||
{
|
||||
list(makeNarAccessor(make_ref<std::string>(readFile(narPath, true))));
|
||||
|
|
|
@ -59,6 +59,12 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
|||
|
||||
NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix")
|
||||
{
|
||||
categories.clear();
|
||||
categories[Command::catDefault] = "Main commands";
|
||||
categories[catSecondary] = "Infrequently used commands";
|
||||
categories[catUtility] = "Utility/scripting commands";
|
||||
categories[catNixInstallation] = "Commands for upgrading or troubleshooting your Nix installation";
|
||||
|
||||
addFlag({
|
||||
.longName = "help",
|
||||
.description = "show usage information",
|
||||
|
@ -111,8 +117,8 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
|||
Args::printFlags(out);
|
||||
std::cout <<
|
||||
"\n"
|
||||
"In addition, most configuration settings can be overriden using '--<name> <value>'.\n"
|
||||
"Boolean settings can be overriden using '--<name>' or '--no-<name>'. See 'nix\n"
|
||||
"In addition, most configuration settings can be overriden using '--" ANSI_ITALIC "name value" ANSI_NORMAL "'.\n"
|
||||
"Boolean settings can be overriden using '--" ANSI_ITALIC "name" ANSI_NORMAL "' or '--no-" ANSI_ITALIC "name" ANSI_NORMAL "'. See 'nix\n"
|
||||
"--help-config' for a list of configuration settings.\n";
|
||||
}
|
||||
|
||||
|
@ -121,10 +127,10 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
|||
MultiCommand::printHelp(programName, out);
|
||||
|
||||
#if 0
|
||||
out << "\nFor full documentation, run 'man " << programName << "' or 'man " << programName << "-<COMMAND>'.\n";
|
||||
out << "\nFor full documentation, run 'man " << programName << "' or 'man " << programName << "-" ANSI_ITALIC "COMMAND" ANSI_NORMAL "'.\n";
|
||||
#endif
|
||||
|
||||
std::cout << "\nNote: this program is EXPERIMENTAL and subject to change.\n";
|
||||
std::cout << "\nNote: this program is " ANSI_RED "EXPERIMENTAL" ANSI_NORMAL " and subject to change.\n";
|
||||
}
|
||||
|
||||
void showHelpAndExit()
|
||||
|
@ -191,8 +197,8 @@ void mainWrapped(int argc, char * * argv)
|
|||
if (args.refresh)
|
||||
settings.tarballTtl = 0;
|
||||
|
||||
args.command->prepare();
|
||||
args.command->run();
|
||||
args.command->second->prepare();
|
||||
args.command->second->run();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ struct CmdMakeContentAddressable : StorePathsCommand, MixJSON
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store, StorePaths storePaths) override
|
||||
{
|
||||
auto paths = store->topoSortPaths(storePathsToSet(storePaths));
|
||||
|
|
|
@ -23,6 +23,8 @@ struct CmdOptimiseStore : StoreCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
store->optimiseStore();
|
||||
|
|
|
@ -29,6 +29,8 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
|
|||
return "query information about store paths";
|
||||
}
|
||||
|
||||
Category category() override { return catSecondary; }
|
||||
|
||||
Examples examples() override
|
||||
{
|
||||
return {
|
||||
|
|
|
@ -21,6 +21,8 @@ struct CmdPingStore : StoreCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
store->connect();
|
||||
|
|
|
@ -13,6 +13,8 @@ struct CmdShowConfig : Command, MixJSON
|
|||
return "show the Nix configuration";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run() override
|
||||
{
|
||||
if (json) {
|
||||
|
|
|
@ -42,6 +42,8 @@ struct CmdShowDerivation : InstallablesCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
auto drvPaths = toDerivations(store, installables, true);
|
||||
|
|
|
@ -27,6 +27,8 @@ struct CmdCopySigs : StorePathsCommand
|
|||
return "copy path signatures from substituters (like binary caches)";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store, StorePaths storePaths) override
|
||||
{
|
||||
if (substituterUris.empty())
|
||||
|
@ -112,6 +114,8 @@ struct CmdSignPaths : StorePathsCommand
|
|||
return "sign the specified paths";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
void run(ref<Store> store, StorePaths storePaths) override
|
||||
{
|
||||
if (secretKeyFile.empty())
|
||||
|
|
|
@ -51,6 +51,8 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catNixInstallation; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
evalSettings.pureEval = true;
|
||||
|
|
|
@ -49,6 +49,8 @@ struct CmdVerify : StorePathsCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catSecondary; }
|
||||
|
||||
void run(ref<Store> store, StorePaths storePaths) override
|
||||
{
|
||||
std::vector<ref<Store>> substituters;
|
||||
|
|
|
@ -68,6 +68,8 @@ struct CmdWhyDepends : SourceExprCommand
|
|||
};
|
||||
}
|
||||
|
||||
Category category() override { return catSecondary; }
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
auto package = parseInstallable(*this, store, _package, false);
|
||||
|
|
Loading…
Reference in a new issue