about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorRobert Hensing <roberth@users.noreply.github.com>2022-04-27 23:33:28 +0200
committerGitHub <noreply@github.com>2022-04-27 23:33:28 +0200
commit5f8cb210112fd2f4414fd4fbba045bdbc18cddf0 (patch)
tree22d074d6ff274af7cfbcb6fc11cb04deed30d6d2 /lib
parent713b41d22ae7008cc5596c58f79459a23b3e9471 (diff)
parent535997fa52e1a407bf5037ff974bbe2dba0e5942 (diff)
Merge pull request #170583 from ncfavier/mkShellVars
lib/strings: add toShellVars
Diffstat (limited to 'lib')
-rw-r--r--lib/default.nix3
-rw-r--r--lib/strings.nix60
-rw-r--r--lib/tests/misc.nix20
3 files changed, 82 insertions, 1 deletions
diff --git a/lib/default.nix b/lib/default.nix
index ec7f536bbdde4..e919509e724a5 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -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
diff --git a/lib/strings.nix b/lib/strings.nix
index 11066890ec3d3..d3ef748fb71e7 100644
--- a/lib/strings.nix
+++ b/lib/strings.nix
@@ -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
diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix
index fcccf89cc888c..c5d1d431677ad 100644
--- a/lib/tests/misc.nix
+++ b/lib/tests/misc.nix
@@ -251,6 +251,26 @@ runTests {
     expected = "&quot;test&quot; &apos;test&apos; &lt; &amp; &gt;";
   };
 
+  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 = {