about summary refs log tree commit diff
path: root/pkgs/profpatsch/execline
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2019-09-26 02:40:07 +0200
committerProfpatsch <mail@profpatsch.de>2019-09-26 03:51:25 +0200
commit61dda874aab6fe77d3d71eb4845ba3717e9c80d2 (patch)
treed0b0e9110bd22ac8c7df0dcab88b32642e6eb33d /pkgs/profpatsch/execline
parente8738a02aab262e1016fe270a16ec2c0f66795dc (diff)
pkgs/profpatsch/runExecline: move to list
We can auto-escape execlines correctly if we model them as nix-style
lists, so we shoud certainly do so. It also helps abstraction.
Diffstat (limited to 'pkgs/profpatsch/execline')
-rw-r--r--pkgs/profpatsch/execline/escape.nix30
-rw-r--r--pkgs/profpatsch/execline/run-execline-tests.nix46
-rw-r--r--pkgs/profpatsch/execline/run-execline.nix11
-rw-r--r--pkgs/profpatsch/execline/symlink.nix40
4 files changed, 82 insertions, 45 deletions
diff --git a/pkgs/profpatsch/execline/escape.nix b/pkgs/profpatsch/execline/escape.nix
new file mode 100644
index 00000000..d9a0be0c
--- /dev/null
+++ b/pkgs/profpatsch/execline/escape.nix
@@ -0,0 +1,30 @@
+{ lib }:
+let
+  # replaces " and \ to \" and \\ respectively and quote with "
+  # e.g.
+  #   a"b\c -> "a\"b\\c"
+  #   a\"bc -> "a\\\"bc"
+  # TODO upsteam into nixpkgs
+  escapeExeclineArg = arg:
+    ''"${builtins.replaceStrings [ ''"'' ''\'' ] [ ''\"'' ''\\'' ] (toString arg)}"'';
+
+  # Escapes an execline (list of execline strings) to be passed to execlineb
+  # Give it a nested list of strings. Nested lists are interpolated as execline
+  # blocks ({}).
+  # Everything is quoted correctly.
+  #
+  # Example:
+  #   escapeExecline [ "if" [ "somecommand" ] "true" ]
+  #   == ''"if" { "somecommand" } "true"''
+  escapeExecline = execlineList: lib.concatStringsSep " "
+    (let
+      go = arg:
+        if      builtins.isString arg then [(escapeExeclineArg arg)]
+        else if lib.isDerivation arg then [(escapeExeclineArg arg)]
+        else if builtins.isList arg then [ "{" ] ++ builtins.concatMap go arg ++ [ "}" ]
+        else abort "escapeExecline can only hande nested lists of strings, was ${lib.generators.toPretty {} arg}";
+     in builtins.concatMap go execlineList);
+
+in {
+  inherit escapeExecline;
+}
diff --git a/pkgs/profpatsch/execline/run-execline-tests.nix b/pkgs/profpatsch/execline/run-execline-tests.nix
index 76f18105..02894956 100644
--- a/pkgs/profpatsch/execline/run-execline-tests.nix
+++ b/pkgs/profpatsch/execline/run-execline-tests.nix
@@ -13,14 +13,14 @@ let
       preferLocalBuild = true;
       allowSubstitutes = false;
     };
-    execline = ''
-      importas -ui s scriptPath
-      importas -ui out out
-      foreground {
-        ${coreutils}/bin/mv $s $out
-      }
-      ${bin.s6-chmod} 0755 $out
-    '';
+    execline = [
+      "importas" "-ui" "s" "scriptPath"
+      "importas" "-ui" "out" "out"
+      "foreground" [
+        "${coreutils}/bin/mv" "$s" "$out"
+      ]
+      "${bin.s6-chmod}" "0755" "$out"
+    ];
    };
 
   # execline block of depth 1
@@ -43,15 +43,17 @@ let
         bin.importas "-ui" "out" "out"
         bin.s6-touch "$out"
       ];
