about summary refs log tree commit diff
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2020-06-27T04·11+0200
committerProfpatsch <mail@profpatsch.de>2020-06-27T17·52+0000
commit3fd583d27c090a62717bf0887499830138c1dcbb (patch)
tree588731c042d56138d849d1ad91ba4b5a68fecb6e
parent22b8a49b87d2b86329add48e9af69ffd29ff6118 (diff)
feat(nix/writeExecline): add writeExecline r/1100
This is a writer, similar to `pkgs.writeBashScript` or
`pkgs.writers.writePython3`.

The difference is that we can correctly write all execline scripts by
using nix lists of lists, so the user doesn’t have to care about
escaping arguments (like they have to in bash scripts with
`lib.escapeShellArg` for example).

Change-Id: I2f2874cf61170ddca07b89b692f762725f4a75dc
Reviewed-on: https://cl.tvl.fyi/c/depot/+/625
Reviewed-by: Kane York <rikingcoding@gmail.com>
Reviewed-by: tazjin <mail@tazj.in>
-rw-r--r--nix/writeExecline/OWNERS3
-rw-r--r--nix/writeExecline/default.nix67
-rw-r--r--third_party/default.nix2
3 files changed, 72 insertions, 0 deletions
diff --git a/nix/writeExecline/OWNERS b/nix/writeExecline/OWNERS
new file mode 100644
index 0000000000..a742d0d22b
--- /dev/null
+++ b/nix/writeExecline/OWNERS
@@ -0,0 +1,3 @@
+inherited: true
+owners:
+  - Profpatsch
diff --git a/nix/writeExecline/default.nix b/nix/writeExecline/default.nix
new file mode 100644
index 0000000000..0916e2d58e
--- /dev/null
+++ b/nix/writeExecline/default.nix
@@ -0,0 +1,67 @@
+{ pkgs, lib, ... }:
+
+# Write an execline script, represented as nested nix lists.
+# Everything is escaped correctly.
+# https://skarnet.org/software/execline/
+
+# TODO(Profpatsch) upstream into nixpkgs
+
+let
+  # replaces " and \ to \" and \\ respectively and quote with "
+  # e.g.
+  #   a"b\c -> "a\"b\\c"
+  #   a\"bc -> "a\\\"bc"
+  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 builtins.isPath 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
+
+name:
+{
+  # "var": substitute readNArgs variables and start $@
+  # from the (readNArgs+1)th argument
+  # "var-full": substitute readNArgs variables and start $@ from $0
+  # "env": don’t substitute, set # and 0…n environment vaariables, where n=$#
+  # "none": don’t substitute or set any positional arguments
+  # "env-no-push": like "env", but bypass the push-phase. Not recommended.
+  argMode ? "var",
+  # Number of arguments to be substituted as variables (passed to "var"/"-s" or "var-full"/"-S"
+  readNArgs ? 0,
+}:
+# Nested list of lists of commands.
+# Inner lists are translated to execline blocks.
+argList:
+
+let
+  env =
+    if      argMode == "var" then "s${toString readNArgs}"
+    else if argMode == "var-full" then "S${toString readNArgs}"
+    else if argMode == "env" then ""
+    else if argMode == "none" then "P"
+    else if argMode == "env-no-push" then "p"
+    else abort ''"${toString argMode}" is not a valid argMode, use one of "var", "var-full", "env", "none", "env-no-push".'';
+
+in
+  # TODO(Profpatsch): rewrite `writeScript` with `runExecline`
+  pkgs.writeScript name ''
+    #!${pkgs.execline}/bin/execlineb -W${env}
+    ${escapeExecline argList}
+  ''
diff --git a/third_party/default.nix b/third_party/default.nix
index 4c29ba4803..c13b8f1b31 100644
--- a/third_party/default.nix
+++ b/third_party/default.nix
@@ -59,6 +59,7 @@ let
       cudatoolkit
       darwin
       dockerTools
+      execline
       fetchFromGitHub
       fetchgit
       fetchurl
@@ -130,6 +131,7 @@ let
       thttpd
       tree
       which
+      writeScript
       writeShellScript
       writeShellScriptBin
       writeText