about summary refs log tree commit diff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/args.cc26
-rw-r--r--src/libutil/args.hh83
-rw-r--r--src/libutil/config.cc29
-rw-r--r--src/libutil/config.hh6
4 files changed, 101 insertions, 43 deletions
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index 115484f9e6c7..df7e040875d6 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -3,6 +3,18 @@
 
 namespace nix {
 
+Args::FlagMaker Args::mkFlag()
+{
+    return FlagMaker(*this);
+}
+
+Args::FlagMaker::~FlagMaker()
+{
+    assert(flag->longName != "");
+    args.longFlags[flag->longName] = flag;
+    if (flag->shortName) args.shortFlags[flag->shortName] = flag;
+}
+
 void Args::parseCmdline(const Strings & _cmdline)
 {
     Strings pendingArgs;
@@ -71,11 +83,13 @@ void Args::printHelp(const string & programName, std::ostream & out)
 void Args::printFlags(std::ostream & out)
 {
     Table2 table;
-    for (auto & flag : longFlags)
+    for (auto & flag : longFlags) {
+        if (hiddenCategories.count(flag.second->category)) continue;
         table.push_back(std::make_pair(
-                (flag.second.shortName ? std::string("-") + flag.second.shortName + ", " : "    ")
-                + "--" + flag.first + renderLabels(flag.second.labels),
-                flag.second.description));
+                (flag.second->shortName ? std::string("-") + flag.second->shortName + ", " : "    ")
+                + "--" + flag.first + renderLabels(flag.second->labels),
+                flag.second->description));
+    }
     printTable(out, table);
 }
 
@@ -99,14 +113,14 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
     if (string(*pos, 0, 2) == "--") {
         auto i = longFlags.find(string(*pos, 2));
         if (i == longFlags.end()) return false;
-        return process("--" + i->first, i->second);
+        return process("--" + i->first, *i->second);
     }
 
     if (string(*pos, 0, 1) == "-" && pos->size() == 2) {
         auto c = (*pos)[1];
         auto i = shortFlags.find(c);
         if (i == shortFlags.end()) return false;
-        return process(std::string("-") + c, i->second);
+        return process(std::string("-") + c, *i->second);
     }
 
     return false;
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index f70bb7823dc0..aa11373d5f1f 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -29,15 +29,18 @@ protected:
     /* Flags. */
     struct Flag
     {
-        char shortName;
+        typedef std::shared_ptr<Flag> ptr;
+        std::string longName;
+        char shortName = 0;
         std::string description;
         Strings labels;
-        size_t arity;
+        size_t arity = 0;
         std::function<void(Strings)> handler;
+        std::string category;
     };
 
-    std::map<std::string, Flag> longFlags;
-    std::map<char, Flag> shortFlags;
+    std::map<std::string, Flag::ptr> longFlags;
+    std::map<char, Flag::ptr> shortFlags;
 
     virtual bool processFlag(Strings::iterator & pos, Strings::iterator end);
 
@@ -55,33 +58,53 @@ protected:
 
     virtual bool processArgs(const Strings & args, bool finish);
 
+    std::set<std::string> hiddenCategories;
+
 public:
 
