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