+    preferLocalBuild = true;
+    allowSubstitutes = false;
   };
 
   # basic test that touches out
   basic = runExecline {
     name = "run-execline-test-basic";
-    execline = ''
-      importas -ui out out
-      ${bin.s6-touch} $out
-    '';
+    execline = [
+      "importas" "-ui" "out" "out"
+      "${bin.s6-touch}" "$out"
+    ];
     derivationArgs = {
       preferLocalBuild = true;
       allowSubstitutes = false;
@@ -62,12 +64,12 @@ let
   stdin = fileHasLine "foo" (runExecline {
     name = "run-execline-test-stdin";
     stdin = "foo\nbar\nfoo";
-    execline = ''
-      importas -ui out out
+    execline = [
+      "importas" "-ui" "out" "out"
       # this pipes stdout of s6-cat to $out
       # and s6-cat redirects from stdin to stdout
-      redirfd -w 1 $out ${bin.s6-cat}
-    '';
+      "redirfd" "-w" "1" "$out" bin.s6-cat
+    ];
     derivationArgs = {
       preferLocalBuild = true;
       allowSubstitutes = false;
@@ -80,12 +82,12 @@ let
       #!${bin.execlineb} -S0
       export myvar myvalue $@
     '';
-    execline = ''
-      importas -ui v myvar
-      if { ${bin.s6-test} myvalue = $v }
-        importas out out
-        ${bin.s6-touch} $out
-    '';
+    execline = [
+      "importas" "-ui" "v" "myvar"
+      "if" [ bin.s6-test "myvalue" "=" "$v" ]
+        "importas" "out" "out"
+        bin.s6-touch "$out"
+    ];
     derivationArgs = {
       preferLocalBuild = true;
       allowSubstitutes = false;
diff --git a/pkgs/profpatsch/execline/run-execline.nix b/pkgs/profpatsch/execline/run-execline.nix
index 18514464..8983dc8e 100644
--- a/pkgs/profpatsch/execline/run-execline.nix
+++ b/pkgs/profpatsch/execline/run-execline.nix
@@ -1,6 +1,8 @@
-{ stdenv, bin }:
+{ stdenv, bin, lib }:
 { name
-# the execline script as string
+# the execline script as a nested list of string,
+# representing the blocks;
+# see docs of `escapeExecline`.
 , execline
 # a string to pass as stdin to the execline script
 , stdin ? ""
@@ -27,7 +29,10 @@ derivation (derivationArgs // {
   # to pass the script and stdin as envvar;
   # this might clash with another passed envar,
   # so we give it a long & unique name
-  _runExeclineScript = execline;
+  _runExeclineScript =
+    let
+      escape = (import ./escape.nix { inherit lib; });
+    in escape.escapeExecline execline;
   _runExeclineStdin = stdin;
   passAsFile = [
     "_runExeclineScript"
diff --git a/pkgs/profpatsch/execline/symlink.nix b/pkgs/profpatsch/execline/symlink.nix
index ca8684d2..83cb710c 100644
--- a/pkgs/profpatsch/execline/symlink.nix
+++ b/pkgs/profpatsch/execline/symlink.nix
@@ -24,27 +24,27 @@ runExecline {
     PATH = lib.makeBinPath [ s6-portable-utils ];
   };
 
-  execline = ''
-    importas -ui p pathTuplesPath
-    importas -ui out out
-    forbacktickx -d "" destorig { ${coreutils}/bin/cat $p }
-      importas -ui do destorig
-      multidefine -d "" $do { destsuffix orig }
-      define dest ''${out}/''${destsuffix}
+  execline = [
+    "importas" "-ui" "p" "pathTuplesPath"
+    "importas" "-ui" "out" "out"
+    "forbacktickx" "-d" "" "destorig" [ "${coreutils}/bin/cat" "$p" ]
+      "importas" "-ui" "do" "destorig"
+      "multidefine" "-d" "" "$do" [ "destsuffix" "orig" ]
+      "define" "dest" ''''${out}/''${destsuffix}''
 
       # this call happens for every file, not very efficient
-      foreground {
-        backtick -n d { s6-dirname $dest }
-        importas -ui d d
-        s6-mkdir -p $d
-      }
+      "foreground" [
+        "backtick" "-n" "d" [ "s6-dirname" "$dest" ]
+        "importas" "-ui" "d" "d"
+        "s6-mkdir" "-p" "$d"
+      ]
 
-      ifthenelse { s6-test -L $orig } {
-        backtick -n res { s6-linkname -f $orig }
-        importas -ui res res
-        s6-ln -fs $res $dest
-      } {
-        s6-ln -fs $orig $dest
-      }
-  '';
+      "ifthenelse" [ "s6-test" "-L" "$orig" ] [
+        "backtick" "-n" "res" [ "s6-linkname" "-f" "$orig" ]
+        "importas" "-ui" "res" "res"
+        "s6-ln" "-fs" "$res" "$dest"
+      ] [
+        "s6-ln" "-fs" "$orig" "$dest"
+      ]
+  ];
 }