about summary refs log tree commit diff
path: root/pkgs
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/aszlig/santander/default.nix2
-rw-r--r--pkgs/aszlig/vim/default.nix47
-rw-r--r--pkgs/build-support/build-sandbox/default.nix4
-rw-r--r--pkgs/build-support/build-sandbox/src/setup.c23
-rw-r--r--pkgs/games/gog/crosscode.nix29
-rw-r--r--pkgs/games/gog/default.nix1
-rw-r--r--pkgs/games/gog/overload.nix4
-rw-r--r--pkgs/games/gog/stardew-valley.nix4
-rw-r--r--pkgs/games/gog/war-for-the-overworld.nix4
-rw-r--r--pkgs/games/humblebundle/default.nix2
-rw-r--r--pkgs/games/humblebundle/the_bridge.nix37
-rw-r--r--pkgs/games/humblebundle/trine2.nix97
-rw-r--r--pkgs/games/itch/invisigun-heroes.nix4
-rw-r--r--pkgs/profpatsch/default.nix71
-rw-r--r--pkgs/profpatsch/execline/run-execline-tests.nix83
-rw-r--r--pkgs/profpatsch/execline/run-execline.nix42
-rw-r--r--pkgs/profpatsch/testing/default.nix94
-rw-r--r--pkgs/sternenseemann/logbook/default.nix1
18 files changed, 508 insertions, 41 deletions
diff --git a/pkgs/aszlig/santander/default.nix b/pkgs/aszlig/santander/default.nix
index bedff554..adac0a8d 100644
--- a/pkgs/aszlig/santander/default.nix
+++ b/pkgs/aszlig/santander/default.nix
@@ -4,7 +4,7 @@
 
 let
   patchedWine = let
-    libpcsclite = "${pcsclite}/lib/libpcsclite.so";
+    libpcsclite = "${lib.getLib pcsclite}/lib/libpcsclite.so";
   in winePackages.minimal.overrideAttrs (drv: {
     scard4wine = fetchgit {
       url = "git://git.code.sf.net/p/scard4wine/code";
diff --git a/pkgs/aszlig/vim/default.nix b/pkgs/aszlig/vim/default.nix
index c75c4f30..6c1c6bab 100644
--- a/pkgs/aszlig/vim/default.nix
+++ b/pkgs/aszlig/vim/default.nix
@@ -1,5 +1,5 @@
 { stdenv, lib, fetchurl, fetchFromGitHub, writeText, writeTextFile, writeScript
-, pythonPackages, ledger, vim
+, python3Packages, ledger, meson, vim
 }:
 
 let
@@ -108,6 +108,27 @@ let
         endfun
       '';
     };
+
+    pug = fetchFromGitHub {
+      owner = "digitaltoad";
+      repo = "vim-pug";
+      rev = "ddc5592f8c36bf4bd915c16b38b8c76292c2b975";
+      sha256 = "069pha18g1nlzg44k742vjxm4zwjd1qjzhfllkr35qaiflvjm84y";
+    };
+
+    scss = fetchFromGitHub {
+      owner = "cakebaker";
+      repo = "scss-syntax.vim";
+      rev = "4461789d02f81fd328afbdf27d6404b6c763c25f";
+      sha256 = "0d227d2c1pvcksk2njzpkgmxivrnfb0apn2r62q7q89s61ggbzfj";
+    };
+
+    less = fetchFromGitHub {
+      owner = "groenewege";
+      repo = "vim-less";
+      rev = "6e818d5614d5fc18d95a48c92b89e6db39f9e3d6";
+      sha256 = "0rhqcdry8ycnfbg534q4b3hm78an7mnqhiazxik7k08a57dk9dbm";
+    };
   };
 
   plugins = pluginDeps // {
@@ -177,8 +198,8 @@ let
       lnl7 = fetchFromGitHub {
         owner = "LnL7";
         repo = "vim-nix";
-        rev = "e9abff9a0f4d594e360a5216c4e8f9ed3bcae2c0";
-        sha256 = "1gznb0wlwsx94b620m8ccl5046di525z698mswy8xxq1vyjcimi7";
+        rev = "be0c6bb409732b79cc86c177ca378b0b334e1efe";
+        sha256 = "1ivkwlm6lz43xk1m7aii0bgn2p3225dixck0qyhxw4zxhp2xiz06";
       };
 
       src = fetchFromGitHub {
@@ -296,6 +317,24 @@ let
       rev = "6eb3bb21aa979cc295d0480b2179938c12b33d0d";
       sha256 = "0rbwyaanvl2bqk8xm4kq8fkv8y92lpf9xx5n8gw54iij7xxhnj01";
     };
+
+    vue = fetchFromGitHub {
+      owner = "posva";
+      repo = "vim-vue";
+      rev = "e531e1d24f24385a5f4d2f1ba36d972a57ec52d9";
+      sha256 = "1vi4i9ybwg1l1xmarsdhzd08py4w0yfg4xswbz3qrvihk8nhg1km";
+    };
+
+    meson = stdenv.mkDerivation {
+      name = "meson-vim-${meson.version}";
+      inherit (meson) src;
+      phases = [ "unpackPhase" "patchPhase" "installPhase" ];
+      postPatch = ''
+        sed -i -e '/^ *echom \+getline/d' \
+          data/syntax-highlighting/vim/indent/meson.vim
+      '';
+      installPhase = "cp -r data/syntax-highlighting/vim \"$out\"";
+    };
   };
 
   generic = ''
