~kaction/config

2c54bac298716db8e2eb66ade81f20f9b60e33e6 — Dmitry Bogatov 3 months ago 01a2c11
manifest: setup ~/githooks directory

For every git hook directory ~/githooks/{hook}.d is created and program
~/githooks/{hook} multiplex arguments and stdin to scripts in that
directory. This way it is possible for multiple hooks, both ad-hoc and
installed by nix-sys, to be run on single git event.

This approach has minor performance penalty, since even if there are no
hooks, git will still run dispatch script, but I do not expect it to be
significant.
3 files changed, 86 insertions(+), 1 deletions(-)

M manifest/default.nix
A manifest/user/githooks/builder.py
A manifest/user/githooks/default.nix
M manifest/default.nix => manifest/default.nix +7 -1
@@ 30,6 30,12 @@ let
    '';
    allowSubstitutes = false;
  };
  importManifest = path: args:
    let drv = callPackage path args;
    in builtins.fromJSON (builtins.readFile drv);
  manifest-githooks = importManifest ./user/githooks {
    githooks-root = "/home/kaction/githooks";
  };
  manifest = {
    base = let
      user-mkdir = {


@@ 74,7 80,7 @@ let
        "/var/log/runit/activate/.keep" = touch;
        "/usr/local/bin/doas" = suid "${doas}/bin/doas";
        "/etc/xbps.d/xbps.conf" = symlink ./xbps.conf;
      };
      } // manifest-githooks;
    in writeText "manifest.json" (builtins.toJSON (stdenv.lib.fix f));
  };
in manifest.base

A manifest/user/githooks/builder.py => manifest/user/githooks/builder.py +66 -0
@@ 0,0 1,66 @@
import sys
import os
import json
from textwrap import dedent

# Extracted directly from githooks(5). Sure, I use only small subset of
# them, but it is convenient to have everything ready to plug any hook
# in ad-hoc fashion.
hooks = [
    ("applypatch-msg"),
    ("pre-applypatch"),
    ("post-applypatch"),
    ("pre-commit"),
    ("pre-merge-commit"),
    ("prepare-commit-msg"),
    ("commit-msg"),
    ("post-commit"),
    ("pre-rebase"),
    ("post-checkout"),
    ("post-merge"),
    ("pre-push"),
    ("pre-receive"),
    ("update"),
    ("proc-receive"),
    ("post-receive"),
    ("post-update"),
    ("reference-transaction"),
    ("push-to-checkout"),
    ("pre-auto-gc"),
    ("post-rewrite"),
    ("sendemail-validate"),
    ("fsmonitor-watchman"),
    ("p4-changelist"),
    ("p4-prepare-changelist"),
    ("p4-post-changelist"),
    ("p4-pre-submit"),
    ("post-index-change"),
]

root = os.environ["root"]
data = os.environ["data"]
out = os.environ["out"]
debianutils = os.environ["debianutils"]
execline = os.environ["execline"]

manifest = {}
os.mkdir(data)

for hook in hooks:
    script = f"{data}/{hook}"
    with open(script, "w") as fp:
        fp.write(dedent(f"""
            #!{execline}/bin/execlineb -WS0
            {debianutils}/bin/run-parts --stdin --arg=$@ {root}/{hook}.d
        """[1:-1]))
    os.chmod(script, 0o555)
    manifest[f"{root}/{hook}"] = dict(action="symlink", path=script)
    # This is bad. I have uid hardcoded in multiple places.
    manifest[f"{root}/{hook}.d"] = {
        "action": "mkdir",
        "owner": 1000,
        "mode": "0700",
    }

with open(out, "w") as fp:
    json.dump(manifest, fp, indent=2)

A manifest/user/githooks/default.nix => manifest/user/githooks/default.nix +13 -0
@@ 0,0 1,13 @@
{ stdenv, python3, debianutils, execline, githooks-root }:
stdenv.mkDerivation {
  name = "manifest.json";
  outputs = [ "out" "data" ];
  nativeBuildInputs = [ python3 ];
  phases = [ "installPhase" ];
  installPhase = ''
    python3 ${./builder.py}
  '';

  root = githooks-root;
  inherit execline debianutils;
}