about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-10-24T10·45+0200
committerEelco Dolstra <edolstra@gmail.com>2017-10-24T10·58+0200
commit0d59f1ca49c9f7f3b2edaadcf590360ec66a6257 (patch)
treea03d53d84fb61eb354e2634705d8a076f0c1c76d /src
parent25f32625e2f2a3a1e1b3a3811da82f21c3a3b880 (diff)
nix: Respect -I, --arg, --argstr
Also, random cleanup to argument handling.
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/common-eval-args.cc57
-rw-r--r--src/libexpr/common-eval-args.hh26
-rw-r--r--src/libexpr/common-opts.cc67
-rw-r--r--src/libexpr/common-opts.hh20
-rw-r--r--src/libmain/common-args.cc28
-rw-r--r--src/libmain/shared.cc116
-rw-r--r--src/libmain/shared.hh14
-rw-r--r--src/libstore/globals.cc6
-rw-r--r--src/libutil/args.cc18
-rw-r--r--src/libutil/args.hh68
-rw-r--r--src/libutil/config.cc6
-rwxr-xr-xsrc/nix-build/nix-build.cc23
-rw-r--r--src/nix-env/nix-env.cc22
-rw-r--r--src/nix-instantiate/nix-instantiate.cc22
-rw-r--r--src/nix-prefetch-url/nix-prefetch-url.cc21
-rw-r--r--src/nix/command.cc6
-rw-r--r--src/nix/command.hh11
-rw-r--r--src/nix/copy.cc12
-rw-r--r--src/nix/hash.cc14
-rw-r--r--src/nix/installables.cc26
-rw-r--r--src/nix/main.cc36
-rw-r--r--src/nix/repl.cc13
-rw-r--r--src/nix/run.cc11
-rw-r--r--src/nix/search.cc4
-rw-r--r--src/nix/sigs.cc9
-rw-r--r--src/nix/verify.cc2
26 files changed, 354 insertions, 304 deletions
diff --git a/src/libexpr/common-eval-args.cc b/src/libexpr/common-eval-args.cc
new file mode 100644
index 0000000000..3e0c78f280
--- /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<std::string> 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<std::string> 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 0000000000..09fa406b2c
--- /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<std::string, std::string> 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 6b31961d34..0000000000
--- 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<string, string> & 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<string, string> & 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 cb2732d6fe..0000000000
--- 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<string, string> & res);
-
-Bindings * evalAutoArgs(EvalState & state, std::map<string, string> & 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 3fa42c2aaf..ea27aaa35e 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<std::string> 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 aef5d88bf4..9123a3d1ae 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<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
+    : MixCommonArgs(programName), parseArg(parseArg)
 {
-    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg;
-
-    LegacyArgs(const std::string & programName,
-        std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
-        : MixCommonArgs(programName), parseArg(parseArg)
-    {
-        mkFlag('Q', "no-build-output", "do not show build output",
-            &settings.verboseBuild, false);
-
-        mkFlag('K', "keep-failed", "keep temporary directories of failed builds",
-            &(bool&) settings.keepFailed);
-
-        mkFlag('k', "keep-going", "keep going after a build fails",
-            &(bool&) settings.keepGoing);
+    mkFlag()
+        .longName("no-build-output")
+        .shortName('Q')
+        .description("do not show build output")
+        .set(&settings.verboseBuild, false);
+
+    mkFlag()
+        .longName("keep-failed")
+        .shortName('K')
+        .description("keep temporary directories of failed builds")
+        .set(&(bool&) settings.keepFailed, true);
+
+    mkFlag()
+        .longName("keep-going")
+        .shortName('k')
+        .description("keep going after a build fails")
+        .set(&(bool&) settings.keepGoing, true);
+
+    mkFlag()
+        .longName("fallback")
+        .description("build from source if substitution fails")
+        .set(&(bool&) settings.tryFallback, true);
+
+    mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) {
+        settings.set("max-jobs", s);
+    });
 
-        mkFlag(0, "fallback", "build from source if substitution fails", []() {
-            settings.tryFallback = true;
+    auto intSettingAlias = [&](char shortName, const std::string & longName,
+        const std::string & description, const std::string & dest) {
+        mkFlag<unsigned int>(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<unsigned int>(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 2a1e42dd97..9219dbed83 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 <signal.h>
 
@@ -69,6 +70,19 @@ template<class N> N getIntArg(const string & opt,
 }
 
 
+struct LegacyArgs : public MixCommonArgs
+{
+    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg;
+
+    LegacyArgs(const std::string & programName,
+        std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> 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 bef2510d94..4fa02f9208 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -116,17 +116,17 @@ template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::s
     args.mkFlag()
         .longName(name)
         .description("Enable sandboxing.")
-        .handler([=](Strings ss) { value = smEnabled; })
+        .handler([=](std::vector<std::string> ss) { value = smEnabled; })
         .category(category);
     args.mkFlag()
         .longName("no-" + name)
         .description("Disable sandboxing.")
-        .handler([=](Strings ss) { value = smDisabled; })
+        .handler([=](std::vector<std::string> 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<std::string> ss) { value = smRelaxed; })
         .category(category);
 }
 
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index d17a1e7a9a..7af2a1bf73 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<std::string> 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<std::string> 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 37e31825ab..ad5fcca394 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<void(Strings)> handler;
+        std::function<void(std::vector<std::string>)> handler;
         std::string category;
     };
 
@@ -54,7 +54,7 @@ protected:
         std::string label;
         size_t arity; // 0 = any
         bool optional;
-        std::function<void(Strings)> handler;
+        std::function<void(std::vector<std::string>)> handler;
     };
 
     std::list<ExpectedArg> 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<void(Strings)> handler) { flag->handler = handler; return *this; };
+        FlagMaker & handler(std::function<void(std::vector<std::string>)> handler) { flag->handler = handler; return *this; };
+        FlagMaker & handler(std::function<void()> handler) { flag->handler = [handler](std::vector<std::string>) { handler(); }; return *this; };
+        FlagMaker & handler(std::function<void(std::string)> handler) {
+            flag->arity = 1;
+            flag->handler = [handler](std::vector<std::string> ss) { handler(std::move(ss[0])); };
+            return *this;
+        };
         FlagMaker & category(const std::string & s) { flag->category = s; return *this; };
 
         template<class T>
-        FlagMaker & dest(T * dest) {
+        FlagMaker & dest(T * dest)
+        {
             flag->arity = 1;
-            flag->handler = [=](Strings ss) { *dest = ss.front(); };
+            flag->handler = [=](std::vector<std::string> ss) { *dest = ss[0]; };
             return *this;
         };
 
         template<class T>
-        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<std::string> 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<void()> 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<void(std::string)> fun)
@@ -121,7 +122,7 @@ public:
             .labels({label})
             .description(description)
             .arity(1)
-            .handler([=](Strings ss) { fun(ss.front()); });
+            .handler([=](std::vector<std::string> 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<class T>
     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<std::string> ss) { *dest = value; });
     }
 
     template<class I>
@@ -171,10 +161,10 @@ public:
             .labels({"N"})
             .description(description)
             .arity(1)
-            .handler([=](Strings ss) {
+            .handler([=](std::vector<std::string> 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<std::string> 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<std::string> * dest)
     {
-        expectedArgs.push_back(ExpectedArg{label, 0, false, [=](Strings ss) {
-            *dest = ss;
+        expectedArgs.push_back(ExpectedArg{label, 0, false, [=](std::vector<std::string> ss) {
+            *dest = std::move(ss);
         }});
     }
 
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index 27157a8317..14c4cca031 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -152,7 +152,7 @@ void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
         .longName(name)
         .description(description)
         .arity(1)
-        .handler([=](Strings ss) { set(*ss.begin()); })
+        .handler([=](std::vector<std::string> ss) { set(ss[0]); })
         .category(category);
 }
 
@@ -201,12 +201,12 @@ template<> void BaseSetting<bool>::convertToArg(Args & args, const std::string &
     args.mkFlag()
         .longName(name)
         .description(description)
-        .handler([=](Strings ss) { value = true; })
+        .handler([=](std::vector<std::string> ss) { value = true; })
         .category(category);
     args.mkFlag()
         .longName("no-" + name)
         .description(description)
-        .handler([=](Strings ss) { value = false; })
+        .handler([=](std::vector<std::string> ss) { value = false; })
         .category(category);
 }
 
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 4541c89a70..85137206fa 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<string, string> 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 94fbc09f66..016caf6d23 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<string, string> 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<EvalState>(new EvalState(searchPath, store));
+        globals.state = std::shared_ptr<EvalState>(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 2498df0f0d..55ac007e86 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 <map>
 #include <iostream>
@@ -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<string, string> 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 7e62a033b4..fef3eaa455 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 <iostream>
@@ -48,15 +48,18 @@ int main(int argc, char * * argv)
 
         HashType ht = htSHA256;
         std::vector<string> args;
-        Strings searchPath;
         bool printPath = getEnv("PRINT_PATH") != "";
         bool fromExpr = false;
         string attrPath;
-        std::map<string, string> 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 70d642605d..1e6f0d2bb7 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<std::string> 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 77ca8cfb64..daa3b3fa70 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<std::string> _installables;
 };
 
 struct InstallableCommand : virtual Args, SourceExprCommand
diff --git a/src/nix/copy.cc b/src/nix/copy.cc
index 071ac3890a..2ddea9e70a 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 923dabb103..64062fb979 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<std::string> 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<std::string> 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<std::string> 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 c83d6316d3..ae93c4ef64 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<EvalState> SourceExprCommand::getEvalState()
 {
     if (!evalState)
-        evalState = std::make_shared<EvalState>(Strings{}, getStore());
+        evalState = std::make_shared<EvalState>(searchPath, getStore());
     return ref<EvalState>(evalState);
 }
 
@@ -120,9 +130,7 @@ struct InstallableValue : Installable
 
         auto v = toValue(*state);
 
-        // FIXME
-        std::map<string, string> 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<string, string> 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<std::shared_ptr<Installable>> parseInstallables(
-    SourceExprCommand & cmd, ref<Store> store, Strings ss, bool useDefaultInstallables)
+    SourceExprCommand & cmd, ref<Store> store, std::vector<std::string> ss, bool useDefaultInstallables)
 {
     std::vector<std::shared_ptr<Installable>> 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 ec9b58b20f..060402cd08 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(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(0, "version", "show version information", std::bind(printVersion, programName));
+        mkFlag()
+            .longName("help")
+            .shortName('h')
+            .description("show usage information")
+            .handler([&]() { showHelpAndExit(); });
+
+        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()
+            .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 781b4463e5..28a8ebc8c4 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> store);
     ~NixRepl();
-    void mainLoop(const Strings & files);
+    void mainLoop(const std::vector<std::string> & 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<std::string> & 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<std::string> files;
 
     CmdRepl()
     {
@@ -682,8 +682,7 @@ struct CmdRepl : StoreCommand
 
     void run(ref<Store> 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 2f93ca3515..6657a86314 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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 9476b79fbc..f458367dcb 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 992ff74283..b1825c412c 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<std::string> 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 4913d99009..6540208a8a 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<std::string> ss) { substituterUris.push_back(ss[0]); });
         mkIntFlag('n', "sigs-needed", "require that each path has at least N valid signatures", &sigsNeeded);
     }