From 0d59f1ca49c9f7f3b2edaadcf590360ec66a6257 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 24 Oct 2017 12:45:11 +0200 Subject: [PATCH] nix: Respect -I, --arg, --argstr Also, random cleanup to argument handling. --- src/libexpr/common-eval-args.cc | 57 ++++++++++++ src/libexpr/common-eval-args.hh | 26 ++++++ src/libexpr/common-opts.cc | 67 -------------- src/libexpr/common-opts.hh | 20 ----- src/libmain/common-args.cc | 28 +++--- src/libmain/shared.cc | 110 ++++++++++++----------- src/libmain/shared.hh | 14 +++ src/libstore/globals.cc | 6 +- src/libutil/args.cc | 18 ++-- src/libutil/args.hh | 68 ++++++-------- src/libutil/config.cc | 6 +- src/nix-build/nix-build.cc | 23 +++-- src/nix-env/nix-env.cc | 22 ++--- src/nix-instantiate/nix-instantiate.cc | 22 ++--- src/nix-prefetch-url/nix-prefetch-url.cc | 21 ++--- src/nix/command.cc | 6 +- src/nix/command.hh | 11 ++- src/nix/copy.cc | 12 ++- src/nix/hash.cc | 14 +-- src/nix/installables.cc | 26 +++--- src/nix/main.cc | 32 ++++--- src/nix/repl.cc | 13 ++- src/nix/run.cc | 11 +-- src/nix/search.cc | 4 +- src/nix/sigs.cc | 9 +- src/nix/verify.cc | 2 +- 26 files changed, 349 insertions(+), 299 deletions(-) create mode 100644 src/libexpr/common-eval-args.cc create mode 100644 src/libexpr/common-eval-args.hh delete mode 100644 src/libexpr/common-opts.cc delete mode 100644 src/libexpr/common-opts.hh diff --git a/src/libexpr/common-eval-args.cc b/src/libexpr/common-eval-args.cc new file mode 100644 index 000000000..3e0c78f28 --- /dev/null +++ b/src/libexpr/common-eval-args.cc @@ -0,0 +1,57 @@ +#include "common-eval-args.hh" +#include "shared.hh" +#include "download.hh" +#include "util.hh" +#include "eval.hh" + +namespace nix { + +MixEvalArgs::MixEvalArgs() +{ + mkFlag() + .longName("arg") + .description("argument to be passed to Nix functions") + .labels({"name", "expr"}) + .handler([&](std::vector ss) { autoArgs[ss[0]] = 'E' + ss[1]; }); + + mkFlag() + .longName("argstr") + .description("string-valued argument to be passed to Nix functions") + .labels({"name", "string"}) + .handler([&](std::vector ss) { autoArgs[ss[0]] = 'S' + ss[1]; }); + + mkFlag() + .shortName('I') + .longName("include") + .description("add a path to the list of locations used to look up <...> file names") + .label("path") + .handler([&](std::string s) { searchPath.push_back(s); }); +} + +Bindings * MixEvalArgs::getAutoArgs(EvalState & state) +{ + Bindings * res = state.allocBindings(autoArgs.size()); + for (auto & i : autoArgs) { + Value * v = state.allocValue(); + if (i.second[0] == 'E') + state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath("."))); + else + mkString(*v, string(i.second, 1)); + res->push_back(Attr(state.symbols.create(i.first), v)); + } + res->sort(); + return res; +} + +Path lookupFileArg(EvalState & state, string s) +{ + if (isUri(s)) + return getDownloader()->downloadCached(state.store, s, true); + else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { + Path p = s.substr(1, s.size() - 2); + return state.findFile(p); + } else + return absPath(s); +} + +} diff --git a/src/libexpr/common-eval-args.hh b/src/libexpr/common-eval-args.hh new file mode 100644 index 000000000..09fa406b2 --- /dev/null +++ b/src/libexpr/common-eval-args.hh @@ -0,0 +1,26 @@ +#pragma once + +#include "args.hh" + +namespace nix { + +class Store; +class EvalState; +struct Bindings; + +struct MixEvalArgs : virtual Args +{ + MixEvalArgs(); + + Bindings * getAutoArgs(EvalState & state); + + Strings searchPath; + +private: + + std::map autoArgs; +}; + +Path lookupFileArg(EvalState & state, string s); + +} diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc deleted file mode 100644 index 6b31961d3..000000000 --- a/src/libexpr/common-opts.cc +++ /dev/null @@ -1,67 +0,0 @@ -#include "common-opts.hh" -#include "shared.hh" -#include "download.hh" -#include "util.hh" - - -namespace nix { - - -bool parseAutoArgs(Strings::iterator & i, - const Strings::iterator & argsEnd, std::map & res) -{ - string arg = *i; - if (arg != "--arg" && arg != "--argstr") return false; - - UsageError error(format("'%1%' requires two arguments") % arg); - - if (++i == argsEnd) throw error; - string name = *i; - if (++i == argsEnd) throw error; - string value = *i; - - res[name] = (arg == "--arg" ? 'E' : 'S') + value; - - return true; -} - - -Bindings * evalAutoArgs(EvalState & state, std::map & in) -{ - Bindings * res = state.allocBindings(in.size()); - for (auto & i : in) { - Value * v = state.allocValue(); - if (i.second[0] == 'E') - state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath("."))); - else - mkString(*v, string(i.second, 1)); - res->push_back(Attr(state.symbols.create(i.first), v)); - } - res->sort(); - return res; -} - - -bool parseSearchPathArg(Strings::iterator & i, - const Strings::iterator & argsEnd, Strings & searchPath) -{ - if (*i != "-I") return false; - if (++i == argsEnd) throw UsageError("'-I' requires an argument"); - searchPath.push_back(*i); - return true; -} - - -Path lookupFileArg(EvalState & state, string s) -{ - if (isUri(s)) - return getDownloader()->downloadCached(state.store, s, true); - else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { - Path p = s.substr(1, s.size() - 2); - return state.findFile(p); - } else - return absPath(s); -} - - -} diff --git a/src/libexpr/common-opts.hh b/src/libexpr/common-opts.hh deleted file mode 100644 index cb2732d6f..000000000 --- a/src/libexpr/common-opts.hh +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "eval.hh" - -namespace nix { - -class Store; - -/* Some common option parsing between nix-env and nix-instantiate. */ -bool parseAutoArgs(Strings::iterator & i, - const Strings::iterator & argsEnd, std::map & res); - -Bindings * evalAutoArgs(EvalState & state, std::map & in); - -bool parseSearchPathArg(Strings::iterator & i, - const Strings::iterator & argsEnd, Strings & searchPath); - -Path lookupFileArg(EvalState & state, string s); - -} diff --git a/src/libmain/common-args.cc b/src/libmain/common-args.cc index 3fa42c2aa..ea27aaa35 100644 --- a/src/libmain/common-args.cc +++ b/src/libmain/common-args.cc @@ -6,28 +6,30 @@ namespace nix { MixCommonArgs::MixCommonArgs(const string & programName) : programName(programName) { - mkFlag('v', "verbose", "increase verbosity level", []() { - verbosity = (Verbosity) (verbosity + 1); - }); + mkFlag() + .longName("verbose") + .shortName('v') + .description("increase verbosity level") + .handler([]() { verbosity = (Verbosity) (verbosity + 1); }); - mkFlag(0, "quiet", "decrease verbosity level", []() { - verbosity = verbosity > lvlError ? (Verbosity) (verbosity - 1) : lvlError; - }); + mkFlag() + .longName("quiet") + .description("decrease verbosity level") + .handler([]() { verbosity = verbosity > lvlError ? (Verbosity) (verbosity - 1) : lvlError; }); - mkFlag(0, "debug", "enable debug output", []() { - verbosity = lvlDebug; - }); + mkFlag() + .longName("debug") + .description("enable debug output") + .handler([]() { verbosity = lvlDebug; }); mkFlag() .longName("option") .labels({"name", "value"}) .description("set a Nix configuration option (overriding nix.conf)") .arity(2) - .handler([](Strings ss) { - auto name = ss.front(); ss.pop_front(); - auto value = ss.front(); + .handler([](std::vector ss) { try { - settings.set(name, value); + settings.set(ss[0], ss[1]); } catch (UsageError & e) { warn(e.what()); } diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index aef5d88bf..9123a3d1a 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -1,4 +1,3 @@ -#include "common-args.hh" #include "globals.hh" #include "shared.hh" #include "store-api.hh" @@ -149,71 +148,78 @@ void initNix() } -struct LegacyArgs : public MixCommonArgs +LegacyArgs::LegacyArgs(const std::string & programName, + std::function parseArg) + : MixCommonArgs(programName), parseArg(parseArg) { - std::function parseArg; + mkFlag() + .longName("no-build-output") + .shortName('Q') + .description("do not show build output") + .set(&settings.verboseBuild, false); - LegacyArgs(const std::string & programName, - std::function parseArg) - : MixCommonArgs(programName), parseArg(parseArg) - { - mkFlag('Q', "no-build-output", "do not show build output", - &settings.verboseBuild, false); + mkFlag() + .longName("keep-failed") + .shortName('K') + .description("keep temporary directories of failed builds") + .set(&(bool&) settings.keepFailed, true); - mkFlag('K', "keep-failed", "keep temporary directories of failed builds", - &(bool&) settings.keepFailed); + mkFlag() + .longName("keep-going") + .shortName('k') + .description("keep going after a build fails") + .set(&(bool&) settings.keepGoing, true); - mkFlag('k', "keep-going", "keep going after a build fails", - &(bool&) settings.keepGoing); + mkFlag() + .longName("fallback") + .description("build from source if substitution fails") + .set(&(bool&) settings.tryFallback, true); - mkFlag(0, "fallback", "build from source if substitution fails", []() { - settings.tryFallback = true; + mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) { + settings.set("max-jobs", s); + }); + + auto intSettingAlias = [&](char shortName, const std::string & longName, + const std::string & description, const std::string & dest) { + mkFlag(shortName, longName, description, [=](unsigned int n) { + settings.set(dest, std::to_string(n)); }); + }; - mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) { - settings.set("max-jobs", s); - }); + intSettingAlias(0, "cores", "maximum number of CPU cores to use inside a build", "cores"); + intSettingAlias(0, "max-silent-time", "number of seconds of silence before a build is killed", "max-silent-time"); + intSettingAlias(0, "timeout", "number of seconds before a build is killed", "timeout"); - auto intSettingAlias = [&](char shortName, const std::string & longName, - const std::string & description, const std::string & dest) { - mkFlag(shortName, longName, description, [=](unsigned int n) { - settings.set(dest, std::to_string(n)); - }); - }; + mkFlag(0, "readonly-mode", "do not write to the Nix store", + &settings.readOnlyMode); - intSettingAlias(0, "cores", "maximum number of CPU cores to use inside a build", "cores"); - intSettingAlias(0, "max-silent-time", "number of seconds of silence before a build is killed", "max-silent-time"); - intSettingAlias(0, "timeout", "number of seconds before a build is killed", "timeout"); + mkFlag(0, "show-trace", "show Nix expression stack trace in evaluation errors", + &settings.showTrace); - mkFlag(0, "readonly-mode", "do not write to the Nix store", - &settings.readOnlyMode); + mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'", + &gcWarning, false); +} - mkFlag(0, "show-trace", "show Nix expression stack trace in evaluation errors", - &settings.showTrace); - mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'", - &gcWarning, false); - } +bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end) +{ + if (MixCommonArgs::processFlag(pos, end)) return true; + bool res = parseArg(pos, end); + if (res) ++pos; + return res; +} - bool processFlag(Strings::iterator & pos, Strings::iterator end) override - { - if (MixCommonArgs::processFlag(pos, end)) return true; - bool res = parseArg(pos, end); - if (res) ++pos; - return res; - } - bool processArgs(const Strings & args, bool finish) override - { - if (args.empty()) return true; - assert(args.size() == 1); - Strings ss(args); - auto pos = ss.begin(); - if (!parseArg(pos, ss.end())) - throw UsageError(format("unexpected argument '%1%'") % args.front()); - return true; - } -}; +bool LegacyArgs::processArgs(const Strings & args, bool finish) +{ + if (args.empty()) return true; + assert(args.size() == 1); + Strings ss(args); + auto pos = ss.begin(); + if (!parseArg(pos, ss.end())) + throw UsageError(format("unexpected argument '%1%'") % args.front()); + return true; +} void parseCmdLine(int argc, char * * argv, diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index 2a1e42dd9..9219dbed8 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -2,6 +2,7 @@ #include "util.hh" #include "args.hh" +#include "common-args.hh" #include @@ -69,6 +70,19 @@ template N getIntArg(const string & opt, } +struct LegacyArgs : public MixCommonArgs +{ + std::function parseArg; + + LegacyArgs(const std::string & programName, + std::function parseArg); + + bool processFlag(Strings::iterator & pos, Strings::iterator end) override; + + bool processArgs(const Strings & args, bool finish) override; +}; + + /* Show the manual page for the specified program. */ void showManPage(const string & name); diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index bef2510d9..4fa02f920 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -116,17 +116,17 @@ template<> void BaseSetting::convertToArg(Args & args, const std::s args.mkFlag() .longName(name) .description("Enable sandboxing.") - .handler([=](Strings ss) { value = smEnabled; }) + .handler([=](std::vector ss) { value = smEnabled; }) .category(category); args.mkFlag() .longName("no-" + name) .description("Disable sandboxing.") - .handler([=](Strings ss) { value = smDisabled; }) + .handler([=](std::vector ss) { value = smDisabled; }) .category(category); args.mkFlag() .longName("relaxed-" + name) .description("Enable sandboxing, but allow builds to disable it.") - .handler([=](Strings ss) { value = smRelaxed; }) + .handler([=](std::vector ss) { value = smRelaxed; }) .category(category); } diff --git a/src/libutil/args.cc b/src/libutil/args.cc index d17a1e7a9..7af2a1bf7 100644 --- a/src/libutil/args.cc +++ b/src/libutil/args.cc @@ -100,7 +100,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end) auto process = [&](const std::string & name, const Flag & flag) -> bool { ++pos; - Strings args; + std::vector args; for (size_t n = 0 ; n < flag.arity; ++n) { if (pos == end) { if (flag.arity == ArityAny) break; @@ -109,7 +109,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end) } args.push_back(*pos++); } - flag.handler(args); + flag.handler(std::move(args)); return true; }; @@ -144,7 +144,9 @@ bool Args::processArgs(const Strings & args, bool finish) if ((exp.arity == 0 && finish) || (exp.arity > 0 && args.size() == exp.arity)) { - exp.handler(args); + std::vector ss; + for (auto & s : args) ss.push_back(s); + exp.handler(std::move(ss)); expectedArgs.pop_front(); res = true; } @@ -155,13 +157,17 @@ bool Args::processArgs(const Strings & args, bool finish) return res; } -void Args::mkHashTypeFlag(const std::string & name, HashType * ht) +Args::FlagMaker & Args::FlagMaker::mkHashTypeFlag(HashType * ht) { - mkFlag1(0, name, "TYPE", "hash algorithm ('md5', 'sha1', 'sha256', or 'sha512')", [=](std::string s) { + arity(1); + label("type"); + description("hash algorithm ('md5', 'sha1', 'sha256', or 'sha512')"); + handler([ht](std::string s) { *ht = parseHashType(s); if (*ht == htUnknown) - throw UsageError(format("unknown hash type '%1%'") % s); + throw UsageError("unknown hash type '%1%'", s); }); + return *this; } Strings argvToStrings(int argc, char * * argv) diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 37e31825a..ad5fcca39 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -37,7 +37,7 @@ protected: std::string description; Strings labels; size_t arity = 0; - std::function handler; + std::function)> handler; std::string category; }; @@ -54,7 +54,7 @@ protected: std::string label; size_t arity; // 0 = any bool optional; - std::function handler; + std::function)> handler; }; std::list expectedArgs; @@ -76,24 +76,35 @@ public: FlagMaker & longName(const std::string & s) { flag->longName = s; return *this; }; FlagMaker & shortName(char s) { flag->shortName = s; return *this; }; FlagMaker & description(const std::string & s) { flag->description = s; return *this; }; - FlagMaker & labels(const Strings & ls) { flag->labels = ls; return *this; }; + FlagMaker & label(const std::string & l) { flag->arity = 1; flag->labels = {l}; return *this; }; + FlagMaker & labels(const Strings & ls) { flag->arity = ls.size(); flag->labels = ls; return *this; }; FlagMaker & arity(size_t arity) { flag->arity = arity; return *this; }; - FlagMaker & handler(std::function handler) { flag->handler = handler; return *this; }; + FlagMaker & handler(std::function)> handler) { flag->handler = handler; return *this; }; + FlagMaker & handler(std::function handler) { flag->handler = [handler](std::vector) { handler(); }; return *this; }; + FlagMaker & handler(std::function handler) { + flag->arity = 1; + flag->handler = [handler](std::vector ss) { handler(std::move(ss[0])); }; + return *this; + }; FlagMaker & category(const std::string & s) { flag->category = s; return *this; }; template - FlagMaker & dest(T * dest) { + FlagMaker & dest(T * dest) + { flag->arity = 1; - flag->handler = [=](Strings ss) { *dest = ss.front(); }; + flag->handler = [=](std::vector ss) { *dest = ss[0]; }; return *this; }; template - FlagMaker & set(T * dest, const T & val) { + FlagMaker & set(T * dest, const T & val) + { flag->arity = 0; - flag->handler = [=](Strings ss) { *dest = val; }; + flag->handler = [=](std::vector ss) { *dest = val; }; return *this; }; + + FlagMaker & mkHashTypeFlag(HashType * ht); }; FlagMaker mkFlag(); @@ -101,16 +112,6 @@ public: /* Helper functions for constructing flags / positional arguments. */ - void mkFlag(char shortName, const std::string & longName, - const std::string & description, std::function fun) - { - mkFlag() - .shortName(shortName) - .longName(longName) - .description(description) - .handler(std::bind(fun)); - } - void mkFlag1(char shortName, const std::string & longName, const std::string & label, const std::string & description, std::function fun) @@ -121,7 +122,7 @@ public: .labels({label}) .description(description) .arity(1) - .handler([=](Strings ss) { fun(ss.front()); }); + .handler([=](std::vector ss) { fun(ss[0]); }); } void mkFlag(char shortName, const std::string & name, @@ -130,17 +131,6 @@ public: mkFlag(shortName, name, description, dest, true); } - void mkFlag(char shortName, const std::string & longName, - const std::string & label, const std::string & description, - string * dest) - { - mkFlag1(shortName, longName, label, description, [=](std::string s) { - *dest = s; - }); - } - - void mkHashTypeFlag(const std::string & name, HashType * ht); - template void mkFlag(char shortName, const std::string & longName, const std::string & description, T * dest, const T & value) @@ -149,7 +139,7 @@ public: .shortName(shortName) .longName(longName) .description(description) - .handler([=](Strings ss) { *dest = value; }); + .handler([=](std::vector ss) { *dest = value; }); } template @@ -171,10 +161,10 @@ public: .labels({"N"}) .description(description) .arity(1) - .handler([=](Strings ss) { + .handler([=](std::vector ss) { I n; - if (!string2Int(ss.front(), n)) - throw UsageError(format("flag '--%1%' requires a integer argument") % longName); + if (!string2Int(ss[0], n)) + throw UsageError("flag '--%s' requires a integer argument", longName); fun(n); }); } @@ -182,16 +172,16 @@ public: /* Expect a string argument. */ void expectArg(const std::string & label, string * dest, bool optional = false) { - expectedArgs.push_back(ExpectedArg{label, 1, optional, [=](Strings ss) { - *dest = ss.front(); + expectedArgs.push_back(ExpectedArg{label, 1, optional, [=](std::vector ss) { + *dest = ss[0]; }}); } /* Expect 0 or more arguments. */ - void expectArgs(const std::string & label, Strings * dest) + void expectArgs(const std::string & label, std::vector * dest) { - expectedArgs.push_back(ExpectedArg{label, 0, false, [=](Strings ss) { - *dest = ss; + expectedArgs.push_back(ExpectedArg{label, 0, false, [=](std::vector ss) { + *dest = std::move(ss); }}); } diff --git a/src/libutil/config.cc b/src/libutil/config.cc index 27157a831..14c4cca03 100644 --- a/src/libutil/config.cc +++ b/src/libutil/config.cc @@ -152,7 +152,7 @@ void BaseSetting::convertToArg(Args & args, const std::string & category) .longName(name) .description(description) .arity(1) - .handler([=](Strings ss) { set(*ss.begin()); }) + .handler([=](std::vector ss) { set(ss[0]); }) .category(category); } @@ -201,12 +201,12 @@ template<> void BaseSetting::convertToArg(Args & args, const std::string & args.mkFlag() .longName(name) .description(description) - .handler([=](Strings ss) { value = true; }) + .handler([=](std::vector ss) { value = true; }) .category(category); args.mkFlag() .longName("no-" + name) .description(description) - .handler([=](Strings ss) { value = false; }) + .handler([=](std::vector ss) { value = false; }) .category(category); } diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 4541c89a7..85137206f 100755 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -14,7 +14,7 @@ #include "eval.hh" #include "eval-inline.hh" #include "get-drvs.hh" -#include "common-opts.hh" +#include "common-eval-args.hh" #include "attr-path.hh" using namespace nix; @@ -80,8 +80,6 @@ void mainWrapped(int argc, char * * argv) auto interactive = isatty(STDIN_FILENO) && isatty(STDERR_FILENO); Strings attrPaths; Strings left; - Strings searchPath; - std::map autoArgs_; RepairFlag repair = NoRepair; Path gcRoot; BuildMode buildMode = bmNormal; @@ -129,7 +127,12 @@ void mainWrapped(int argc, char * * argv) } catch (SysError &) { } } - parseCmdLine(myName, args, [&](Strings::iterator & arg, const Strings::iterator & end) { + struct MyArgs : LegacyArgs, MixEvalArgs + { + using LegacyArgs::LegacyArgs; + }; + + MyArgs myArgs(myName, [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--help") { deletePath(tmpDir); showManPage(myName); @@ -153,12 +156,6 @@ void mainWrapped(int argc, char * * argv) else if (*arg == "--out-link" || *arg == "-o") outLink = getArg(*arg, arg, end); - else if (parseAutoArgs(arg, end, autoArgs_)) - ; - - else if (parseSearchPathArg(arg, end, searchPath)) - ; - else if (*arg == "--add-root") gcRoot = getArg(*arg, arg, end); @@ -237,15 +234,17 @@ void mainWrapped(int argc, char * * argv) return true; }); + myArgs.parseCmdline(args); + if (packages && fromArgs) throw UsageError("'-p' and '-E' are mutually exclusive"); auto store = openStore(); - EvalState state(searchPath, store); + EvalState state(myArgs.searchPath, store); state.repair = repair; - Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); + Bindings & autoArgs = *myArgs.getAutoArgs(state); if (packages) { std::ostringstream joined; diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 94fbc09f6..016caf6d2 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1,5 +1,5 @@ #include "attr-path.hh" -#include "common-opts.hh" +#include "common-eval-args.hh" #include "derivations.hh" #include "eval.hh" #include "get-drvs.hh" @@ -1309,8 +1309,7 @@ int main(int argc, char * * argv) initNix(); initGC(); - Strings opFlags, opArgs, searchPath; - std::map autoArgs_; + Strings opFlags, opArgs; Operation op = 0; RepairFlag repair = NoRepair; string file; @@ -1326,7 +1325,12 @@ int main(int argc, char * * argv) globals.removeAll = false; globals.prebuiltOnly = false; - parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { + struct MyArgs : LegacyArgs, MixEvalArgs + { + using LegacyArgs::LegacyArgs; + }; + + MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) { Operation oldOp = op; if (*arg == "--help") @@ -1335,10 +1339,6 @@ int main(int argc, char * * argv) op = opVersion; else if (*arg == "--install" || *arg == "-i") op = opInstall; - else if (parseAutoArgs(arg, end, autoArgs_)) - ; - else if (parseSearchPathArg(arg, end, searchPath)) - ; else if (*arg == "--force-name") // undocumented flag for nix-install-package globals.forceName = getArg(*arg, arg, end); else if (*arg == "--uninstall" || *arg == "-e") @@ -1391,17 +1391,19 @@ int main(int argc, char * * argv) return true; }); + myArgs.parseCmdline(argvToStrings(argc, argv)); + if (!op) throw UsageError("no operation specified"); auto store = openStore(); - globals.state = std::shared_ptr(new EvalState(searchPath, store)); + globals.state = std::shared_ptr(new EvalState(myArgs.searchPath, store)); globals.state->repair = repair; if (file != "") globals.instSource.nixExprPath = lookupFileArg(*globals.state, file); - globals.instSource.autoArgs = evalAutoArgs(*globals.state, autoArgs_); + globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state); if (globals.profile == "") globals.profile = getEnv("NIX_PROFILE", ""); diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 2498df0f0..55ac007e8 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -8,7 +8,7 @@ #include "value-to-json.hh" #include "util.hh" #include "store-api.hh" -#include "common-opts.hh" +#include "common-eval-args.hh" #include #include @@ -89,7 +89,7 @@ int main(int argc, char * * argv) initNix(); initGC(); - Strings files, searchPath; + Strings files; bool readStdin = false; bool fromArgs = false; bool findFile = false; @@ -100,10 +100,14 @@ int main(int argc, char * * argv) bool strict = false; Strings attrPaths; bool wantsReadWrite = false; - std::map autoArgs_; RepairFlag repair = NoRepair; - parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { + struct MyArgs : LegacyArgs, MixEvalArgs + { + using LegacyArgs::LegacyArgs; + }; + + MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--help") showManPage("nix-instantiate"); else if (*arg == "--version") @@ -122,10 +126,6 @@ int main(int argc, char * * argv) findFile = true; else if (*arg == "--attr" || *arg == "-A") attrPaths.push_back(getArg(*arg, arg, end)); - else if (parseAutoArgs(arg, end, autoArgs_)) - ; - else if (parseSearchPathArg(arg, end, searchPath)) - ; else if (*arg == "--add-root") gcRoot = getArg(*arg, arg, end); else if (*arg == "--indirect") @@ -149,15 +149,17 @@ int main(int argc, char * * argv) return true; }); + myArgs.parseCmdline(argvToStrings(argc, argv)); + if (evalOnly && !wantsReadWrite) settings.readOnlyMode = true; auto store = openStore(); - EvalState state(searchPath, store); + EvalState state(myArgs.searchPath, store); state.repair = repair; - Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); + Bindings & autoArgs = *myArgs.getAutoArgs(state); if (attrPaths.empty()) attrPaths = {""}; diff --git a/src/nix-prefetch-url/nix-prefetch-url.cc b/src/nix-prefetch-url/nix-prefetch-url.cc index 7e62a033b..fef3eaa45 100644 --- a/src/nix-prefetch-url/nix-prefetch-url.cc +++ b/src/nix-prefetch-url/nix-prefetch-url.cc @@ -4,7 +4,7 @@ #include "store-api.hh" #include "eval.hh" #include "eval-inline.hh" -#include "common-opts.hh" +#include "common-eval-args.hh" #include "attr-path.hh" #include @@ -48,15 +48,18 @@ int main(int argc, char * * argv) HashType ht = htSHA256; std::vector args; - Strings searchPath; bool printPath = getEnv("PRINT_PATH") != ""; bool fromExpr = false; string attrPath; - std::map autoArgs_; bool unpack = false; string name; - parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { + struct MyArgs : LegacyArgs, MixEvalArgs + { + using LegacyArgs::LegacyArgs; + }; + + MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--help") showManPage("nix-prefetch-url"); else if (*arg == "--version") @@ -77,10 +80,6 @@ int main(int argc, char * * argv) unpack = true; else if (*arg == "--name") name = getArg(*arg, arg, end); - else if (parseAutoArgs(arg, end, autoArgs_)) - ; - else if (parseSearchPathArg(arg, end, searchPath)) - ; else if (*arg != "" && arg->at(0) == '-') return false; else @@ -88,13 +87,15 @@ int main(int argc, char * * argv) return true; }); + myArgs.parseCmdline(argvToStrings(argc, argv)); + if (args.size() > 2) throw UsageError("too many arguments"); auto store = openStore(); - EvalState state(searchPath, store); + EvalState state(myArgs.searchPath, store); - Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); + Bindings & autoArgs = *myArgs.getAutoArgs(state); /* If -A is given, get the URI from the specified Nix expression. */ diff --git a/src/nix/command.cc b/src/nix/command.cc index 70d642605..1e6f0d2bb 100644 --- a/src/nix/command.cc +++ b/src/nix/command.cc @@ -24,11 +24,11 @@ void Command::printHelp(const string & programName, std::ostream & out) MultiCommand::MultiCommand(const Commands & _commands) : commands(_commands) { - expectedArgs.push_back(ExpectedArg{"command", 1, true, [=](Strings ss) { + expectedArgs.push_back(ExpectedArg{"command", 1, true, [=](std::vector ss) { assert(!command); - auto i = commands.find(ss.front()); + auto i = commands.find(ss[0]); if (i == commands.end()) - throw UsageError(format("'%1%' is not a recognised command") % ss.front()); + throw UsageError("'%s' is not a recognised command", ss[0]); command = i->second; }}); } diff --git a/src/nix/command.hh b/src/nix/command.hh index 77ca8cfb6..daa3b3fa7 100644 --- a/src/nix/command.hh +++ b/src/nix/command.hh @@ -1,10 +1,12 @@ #pragma once #include "args.hh" +#include "common-eval-args.hh" namespace nix { struct Value; +struct Bindings; class EvalState; /* A command is an argument parser that can be executed by calling its @@ -68,14 +70,11 @@ struct Installable } }; -struct SourceExprCommand : virtual Args, StoreCommand +struct SourceExprCommand : virtual Args, StoreCommand, MixEvalArgs { Path file; - SourceExprCommand() - { - mkFlag('f', "file", "file", "evaluate FILE rather than the default", &file); - } + SourceExprCommand(); /* Return a value representing the Nix expression from which we are installing. This is either the file specified by ‘--file’, @@ -111,7 +110,7 @@ struct InstallablesCommand : virtual Args, SourceExprCommand private: - Strings _installables; + std::vector _installables; }; struct InstallableCommand : virtual Args, SourceExprCommand diff --git a/src/nix/copy.cc b/src/nix/copy.cc index 071ac3890..2ddea9e70 100644 --- a/src/nix/copy.cc +++ b/src/nix/copy.cc @@ -19,8 +19,16 @@ struct CmdCopy : StorePathsCommand CmdCopy() : StorePathsCommand(true) { - mkFlag(0, "from", "store-uri", "URI of the source Nix store", &srcUri); - mkFlag(0, "to", "store-uri", "URI of the destination Nix store", &dstUri); + mkFlag() + .longName("from") + .labels({"store-uri"}) + .description("URI of the source Nix store") + .dest(&srcUri); + mkFlag() + .longName("to") + .labels({"store-uri"}) + .description("URI of the destination Nix store") + .dest(&dstUri); mkFlag() .longName("no-check-sigs") diff --git a/src/nix/hash.cc b/src/nix/hash.cc index 923dabb10..64062fb97 100644 --- a/src/nix/hash.cc +++ b/src/nix/hash.cc @@ -12,14 +12,16 @@ struct CmdHash : Command Base base = Base16; bool truncate = false; HashType ht = htSHA512; - Strings paths; + std::vector paths; CmdHash(Mode mode) : mode(mode) { mkFlag(0, "base64", "print hash in base-64", &base, Base64); mkFlag(0, "base32", "print hash in base-32 (Nix-specific)", &base, Base32); mkFlag(0, "base16", "print hash in base-16", &base, Base16); - mkHashTypeFlag("type", &ht); + mkFlag() + .longName("type") + .mkHashTypeFlag(&ht); expectArgs("paths", &paths); } @@ -53,11 +55,13 @@ struct CmdToBase : Command { Base base; HashType ht = htSHA512; - Strings args; + std::vector args; CmdToBase(Base base) : base(base) { - mkHashTypeFlag("type", &ht); + mkFlag() + .longName("type") + .mkHashTypeFlag(&ht); expectArgs("strings", &args); } @@ -95,7 +99,7 @@ static int compatNixHash(int argc, char * * argv) bool base32 = false; bool truncate = false; enum { opHash, opTo32, opTo16 } op = opHash; - Strings ss; + std::vector ss; parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--help") diff --git a/src/nix/installables.cc b/src/nix/installables.cc index c83d6316d..ae93c4ef6 100644 --- a/src/nix/installables.cc +++ b/src/nix/installables.cc @@ -1,6 +1,6 @@ #include "command.hh" #include "attr-path.hh" -#include "common-opts.hh" +#include "common-eval-args.hh" #include "derivations.hh" #include "eval-inline.hh" #include "eval.hh" @@ -12,6 +12,16 @@ namespace nix { +SourceExprCommand::SourceExprCommand() +{ + mkFlag() + .shortName('f') + .longName("file") + .label("file") + .description("evaluate FILE rather than the default") + .dest(&file); +} + Value * SourceExprCommand::getSourceExpr(EvalState & state) { if (vSourceExpr) return vSourceExpr; @@ -66,7 +76,7 @@ Value * SourceExprCommand::getSourceExpr(EvalState & state) ref SourceExprCommand::getEvalState() { if (!evalState) - evalState = std::make_shared(Strings{}, getStore()); + evalState = std::make_shared(searchPath, getStore()); return ref(evalState); } @@ -120,9 +130,7 @@ struct InstallableValue : Installable auto v = toValue(*state); - // FIXME - std::map autoArgs_; - Bindings & autoArgs(*evalAutoArgs(*state, autoArgs_)); + Bindings & autoArgs = *cmd.getAutoArgs(*state); DrvInfos drvs; getDerivations(*state, *v, "", autoArgs, drvs, false); @@ -187,9 +195,7 @@ struct InstallableAttrPath : InstallableValue { auto source = cmd.getSourceExpr(state); - // FIXME - std::map autoArgs_; - Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); + Bindings & autoArgs = *cmd.getAutoArgs(state); Value * v = findAlongAttrPath(state, attrPath, autoArgs, *source); state.forceValue(*v); @@ -203,14 +209,14 @@ std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)"; static std::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex)); static std::vector> parseInstallables( - SourceExprCommand & cmd, ref store, Strings ss, bool useDefaultInstallables) + SourceExprCommand & cmd, ref store, std::vector ss, bool useDefaultInstallables) { std::vector> result; if (ss.empty() && useDefaultInstallables) { if (cmd.file == "") cmd.file = "."; - ss = Strings{""}; + ss = {""}; } for (auto & s : ss) { diff --git a/src/nix/main.cc b/src/nix/main.cc index ec9b58b20..060402cd0 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -20,19 +20,29 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs { NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix") { - mkFlag('h', "help", "show usage information", [&]() { showHelpAndExit(); }); + mkFlag() + .longName("help") + .shortName('h') + .description("show usage information") + .handler([&]() { showHelpAndExit(); }); - mkFlag(0, "help-config", "show configuration options", [=]() { - std::cout << "The following configuration options are available:\n\n"; - Table2 tbl; - for (const auto & s : settings._getSettings()) - if (!s.second.isAlias) - tbl.emplace_back(s.first, s.second.setting->description); - printTable(std::cout, tbl); - throw Exit(); - }); + mkFlag() + .longName("help-config") + .description("show configuration options") + .handler([&]() { + std::cout << "The following configuration options are available:\n\n"; + Table2 tbl; + for (const auto & s : settings._getSettings()) + if (!s.second.isAlias) + tbl.emplace_back(s.first, s.second.setting->description); + printTable(std::cout, tbl); + throw Exit(); + }); - mkFlag(0, "version", "show version information", std::bind(printVersion, programName)); + mkFlag() + .longName("version") + .description("show version information") + .handler([&]() { printVersion(programName); }); std::string cat = "config"; settings.convertToArgs(*this, cat); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 781b4463e..28a8ebc8c 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -7,7 +7,7 @@ #include "eval.hh" #include "eval-inline.hh" #include "store-api.hh" -#include "common-opts.hh" +#include "common-eval-args.hh" #include "get-drvs.hh" #include "derivations.hh" #include "affinity.hh" @@ -44,7 +44,7 @@ struct NixRepl NixRepl(const Strings & searchPath, nix::ref store); ~NixRepl(); - void mainLoop(const Strings & files); + void mainLoop(const std::vector & files); StringSet completePrefix(string prefix); bool getLine(string & input, const std::string &prompt); Path getDerivationPath(Value & v); @@ -131,7 +131,7 @@ static void completionCallback(const char * s, linenoiseCompletions *lc) } -void NixRepl::mainLoop(const Strings & files) +void NixRepl::mainLoop(const std::vector & files) { string error = ANSI_RED "error:" ANSI_NORMAL " "; std::cout << "Welcome to Nix version " << nixVersion << ". Type :? for help." << std::endl << std::endl; @@ -664,9 +664,9 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m return str; } -struct CmdRepl : StoreCommand +struct CmdRepl : StoreCommand, MixEvalArgs { - Strings files; + std::vector files; CmdRepl() { @@ -682,8 +682,7 @@ struct CmdRepl : StoreCommand void run(ref store) override { - // FIXME: pass searchPath - NixRepl repl({}, openStore()); + NixRepl repl(searchPath, openStore()); repl.mainLoop(files); } }; diff --git a/src/nix/run.cc b/src/nix/run.cc index 2f93ca351..6657a8631 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -20,7 +20,7 @@ extern char * * environ; struct CmdRun : InstallablesCommand { - Strings command = { "bash" }; + std::vector command = { "bash" }; StringSet keep, unset; bool ignoreEnvironment = false; @@ -32,7 +32,7 @@ struct CmdRun : InstallablesCommand .description("command and arguments to be executed; defaults to 'bash'") .arity(ArityAny) .labels({"command", "args"}) - .handler([&](Strings ss) { + .handler([&](std::vector ss) { if (ss.empty()) throw UsageError("--command requires at least one argument"); command = ss; }); @@ -49,7 +49,7 @@ struct CmdRun : InstallablesCommand .description("keep specified environment variable") .arity(1) .labels({"name"}) - .handler([&](Strings ss) { keep.insert(ss.front()); }); + .handler([&](std::vector ss) { keep.insert(ss.front()); }); mkFlag() .longName("unset") @@ -57,7 +57,7 @@ struct CmdRun : InstallablesCommand .description("unset specified environment variable") .arity(1) .labels({"name"}) - .handler([&](Strings ss) { unset.insert(ss.front()); }); + .handler([&](std::vector ss) { unset.insert(ss.front()); }); } std::string name() override @@ -126,7 +126,8 @@ struct CmdRun : InstallablesCommand setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1); std::string cmd = *command.begin(); - Strings args = command; + Strings args; + for (auto & arg : command) args.push_back(arg); stopProgressBar(); diff --git a/src/nix/search.cc b/src/nix/search.cc index 9476b79fb..f458367dc 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -38,12 +38,12 @@ struct CmdSearch : SourceExprCommand, MixJSON .longName("update-cache") .shortName('u') .description("update the package search cache") - .handler([&](Strings ss) { writeCache = true; useCache = false; }); + .handler([&]() { writeCache = true; useCache = false; }); mkFlag() .longName("no-cache") .description("do not use or update the package search cache") - .handler([&](Strings ss) { writeCache = false; useCache = false; }); + .handler([&]() { writeCache = false; useCache = false; }); } std::string name() override diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc index 992ff7428..b1825c412 100644 --- a/src/nix/sigs.cc +++ b/src/nix/sigs.cc @@ -19,7 +19,7 @@ struct CmdCopySigs : StorePathsCommand .labels({"store-uri"}) .description("use signatures from specified store") .arity(1) - .handler([&](Strings ss) { substituterUris.push_back(ss.front()); }); + .handler([&](std::vector ss) { substituterUris.push_back(ss[0]); }); } std::string name() override @@ -101,7 +101,12 @@ struct CmdSignPaths : StorePathsCommand CmdSignPaths() { - mkFlag('k', "key-file", {"file"}, "file containing the secret signing key", &secretKeyFile); + mkFlag() + .shortName('k') + .longName("key-file") + .label("file") + .description("file containing the secret signing key") + .dest(&secretKeyFile); } std::string name() override diff --git a/src/nix/verify.cc b/src/nix/verify.cc index 4913d9900..6540208a8 100644 --- a/src/nix/verify.cc +++ b/src/nix/verify.cc @@ -25,7 +25,7 @@ struct CmdVerify : StorePathsCommand .labels({"store-uri"}) .description("use signatures from specified store") .arity(1) - .handler([&](Strings ss) { substituterUris.push_back(ss.front()); }); + .handler([&](std::vector ss) { substituterUris.push_back(ss[0]); }); mkIntFlag('n', "sigs-needed", "require that each path has at least N valid signatures", &sigsNeeded); }