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 `toGNUCommandLineShell` returns an escaped shell string.
11
12
13 # Inputs
14
15 `options`
16
17 : How to format the arguments, see `toGNUCommandLine`
18
19 `attrs`
20
21 : The attributes to transform into arguments.
22
23
24 # Examples
25 :::{.example}
26 ## `lib.cli.toGNUCommandLineShell` usage example
27
28 ```nix
29 cli.toGNUCommandLineShell {} {
30 data = builtins.toJSON { id = 0; };
31 X = "PUT";
32 retry = 3;
33 retry-delay = null;
34 url = [ "https://example.com/foo" "https://example.com/bar" ];
35 silent = false;
36 verbose = true;
37 }
38 => "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
39 ```
40
41 :::
42 */
43 toGNUCommandLineShell =
44 options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
45
46 /**
47 Automatically convert an attribute set to a list of command-line options.
48
49 `toGNUCommandLine` returns a list of string arguments.
50
51
52 # Inputs
53
54 `options`
55
56 : How to format the arguments, see below.
57
58 `attrs`
59
60 : The attributes to transform into arguments.
61
62 # Options
63
64 `mkOptionName`
65
66 : How to string-format the option name;
67 By default one character is a short option (`-`), more than one characters a long option (`--`).
68
69 `mkBool`
70
71 : How to format a boolean value to a command list;
72 By default it’s a flag option (only the option name if true, left out completely if false).
73
74 `mkList`
75
76 : How to format a list value to a command list;
77 By default the option name is repeated for each value and `mkOption` is applied to the values themselves.
78
79
80 `mkOption`
81
82 : How to format any remaining value to a command list;
83 On the toplevel, booleans and lists are handled by `mkBool` and `mkList`, though they can still appear as values of a list.
84 By default, everything is printed verbatim and complex types are forbidden (lists, attrsets, functions). `null` values are omitted.
85
86 `optionValueSeparator`
87
88 : How to separate an option from its flag;
89 By default, there is no separator, so option `-c` and value `5` would become ["-c" "5"].
90 This is useful if the command requires equals, for example, `-c=5`.
91
92
93 # Examples
94 :::{.example}
95 ## `lib.cli.toGNUCommandLine` usage example
96
97 ```nix
98 cli.toGNUCommandLine {} {
99 data = builtins.toJSON { id = 0; };
100 X = "PUT";
101 retry = 3;
102 retry-delay = null;
103 url = [ "https://example.com/foo" "https://example.com/bar" ];
104 silent = false;
105 verbose = true;
106 }
107 => [
108 "-X" "PUT"
109 "--data" "{\"id\":0}"
110 "--retry" "3"
111 "--url" "https://example.com/foo"
112 "--url" "https://example.com/bar"
113 "--verbose"
114 ]
115 ```
116
117 :::
118 */
119 toGNUCommandLine = {
120 mkOptionName ?
121 k: if builtins.stringLength k == 1
122 then "-${k}"
123 else "--${k}",
124
125 mkBool ? k: v: lib.optional v (mkOptionName k),
126
127 mkList ? k: v: lib.concatMap (mkOption k) v,
128
129 mkOption ?
130 k: v: if v == null
131 then []
132 else if optionValueSeparator == null then
133 [ (mkOptionName k) (lib.generators.mkValueStringDefault {} v) ]
134 else
135 [ "${mkOptionName k}${optionValueSeparator}${lib.generators.mkValueStringDefault {} v}" ],
136
137 optionValueSeparator ? null
138 }:
139 options:
140 let
141 render = k: v:
142 if builtins.isBool v then mkBool k v
143 else if builtins.isList v then mkList k v
144 else mkOption k v;
145
146 in
147 builtins.concatLists (lib.mapAttrsToList render options);
148}