Merge pull request #300257 from mschwaig/fix-mivisionx
[NixPkgs.git] / lib / cli.nix
blobfcffacb5ea9966a63e06f4759dd4053319581ec5
1 { lib }:
3 rec {
4   /**
5     Automatically convert an attribute set to command-line options.
7     This helps protect against malformed command lines and also to reduce
8     boilerplate related to command-line construction for simple use cases.
10     `toGNUCommandLine` returns a list of nix strings.
12     `toGNUCommandLineShell` returns an escaped shell string.
15     # Inputs
17     `options`
19     : 1\. Function argument
21     `attrs`
23     : 2\. Function argument
26     # Examples
27     :::{.example}
28     ## `lib.cli.toGNUCommandLineShell` usage example
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     ]
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     ```
61     :::
62   */
63   toGNUCommandLineShell =
64     options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
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}",
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),
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,
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;
102       in
103         builtins.concatLists (lib.mapAttrsToList render options);