+    class FlagMaker
+    {
+        Args & args;
+        Flag::ptr flag;
+        friend class Args;
+        FlagMaker(Args & args) : args(args), flag(std::make_shared<Flag>()) { };
+    public:
+        ~FlagMaker();
+        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 & arity(size_t arity) { flag->arity = arity; return *this; };
+        FlagMaker & handler(std::function<void(Strings)> handler) { flag->handler = handler; return *this; };
+        FlagMaker & category(const std::string & s) { flag->category = s; return *this; };
+    };
+
+    FlagMaker mkFlag();
+
     /* Helper functions for constructing flags / positional
        arguments. */
 
     void mkFlag(char shortName, const std::string & longName,
-        const Strings & labels, const std::string & description,
-        size_t arity, std::function<void(Strings)> handler)
-    {
-        auto flag = Flag{shortName, description, labels, arity, handler};
-        if (shortName) shortFlags[shortName] = flag;
-        longFlags[longName] = flag;
-    }
-
-    void mkFlag(char shortName, const std::string & longName,
         const std::string & description, std::function<void()> fun)
     {
-        mkFlag(shortName, longName, {}, description, 0, std::bind(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)
     {
-        mkFlag(shortName, longName, {label}, description, 1, [=](Strings ss) {
-            fun(ss.front());
-        });
+        mkFlag()
+            .shortName(shortName)
+            .longName(longName)
+            .labels({label})
+            .description(description)
+            .arity(1)
+            .handler([=](Strings ss) { fun(ss.front()); });
     }
 
     void mkFlag(char shortName, const std::string & name,
@@ -105,9 +128,11 @@ public:
     void mkFlag(char shortName, const std::string & longName, const std::string & description,
         T * dest, const T & value)
     {
-        mkFlag(shortName, longName, {}, description, 0, [=](Strings ss) {
-            *dest = value;
-        });
+        mkFlag()
+            .shortName(shortName)
+            .longName(longName)
+            .description(description)
+            .handler([=](Strings ss) { *dest = value; });
     }
 
     template<class I>
@@ -123,12 +148,18 @@ public:
     void mkFlag(char shortName, const std::string & longName,
         const std::string & description, std::function<void(I)> fun)
     {
-        mkFlag(shortName, longName, {"N"}, description, 1, [=](Strings ss) {
-            I n;
-            if (!string2Int(ss.front(), n))
-                throw UsageError(format("flag ‘--%1%’ requires a integer argument") % longName);
-            fun(n);
-        });
+        mkFlag()
+            .shortName(shortName)
+            .longName(longName)
+            .labels({"N"})
+            .description(description)
+            .arity(1)
+            .handler([=](Strings ss) {
+                I n;
+                if (!string2Int(ss.front(), n))
+                    throw UsageError(format("flag ‘--%1%’ requires a integer argument") % longName);
+                fun(n);
+            });
     }
 
     /* Expect a string argument. */
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index 612fb6e68350..0682bcd5dbc3 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -115,11 +115,11 @@ void Config::toJSON(JSONObject & out)
         }
 }
 
-void Config::convertToArgs(Args & args)
+void Config::convertToArgs(Args & args, const std::string & category)
 {
     for (auto & s : _settings)
         if (!s.second.isAlias)
-            s.second.setting->convertToArg(args);
+            s.second.setting->convertToArg(args, category);
 }
 
 AbstractSetting::AbstractSetting(
@@ -135,7 +135,7 @@ void AbstractSetting::toJSON(JSONPlaceholder & out)
     out.write(to_string());
 }
 
-void AbstractSetting::convertToArg(Args & args)
+void AbstractSetting::convertToArg(Args & args, const std::string & category)
 {
 }
 
@@ -146,9 +146,14 @@ void BaseSetting<T>::toJSON(JSONPlaceholder & out)
 }
 
 template<typename T>
-void BaseSetting<T>::convertToArg(Args & args)
+void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
 {
-    args.mkFlag(0, name, {}, description, 1, [=](Strings ss) { set(*ss.begin()); });
+    args.mkFlag()
+        .longName(name)
+        .description(description)
+        .arity(1)
+        .handler([=](Strings ss) { set(*ss.begin()); })
+        .category(category);
 }
 
 template<> void BaseSetting<std::string>::set(const std::string & str)
@@ -191,10 +196,18 @@ template<> std::string BaseSetting<bool>::to_string()
     return value ? "true" : "false";
 }
 
-template<> void BaseSetting<bool>::convertToArg(Args & args)
+template<> void BaseSetting<bool>::convertToArg(Args & args, const std::string & category)
 {
-    args.mkFlag(0, name, {}, description, 0, [=](Strings ss) { value = true; });
-    args.mkFlag(0, "no-" + name, {}, description, 0, [=](Strings ss) { value = false; });
+    args.mkFlag()
+        .longName(name)
+        .description(description)
+        .handler([=](Strings ss) { value = true; })
+        .category(category);
+    args.mkFlag()
+        .longName("no-" + name)
+        .description(description)
+        .handler([=](Strings ss) { value = false; })
+        .category(category);
 }
 
 template<> void BaseSetting<Strings>::set(const std::string & str)
diff --git a/src/libutil/config.hh b/src/libutil/config.hh
index 994eab911707..99850c1cdfd5 100644
--- a/src/libutil/config.hh
+++ b/src/libutil/config.hh
@@ -72,7 +72,7 @@ public:
 
     void toJSON(JSONObject & out);
 
-    void convertToArgs(Args & args);
+    void convertToArgs(Args & args, const std::string & category);
 };
 
 class AbstractSetting
@@ -109,7 +109,7 @@ protected:
 
     virtual void toJSON(JSONPlaceholder & out);
 
-    virtual void convertToArg(Args & args);
+    virtual void convertToArg(Args & args, const std::string & category);
 
     bool isOverriden() { return overriden; }
 };
@@ -144,7 +144,7 @@ public:
 
     std::string to_string() override;
 
-    void convertToArg(Args & args) override;
+    void convertToArg(Args & args, const std::string & category) override;
 
     void toJSON(JSONPlaceholder & out) override;
 };