nix: Respect -I, --arg, --argstr

Also, random cleanup to argument handling.
This commit is contained in:
Eelco Dolstra 2017-10-24 12:45:11 +02:00
parent 25f32625e2
commit 0d59f1ca49
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
26 changed files with 349 additions and 299 deletions

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -6,28 +6,30 @@ namespace nix {
MixCommonArgs::MixCommonArgs(const string & programName) MixCommonArgs::MixCommonArgs(const string & programName)
: programName(programName) : programName(programName)
{ {
mkFlag('v', "verbose", "increase verbosity level", []() { mkFlag()
verbosity = (Verbosity) (verbosity + 1); .longName("verbose")
}); .shortName('v')
.description("increase verbosity level")
.handler([]() { verbosity = (Verbosity) (verbosity + 1); });
mkFlag(0, "quiet", "decrease verbosity level", []() { mkFlag()
verbosity = verbosity > lvlError ? (Verbosity) (verbosity - 1) : lvlError; .longName("quiet")
}); .description("decrease verbosity level")
.handler([]() { verbosity = verbosity > lvlError ? (Verbosity) (verbosity - 1) : lvlError; });
mkFlag(0, "debug", "enable debug output", []() { mkFlag()
verbosity = lvlDebug; .longName("debug")
}); .description("enable debug output")
.handler([]() { verbosity = lvlDebug; });
mkFlag() mkFlag()
.longName("option") .longName("option")
.labels({"name", "value"}) .labels({"name", "value"})
.description("set a Nix configuration option (overriding nix.conf)") .description("set a Nix configuration option (overriding nix.conf)")
.arity(2) .arity(2)
.handler([](Strings ss) { .handler([](std::vector<std::string> ss) {
auto name = ss.front(); ss.pop_front();
auto value = ss.front();
try { try {
settings.set(name, value); settings.set(ss[0], ss[1]);
} catch (UsageError & e) { } catch (UsageError & e) {
warn(e.what()); warn(e.what());
} }

View file

@ -1,4 +1,3 @@
#include "common-args.hh"
#include "globals.hh" #include "globals.hh"
#include "shared.hh" #include "shared.hh"
#include "store-api.hh" #include "store-api.hh"
@ -149,26 +148,32 @@ void initNix()
} }
struct LegacyArgs : public MixCommonArgs LegacyArgs::LegacyArgs(const std::string & programName,
{
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) std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
: MixCommonArgs(programName), parseArg(parseArg) : MixCommonArgs(programName), parseArg(parseArg)
{ {
mkFlag('Q', "no-build-output", "do not show build output", mkFlag()
&settings.verboseBuild, false); .longName("no-build-output")
.shortName('Q')
.description("do not show build output")
.set(&settings.verboseBuild, false);
mkFlag('K', "keep-failed", "keep temporary directories of failed builds", mkFlag()
&(bool&) settings.keepFailed); .longName("keep-failed")
.shortName('K')
.description("keep temporary directories of failed builds")
.set(&(bool&) settings.keepFailed, true);
mkFlag('k', "keep-going", "keep going after a build fails", mkFlag()
&(bool&) settings.keepGoing); .longName("keep-going")
.shortName('k')
.description("keep going after a build fails")
.set(&(bool&) settings.keepGoing, true);
mkFlag(0, "fallback", "build from source if substitution fails", []() { mkFlag()
settings.tryFallback = true; .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) { mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) {
settings.set("max-jobs", s); settings.set("max-jobs", s);
@ -195,7 +200,8 @@ struct LegacyArgs : public MixCommonArgs
&gcWarning, false); &gcWarning, false);
} }
bool processFlag(Strings::iterator & pos, Strings::iterator end) override
bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end)
{ {
if (MixCommonArgs::processFlag(pos, end)) return true; if (MixCommonArgs::processFlag(pos, end)) return true;
bool res = parseArg(pos, end); bool res = parseArg(pos, end);
@ -203,7 +209,8 @@ struct LegacyArgs : public MixCommonArgs
return res; return res;
} }
bool processArgs(const Strings & args, bool finish) override
bool LegacyArgs::processArgs(const Strings & args, bool finish)
{ {
if (args.empty()) return true; if (args.empty()) return true;
assert(args.size() == 1); assert(args.size() == 1);
@ -213,7 +220,6 @@ struct LegacyArgs : public MixCommonArgs
throw UsageError(format("unexpected argument '%1%'") % args.front()); throw UsageError(format("unexpected argument '%1%'") % args.front());
return true; return true;
} }
};
void parseCmdLine(int argc, char * * argv, void parseCmdLine(int argc, char * * argv,

View file

@ -2,6 +2,7 @@
#include "util.hh" #include "util.hh"
#include "args.hh" #include "args.hh"
#include "common-args.hh"
#include <signal.h> #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. */ /* Show the manual page for the specified program. */
void showManPage(const string & name); void showManPage(const string & name);

View file

@ -116,17 +116,17 @@ template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::s
args.mkFlag() args.mkFlag()
.longName(name) .longName(name)
.description("Enable sandboxing.") .description("Enable sandboxing.")
.handler([=](Strings ss) { value = smEnabled; }) .handler([=](std::vector<std::string> ss) { value = smEnabled; })
.category(category); .category(category);
args.mkFlag() args.mkFlag()
.longName("no-" + name) .longName("no-" + name)
.description("Disable sandboxing.") .description("Disable sandboxing.")
.handler([=](Strings ss) { value = smDisabled; }) .handler([=](std::vector<std::string> ss) { value = smDisabled; })
.category(category); .category(category);
args.mkFlag() args.mkFlag()
.longName("relaxed-" + name) .longName("relaxed-" + name)
.description("Enable sandboxing, but allow builds to disable it.") .description("Enable sandboxing, but allow builds to disable it.")
.handler([=](Strings ss) { value = smRelaxed; }) .handler([=](std::vector<std::string> ss) { value = smRelaxed; })
.category(category); .category(category);
} }

View file

@ -100,7 +100,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
auto process = [&](const std::string & name, const Flag & flag) -> bool { auto process = [&](const std::string & name, const Flag & flag) -> bool {
++pos; ++pos;
Strings args; std::vector<std::string> args;
for (size_t n = 0 ; n < flag.arity; ++n) { for (size_t n = 0 ; n < flag.arity; ++n) {
if (pos == end) { if (pos == end) {
if (flag.arity == ArityAny) break; if (flag.arity == ArityAny) break;
@ -109,7 +109,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
} }
args.push_back(*pos++); args.push_back(*pos++);
} }
flag.handler(args); flag.handler(std::move(args));
return true; return true;
}; };
@ -144,7 +144,9 @@ bool Args::processArgs(const Strings & args, bool finish)
if ((exp.arity == 0 && finish) || if ((exp.arity == 0 && finish) ||
(exp.arity > 0 && args.size() == exp.arity)) (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(); expectedArgs.pop_front();
res = true; res = true;
} }
@ -155,13 +157,17 @@ bool Args::processArgs(const Strings & args, bool finish)
return res; 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); *ht = parseHashType(s);
if (*ht == htUnknown) 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) Strings argvToStrings(int argc, char * * argv)

View file

@ -37,7 +37,7 @@ protected:
std::string description; std::string description;
Strings labels; Strings labels;
size_t arity = 0; size_t arity = 0;
std::function<void(Strings)> handler; std::function<void(std::vector<std::string>)> handler;
std::string category; std::string category;
}; };
@ -54,7 +54,7 @@ protected:
std::string label; std::string label;
size_t arity; // 0 = any size_t arity; // 0 = any
bool optional; bool optional;
std::function<void(Strings)> handler; std::function<void(std::vector<std::string>)> handler;
}; };
std::list<ExpectedArg> expectedArgs; std::list<ExpectedArg> expectedArgs;
@ -76,24 +76,35 @@ public:
FlagMaker & longName(const std::string & s) { flag->longName = s; return *this; }; FlagMaker & longName(const std::string & s) { flag->longName = s; return *this; };
FlagMaker & shortName(char s) { flag->shortName = s; return *this; }; FlagMaker & shortName(char s) { flag->shortName = s; return *this; };
FlagMaker & description(const std::string & s) { flag->description = 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 & 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; }; FlagMaker & category(const std::string & s) { flag->category = s; return *this; };
template<class T> template<class T>
FlagMaker & dest(T * dest) { FlagMaker & dest(T * dest)
{
flag->arity = 1; flag->arity = 1;
flag->handler = [=](Strings ss) { *dest = ss.front(); }; flag->handler = [=](std::vector<std::string> ss) { *dest = ss[0]; };
return *this; return *this;
}; };
template<class T> template<class T>
FlagMaker & set(T * dest, const T & val) { FlagMaker & set(T * dest, const T & val)
{
flag->arity = 0; flag->arity = 0;
flag->handler = [=](Strings ss) { *dest = val; }; flag->handler = [=](std::vector<std::string> ss) { *dest = val; };
return *this; return *this;
}; };
FlagMaker & mkHashTypeFlag(HashType * ht);
}; };
FlagMaker mkFlag(); FlagMaker mkFlag();
@ -101,16 +112,6 @@ public:
/* Helper functions for constructing flags / positional /* Helper functions for constructing flags / positional
arguments. */ 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, void mkFlag1(char shortName, const std::string & longName,
const std::string & label, const std::string & description, const std::string & label, const std::string & description,
std::function<void(std::string)> fun) std::function<void(std::string)> fun)
@ -121,7 +122,7 @@ public:
.labels({label}) .labels({label})
.description(description) .description(description)
.arity(1) .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, void mkFlag(char shortName, const std::string & name,
@ -130,17 +131,6 @@ public:
mkFlag(shortName, name, description, dest, true); 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> template<class T>
void mkFlag(char shortName, const std::string & longName, const std::string & description, void mkFlag(char shortName, const std::string & longName, const std::string & description,
T * dest, const T & value) T * dest, const T & value)
@ -149,7 +139,7 @@ public:
.shortName(shortName) .shortName(shortName)
.longName(longName) .longName(longName)
.description(description) .description(description)
.handler([=](Strings ss) { *dest = value; }); .handler([=](std::vector<std::string> ss) { *dest = value; });
} }
template<class I> template<class I>
@ -171,10 +161,10 @@ public:
.labels({"N"}) .labels({"N"})
.description(description) .description(description)
.arity(1) .arity(1)
.handler([=](Strings ss) { .handler([=](std::vector<std::string> ss) {
I n; I n;
if (!string2Int(ss.front(), n)) if (!string2Int(ss[0], n))
throw UsageError(format("flag '--%1%' requires a integer argument") % longName); throw UsageError("flag '--%s' requires a integer argument", longName);
fun(n); fun(n);
}); });
} }
@ -182,16 +172,16 @@ public:
/* Expect a string argument. */ /* Expect a string argument. */
void expectArg(const std::string & label, string * dest, bool optional = false) void expectArg(const std::string & label, string * dest, bool optional = false)
{ {
expectedArgs.push_back(ExpectedArg{label, 1, optional, [=](Strings ss) { expectedArgs.push_back(ExpectedArg{label, 1, optional, [=](std::vector<std::string> ss) {
*dest = ss.front(); *dest = ss[0];
}}); }});
} }
/* Expect 0 or more arguments. */ /* 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) { expectedArgs.push_back(ExpectedArg{label, 0, false, [=](std::vector<std::string> ss) {
*dest = ss; *dest = std::move(ss);
}}); }});
} }

View file

@ -152,7 +152,7 @@ void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
.longName(name) .longName(name)
.description(description) .description(description)
.arity(1) .arity(1)
.handler([=](Strings ss) { set(*ss.begin()); }) .handler([=](std::vector<std::string> ss) { set(ss[0]); })
.category(category); .category(category);
} }
@ -201,12 +201,12 @@ template<> void BaseSetting<bool>::convertToArg(Args & args, const std::string &
args.mkFlag() args.mkFlag()
.longName(name) .longName(name)
.description(description) .description(description)
.handler([=](Strings ss) { value = true; }) .handler([=](std::vector<std::string> ss) { value = true; })
.category(category); .category(category);
args.mkFlag() args.mkFlag()
.longName("no-" + name) .longName("no-" + name)
.description(description) .description(description)
.handler([=](Strings ss) { value = false; }) .handler([=](std::vector<std::string> ss) { value = false; })
.category(category); .category(category);
} }

View file

@ -14,7 +14,7 @@
#include "eval.hh" #include "eval.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
#include "get-drvs.hh" #include "get-drvs.hh"
#include "common-opts.hh" #include "common-eval-args.hh"
#include "attr-path.hh" #include "attr-path.hh"
using namespace nix; using namespace nix;
@ -80,8 +80,6 @@ void mainWrapped(int argc, char * * argv)
auto interactive = isatty(STDIN_FILENO) && isatty(STDERR_FILENO); auto interactive = isatty(STDIN_FILENO) && isatty(STDERR_FILENO);
Strings attrPaths; Strings attrPaths;
Strings left; Strings left;
Strings searchPath;
std::map<string, string> autoArgs_;
RepairFlag repair = NoRepair; RepairFlag repair = NoRepair;
Path gcRoot; Path gcRoot;
BuildMode buildMode = bmNormal; BuildMode buildMode = bmNormal;
@ -129,7 +127,12 @@ void mainWrapped(int argc, char * * argv)
} catch (SysError &) { } } 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") { if (*arg == "--help") {
deletePath(tmpDir); deletePath(tmpDir);
showManPage(myName); showManPage(myName);
@ -153,12 +156,6 @@ void mainWrapped(int argc, char * * argv)
else if (*arg == "--out-link" || *arg == "-o") else if (*arg == "--out-link" || *arg == "-o")
outLink = getArg(*arg, arg, end); outLink = getArg(*arg, arg, end);
else if (parseAutoArgs(arg, end, autoArgs_))
;
else if (parseSearchPathArg(arg, end, searchPath))
;
else if (*arg == "--add-root") else if (*arg == "--add-root")
gcRoot = getArg(*arg, arg, end); gcRoot = getArg(*arg, arg, end);
@ -237,15 +234,17 @@ void mainWrapped(int argc, char * * argv)
return true; return true;
}); });
myArgs.parseCmdline(args);
if (packages && fromArgs) if (packages && fromArgs)
throw UsageError("'-p' and '-E' are mutually exclusive"); throw UsageError("'-p' and '-E' are mutually exclusive");
auto store = openStore(); auto store = openStore();
EvalState state(searchPath, store); EvalState state(myArgs.searchPath, store);
state.repair = repair; state.repair = repair;
Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); Bindings & autoArgs = *myArgs.getAutoArgs(state);
if (packages) { if (packages) {
std::ostringstream joined; std::ostringstream joined;

View file

@ -1,5 +1,5 @@
#include "attr-path.hh" #include "attr-path.hh"
#include "common-opts.hh" #include "common-eval-args.hh"
#include "derivations.hh" #include "derivations.hh"
#include "eval.hh" #include "eval.hh"
#include "get-drvs.hh" #include "get-drvs.hh"
@ -1309,8 +1309,7 @@ int main(int argc, char * * argv)
initNix(); initNix();
initGC(); initGC();
Strings opFlags, opArgs, searchPath; Strings opFlags, opArgs;
std::map<string, string> autoArgs_;
Operation op = 0; Operation op = 0;
RepairFlag repair = NoRepair; RepairFlag repair = NoRepair;
string file; string file;
@ -1326,7 +1325,12 @@ int main(int argc, char * * argv)
globals.removeAll = false; globals.removeAll = false;
globals.prebuiltOnly = 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; Operation oldOp = op;
if (*arg == "--help") if (*arg == "--help")
@ -1335,10 +1339,6 @@ int main(int argc, char * * argv)
op = opVersion; op = opVersion;
else if (*arg == "--install" || *arg == "-i") else if (*arg == "--install" || *arg == "-i")
op = opInstall; 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 else if (*arg == "--force-name") // undocumented flag for nix-install-package
globals.forceName = getArg(*arg, arg, end); globals.forceName = getArg(*arg, arg, end);
else if (*arg == "--uninstall" || *arg == "-e") else if (*arg == "--uninstall" || *arg == "-e")
@ -1391,17 +1391,19 @@ int main(int argc, char * * argv)
return true; return true;
}); });
myArgs.parseCmdline(argvToStrings(argc, argv));
if (!op) throw UsageError("no operation specified"); if (!op) throw UsageError("no operation specified");
auto store = openStore(); 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; globals.state->repair = repair;
if (file != "") if (file != "")
globals.instSource.nixExprPath = lookupFileArg(*globals.state, 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 == "") if (globals.profile == "")
globals.profile = getEnv("NIX_PROFILE", ""); globals.profile = getEnv("NIX_PROFILE", "");

View file

@ -8,7 +8,7 @@
#include "value-to-json.hh" #include "value-to-json.hh"
#include "util.hh" #include "util.hh"
#include "store-api.hh" #include "store-api.hh"
#include "common-opts.hh" #include "common-eval-args.hh"
#include <map> #include <map>
#include <iostream> #include <iostream>
@ -89,7 +89,7 @@ int main(int argc, char * * argv)
initNix(); initNix();
initGC(); initGC();
Strings files, searchPath; Strings files;
bool readStdin = false; bool readStdin = false;
bool fromArgs = false; bool fromArgs = false;
bool findFile = false; bool findFile = false;
@ -100,10 +100,14 @@ int main(int argc, char * * argv)
bool strict = false; bool strict = false;
Strings attrPaths; Strings attrPaths;
bool wantsReadWrite = false; bool wantsReadWrite = false;
std::map<string, string> autoArgs_;
RepairFlag repair = NoRepair; 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") if (*arg == "--help")
showManPage("nix-instantiate"); showManPage("nix-instantiate");
else if (*arg == "--version") else if (*arg == "--version")
@ -122,10 +126,6 @@ int main(int argc, char * * argv)
findFile = true; findFile = true;
else if (*arg == "--attr" || *arg == "-A") else if (*arg == "--attr" || *arg == "-A")
attrPaths.push_back(getArg(*arg, arg, end)); attrPaths.push_back(getArg(*arg, arg, end));
else if (parseAutoArgs(arg, end, autoArgs_))
;
else if (parseSearchPathArg(arg, end, searchPath))
;
else if (*arg == "--add-root") else if (*arg == "--add-root")
gcRoot = getArg(*arg, arg, end); gcRoot = getArg(*arg, arg, end);
else if (*arg == "--indirect") else if (*arg == "--indirect")
@ -149,15 +149,17 @@ int main(int argc, char * * argv)
return true; return true;
}); });
myArgs.parseCmdline(argvToStrings(argc, argv));
if (evalOnly && !wantsReadWrite) if (evalOnly && !wantsReadWrite)
settings.readOnlyMode = true; settings.readOnlyMode = true;
auto store = openStore(); auto store = openStore();
EvalState state(searchPath, store); EvalState state(myArgs.searchPath, store);
state.repair = repair; state.repair = repair;
Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); Bindings & autoArgs = *myArgs.getAutoArgs(state);
if (attrPaths.empty()) attrPaths = {""}; if (attrPaths.empty()) attrPaths = {""};

View file

@ -4,7 +4,7 @@
#include "store-api.hh" #include "store-api.hh"
#include "eval.hh" #include "eval.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
#include "common-opts.hh" #include "common-eval-args.hh"
#include "attr-path.hh" #include "attr-path.hh"
#include <iostream> #include <iostream>
@ -48,15 +48,18 @@ int main(int argc, char * * argv)
HashType ht = htSHA256; HashType ht = htSHA256;
std::vector<string> args; std::vector<string> args;
Strings searchPath;
bool printPath = getEnv("PRINT_PATH") != ""; bool printPath = getEnv("PRINT_PATH") != "";
bool fromExpr = false; bool fromExpr = false;
string attrPath; string attrPath;
std::map<string, string> autoArgs_;
bool unpack = false; bool unpack = false;
string name; 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") if (*arg == "--help")
showManPage("nix-prefetch-url"); showManPage("nix-prefetch-url");
else if (*arg == "--version") else if (*arg == "--version")
@ -77,10 +80,6 @@ int main(int argc, char * * argv)
unpack = true; unpack = true;
else if (*arg == "--name") else if (*arg == "--name")
name = getArg(*arg, arg, end); name = getArg(*arg, arg, end);
else if (parseAutoArgs(arg, end, autoArgs_))
;
else if (parseSearchPathArg(arg, end, searchPath))
;
else if (*arg != "" && arg->at(0) == '-') else if (*arg != "" && arg->at(0) == '-')
return false; return false;
else else
@ -88,13 +87,15 @@ int main(int argc, char * * argv)
return true; return true;
}); });
myArgs.parseCmdline(argvToStrings(argc, argv));
if (args.size() > 2) if (args.size() > 2)
throw UsageError("too many arguments"); throw UsageError("too many arguments");
auto store = openStore(); 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 /* If -A is given, get the URI from the specified Nix
expression. */ expression. */

