#include #include "command.hh" #include "common-args.hh" #include "eval.hh" #include "globals.hh" #include "legacy.hh" #include "shared.hh" #include "store-api.hh" #include "filetransfer.hh" #include "finally.hh" #include "loggers.hh" #include #include #include #include #include #include extern std::string chrootHelperName; void chrootHelper(int argc, char * * argv); namespace nix { /* Check if we have a non-loopback/link-local network interface. */ static bool haveInternet() { struct ifaddrs * addrs; if (getifaddrs(&addrs)) return true; Finally free([&]() { freeifaddrs(addrs); }); for (auto i = addrs; i; i = i->ifa_next) { if (!i->ifa_addr) continue; if (i->ifa_addr->sa_family == AF_INET) { if (ntohl(((sockaddr_in *) i->ifa_addr)->sin_addr.s_addr) != INADDR_LOOPBACK) { return true; } } else if (i->ifa_addr->sa_family == AF_INET6) { if (!IN6_IS_ADDR_LOOPBACK(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr) && !IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr)) return true; } } return false; } std::string programPath; struct NixArgs : virtual MultiCommand, virtual MixCommonArgs { bool printBuildLogs = false; bool useNet = true; bool refresh = false; 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", .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 settings; globalConfig.getSettings(settings); for (const auto & s : settings) tbl.emplace_back(s.first, s.second.description); printTable(std::cout, tbl); throw Exit(); }}, }); addFlag({ .longName = "print-build-logs", .shortName = 'L', .description = "print full build logs on stderr", .handler = {[&]() {setLogFormat(LogFormat::barWithLogs); }}, }); addFlag({ .longName = "version", .description = "show version information", .handler = {[&]() { if (!completions) printVersion(programName); }}, }); addFlag({ .longName = "no-net", .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", .handler = {[&]() { refresh = true; }}, }); deprecatedAliases.insert({"dev-shell", "develop"}); } void printFlags(std::ostream & out) 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"; } void printHelp(const string & programName, std::ostream & out) override { MultiCommand::printHelp(programName, out); #if 0 out << "\nFor full documentation, run 'man " << programName << "' or 'man " << programName << "-" ANSI_ITALIC "COMMAND" ANSI_NORMAL "'.\n"; #endif std::cout << "\nNote: this program is " ANSI_RED "EXPERIMENTAL" ANSI_NORMAL " and subject to change.\n"; } void showHelpAndExit() { printHelp(programName, std::cout); throw Exit(); } std::string description() override { return "a tool for reproducible and declarative configuration management"; } }; void mainWrapped(int argc, char * * argv) { /* The chroot helper needs to be run before any threads have been started. */ if (argc > 0 && argv[0] == chrootHelperName) { chrootHelper(argc, argv); return; } initNix(); initGC(); programPath = argv[0]; auto programName = std::string(baseNameOf(programPath)); { auto legacy = (*RegisterLegacyCommand::commands)[programName]; if (legacy) return legacy(argc, argv); } verbosity = lvlWarn; settings.verboseBuild = false; evalSettings.pureEval = true; setLogFormat("bar"); Finally f([] { logger->stop(); }); NixArgs args; if (argc == 2 && std::string(argv[1]) == "__dump-args") { std::cout << args.toJSON().dump() << "\n"; return; } if (argc == 2 && std::string(argv[1]) == "__dump-builtins") { evalSettings.pureEval = false; EvalState state({}, openStore("dummy://")); auto res = nlohmann::json::object(); auto builtins = state.baseEnv.values[0]->attrs; for (auto & builtin : *builtins) { auto b = nlohmann::json::object(); if (builtin.value->type != tPrimOp) continue; auto primOp = builtin.value->primOp; if (!primOp->doc) continue; b["arity"] = primOp->arity; b["args"] = primOp->args; b["doc"] = trim(stripIndentation(primOp->doc)); res[(std::string) builtin.name] = std::move(b); } std::cout << res.dump() << "\n"; return; } Finally printCompletions([&]() { if (completions) { std::cout << (pathCompletions ? "filenames\n" : "no-filenames\n"); for (auto & s : *completions) std::cout << s << "\n"; } }); try { args.parseCmdline(argvToStrings(argc, argv)); } catch (UsageError &) { if (!completions) throw; } if (completions) return; initPlugins(); if (!args.command) args.showHelpAndExit(); if (args.command->first != "repl" && args.command->first != "doctor" && args.command->first != "upgrade-nix") settings.requireExperimentalFeature("nix-command"); if (args.useNet && !haveInternet()) { warn("you don't have Internet access; disabling some network-dependent features"); args.useNet = false; } if (!args.useNet) { // FIXME: should check for command line overrides only. if (!settings.useSubstitutes.overriden) settings.useSubstitutes = false; if (!settings.tarballTtl.overriden) settings.tarballTtl = std::numeric_limits::max(); if (!fileTransferSettings.tries.overriden) fileTransferSettings.tries = 0; if (!fileTransferSettings.connectTimeout.overriden) fileTransferSettings.connectTimeout = 1; } if (args.refresh) settings.tarballTtl = 0; args.command->second->prepare(); args.command->second->run(); } } int main(int argc, char * * argv) { return nix::handleExceptions(argv[0], [&]() { nix::mainWrapped(argc, argv); }); }