diff options
Diffstat (limited to 'src/nix/main.cc')
-rw-r--r-- | src/nix/main.cc | 183 |
1 files changed, 135 insertions, 48 deletions
diff --git a/src/nix/main.cc b/src/nix/main.cc index 5056ceb78..06e221682 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -17,6 +17,10 @@ #include <netdb.h> #include <netinet/in.h> +#if __linux__ +#include <sys/resource.h> +#endif + #include <nlohmann/json.hpp> extern std::string chrootHelperName; @@ -52,14 +56,18 @@ static bool haveInternet() } std::string programPath; +char * * savedArgv; + +struct HelpRequested { }; struct NixArgs : virtual MultiCommand, virtual MixCommonArgs { bool printBuildLogs = false; bool useNet = true; bool refresh = false; + bool showVersion = false; - NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix") + NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("nix") { categories.clear(); categories[Command::catDefault] = "Main commands"; @@ -69,88 +77,137 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs addFlag({ .longName = "help", - .description = "show usage information", - .handler = {[&]() { if (!completions) showHelpAndExit(); }}, - }); - - addFlag({ - .longName = "help-config", - .description = "show configuration options", - .handler = {[&]() { - std::cout << "The following configuration options are available:\n\n"; - Table2 tbl; - std::map<std::string, Config::SettingInfo> settings; - globalConfig.getSettings(settings); - for (const auto & s : settings) - tbl.emplace_back(s.first, s.second.description); - printTable(std::cout, tbl); - throw Exit(); - }}, + .description = "Show usage information.", + .handler = {[&]() { throw HelpRequested(); }}, }); addFlag({ .longName = "print-build-logs", .shortName = 'L', - .description = "print full build logs on stderr", + .description = "Print full build logs on standard error.", + .category = loggingCategory, .handler = {[&]() {setLogFormat(LogFormat::barWithLogs); }}, }); addFlag({ .longName = "version", - .description = "show version information", - .handler = {[&]() { if (!completions) printVersion(programName); }}, + .description = "Show version information.", + .handler = {[&]() { showVersion = true; }}, }); addFlag({ - .longName = "no-net", - .description = "disable substituters and consider all previously downloaded files up-to-date", + .longName = "offline", + .aliases = {"no-net"}, // FIXME: remove + .description = "Disable substituters and consider all previously downloaded files up-to-date.", .handler = {[&]() { useNet = false; }}, }); addFlag({ .longName = "refresh", - .description = "consider all previously downloaded files out-of-date", + .description = "Consider all previously downloaded files out-of-date.", .handler = {[&]() { refresh = true; }}, }); - - deprecatedAliases.insert({"dev-shell", "develop"}); } - void printFlags(std::ostream & out) override + std::map<std::string, std::vector<std::string>> 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-addressable"}}, + {"optimise-store", {"store", "optimise"}}, + {"ping-store", {"store", "ping"}}, + {"sign-paths", {"store", "sign"}}, + {"to-base16", {"hash", "to-base16"}}, + {"to-base32", {"hash", "to-base32"}}, + {"to-base64", {"hash", "to-base64"}}, + {"verify", {"store", "verify"}}, + }; + + bool aliasUsed = false; + + Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override { - Args::printFlags(out); - std::cout << - "\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"; + if (aliasUsed || command || pos == args.end()) return pos; + 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)); + pos = args.erase(pos); + for (auto j = i->second.rbegin(); j != i->second.rend(); ++j) + pos = args.insert(pos, *j); + aliasUsed = true; + return pos; } - void printHelp(const string & programName, std::ostream & out) override + std::string description() override { - MultiCommand::printHelp(programName, out); + return "a tool for reproducible and declarative configuration management"; + } -#if 0 - out << "\nFor full documentation, run 'man " << programName << "' or 'man " << programName << "-" ANSI_ITALIC "COMMAND" ANSI_NORMAL "'.\n"; -#endif + std::string doc() override + { + return + #include "nix.md" + ; + } - std::cout << "\nNote: this program is " ANSI_RED "EXPERIMENTAL" ANSI_NORMAL " and subject to change.\n"; + // Plugins may add new subcommands. + void pluginsInited() override + { + commands = RegisterCommand::getCommandsFor({}); } +}; - void showHelpAndExit() +static void showHelp(std::vector<std::string> subcommand) +{ + showManPage(subcommand.empty() ? "nix" : fmt("nix3-%s", concatStringsSep("-", subcommand))); +} + +struct CmdHelp : Command +{ + std::vector<std::string> subcommand; + + CmdHelp() { - printHelp(programName, std::cout); - throw Exit(); + expectArgs({ + .label = "subcommand", + .handler = {&subcommand}, + }); } std::string description() override { - return "a tool for reproducible and declarative configuration management"; + return "show help about `nix` or a particular subcommand"; + } + + std::string doc() override + { + return + #include "help.md" + ; + } + + void run() override + { + showHelp(subcommand); } }; +static auto rCmdHelp = registerCommand<CmdHelp>("help"); + void mainWrapped(int argc, char * * argv) { + savedArgv = argv; + /* The chroot helper needs to be run before any threads have been started. */ if (argc > 0 && argv[0] == chrootHelperName) { @@ -169,7 +226,7 @@ void mainWrapped(int argc, char * * argv) if (legacy) return legacy(argc, argv); } - verbosity = lvlWarn; + verbosity = lvlNotice; settings.verboseBuild = false; evalSettings.pureEval = true; @@ -191,7 +248,7 @@ void mainWrapped(int argc, char * * argv) auto builtins = state.baseEnv.values[0]->attrs; for (auto & builtin : *builtins) { auto b = nlohmann::json::object(); - if (builtin.value->type != tPrimOp) continue; + if (!builtin.value->isPrimOp()) continue; auto primOp = builtin.value->primOp; if (!primOp->doc) continue; b["arity"] = primOp->arity; @@ -214,15 +271,31 @@ void mainWrapped(int argc, char * * argv) try { args.parseCmdline(argvToStrings(argc, argv)); + } catch (HelpRequested &) { + std::vector<std::string> subcommand; + MultiCommand * command = &args; + while (command) { + if (command && command->command) { + subcommand.push_back(command->command->first); + command = dynamic_cast<MultiCommand *>(&*command->command->second); + } else + break; + } + showHelp(subcommand); + return; } catch (UsageError &) { if (!completions) throw; } if (completions) return; - initPlugins(); + if (args.showVersion) { + printVersion(programName); + return; + } - if (!args.command) args.showHelpAndExit(); + if (!args.command) + throw UsageError("no subcommand specified"); if (args.command->first != "repl" && args.command->first != "doctor" @@ -246,8 +319,11 @@ void mainWrapped(int argc, char * * argv) fileTransferSettings.connectTimeout = 1; } - if (args.refresh) + if (args.refresh) { settings.tarballTtl = 0; + settings.ttlNegativeNarInfoCache = 0; + settings.ttlPositiveNarInfoCache = 0; + } args.command->second->prepare(); args.command->second->run(); @@ -257,6 +333,17 @@ void mainWrapped(int argc, char * * argv) int main(int argc, char * * argv) { + // Increase the default stack size for the evaluator and for + // libstdc++'s std::regex. + #if __linux__ + rlim_t stackSize = 64 * 1024 * 1024; + struct rlimit limit; + if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur < stackSize) { + limit.rlim_cur = stackSize; + setrlimit(RLIMIT_STACK, &limit); + } + #endif + return nix::handleExceptions(argv[0], [&]() { nix::mainWrapped(argc, argv); }); |