at 24.11-pre 3.0 kB view raw
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}