summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/cli.nix56
-rw-r--r--lib/default.nix2
-rw-r--r--lib/tests/misc.nix21
3 files changed, 79 insertions, 0 deletions
diff --git a/lib/cli.nix b/lib/cli.nix
new file mode 100644
index 000000000000..f47625d2f537
--- /dev/null
+++ b/lib/cli.nix
@@ -0,0 +1,56 @@
+{ lib }:
+
+rec {
+ /* Automatically convert an attribute set to command-line options.
+
+ 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;
+
+ 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 =
+ options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
+
+ toGNUCommandLine =
+ { renderKey ?
+ key: if builtins.stringLength key == 1 then "-${key}" else "--${key}"
+
+ , renderOption ?
+ key: value:
+ if value == null
+ then []
+ else [ (renderKey key) (builtins.toString value) ]
+
+ , renderBool ? key: value: lib.optional value (renderKey key)
+
+ , renderList ? key: value: lib.concatMap (renderOption key) value
+ }:
+ 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;
+
+ in
+ builtins.concatLists (lib.mapAttrsToList render options);
+}
diff --git a/lib/default.nix b/lib/default.nix
index 77dda17f3b4f..5abafe1b2acf 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -39,6 +39,7 @@ let
# misc
asserts = callLibs ./asserts.nix;
+ cli = callLibs ./cli.nix;
debug = callLibs ./debug.nix;
generators = callLibs ./generators.nix;
misc = callLibs ./deprecated.nix;
@@ -120,6 +121,7 @@ let
isOptionType mkOptionType;
inherit (asserts)
assertMsg assertOneOf;
+ inherit (cli) encodeGNUCommandLine toGNUCommandLine;
inherit (debug) addErrorContextToAttrs traceIf traceVal traceValFn
traceXMLVal traceXMLValMarked traceSeq traceSeqN traceValSeq
traceValSeqFn traceValSeqN traceValSeqNFn traceShowVal
diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix
index b064faa1e1ba..e47b48b5017d 100644
--- a/lib/tests/misc.nix
+++ b/lib/tests/misc.nix
@@ -441,4 +441,25 @@ runTests {
expected = "«foo»";
};
+ testRenderOptions = {
+ expr =
+ encodeGNUCommandLine
+ { }
+ { 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;
+ };
+
+ expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
+ };
}