lib/cli: add toCommandLine
This commit is contained in:
@@ -360,3 +360,5 @@
|
||||
See the neovim help page [`:help startup`](https://neovim.io/doc/user/starting.html#startup) for more information, as well as [the nixpkgs neovim wrapper documentation](#neovim-custom-configuration).
|
||||
|
||||
- `cloudflare-ddns`: Added package cloudflare-ddns.
|
||||
|
||||
- `lib.cli.toCommandLine`, `lib.cli.toCommandLineShell`, `lib.cli.toCommandLineGNU` and `lib.cli.toCommandLineShellGNU` have been added to address multiple issues in `lib.cli.toGNUCommandLine` and `lib.cli.toGNUCommandLineShell`.
|
||||
|
||||
191
lib/cli.nix
191
lib/cli.nix
@@ -1,6 +1,6 @@
|
||||
{ lib }:
|
||||
|
||||
rec {
|
||||
{
|
||||
/**
|
||||
Automatically convert an attribute set to command-line options.
|
||||
|
||||
@@ -20,6 +20,7 @@ rec {
|
||||
: The attributes to transform into arguments.
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.cli.toGNUCommandLineShell` usage example
|
||||
|
||||
@@ -38,7 +39,8 @@ rec {
|
||||
|
||||
:::
|
||||
*/
|
||||
toGNUCommandLineShell = options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
|
||||
toGNUCommandLineShell =
|
||||
options: attrs: lib.escapeShellArgs (lib.cli.toGNUCommandLine options attrs);
|
||||
|
||||
/**
|
||||
Automatically convert an attribute set to a list of command-line options.
|
||||
@@ -55,7 +57,7 @@ rec {
|
||||
|
||||
: The attributes to transform into arguments.
|
||||
|
||||
# Options
|
||||
## Options
|
||||
|
||||
`mkOptionName`
|
||||
|
||||
@@ -85,6 +87,7 @@ rec {
|
||||
This is useful if the command requires equals, for example, `-c=5`.
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.cli.toGNUCommandLine` usage example
|
||||
|
||||
@@ -145,4 +148,186 @@ rec {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -3106,6 +3106,86 @@ runTests {
|
||||
expected = "-X PUT --data '{\"id\":0}' --retry 3 --url https://example.com/foo --url https://example.com/bar --verbose";
|
||||
};
|
||||
|
||||
testToCommandLine = {
|
||||
expr =
|
||||
let
|
||||
optionFormat = optionName: {
|
||||
option = "-${optionName}";
|
||||
sep = "=";
|
||||
explicitBool = true;
|
||||
};
|
||||
in
|
||||
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; };
|
||||
};
|
||||
|
||||
expected = [
|
||||
"-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"
|
||||
];
|
||||
};
|
||||
|
||||
testToCommandLineGNU = {
|
||||
expr = 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; };
|
||||
};
|
||||
|
||||
expected = [
|
||||
"--data={\"id\":0}"
|
||||
"-es/a/b/"
|
||||
"-es/b/c/"
|
||||
"-i.bak"
|
||||
"--testsuite=unit"
|
||||
"--testsuite=integration"
|
||||
"-v"
|
||||
"--verbose"
|
||||
"--verbose"
|
||||
];
|
||||
};
|
||||
|
||||
testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName {
|
||||
name = "..foo";
|
||||
expected = "foo";
|
||||
|
||||
Reference in New Issue
Block a user