summary refs log tree commit diff
path: root/lib/cli.nix
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cli.nix')
-rw-r--r--lib/cli.nix93
1 files changed, 60 insertions, 33 deletions
diff --git a/lib/cli.nix b/lib/cli.nix
index f47625d2f53..c96d4dbb043 100644
--- a/lib/cli.nix
+++ b/lib/cli.nix
@@ -6,50 +6,77 @@ rec {
      This helps protect against malformed command lines and also to reduce
      boilerplate related to command-line construction for simple use cases.
 
-     Example:
-       encodeGNUCommandLine
-         { }
-         { data = builtins.toJSON { id = 0; };
-
-           X = "PUT";
-
-           retry = 3;
+     `toGNUCommandLine` returns a list of nix strings.
+     `toGNUCommandLineShell` returns an escaped shell string.
 
-           retry-delay = null;
-
-           url = [ "https://example.com/foo" "https://example.com/bar" ];
-
-           silent = false;
+     Example:
+       cli.toGNUCommandLine {} {
+         data = builtins.toJSON { id = 0; };
+         X = "PUT";
+         retry = 3;
+         retry-delay = null;
+         url = [ "https://example.com/foo" "https://example.com/bar" ];
+         silent = false;
+         verbose = true;
+       }
+       => [
+         "-X" "PUT"
+         "--data" "{\"id\":0}"
+         "--retry" "3"
+         "--url" "https://example.com/foo"
+         "--url" "https://example.com/bar"
+         "--verbose"
+       ]
 
-           verbose = true;
-         };
-       => "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'"
+       cli.toGNUCommandLineShell {} {
+         data = builtins.toJSON { id = 0; };
+         X = "PUT";
+         retry = 3;
+         retry-delay = null;
+         url = [ "https://example.com/foo" "https://example.com/bar" ];
+         silent = false;
+         verbose = true;
+       }
+       => "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
   */
-  encodeGNUCommandLine =
+  toGNUCommandLineShell =
     options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
 
-  toGNUCommandLine =
-    { renderKey ?
-        key: if builtins.stringLength key == 1 then "-${key}" else "--${key}"
+  toGNUCommandLine = {
+    # how to string-format the option name;
+    # by default one character is a short option (`-`),
+    # more than one characters a long option (`--`).
+    mkOptionName ?
+      k: if builtins.stringLength k == 1
+          then "-${k}"
+          else "--${k}",
 
-    , renderOption ?
-        key: value:
-          if value == null
-          then []
-          else [ (renderKey key) (builtins.toString value) ]
+    # how to format a boolean value to a command list;
+    # by default it’s a flag option
+    # (only the option name if true, left out completely if false).
+    mkBool ? k: v: lib.optional v (mkOptionName k),
 
-    , renderBool ? key: value: lib.optional value (renderKey key)
+    # how to format a list value to a command list;
+    # by default the option name is repeated for each value
+    # and `mkOption` is applied to the values themselves.
+    mkList ? k: v: lib.concatMap (mkOption k) v,
 
-    , renderList ? key: value: lib.concatMap (renderOption key) value
+    # how to format any remaining value to a command list;
+    # on the toplevel, booleans and lists are handled by `mkBool` and `mkList`,
+    # though they can still appear as values of a list.
+    # By default, everything is printed verbatim and complex types
+    # are forbidden (lists, attrsets, functions). `null` values are omitted.
+    mkOption ?
+      k: v: if v == null
+            then []
+            else [ (mkOptionName k) (lib.generators.mkValueStringDefault {} v) ]
     }:
     options:
       let
-        render = key: value:
-                 if builtins.isBool value
-            then renderBool key value
-            else if builtins.isList value
-            then renderList key value
-            else renderOption key value;
+        render = k: v:
+          if      builtins.isBool v then mkBool k v
+          else if builtins.isList v then mkList k v
+          else mkOption k v;
 
       in
         builtins.concatLists (lib.mapAttrsToList render options);