mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-11-09 16:18:34 +01:00
340 lines
8.6 KiB
Nix
340 lines
8.6 KiB
Nix
{ lib }:
|
||
|
||
{
|
||
/**
|
||
Automatically convert an attribute set to command-line options.
|
||
|
||
This helps protect against malformed command lines and also to reduce
|
||
boilerplate related to command-line construction for simple use cases.
|
||
|
||
`toGNUCommandLineShell` returns an escaped shell string.
|
||
|
||
# Inputs
|
||
|
||
`options`
|
||
|
||
: How to format the arguments, see `toGNUCommandLine`
|
||
|
||
`attrs`
|
||
|
||
: The attributes to transform into arguments.
|
||
|
||
# Examples
|
||
|
||
:::{.example}
|
||
## `lib.cli.toGNUCommandLineShell` usage example
|
||
|
||
```nix
|
||
cli.toGNUCommandLineShell {} {
|
||
data = builtins.toJSON { id = 0; };
|
||
X = "PUT";
|
||
retry = 3;
|
||
retry-delay = null;
|
||
url = [ "https://example.com/foo" "https://example.com/bar" ];
|
||
silent = false;
|
||
verbose = true;
|
||
}
|
||
=> "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
|
||
```
|
||
|
||
:::
|
||
*/
|
||
toGNUCommandLineShell =
|
||
lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2511)
|
||
"lib.cli.toGNUCommandLineShell is deprecated, please use lib.cli.toCommandLineShell or lib.cli.toCommandLineShellGNU instead."
|
||
(options: attrs: lib.escapeShellArgs (lib.cli.toGNUCommandLine options attrs));
|
||
|
||
/**
|
||
Automatically convert an attribute set to a list of command-line options.
|
||
|
||
`toGNUCommandLine` returns a list of string arguments.
|
||
|
||
# Inputs
|
||
|
||
`options`
|
||
|
||
: How to format the arguments, see below.
|
||
|
||
`attrs`
|
||
|
||
: The attributes to transform into arguments.
|
||
|
||
## Options
|
||
|
||
`mkOptionName`
|
||
|
||
: How to string-format the option name;
|
||
By default one character is a short option (`-`), more than one characters a long option (`--`).
|
||
|
||
`mkBool`
|
||
|
||
: How to format a boolean value to a command list;
|
||
By default it’s a flag option (only the option name if true, left out completely if false).
|
||
|
||
`mkList`
|
||
|
||
: How to format a list value to a command list;
|
||
By default the option name is repeated for each value and `mkOption` is applied to the values themselves.
|
||
|
||
`mkOption`
|
||
|
||
: How to format any remaining value to a command list;
|
||
On the toplevel, booleans and lists are handled by `mkBool` and `mkList`, though they can still appear as values of a list.
|
||
By default, everything is printed verbatim and complex types are forbidden (lists, attrsets, functions). `null` values are omitted.
|
||
|
||
`optionValueSeparator`
|
||
|
||
: How to separate an option from its flag;
|
||
By default, there is no separator, so option `-c` and value `5` would become ["-c" "5"].
|
||
This is useful if the command requires equals, for example, `-c=5`.
|
||
|
||
# Examples
|
||
|
||
:::{.example}
|
||
## `lib.cli.toGNUCommandLine` usage example
|
||
|
||
```nix
|
||
cli.toGNUCommandLine {} {
|
||
data = builtins.toJSON { id = 0; };
|
||
X = "PUT";
|
||
retry = 3;
|
||
retry-delay = null;
|
||
url = [ "https://example.com/foo" "https://example.com/bar" ];
|
||
silent = false;
|
||
verbose = true;
|
||
}
|
||
=> [
|
||
"-X" "PUT"
|
||
"--data" "{\"id\":0}"
|
||
"--retry" "3"
|
||
"--url" "https://example.com/foo"
|
||
"--url" "https://example.com/bar"
|
||
"--verbose"
|
||
]
|
||
```
|
||
|
||
:::
|
||
*/
|
||
toGNUCommandLine =
|
||
lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2511)
|
||
"lib.cli.toGNUCommandLine is deprecated, please use lib.cli.toCommandLine or lib.cli.toCommandLineShellGNU instead."
|
||
(
|
||
{
|
||
mkOptionName ? k: if builtins.stringLength k == 1 then "-${k}" else "--${k}",
|
||
|
||
mkBool ? k: v: lib.optional v (mkOptionName k),
|
||
|
||
mkList ? k: v: lib.concatMap (mkOption k) v,
|
||
|
||
mkOption ?
|
||
k: v:
|
||
if v == null then
|
||
[ ]
|
||
else if optionValueSeparator == null then
|
||
[
|
||
(mkOptionName k)
|
||
(lib.generators.mkValueStringDefault { } v)
|
||
]
|
||
else
|
||
[ "${mkOptionName k}${optionValueSeparator}${lib.generators.mkValueStringDefault { } v}" ],
|
||
|
||
optionValueSeparator ? null,
|
||
}:
|
||
options:
|
||
let
|
||
render =
|
||
k: v:
|
||
if builtins.isBool v then
|
||
mkBool k v
|
||
else if builtins.isList v then
|
||
mkList k v
|
||
else
|
||
mkOption k v;
|
||
|
||
in
|
||
builtins.concatLists (lib.mapAttrsToList render options)
|
||
);
|
||
|
||
/**
|
||
Converts the given attributes into a single shell-escaped command-line string.
|
||
Similar to `toCommandLineGNU`, but returns a single escaped string instead of an array of arguments.
|
||
For further reference see: [`lib.cli.toCommandLineGNU`](#function-library-lib.cli.toCommandLineGNU)
|
||
*/
|
||
toCommandLineShellGNU =
|
||
options: attrs: lib.escapeShellArgs (lib.cli.toCommandLineGNU options attrs);
|
||
|
||
/**
|
||
Converts an attribute set into a list of GNU-style command line options.
|
||
|
||
`toCommandLineGNU` returns a list of string arguments.
|
||
|
||
# Inputs
|
||
|
||
`options`
|
||
|
||
: Options, see below.
|
||
|
||
`attrs`
|
||
|
||
: The attributes to transform into arguments.
|
||
|
||
## Options
|
||
|
||
`isLong`
|
||
|
||
: A function that determines whether an option is long or short.
|
||
|
||
`explicitBool`
|
||
|
||
: Whether or not boolean option arguments should be formatted explicitly.
|
||
|
||
`formatArg`
|
||
|
||
: A function that turns the option argument into a string.
|
||
|
||
# Examples
|
||
|
||
:::{.example}
|
||
## `lib.cli.toCommandLineGNU` usage example
|
||
|
||
```nix
|
||
lib.cli.toCommandLineGNU {} {
|
||
v = true;
|
||
verbose = [true true false null];
|
||
i = ".bak";
|
||
testsuite = ["unit" "integration"];
|
||
e = ["s/a/b/" "s/b/c/"];
|
||
n = false;
|
||
data = builtins.toJSON {id = 0;};
|
||
}
|
||
=> [
|
||
"--data={\"id\":0}"
|
||
"-es/a/b/"
|
||
"-es/b/c/"
|
||
"-i.bak"
|
||
"--testsuite=unit"
|
||
"--testsuite=integration"
|
||
"-v"
|
||
"--verbose"
|
||
"--verbose"
|
||
]
|
||
```
|
||
|
||
:::
|
||
*/
|
||
toCommandLineGNU =
|
||
{
|
||
isLong ? optionName: builtins.stringLength optionName > 1,
|
||
explicitBool ? false,
|
||
formatArg ? lib.generators.mkValueStringDefault { },
|
||
}:
|
||
let
|
||
optionFormat = optionName: {
|
||
option = if isLong optionName then "--${optionName}" else "-${optionName}";
|
||
sep = if isLong optionName then "=" else "";
|
||
inherit explicitBool formatArg;
|
||
};
|
||
in
|
||
lib.cli.toCommandLine optionFormat;
|
||
|
||
/**
|
||
Converts the given attributes into a single shell-escaped command-line string.
|
||
Similar to `toCommandLine`, but returns a single escaped string instead of an array of arguments.
|
||
For further reference see: [`lib.cli.toCommandLine`](#function-library-lib.cli.toCommandLine)
|
||
*/
|
||
toCommandLineShell =
|
||
optionFormat: attrs: lib.escapeShellArgs (lib.cli.toCommandLine optionFormat attrs);
|
||
|
||
/**
|
||
Converts an attribute set into a list of command line options.
|
||
|
||
`toCommandLine` returns a list of string arguments.
|
||
|
||
# Inputs
|
||
|
||
`optionFormat`
|
||
|
||
: The option format that describes how options and their arguments should be formatted.
|
||
|
||
`attrs`
|
||
|
||
: The attributes to transform into arguments.
|
||
|
||
# Examples
|
||
:::{.example}
|
||
## `lib.cli.toCommandLine` usage example
|
||
|
||
```nix
|
||
let
|
||
optionFormat = optionName: {
|
||
option = "-${optionName}";
|
||
sep = "=";
|
||
explicitBool = true;
|
||
};
|
||
in lib.cli.toCommandLine optionFormat {
|
||
v = true;
|
||
verbose = [true true false null];
|
||
i = ".bak";
|
||
testsuite = ["unit" "integration"];
|
||
e = ["s/a/b/" "s/b/c/"];
|
||
n = false;
|
||
data = builtins.toJSON {id = 0;};
|
||
}
|
||
=> [
|
||
"-data={\"id\":0}"
|
||
"-e=s/a/b/"
|
||
"-e=s/b/c/"
|
||
"-i=.bak"
|
||
"-n=false"
|
||
"-testsuite=unit"
|
||
"-testsuite=integration"
|
||
"-v=true"
|
||
"-verbose=true"
|
||
"-verbose=true"
|
||
"-verbose=false"
|
||
]
|
||
```
|
||
|
||
:::
|
||
*/
|
||
toCommandLine =
|
||
optionFormat: attrs:
|
||
let
|
||
handlePair =
|
||
k: v:
|
||
if k == "" then
|
||
lib.throw "lib.cli.toCommandLine only accepts non-empty option names."
|
||
else if builtins.isList v then
|
||
builtins.concatMap (handleOption k) v
|
||
else
|
||
handleOption k v;
|
||
|
||
handleOption = k: renderOption (optionFormat k) k;
|
||
|
||
renderOption =
|
||
{
|
||
option,
|
||
sep,
|
||
explicitBool,
|
||
formatArg ? lib.generators.mkValueStringDefault { },
|
||
}:
|
||
k: v:
|
||
if v == null || (!explicitBool && v == false) then
|
||
[ ]
|
||
else if !explicitBool && v == true then
|
||
[ option ]
|
||
else
|
||
let
|
||
arg = formatArg v;
|
||
in
|
||
if sep != null then
|
||
[ "${option}${sep}${arg}" ]
|
||
else
|
||
[
|
||
option
|
||
arg
|
||
];
|
||
in
|
||
builtins.concatLists (lib.mapAttrsToList handlePair attrs);
|
||
}
|