about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorNaïm Favier <n@monade.li>2022-11-07 13:01:13 +0100
committerpennae <82953136+pennae@users.noreply.github.com>2022-12-08 17:52:52 +0100
commit0b661ce32af9baa07da56b3f48fcd3ef5611b66c (patch)
tree71056af5bcad19b694c5fcf980ba5180f9574f0f /lib
parent0fa7b1b004788881733dc117edd7699f77384166 (diff)
lib/generators.toPretty: escape strings properly
Diffstat (limited to 'lib')
-rw-r--r--lib/generators.nix24
-rw-r--r--lib/tests/misc.nix16
2 files changed, 21 insertions, 19 deletions
diff --git a/lib/generators.nix b/lib/generators.nix
index 9620b8b27b9b9..06823d215e360 100644
--- a/lib/generators.nix
+++ b/lib/generators.nix
@@ -297,17 +297,19 @@ rec {
     else if isFloat    v then "~${toString v}"
     else if isString   v then
       let
-        # Separate a string into its lines
-        newlineSplits = filter (v: ! isList v) (builtins.split "\n" v);
-        # For a '' string terminated by a \n, which happens when the closing '' is on a new line
-        multilineResult = "''" + introSpace + concatStringsSep introSpace (lib.init newlineSplits) + outroSpace + "''";
-        # For a '' string not terminated by a \n, which happens when the closing '' is not on a new line
-        multilineResult' = "''" + introSpace + concatStringsSep introSpace newlineSplits + "''";
-        # For single lines, replace all newlines with their escaped representation
-        singlelineResult = "\"" + libStr.escape [ "\"" ] (concatStringsSep "\\n" newlineSplits) + "\"";
-      in if multiline && length newlineSplits > 1 then
-        if lib.last newlineSplits == "" then multilineResult else multilineResult'
-      else singlelineResult
+        lines = filter (v: ! isList v) (builtins.split "\n" v);
+        escapeSingleline = libStr.escape [ "\\" "\"" "\${" ];
+        escapeMultiline = libStr.replaceStrings [ "\${" "''" ] [ "''\${" "'''" ];
+        singlelineResult = "\"" + concatStringsSep "\\n" (map escapeSingleline lines) + "\"";
+        multilineResult = let
+          escapedLines = map escapeMultiline lines;
+          # The last line gets a special treatment: if it's empty, '' is on its own line at the "outer"
+          # indentation level. Otherwise, '' is appended to the last line.
+          lastLine = lib.last escapedLines;
+        in "''" + introSpace + concatStringsSep introSpace (lib.init escapedLines)
+                + (if lastLine == "" then outroSpace else introSpace + lastLine) + "''";
+      in
+        if multiline && length lines > 1 then multilineResult else singlelineResult
     else if true  ==   v then "true"
     else if false ==   v then "false"
     else if null  ==   v then "null"
diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix
index 9267e1f57694c..cfad5a3cd92a0 100644
--- a/lib/tests/misc.nix
+++ b/lib/tests/misc.nix
@@ -727,7 +727,7 @@ runTests {
       float = 0.1337;
       bool = true;
       emptystring = "";
-      string = ''fno"rd'';
+      string = "fn\${o}\"r\\d";
       newlinestring = "\n";
       path = /. + "/foo";
       null_ = null;
@@ -735,7 +735,7 @@ runTests {
       functionArgs = { arg ? 4, foo }: arg;
       list = [ 3 4 function [ false ] ];
       emptylist = [];
-      attrs = { foo = null; "foo bar" = "baz"; };
+      attrs = { foo = null; "foo b/ar" = "baz"; };
       emptyattrs = {};
       drv = deriv;
     };
@@ -744,7 +744,7 @@ runTests {
       float = "~0.133700";
       bool = "true";
       emptystring = ''""'';
-      string = ''"fno\"rd"'';
+      string = ''"fn\''${o}\"r\\d"'';
       newlinestring = "\"\\n\"";
       path = "/foo";
       null_ = "null";
@@ -752,7 +752,7 @@ runTests {
       functionArgs = "<function, args: {arg?, foo}>";
       list = "[ 3 4 ${function} [ false ] ]";
       emptylist = "[ ]";
-      attrs = "{ foo = null; \"foo bar\" = \"baz\"; }";
+      attrs = "{ foo = null; \"foo b/ar\" = \"baz\"; }";
       emptyattrs = "{ }";
       drv = "<derivation ${deriv.name}>";
     };
@@ -799,8 +799,8 @@ runTests {
       newlinestring = "\n";
       multilinestring = ''
         hello
-        there
-        test
+        ''${there}
+        te'''st
       '';
       multilinestring' = ''
         hello
@@ -827,8 +827,8 @@ runTests {
       multilinestring = ''
         '''
           hello
-          there
-          test
+          '''''${there}
+          te''''st
         ''''';
       multilinestring' = ''
         '''