lib/strings: add toShellVars

A straightforward piece of plumbing to safely inject Nix variables into
shell scripts:

''
  ${lib.toShellVars { inherit foo bar; }}
  cmd "$foo" --bar "$bar"
''
This commit is contained in:
Naïm Favier 2022-04-27 10:02:49 +02:00
parent 68322e1297
commit 226bc99659
No known key found for this signature in database
GPG Key ID: 49B07322580B7EE2
3 changed files with 82 additions and 1 deletions

View File

@ -94,7 +94,8 @@ let
concatImapStringsSep makeSearchPath makeSearchPathOutput
makeLibraryPath makeBinPath optionalString
hasInfix hasPrefix hasSuffix stringToCharacters stringAsChars escape
escapeShellArg escapeShellArgs escapeRegex escapeXML replaceChars lowerChars
escapeShellArg escapeShellArgs isValidPosixName toShellVar toShellVars
escapeRegex escapeXML replaceChars lowerChars
upperChars toLower toUpper addContextFrom splitString
removePrefix removeSuffix versionOlder versionAtLeast
getName getVersion

View File

@ -17,6 +17,7 @@ rec {
head
isInt
isList
isAttrs
isString
match
parseDrvName
@ -324,6 +325,65 @@ rec {
*/
escapeShellArgs = concatMapStringsSep " " escapeShellArg;
/* Test whether the given name is a valid POSIX shell variable name.
Type: string -> bool
Example:
isValidPosixName "foo_bar000"
=> true
isValidPosixName "0-bad.jpg"
=> false
*/
isValidPosixName = name: match "[a-zA-Z_][a-zA-Z0-9_]*" name != null;
/* Translate a Nix value into a shell variable declaration, with proper escaping.
Supported value types are strings (mapped to regular variables), lists of strings
(mapped to Bash-style arrays) and attribute sets of strings (mapped to Bash-style
associative arrays). Note that "strings" include string-coercible values like paths.
Strings are translated into POSIX sh-compatible code; lists and attribute sets
assume a shell that understands Bash syntax (e.g. Bash or ZSH).
Type: string -> (string | listOf string | attrsOf string) -> string
Example:
''
${toShellVar foo "some string"}
[[ "$foo" == "some string" ]]
''
*/
toShellVar = name: value:
lib.throwIfNot (isValidPosixName name) "toShellVar: ${name} is not a valid shell variable name" (
if isAttrs value then
"declare -A ${name}=(${
concatStringsSep " " (lib.mapAttrsToList (n: v:
"[${escapeShellArg n}]=${escapeShellArg v}"
) value)
})"
else if isList value then
"declare -a ${name}=(${escapeShellArgs value})"
else
"${name}=${escapeShellArg value}"
);
/* Translate an attribute set into corresponding shell variable declarations
using `toShellVar`.
Type: attrsOf (string | listOf string | attrsOf string) -> string
Example:
let
foo = "value";
bar = foo;
in ''
${toShellVars { inherit foo bar; }}
[[ "$foo" == "$bar" ]]
''
*/
toShellVars = vars: concatStringsSep "\n" (lib.mapAttrsToList toShellVar vars);
/* Turn a string into a Nix expression representing that string
Type: string -> string

View File

@ -251,6 +251,26 @@ runTests {
expected = ""test" 'test' < & >";
};
testToShellVars = {
expr = ''
${toShellVars {
STRing01 = "just a 'string'";
_array_ = [ "with" "more strings" ];
assoc."with some" = ''
strings
possibly newlines
'';
}}
'';
expected = ''
STRing01='just a '\'''string'\''''
declare -a _array_=('with' 'more strings')
declare -A assoc=(['with some']='strings
possibly newlines
')
'';
};
# LISTS
testFilter = {