View file

@ -24,11 +24,11 @@ void Command::printHelp(const string & programName, std::ostream & out)
MultiCommand::MultiCommand(const Commands & _commands) MultiCommand::MultiCommand(const Commands & _commands)
: 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); assert(!command);
auto i = commands.find(ss.front()); auto i = commands.find(ss[0]);
if (i == commands.end()) 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; command = i->second;
}}); }});
} }

View file

@ -1,10 +1,12 @@
#pragma once #pragma once
#include "args.hh" #include "args.hh"
#include "common-eval-args.hh"
namespace nix { namespace nix {
struct Value; struct Value;
struct Bindings;
class EvalState; class EvalState;
/* A command is an argument parser that can be executed by calling its /* 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; Path file;
SourceExprCommand() SourceExprCommand();
{
mkFlag('f', "file", "file", "evaluate FILE rather than the default", &file);
}
/* Return a value representing the Nix expression from which we /* Return a value representing the Nix expression from which we
are installing. This is either the file specified by --file, are installing. This is either the file specified by --file,
@ -111,7 +110,7 @@ struct InstallablesCommand : virtual Args, SourceExprCommand
private: private:
Strings _installables; std::vector<std::string> _installables;
}; };
struct InstallableCommand : virtual Args, SourceExprCommand struct InstallableCommand : virtual Args, SourceExprCommand

View file

@ -19,8 +19,16 @@ struct CmdCopy : StorePathsCommand
CmdCopy() CmdCopy()
: StorePathsCommand(true) : StorePathsCommand(true)
{ {
mkFlag(0, "from", "store-uri", "URI of the source Nix store", &srcUri); mkFlag()
mkFlag(0, "to", "store-uri", "URI of the destination Nix store", &dstUri); .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() mkFlag()
.longName("no-check-sigs") .longName("no-check-sigs")

View file

@ -12,14 +12,16 @@ struct CmdHash : Command
Base base = Base16; Base base = Base16;
bool truncate = false; bool truncate = false;
HashType ht = htSHA512; HashType ht = htSHA512;
Strings paths; std::vector<std::string> paths;
CmdHash(Mode mode) : mode(mode) CmdHash(Mode mode) : mode(mode)
{ {
mkFlag(0, "base64", "print hash in base-64", &base, Base64); mkFlag(0, "base64", "print hash in base-64", &base, Base64);
mkFlag(0, "base32", "print hash in base-32 (Nix-specific)", &base, Base32); mkFlag(0, "base32", "print hash in base-32 (Nix-specific)", &base, Base32);
mkFlag(0, "base16", "print hash in base-16", &base, Base16); mkFlag(0, "base16", "print hash in base-16", &base, Base16);
mkHashTypeFlag("type", &ht); mkFlag()
.longName("type")
.mkHashTypeFlag(&ht);
expectArgs("paths", &paths); expectArgs("paths", &paths);
} }
@ -53,11 +55,13 @@ struct CmdToBase : Command
{ {
Base base; Base base;
HashType ht = htSHA512; HashType ht = htSHA512;
Strings args; std::vector<std::string> args;
CmdToBase(Base base) : base(base) CmdToBase(Base base) : base(base)
{ {
mkHashTypeFlag("type", &ht); mkFlag()
.longName("type")
.mkHashTypeFlag(&ht);
expectArgs("strings", &args); expectArgs("strings", &args);
} }
@ -95,7 +99,7 @@ static int compatNixHash(int argc, char * * argv)
bool base32 = false; bool base32 = false;
bool truncate = false; bool truncate = false;
enum { opHash, opTo32, opTo16 } op = opHash; enum { opHash, opTo32, opTo16 } op = opHash;
Strings ss; std::vector<std::string> ss;
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
if (*arg == "--help") if (*arg == "--help")

View file

@ -1,6 +1,6 @@
#include "command.hh" #include "command.hh"
#include "attr-path.hh" #include "attr-path.hh"
#include "common-opts.hh" #include "common-eval-args.hh"
#include "derivations.hh" #include "derivations.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
#include "eval.hh" #include "eval.hh"
@ -12,6 +12,16 @@
namespace nix { 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) Value * SourceExprCommand::getSourceExpr(EvalState & state)
{ {
if (vSourceExpr) return vSourceExpr; if (vSourceExpr) return vSourceExpr;
@ -66,7 +76,7 @@ Value * SourceExprCommand::getSourceExpr(EvalState & state)
ref<EvalState> SourceExprCommand::getEvalState() ref<EvalState> SourceExprCommand::getEvalState()
{ {
if (!evalState) if (!evalState)
evalState = std::make_shared<EvalState>(Strings{}, getStore()); evalState = std::make_shared<EvalState>(searchPath, getStore());
return ref<EvalState>(evalState); return ref<EvalState>(evalState);
} }
@ -120,9 +130,7 @@ struct InstallableValue : Installable
auto v = toValue(*state); auto v = toValue(*state);
// FIXME Bindings & autoArgs = *cmd.getAutoArgs(*state);
std::map<string, string> autoArgs_;
Bindings & autoArgs(*evalAutoArgs(*state, autoArgs_));
DrvInfos drvs; DrvInfos drvs;
getDerivations(*state, *v, "", autoArgs, drvs, false); getDerivations(*state, *v, "", autoArgs, drvs, false);
@ -187,9 +195,7 @@ struct InstallableAttrPath : InstallableValue
{ {
auto source = cmd.getSourceExpr(state); auto source = cmd.getSourceExpr(state);
// FIXME Bindings & autoArgs = *cmd.getAutoArgs(state);
std::map<string, string> autoArgs_;
Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
Value * v = findAlongAttrPath(state, attrPath, autoArgs, *source); Value * v = findAlongAttrPath(state, attrPath, autoArgs, *source);
state.forceValue(*v); 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::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex));
static std::vector<std::shared_ptr<Installable>> parseInstallables( 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; std::vector<std::shared_ptr<Installable>> result;
if (ss.empty() && useDefaultInstallables) { if (ss.empty() && useDefaultInstallables) {
if (cmd.file == "") if (cmd.file == "")
cmd.file = "."; cmd.file = ".";
ss = Strings{""}; ss = {""};
} }
for (auto & s : ss) { for (auto & s : ss) {

View file

@ -20,9 +20,16 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
{ {
NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix") 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", [=]() { mkFlag()
.longName("help-config")
.description("show configuration options")
.handler([&]() {
std::cout << "The following configuration options are available:\n\n"; std::cout << "The following configuration options are available:\n\n";
Table2 tbl; Table2 tbl;
for (const auto & s : settings._getSettings()) for (const auto & s : settings._getSettings())
@ -32,7 +39,10 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
throw Exit(); 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"; std::string cat = "config";
settings.convertToArgs(*this, cat); settings.convertToArgs(*this, cat);

View file

@ -7,7 +7,7 @@
#include "eval.hh" #include "eval.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
#include "store-api.hh" #include "store-api.hh"
#include "common-opts.hh" #include "common-eval-args.hh"
#include "get-drvs.hh" #include "get-drvs.hh"
#include "derivations.hh" #include "derivations.hh"
#include "affinity.hh" #include "affinity.hh"
@ -44,7 +44,7 @@ struct NixRepl
NixRepl(const Strings & searchPath, nix::ref<Store> store); NixRepl(const Strings & searchPath, nix::ref<Store> store);
~NixRepl(); ~NixRepl();
void mainLoop(const Strings & files); void mainLoop(const std::vector<std::string> & files);
StringSet completePrefix(string prefix); StringSet completePrefix(string prefix);
bool getLine(string & input, const std::string &prompt); bool getLine(string & input, const std::string &prompt);
Path getDerivationPath(Value & v); 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 " "; string error = ANSI_RED "error:" ANSI_NORMAL " ";
std::cout << "Welcome to Nix version " << nixVersion << ". Type :? for help." << std::endl << std::endl; 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; return str;
} }
struct CmdRepl : StoreCommand struct CmdRepl : StoreCommand, MixEvalArgs
{ {
Strings files; std::vector<std::string> files;
CmdRepl() CmdRepl()
{ {
@ -682,8 +682,7 @@ struct CmdRepl : StoreCommand
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
// FIXME: pass searchPath NixRepl repl(searchPath, openStore());
NixRepl repl({}, openStore());
repl.mainLoop(files); repl.mainLoop(files);
} }
}; };

View file

@ -20,7 +20,7 @@ extern char * * environ;
struct CmdRun : InstallablesCommand struct CmdRun : InstallablesCommand
{ {
Strings command = { "bash" }; std::vector<std::string> command = { "bash" };
StringSet keep, unset; StringSet keep, unset;
bool ignoreEnvironment = false; bool ignoreEnvironment = false;
@ -32,7 +32,7 @@ struct CmdRun : InstallablesCommand
.description("command and arguments to be executed; defaults to 'bash'") .description("command and arguments to be executed; defaults to 'bash'")
.arity(ArityAny) .arity(ArityAny)
.labels({"command", "args"}) .labels({"command", "args"})
.handler([&](Strings ss) { .handler([&](std::vector<std::string> ss) {
if (ss.empty()) throw UsageError("--command requires at least one argument"); if (ss.empty()) throw UsageError("--command requires at least one argument");
command = ss; command = ss;
}); });
@ -49,7 +49,7 @@ struct CmdRun : InstallablesCommand
.description("keep specified environment variable") .description("keep specified environment variable")
.arity(1) .arity(1)
.labels({"name"}) .labels({"name"})
.handler([&](Strings ss) { keep.insert(ss.front()); }); .handler([&](std::vector<std::string> ss) { keep.insert(ss.front()); });
mkFlag() mkFlag()
.longName("unset") .longName("unset")
@ -57,7 +57,7 @@ struct CmdRun : InstallablesCommand
.description("unset specified environment variable") .description("unset specified environment variable")
.arity(1) .arity(1)
.labels({"name"}) .labels({"name"})
.handler([&](Strings ss) { unset.insert(ss.front()); }); .handler([&](std::vector<std::string> ss) { unset.insert(ss.front()); });
} }
std::string name() override std::string name() override
@ -126,7 +126,8 @@ struct CmdRun : InstallablesCommand
setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1); setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1);
std::string cmd = *command.begin(); std::string cmd = *command.begin();
Strings args = command; Strings args;
for (auto & arg : command) args.push_back(arg);
stopProgressBar(); stopProgressBar();

View file

@ -38,12 +38,12 @@ struct CmdSearch : SourceExprCommand, MixJSON
.longName("update-cache") .longName("update-cache")
.shortName('u') .shortName('u')
.description("update the package search cache") .description("update the package search cache")
.handler([&](Strings ss) { writeCache = true; useCache = false; }); .handler([&]() { writeCache = true; useCache = false; });
mkFlag() mkFlag()
.longName("no-cache") .longName("no-cache")
.description("do not use or update the package search 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 std::string name() override

View file

@ -19,7 +19,7 @@ struct CmdCopySigs : StorePathsCommand
.labels({"store-uri"}) .labels({"store-uri"})
.description("use signatures from specified store") .description("use signatures from specified store")
.arity(1) .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 std::string name() override
@ -101,7 +101,12 @@ struct CmdSignPaths : StorePathsCommand
CmdSignPaths() 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 std::string name() override

View file

@ -25,7 +25,7 @@ struct CmdVerify : StorePathsCommand
.labels({"store-uri"}) .labels({"store-uri"})
.description("use signatures from specified store") .description("use signatures from specified store")
.arity(1) .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); mkIntFlag('n', "sigs-needed", "require that each path has at least N valid signatures", &sigsNeeded);
} }