1{ lib }:
2
3rec {
4 /**
5 Automatically convert an attribute set to command-line options.
6
7 This helps protect against malformed command lines and also to reduce
8 boilerplate related to command-line construction for simple use cases.
9
10 `toGNUCommandLine` returns a list of nix strings.
11
12 `toGNUCommandLineShell` returns an escaped shell string.
13
14
15 # Inputs
16
17 `options`
18
19 : 1\. Function argument
20
21 `attrs`
22
23 : 2\. Function argument
24
25
26 # Examples
27 :::{.example}
28 ## `lib.cli.toGNUCommandLineShell` usage example
29
30 ```nix
31 cli.toGNUCommandLine {} {
32 data = builtins.toJSON { id = 0; };
33 X = "PUT";
34 retry = 3;
35 retry-delay = null;
36 url = [ "https://example.com/foo" "https://example.com/bar" ];
37 silent = false;
38 verbose = true;
39 }
40 => [
41 "-X" "PUT"
42 "--data" "{\"id\":0}"
43 "--retry" "3"
44 "--url" "https://example.com/foo"
45 "--url" "https://example.com/bar"
46 "--verbose"
47 ]
48
49 cli.toGNUCommandLineShell {} {
50 data = builtins.toJSON { id = 0; };
51 X = "PUT";
52 retry = 3;
53 retry-delay = null;
54 url = [ "https://example.com/foo" "https://example.com/bar" ];
55 silent = false;
56 verbose = true;
57 }
58 => "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
59 ```
60
61 :::
62 */
63 toGNUCommandLineShell =
64 options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
65
66 toGNUCommandLine = {
67 # how to string-format the option name;
68 # by default one character is a short option (`-`),
69 # more than one characters a long option (`--`).
70 mkOptionName ?
71 k: if builtins.stringLength k == 1
72 then "-${k}"
73 else "--${k}",
74
75 # how to format a boolean value to a command list;
76 # by default it’s a flag option
77 # (only the option name if true, left out completely if false).
78 mkBool ? k: v: lib.optional v (mkOptionName k),
79
80 # how to format a list value to a command list;
81 # by default the option name is repeated for each value
82 # and `mkOption` is applied to the values themselves.
83 mkList ? k: v: lib.concatMap (mkOption k) v,
84
85 # how to format any remaining value to a command list;
86 # on the toplevel, booleans and lists are handled by `mkBool` and `mkList`,
87 # though they can still appear as values of a list.
88 # By default, everything is printed verbatim and complex types
89 # are forbidden (lists, attrsets, functions). `null` values are omitted.
90 mkOption ?
91 k: v: if v == null
92 then []
93 else [ (mkOptionName k) (lib.generators.mkValueStringDefault {} v) ]
94 }:
95 options:
96 let
97 render = k: v:
98 if builtins.isBool v then mkBool k v
99 else if builtins.isList v then mkList k v
100 else mkOption k v;
101
102 in
103 builtins.concatLists (lib.mapAttrsToList render options);
104}