about summary refs log tree commit diff
path: root/pkgs/profpatsch/execline
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2018-07-25 03:11:41 +0200
committerProfpatsch <mail@profpatsch.de>2018-07-25 03:17:14 +0200
commit097307c46fc5a7bda63a5916cfd1ee3ad661a0a6 (patch)
tree21aad88f5d534f3546e3d3a6b43ed64c2d275c6e /pkgs/profpatsch/execline
parentfd8db354af44cfd2142186c762d2c280c0639233 (diff)
pkgs/profpatsch: WIP execline experiments
* runExecline: like runCommand, but a lot more lightweight
* symlink: symlink a given list of links together
* importer: a small DSL to “import” “modules” into a build context

Some highlights:
* runExecline does not use any stdenv (apart from the `execline` build)
* symlink uses netstrings to pass correct fields into the derivation
* no use of bash, everything uses execline.
Diffstat (limited to 'pkgs/profpatsch/execline')
-rw-r--r--pkgs/profpatsch/execline/importer.nix45
-rw-r--r--pkgs/profpatsch/execline/run-execline.nix38
-rw-r--r--pkgs/profpatsch/execline/symlink.nix50
3 files changed, 133 insertions, 0 deletions
diff --git a/pkgs/profpatsch/execline/importer.nix b/pkgs/profpatsch/execline/importer.nix
new file mode 100644
index 00000000..67464d17
--- /dev/null
+++ b/pkgs/profpatsch/execline/importer.nix
@@ -0,0 +1,45 @@
+{ lib, coreutils, s6-portable-utils, symlink }:
+let
+  example = {from, as, just, ...}:
+    [
+      (from coreutils [
+        (just "echo")
+        (as "core-ls" "ls")
+      ])
+      (from s6-portable-utils [
+        (as "ls" "s6-ls")
+        (just "s6-echo")
+      ])
+    ];
+
+  runImport = impsFn:
+    let
+      combinators = rec {
+        from = source: imports: {
+          inherit source imports;
+        };
+        as = newname: oldname: {
+          inherit oldname newname;
+        };
+        just = x: as x x;
+      };
+
+      # Drv -> As -> Symlink
+      toBin = module: {oldname, newname}: {
+        dest = "bin/${newname}";
+        orig = "${module}/bin/${oldname}";
+      };
+      # List (Import { source: Drv
+      #              , imports: List (As { oldname: String
+      #                                  , newname: String }))
+      # -> Drv
+      run = imps:
+        symlink "foo" (lib.concatLists
+          (map ({source, imports}:
+                   map (toBin source) imports)
+               imps));
+
+    # TODO: typecheck w/ newtypes
+    in run (impsFn combinators);
+
+in runImport example
diff --git a/pkgs/profpatsch/execline/run-execline.nix b/pkgs/profpatsch/execline/run-execline.nix
new file mode 100644
index 00000000..40915f25
--- /dev/null
+++ b/pkgs/profpatsch/execline/run-execline.nix
@@ -0,0 +1,38 @@
+{ stdenv, importasCommand, execlinebCommand }:
+{ name
+# the execline script
+, execline
+# additional arguments to pass to the derivation
+, derivationArgs ? {}
+}:
+
+# those arguments can’t be overwritten
+assert !derivationArgs ? system;
+assert !derivationArgs ? name;
+assert !derivationArgs ? builder;
+assert !derivationArgs ? args;
+
+derivation (derivationArgs // {
+  inherit (stdenv) system;
+  inherit name;
+
+  # okay, `builtins.toFile` does not accept strings
+  # that reference drv outputs. This means we need
+  # to pass the script as envvar;
+  # this might clash with another passed envar,
+  # so we give it a long & unique name
+  _runExeclineScript = execline;
+  passAsFile = [ "_runExeclineScript" ]
+            ++ derivationArgs.passAsFile or [];
+
+  builder = importasCommand;
+  args = [
+    "-ui"                    # drop the envvar afterwards
+    "script"                 # substitution name
+    "_runExeclineScriptPath" # passed script file
+    execlinebCommand         # the actual invocation
+    "-P"                     # ignore command line arguments
+    "-W"                     # die on syntax error
+    "$script"                # substituted by importas
+  ];
+})
diff --git a/pkgs/profpatsch/execline/symlink.nix b/pkgs/profpatsch/execline/symlink.nix
new file mode 100644
index 00000000..ca8684d2
--- /dev/null
+++ b/pkgs/profpatsch/execline/symlink.nix
@@ -0,0 +1,50 @@
+{ lib, s6-portable-utils, coreutils, runExecline }:
+# DrvPath :: path relative to the derivation
+# AbsPath :: absolute path in the store
+#    Name
+# -> List (Symlink { dest: DrvPath, orig: AbsPath })
+# -> Drv
+name: links:
+
+let
+  toNetstring = s:
+    "${toString (builtins.stringLength s)}:${s},";
+
+in
+runExecline {
+  inherit name;
+
+  derivationArgs = {
+    pathTuples = lib.concatMapStrings
+      ({dest, orig}: toNetstring
+        (toNetstring dest + (toNetstring orig)))
+      links;
+    passAsFile = [ "pathTuples" ];
+    # bah! coreutils just for cat :(
+    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}
+
+      # 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
+      }
+  '';
+}