about summary refs log tree commit diff
path: root/pkgs/profpatsch/execline
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/profpatsch/execline')
-rw-r--r--pkgs/profpatsch/execline/escape.nix30
-rw-r--r--pkgs/profpatsch/execline/run-execline-tests.nix82
-rw-r--r--pkgs/profpatsch/execline/run-execline.nix19
-rw-r--r--pkgs/profpatsch/execline/symlink.nix48
4 files changed, 109 insertions, 70 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 ebfdeb20..c3f534cc 100644
--- a/pkgs/profpatsch/execline/run-execline-tests.nix
+++ b/pkgs/profpatsch/execline/run-execline-tests.nix
@@ -2,26 +2,24 @@
 # https://www.mail-archive.com/skaware@list.skarnet.org/msg01256.html
 , coreutils }:
 
-# TODO: run all of these locally! runExeclineLocal
-
 let
 
   # lol
-  writeScript = name: script: runExecline {
-    inherit name;
+  writeScript = name: script: runExecline name {
     derivationArgs = {
       inherit script;
       passAsFile = [ "script" ];
+      preferLocalBuild = true;
+      allowSubstitutes = false;
     };
-    execline = ''
-      importas -ui s scriptPath
-      importas -ui out out
-      foreground {
-        ${coreutils}/bin/mv $s $out
-      }
-      ${bin.s6-chmod} 0755 $out
-    '';
-   };
+  } [
+      "importas" "-ui" "s" "scriptPath"
+      "importas" "-ui" "out" "out"
+      "foreground" [
+        "${coreutils}/bin/mv" "$s" "$out"
+      ]
+      "${bin.s6-chmod}" "0755" "$out"
+  ];
 
   # execline block of depth 1
   block = args: builtins.map (arg: " ${arg}") args ++ [ "" ];
@@ -30,7 +28,7 @@ let
   # in the given file. Does not use runExecline, because
   # that should be tested after all.
   fileHasLine = line: file: derivation {
-    name = "file-${file.name}-has-line";
+    name = "run-execline-test-file-${file.name}-has-line";
     inherit (stdenv) system;
     builder = bin.execlineIf;
     args =
@@ -43,41 +41,49 @@ let
         bin.importas "-ui" "out" "out"
         bin.s6-touch "$out"
       ];
+    preferLocalBuild = true;
+    allowSubstitutes = false;
   };
 
   # basic test that touches out
-  basic = runExecline {
-    name = "basic";
-    execline = ''
-      importas -ui out out
-      ${bin.s6-touch} $out
-    '';
-  };
+  basic = runExecline "run-execline-test-basic" {
+    derivationArgs = {
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+    };
+  } [
+      "importas" "-ui" "out" "out"
+      "${bin.s6-touch}" "$out"
+  ];
 
   # whether the stdin argument works as intended
-  stdin = fileHasLine "foo" (runExecline {
-    name = "stdin";
+  stdin = fileHasLine "foo" (runExecline "run-execline-test-stdin" {
     stdin = "foo\nbar\nfoo";
-    execline = ''
-      importas -ui out out
+    derivationArgs = {
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+    };
+  } [
+      "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
+  ]);
 
-  wrapWithVar = runExecline {
-    name = "wrap-with-var";
+  wrapWithVar = runExecline "run-execline-test-wrap-with-var" {
     builderWrapper = writeScript "var-wrapper" ''
       #!${bin.execlineb} -S0
       export myvar myvalue $@
     '';
-    execline = ''
-      importas -ui v myvar
-      if { ${bin.s6-test} myvalue = $v }
-        importas out out
-        ${bin.s6-touch} $out
-    '';
-  };
+    derivationArgs = {
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+    };
+  } [
+    "importas" "-ui" "v" "myvar"
+    "if" [ bin.s6-test "myvalue" "=" "$v" ]
+      "importas" "out" "out"
+      bin.s6-touch "$out"
+  ];
 
-in args: drvSeqL [ basic stdin wrapWithVar ] (runExecline args)
+in [ basic stdin wrapWithVar ]
diff --git a/pkgs/profpatsch/execline/run-execline.nix b/pkgs/profpatsch/execline/run-execline.nix
index dbc6f4fd..2efe43d6 100644
--- a/pkgs/profpatsch/execline/run-execline.nix
+++ b/pkgs/profpatsch/execline/run-execline.nix
@@ -1,15 +1,18 @@
-{ stdenv, bin }:
-{ name
-# the execline script as string
-, execline
+{ stdenv, bin, lib }:
+name:
+{
 # a string to pass as stdin to the execline script
-, stdin ? ""
+stdin ? ""
 # a program wrapping the acutal execline invocation;
 # should be in Bernstein-chaining style
 , builderWrapper ? bin.exec
 # additional arguments to pass to the derivation
 , derivationArgs ? {}
 }:
+# the execline script as a nested list of string,
+# representing the blocks;
+# see docs of `escapeExecline`.
+ execline:
 
 # those arguments can’t be overwritten
 assert !derivationArgs ? system;
@@ -18,6 +21,7 @@ assert !derivationArgs ? builder;
 assert !derivationArgs ? args;
 
 derivation (derivationArgs // {
+  # TODO: what about cross?
   inherit (stdenv) system;
   inherit name;
 
@@ -26,7 +30,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..c6a311d8 100644
--- a/pkgs/profpatsch/execline/symlink.nix
+++ b/pkgs/profpatsch/execline/symlink.nix
@@ -11,9 +11,7 @@ let
     "${toString (builtins.stringLength s)}:${s},";
 
 in
-runExecline {
-  inherit name;
-
+runExecline name {
   derivationArgs = {
     pathTuples = lib.concatMapStrings
       ({dest, orig}: toNetstring
@@ -23,28 +21,26 @@ runExecline {
     # bah! coreutils just for cat :(
     PATH = lib.makeBinPath [ s6-portable-utils ];
   };
+} [
+  "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
-      }
+    # this call happens for every file, not very efficient
+    "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"
+    ]
+]