@@ -334,7 +373,7 @@ let
     let python_highlight_numbers = 1
     let python_highlight_builtins = 1
     let python_highlight_exceptions = 1
-    let g:flake8_cmd = '${pythonPackages.flake8}/bin/flake8'
+    let g:flake8_cmd = '${python3Packages.flake8}/bin/flake8'
 
     " ledger
     let g:ledger_bin = '${ledger}/bin/ledger'
diff --git a/pkgs/build-support/build-sandbox/default.nix b/pkgs/build-support/build-sandbox/default.nix
index a52be5c9..4265d30d 100644
--- a/pkgs/build-support/build-sandbox/default.nix
+++ b/pkgs/build-support/build-sandbox/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, lib, pkgconfig, nix }:
+{ stdenv, lib, pkgconfig, nix, boost }:
 
 drv: { paths ? {}, ... }@attrs:
 
@@ -78,7 +78,7 @@ in stdenv.mkDerivation ({
   '';
 
   nativeBuildInputs = [ pkgconfig ];
-  buildInputs = [ nix ];
+  buildInputs = [ nix boost ];
   makeFlags = [ "BINDIR=${drv}/bin" ];
 
 } // removeAttrs attrs [ "paths" ])
diff --git a/pkgs/build-support/build-sandbox/src/setup.c b/pkgs/build-support/build-sandbox/src/setup.c
index d95927dc..cf73d3e8 100644
--- a/pkgs/build-support/build-sandbox/src/setup.c
+++ b/pkgs/build-support/build-sandbox/src/setup.c
@@ -747,9 +747,14 @@ static bool setup_chroot(void)
     if (!bind_mount("/dev", false, false, false))
         return false;
 
-    if (!bind_mount("/proc", false, false, false))
+    if (!makedirs(FS_ROOT_DIR "/proc", false))
         return false;
 
+    if (mount("none", FS_ROOT_DIR "/proc", "proc", 0, NULL) == -1) {
+        perror("mount /proc");
+        return false;
+    }
+
     if (!bind_mount("/sys", false, false, false))
         return false;
 
@@ -815,7 +820,8 @@ bool setup_sandbox(void)
             close(sync_pipe[0]);
             _exit(write_maps(parent_pid) ? 0 : 1);
         default:
-            if (unshare(CLONE_NEWNS | CLONE_NEWUSER) == -1) {
+            if (unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWPID |
+                        CLONE_NEWUTS | CLONE_NEWIPC) == -1) {
                 perror("unshare");
                 if (write(sync_pipe[1], "X", 1) == -1)
                     perror("signal child exit");
@@ -830,6 +836,19 @@ bool setup_sandbox(void)
             return false;
     }
 
+    if ((pid = fork()) == -1) {
+        perror("fork PID namespace");
+        return false;
+    }
+
+    /* Just wait in the parent until the child exits. We need to fork because
+     * otherwise we can't mount /proc in the right PID namespace.
+     */
+    if (pid > 0) {
+        waitpid(pid, NULL, 0);
+        _exit(1);
+    }
+
     cached_paths = new_path_cache();
 
     if (!setup_chroot()) {
diff --git a/pkgs/games/gog/crosscode.nix b/pkgs/games/gog/crosscode.nix
new file mode 100644
index 00000000..d3915895
--- /dev/null
+++ b/pkgs/games/gog/crosscode.nix
@@ -0,0 +1,29 @@
+{ lib, buildGame, fetchGog, makeWrapper, nwjs }:
+
+buildGame rec {
+  name = "crosscode-${version}";
+  version = "1.0.1.1";
+
+  src = fetchGog {
+    productId = 1252295864;
+    downloadName = "en3installer0";
+    sha256 = "0v5vh4fazkjgaxxffad7k230wzdgwd6dnymf3i72d25pwaqdsssd";
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  buildPhase = ''
+    substituteInPlace package.json --replace assets/ ""
+  '';
+
+  installPhase = ''
+    mkdir -p "$out/share" "$out/bin"
+    cp -r assets "$out/share/crosscode"
+    install -vD -m 0644 package.json "$out/share/crosscode/package.json"
+
+    makeWrapper ${lib.escapeShellArg "${nwjs}/bin/nw"} "$out/bin/crosscode" \
+      --run "cd '$out/share/crosscode'" --add-flags .
+  '';
+
+  sandbox.paths.required = [ "$XDG_CONFIG_HOME/CrossCode" ];
+}
diff --git a/pkgs/games/gog/default.nix b/pkgs/games/gog/default.nix
index edd81bc4..1ef58c30 100644
--- a/pkgs/games/gog/default.nix
+++ b/pkgs/games/gog/default.nix
@@ -12,6 +12,7 @@ let
     };
 
     albion = callPackage_i686 ./albion {};
+    crosscode = callPackage ./crosscode.nix {};
     dungeons3 = callPackage ./dungeons3.nix {};
     epistory = callPackage ./epistory.nix { };
     overload = callPackage ./overload.nix {};
diff --git a/pkgs/games/gog/overload.nix b/pkgs/games/gog/overload.nix
index 00410356..f1807931 100644
--- a/pkgs/games/gog/overload.nix
+++ b/pkgs/games/gog/overload.nix
@@ -4,11 +4,11 @@ buildUnity {
   name = "overload";
   fullName = "Overload";
   saveDir = "Revival/Overload";
-  version = "1.0.1839";
+  version = "1.0.1854";
 
   src = fetchGog {
     productId = 1309632191;
     downloadName = "en3installer0";
-    sha256 = "1r42ll6k2xif405rp85gn3sbhacrhf1kkpqx2ahp8j5f9alscdxm";
+    sha256 = "1qyd78xzd39763dmrb5rb8g0v0qi45jjkb9id9gjvvmh41m0731i";
   };
 }
diff --git a/pkgs/games/gog/stardew-valley.nix b/pkgs/games/gog/stardew-valley.nix
index 815e37ed..820e98de 100644
--- a/pkgs/games/gog/stardew-valley.nix
+++ b/pkgs/games/gog/stardew-valley.nix
@@ -4,12 +4,12 @@
 
 buildGame rec {
   name = "stardew-valley-${version}";
-  version = "1.3.27";
+  version = "1.3.32";
 
   src = fetchGog {
     productId = 1453375253;
     downloadName = "en3installer0";
-    sha256 = "0i4wq6ii8r82gan1j8j9zd5f0cqs7by0s7h9axnb5zi2j0pxlk2i";
+    sha256 = "1j6zzdjif2xbihcmpf66af4mbnxnvzjnfn0sq597i9a26h3caia2";
   };
 
   nativeBuildInputs = [ makeWrapper ];
diff --git a/pkgs/games/gog/war-for-the-overworld.nix b/pkgs/games/gog/war-for-the-overworld.nix
index 8e46ec32..fb139fd8 100644
--- a/pkgs/games/gog/war-for-the-overworld.nix
+++ b/pkgs/games/gog/war-for-the-overworld.nix
@@ -4,12 +4,12 @@ buildUnity {
   name = "war-for-the-overworld";
   fullName = "WFTOGame";
   saveDir = "Subterranean Games/War For The Overworld";
-  version = "2.0.3f1";
+  version = "2.0.4";
 
   src = fetchGog {
     productId = 1964276929;
     downloadName = "en3installer0";
-    sha256 = "07yj9clf3hmy7z67ck9sqf3gnrazx5rzifg91jas77z774vwdg8k";
+    sha256 = "0p54dhd2j7zvc78444jnjmkjv7kf6sskbphxkj5vlxmfcrmbd2xq";
   };
 
   nativeBuildInputs = [ mono monogamePatcher ];
diff --git a/pkgs/games/humblebundle/default.nix b/pkgs/games/humblebundle/default.nix
index 4a0792c4..c5ec988a 100644
--- a/pkgs/games/humblebundle/default.nix
+++ b/pkgs/games/humblebundle/default.nix
@@ -31,6 +31,8 @@ let
     spaz = callPackage ./spaz.nix {};
     starbound = callPackage ./starbound.nix {};
     swordsandsoldiers = callPackage ./swordsandsoldiers.nix {};
+    the_bridge = callPackage_i686 ./the_bridge.nix {};
+    trine2 = callPackage_i686 ./trine2.nix {};
     unepic = callPackage ./unepic.nix {};
   };
 in with lib; {
diff --git a/pkgs/games/humblebundle/the_bridge.nix b/pkgs/games/humblebundle/the_bridge.nix
new file mode 100644
index 00000000..92e5b691
--- /dev/null
+++ b/pkgs/games/humblebundle/the_bridge.nix
@@ -0,0 +1,37 @@
+{ buildUnity, fetchHumbleBundle
+, libGLU
+}:
+
+buildUnity rec {
+  fullName = "TheBridge";
+  name = fullName;
+  version = "20140908"; # 1410197597, or 1410196636 (same date).
+
+  src = fetchHumbleBundle {
+    name = "TheBridgeLinux_1410196636.zip";
+    machineName = "thebridge_linux";
+    downloadName = "Download";
+    md5 = "6d3f5e7ff8d10d47f04ffabb8b9a031e";
+  };
+
+  buildInputs = [ libGLU ];
+
+  meta = {
+    homepage = [
+      http://thebridgeisblackandwhite.com
+      https://www.humblebundle.com/store/the-bridge
+    ];
+    #editor = "The Quantum Astrophysicists Guild";
+    description = "A 2D logic puzzle game that plays with physics and perspective";
+    longDescription = ''
+      The Bridge is a 2D logic puzzle game that forces the player to reevaluate
+      their preconceptions of physics and perspective. It is Isaac Newton meets
+      M. C. Escher. Manipulate gravity to redefine the ceiling as the floor
+      while venturing through impossible architectures. Explore increasingly
+      difficult worlds, each uniquely detailed and designed to leave the player
+      with a pronounced sense of intellectual accomplishment. The Bridge
+      exemplifies games as an art form, with beautifully hand-drawn art in the
+      style of a black-and-white lithograph.
+    '';
+  };
+}
diff --git a/pkgs/games/humblebundle/trine2.nix b/pkgs/games/humblebundle/trine2.nix
new file mode 100644
index 00000000..a6cef22d
--- /dev/null
+++ b/pkgs/games/humblebundle/trine2.nix
@@ -0,0 +1,97 @@
+{ buildGame, fetchHumbleBundle, makeWrapper, runCommandCC, writeText
+, coreutils, openal, libvorbis, libGLU, SDL2, freetype, alsaLib
+}:
+
+buildGame rec {
+  name = "trine2-${version}";
+  version = "2.01";
+
+  src = fetchHumbleBundle {
+    machineName = "trine2complete_linux";
+    suffix = "zip";
+    md5 = "82049b65c1bce6841335935bc05139c8";
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+  buildInputs = [ openal libvorbis libGLU freetype alsaLib ];
+
+  patchPhase = ''
+    patchelf --replace-needed libSDL-1.3.so.0 libSDL.so \
+      bin/trine2_linux_32bit
+    patchelf --replace-needed libPhysXLoader.so.1 libPhysXLoader.so \
+      bin/trine2_linux_32bit
+  '';
+
+  getResolutionArgs = runCommandCC "get-resolution-args" {
+    buildInputs = [ SDL2 ];
+    src = writeText "get-resolution-args.c" ''
+      #include <SDL.h>
+
+      int main(void)
+      {
+        int width = 0, height = 0;
+        SDL_DisplayMode current;
+
+        SDL_Init(SDL_INIT_VIDEO);
+
+        int displays = SDL_GetNumVideoDisplays();
+
+        for (int i = 0; i < displays; ++i) {
+          if (SDL_GetCurrentDisplayMode(i, &current) != 0)
+            goto err;
+
+          if (current.w * current.h > width * height) {
+            width = current.w;
+            height = current.h;
+          }
+        }
+
+        if (width == 0 && height == 0)
+          goto err;
+
+        SDL_Quit();
+        printf("-RenderingModule:DetectedFullscreenWidth=%d\n", width);
+        printf("-RenderingModule:DetectedFullscreenHeight=%d\n", height);
+        return EXIT_SUCCESS;
+
+      err:
+        fputs("Unable to get current display mode.\n", stderr);
+        SDL_Quit();
+        return EXIT_FAILURE;
+      }
+    '';
+  } "gcc -Wall $(sdl2-config --cflags --libs) -o \"$out\" \"$src\"";
+
+  installPhase = ''
+    for name in Cg CgGL PhysXCooking PhysXCore PhysXLoader; do
+      install -vD "lib/lib32/lib$name.so" "$out/libexec/trine2/lib$name.so"
+    done
+
+    install -vD lib/lib32/libSDL-1.3.so.0 "$out/libexec/trine2/libSDL.so"
+
+    mkdir -p "$out/share/trine2"
+    cp -rvt "$out/share/trine2" *.fbq trine2.png data
+
+    install -vD bin/trine2_linux_32bit "$out/libexec/trine2/trine2"
+
+    rtDataPath="\''${XDG_DATA_HOME:-\$HOME/.local/share}"
+    makeWrapper "$out/libexec/trine2/trine2" "$out/bin/trine2" \
+      --run "cd '$out/share/trine2'" \
+      --run '${coreutils}/bin/ln -s "'"$rtDataPath"'" "$HOME/.frozenbyte"' \
+      --prefix LD_LIBRARY_PATH : "$out/libexec/trine2" \
+      --add-flags "\$($getResolutionArgs)"
+
+    mkdir -p "$out/share/applications"
+    cat > "$out/share/applications/trine2.desktop" <<EOF
+    [Desktop Entry]
+    Name=Trine 2
+    Type=Application
+    Version=1.1
+    Exec=$out/bin/trine2
+    Icon=$out/share/trine2/trine2.png
+    Categories=Game
+    EOF
+  '';
+
+  sandbox.paths.required = [ "$XDG_DATA_HOME/Trine2" ];
+}
diff --git a/pkgs/games/itch/invisigun-heroes.nix b/pkgs/games/itch/invisigun-heroes.nix
index cf074d66..f584db5e 100644
--- a/pkgs/games/itch/invisigun-heroes.nix
+++ b/pkgs/games/itch/invisigun-heroes.nix
@@ -4,14 +4,14 @@ buildUnity rec {
   name = "invisigun-heroes";
   fullName = "Invisigun Heroes";
   saveDir = "Sombr Studio/Invisigun Heroes";
-  version = "1.6.71";
+  version = "1.6.101";
 
   src = fetchItch {
     name = "${name}-${version}.zip";
     gameId = 25561;
     uploadId = 208583;
     version = "v${version}";
-    sha256 = "16bcyypigk0nm7ckdfxc9hkwv8dznqs936qmkzbjb22va2j4ip0s";
+    sha256 = "0l3dqkda9xxvlx5jbb5s3gp8yblzvp2k2wjsg8h9xx860c5nj3cy";
   };
 
   sandbox.paths.required = [ "$HOME/Invisigun Heroes" ];
diff --git a/pkgs/profpatsch/default.nix b/pkgs/profpatsch/default.nix
index f14eb61c..692820e6 100644
--- a/pkgs/profpatsch/default.nix
+++ b/pkgs/profpatsch/default.nix
@@ -1,8 +1,35 @@
-{ stdenv, pkgs }:
+{ stdenv, lib, pkgs }:
 
 let
   inherit (pkgs) callPackage;
 
+  # wrapper for execlineb that doesn’t need the execline commands
+  # in PATH to work (making them appear like “builtins”)
+  execlineb-with-builtins =
+    let eldir = "${pkgs.execline}/bin";
+    in pkgs.writeScriptBin "execlineb" ''
+      #!${eldir}/execlineb -s0
+      ${eldir}/define eldir ${eldir}
+      ''${eldir}/importas oldpath PATH
+      ''${eldir}/export PATH "''${eldir}:''${oldpath}"
+      ''${eldir}/execlineb $@
+    '';
+
+  # Takes a derivation and a list of binary names
+  # and returns an attribute set of `name -> path`.
+  # The list can also contain renames in the form of
+  # { use, as }, which goes `as -> usePath`.
+  bins = drv: xs:
+    let f = x:
+      # TODO: typecheck
+      let x' = if builtins.isString x then { use = x; as = x; } else x;
+      in {
+        name = x'.as;
+        value = "${lib.getBin drv}/bin/${x'.use}";
+      };
+    in builtins.listToAttrs (builtins.map f xs);
+
+
 in rec {
   backlight = callPackage ./backlight { inherit (pkgs.xorg) xbacklight; };
   display-infos = callPackage ./display-infos {};
@@ -33,22 +60,34 @@ in rec {
     ];
   });
 
-  # wrapper for execlineb that doesn’t need the execline commands
-  # in PATH to work (making them appear like “builtins”)
-  execlineb-with-builtins =
-    let eldir = "${pkgs.execline}/bin";
-    in pkgs.writeScriptBin "execlineb" ''
-      #!${eldir}/execlineb -s0
-      ${eldir}/define eldir ${eldir}
-      ''${eldir}/importas oldpath PATH
-      ''${eldir}/export PATH "''${eldir}:''${oldpath}"
-      ''${eldir}/execlineb $@
-    '';
+  runExecline =
+    # todo: factor out calling tests
+    let
+      it = import ./execline/run-execline.nix {
+        bin = (bins execlineb-with-builtins [ "execlineb" ])
+           // (bins pkgs.execline [ "redirfd" "importas" "exec" ]);
+        inherit stdenv;
+      };
+      tests = import ./execline/run-execline-tests.nix {
+        runExecline = it;
+        inherit (testing) drvSeqL;
+        inherit (pkgs) coreutils;
+        inherit stdenv;
+        bin = (bins execlineb-with-builtins [ "execlineb" ])
+           // (bins pkgs.execline [
+                 { use = "if"; as = "execlineIf"; }
+                 "redirfd" "importas"
+               ])
+           // (bins pkgs.s6PortableUtils
+                [ "s6-cat" "s6-grep" "s6-touch" "s6-test" "s6-chmod" ]);
+       };
+    in tests;
+
 
-  runExecline = import ./execline/run-execline.nix {
-    inherit stdenv;
-    execlinebCommand = "${execlineb-with-builtins}/bin/execlineb";
-    importasCommand = "${pkgs.execline}/bin/importas";
+  testing = import ./testing {
+    inherit stdenv lib runExecline;
+    inherit (pkgs) runCommand;
+    bin = bins pkgs.s6PortableUtils [ "s6-touch" "s6-echo" ];
   };
 
   symlink = pkgs.callPackage ./execline/symlink.nix {
diff --git a/pkgs/profpatsch/execline/run-execline-tests.nix b/pkgs/profpatsch/execline/run-execline-tests.nix
new file mode 100644
index 00000000..ebfdeb20
--- /dev/null
+++ b/pkgs/profpatsch/execline/run-execline-tests.nix
@@ -0,0 +1,83 @@
+{ stdenv, drvSeqL, runExecline, bin
+# 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;
+    derivationArgs = {
+      inherit script;
+      passAsFile = [ "script" ];
+    };
+    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
+  block = args: builtins.map (arg: " ${arg}") args ++ [ "" ];
+
+  # derivation that tests whether a given line exists
+  # 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";
+    inherit (stdenv) system;
+    builder = bin.execlineIf;
+    args =
+      (block [
+        bin.redirfd "-r" "0" file   # read file to stdin
+        bin.s6-grep "-F" "-q" line   # and grep for the line
+      ])
+      ++ [
+        # if the block succeeded, touch $out
+        bin.importas "-ui" "out" "out"
+        bin.s6-touch "$out"
+      ];
+  };
+
+  # basic test that touches out
+  basic = runExecline {
+    name = "basic";
+    execline = ''
+      importas -ui out out
+      ${bin.s6-touch} $out
+    '';
+  };
+
+  # whether the stdin argument works as intended
+  stdin = fileHasLine "foo" (runExecline {
+    name = "stdin";
+    stdin = "foo\nbar\nfoo";
+    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}
+    '';
+  });
+
+  wrapWithVar = runExecline {
+    name = "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
+    '';
+  };
+
+in args: drvSeqL [ basic stdin wrapWithVar ] (runExecline args)
diff --git a/pkgs/profpatsch/execline/run-execline.nix b/pkgs/profpatsch/execline/run-execline.nix
index 40915f25..dbc6f4fd 100644
--- a/pkgs/profpatsch/execline/run-execline.nix
+++ b/pkgs/profpatsch/execline/run-execline.nix
@@ -1,7 +1,12 @@
-{ stdenv, importasCommand, execlinebCommand }:
+{ stdenv, bin }:
 { name
-# the execline script
+# the execline script as string
 , execline
+# a string to pass as stdin to the execline script
+, 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 ? {}
 }:
@@ -18,20 +23,41 @@ derivation (derivationArgs // {
 
   # okay, `builtins.toFile` does not accept strings
   # that reference drv outputs. This means we need
-  # to pass the script as envvar;
+  # 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;
-  passAsFile = [ "_runExeclineScript" ]
-            ++ derivationArgs.passAsFile or [];
+  _runExeclineStdin = stdin;
+  passAsFile = [
+    "_runExeclineScript"
+    "_runExeclineStdin"
+  ] ++ derivationArgs.passAsFile or [];
+
+  # the default, exec acts as identity executable
+  builder = builderWrapper;
 
-  builder = importasCommand;
   args = [
+    bin.importas             # import script file as $script
     "-ui"                    # drop the envvar afterwards
     "script"                 # substitution name
     "_runExeclineScriptPath" # passed script file
-    execlinebCommand         # the actual invocation
-    "-P"                     # ignore command line arguments
+
+    # TODO: can we scrap stdin via builderWrapper?
+    bin.importas             # do the same for $stdin
+    "-ui"
+    "stdin"
+    "_runExeclineStdinPath"
+
+    bin.redirfd              # now we
+    "-r"                     # read the file
+    "0"                      # into the stdin of execlineb
+    "$stdin"                 # that was given via stdin
+
+    bin.execlineb            # the actual invocation
+    # TODO: depending on the use-case, -S0 might not be enough
+    # in all use-cases, then a wrapper for execlineb arguments
+    # should be added (-P, -S, -s).
+    "-S0"                    # set $@ inside the execline script
     "-W"                     # die on syntax error
     "$script"                # substituted by importas
   ];
diff --git a/pkgs/profpatsch/testing/default.nix b/pkgs/profpatsch/testing/default.nix
new file mode 100644
index 00000000..21f814e4
--- /dev/null
+++ b/pkgs/profpatsch/testing/default.nix
@@ -0,0 +1,94 @@
+{ stdenv, runCommand, lib
+, runExecline, bin }:
+
+let
+
+  /* Realize drvDep, then return drvOut if that succeds.
+   * This can be used to make drvOut depend on the
+   * build success of drvDep without making drvDep a
+   * dependency of drvOut
+   * => drvOut is not rebuilt if drvDep changes
+   */
+  drvSeq = drvDep: drvOut: drvSeqL [drvDep] drvOut;
+
+  /* TODO DOCS */
+  drvSeqL = drvDeps: drvOut: let
+  drvOutOutputs = drvOut.outputs or ["out"];
+  in
+    runCommand drvOut.name {
+      # we inherit all attributes in order to replicate
+      # the original derivation as much as possible
+      outputs = drvOutOutputs;
+      passthru = drvOut.drvAttrs;
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+      # depend on drvDeps (by putting it in builder context)
+      inherit drvDeps;
+    }
+    # the outputs of the original derivation are replicated
+    # by creating a symlink to the old output path
+    (lib.concatMapStrings (output: ''
+      target=${lib.escapeShellArg drvOut.${output}}
+      # if the target is already a symlink, follow it until it’s not;
+      # this is done to prevent too many dereferences
+      target=$(readlink -e "$target")
+      # link to the output
+      ln -s "$target" "${"$"}${output}"
+    '') drvOutOutputs);
+
+  /* Takes a derivation and an attribute set of
+   * test names to tests.
+   * Tests can be constructed by calling test
+   * functions like `bashTest` or `execlineTest`.
+   * They generally take scripts that
+   * is not sucessful and succeed otherwise.
+   */
+  withTests = tests: drv:
+    assert lib.isDerivation drv; # drv needs to be a derivation!
+    let testDrvs = lib.mapAttrsToList
+          (testName: testFun: testFun {
+            drvName = "${drv.name}-test-${testName}";
+          }) tests;
+    in drvSeqL testDrvs drv;
+
+  # /* Constructs a test from a bash script.
+  #  * The test will fail if the bash script exits
+  #  * with an exit code other than 0. */
+  # bashTest = testScript: { drvName }:
+  #   runCommand drvName {
+  #     preferLocalBuild = true;
+  #     allowSubstitutes = false;
+  #   } ''
+  #     ${testScript}
+  #     touch "$out"
+  #   '';
+
+  # /* Constructs a test from an execline script.
+  #  * The test will fail if the bash script exits
+  #  * with an exit code other than 0. */
+  # execlineTest = testScript: { drvName }:
+  #   runExecline {
+  #     name = drvName;
+  #     execline = testScript;
+  #     builderWrapper = runExecline {
+  #       name = "touch-out";
+  #       execline = ''
+  #         importas -i out out
+  #         ifte
+  #           # if $@ succeeds, $out is touched
+  #           { ${bin.s6-touch} $out }
+  #           # otherwise we return the exit code
+  #           { importas exit ?
+  #             ${bin.s6-echo} $exit }
+  #           # condition
+  #           $@
+  #       '';
+  #     derivationArgs = {
+  #       preferLocalBuild = true;
+  #       allowSubstitutes = false;
+  #     };
+  #   };
+  # };
+
+in
+  { inherit drvSeq drvSeqL withTests; }
diff --git a/pkgs/sternenseemann/logbook/default.nix b/pkgs/sternenseemann/logbook/default.nix
index 7a919ade..78f12f4d 100644
--- a/pkgs/sternenseemann/logbook/default.nix
+++ b/pkgs/sternenseemann/logbook/default.nix
@@ -20,6 +20,7 @@ stdenv.mkDerivation rec {
   meta = with stdenv.lib; {
     description = "A tool for personal log files";
     platforms = ocaml.meta.platforms;
+    hydraPlatforms = [ "x86_64-linux" ];
     license = licenses.bsd3;
   };
 }