zaphyra's git: nixfiles

zaphyra and void's nixfiles

commit 1de3fc7316426d1fee00bf583da083b2634f5bc2
parent 13d213e83a53b3823af22a0b0470c68cdceee1ef
Author: Katja (zaphyra) <git@ctu.cx>
Date: Fri, 23 May 2025 11:29:19 +0200

config/nixos/modules/services: add `gitolite`
1 file changed, 236 insertions(+), 0 deletions(-)
A
config/nixos/modules/services/gitolite.nix
|
236
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/config/nixos/modules/services/gitolite.nix b/config/nixos/modules/services/gitolite.nix
@@ -0,0 +1,236 @@
+{
+  povSelf,
+  config,
+  pkgs,
+  lib,
+  ...
+}:
+let
+  inherit (lib) types;
+  cfg = lib.getAttrFromPath povSelf config;
+
+in
+{
+
+  options = {
+    enable = {
+      type = types.bool;
+      default = false;
+    };
+
+    dataDir = {
+      type = types.str;
+      default = "/var/lib/gitolite";
+    };
+
+    adminPubkey = {
+      type = types.str;
+    };
+
+    commonHooks = {
+      type = types.attrsOf types.lines;
+      default = { };
+    };
+
+    triggers = {
+      type = types.attrsOf types.lines;
+      default = { };
+    };
+
+    commands = {
+      type = types.attrsOf types.lines;
+      default = { };
+    };
+
+    extraGitoliteRc = {
+      type = types.lines;
+      default = "";
+    };
+
+    user = {
+      type = types.str;
+      default = "gitolite";
+    };
+
+    group = {
+      type = types.str;
+      default = "gitolite";
+    };
+  };
+
+  config = lib.mkIf cfg.enable (
+    let
+      # Use writeTextDir to not leak Nix store hash into file name
+      pubkeyFile = (pkgs.writeTextDir "gitolite-admin.pub" cfg.adminPubkey) + "/gitolite-admin.pub";
+      hooks = lib.mapAttrs (
+        name: script:
+        (pkgs.writeShellScript name (
+          if name == "post-receive" then
+            ''
+              read oldrev newrev ref
+              [ -t 0 ] || cat >/dev/null
+              [ -z "$GL_REPO" ] && die GL_REPO not set
+
+            ''
+            + script
+          else
+            script
+        ))
+      ) cfg.commonHooks;
+      triggers = lib.mapAttrs (name: script: (pkgs.writeShellScript name script)) cfg.triggers;
+      commands = lib.mapAttrs (name: script: (pkgs.writeShellScript name script)) cfg.commands;
+      manageGitoliteRc = cfg.extraGitoliteRc != "";
+      rcDir = pkgs.runCommand "gitolite-rc" { preferLocalBuild = true; } rcDirScript;
+      rcDirScript =
+        ''
+          mkdir "$out"
+          export HOME=temp-home
+          mkdir -p "$HOME/.gitolite/logs" # gitolite can't run without it
+          '${pkgs.gitolite}'/bin/gitolite print-default-rc >>"$out/gitolite.rc.default"
+          cat <<END >>"$out/gitolite.rc"
+          # This file is managed by NixOS.
+          # Use services.gitolite options to control it.
+
+          END
+          cat "$out/gitolite.rc.default" >>"$out/gitolite.rc"
+        ''
+        + lib.optionalString (cfg.extraGitoliteRc != "") ''
+          echo -n ${lib.escapeShellArg ''
+
+            # Added by NixOS:
+            ${lib.removeSuffix "\n" cfg.extraGitoliteRc}
+
+            # per perl rules, this should be the last line in such a file:
+            1;
+          ''} >>"$out/gitolite.rc"
+        '';
+
+    in
+    {
+      modules.services.gitolite.extraGitoliteRc = ''
+        $RC{LOCAL_CODE} = "$ENV{HOME}/.gitolite/local";
+      '';
+
+      users.users.${cfg.user} = {
+        home = cfg.dataDir;
+        uid = config.ids.uids.gitolite;
+        group = cfg.group;
+        extraGroups = [ "ssh" ];
+        useDefaultShell = true;
+      };
+
+      users.groups.${cfg.group}.gid = config.ids.gids.gitolite;
+
+      systemd.services.gitolite-init = {
+        description = "Gitolite initialization";
+        wantedBy = [ "multi-user.target" ];
+        unitConfig.RequiresMountsFor = cfg.dataDir;
+
+        environment = {
+          GITOLITE_RC = ".gitolite.rc";
+          GITOLITE_RC_DEFAULT = "${rcDir}/gitolite.rc.default";
+        };
+
+        serviceConfig = lib.mkMerge [
+          (lib.mkIf (cfg.dataDir == "/var/lib/gitolite") {
+            StateDirectory = "gitolite gitolite/.gitolite gitolite/.gitolite/logs";
+            StateDirectoryMode = "0750";
+          })
+          {
+            Type = "oneshot";
+            User = cfg.user;
+            Group = cfg.group;
+            WorkingDirectory = "~";
+            RemainAfterExit = true;
+          }
+        ];
+
+        path = [
+          pkgs.gitolite
+          pkgs.git
+          pkgs.perl
+          pkgs.bash
+          pkgs.diffutils
+          config.programs.ssh.package
+        ];
+        script =
+          let
+            rcSetupScriptIfCustomFile =
+              if manageGitoliteRc then
+                ''
+                  cat <<END
+                  <3>ERROR: NixOS can't apply declarative configuration
+                  <3>to your .gitolite.rc file, because it seems to be
+                  <3>already customized manually.
+                  <3>See the services.gitolite.extraGitoliteRc option
+                  <3>in "man configuration.nix" for more information.
+                  END
+                  # Not sure if the line below addresses the issue directly or just
+                  # adds a delay, but without it our error message often doesn't
+                  # show up in `systemctl status gitolite-init`.
+                  journalctl --flush
+                  exit 1
+                ''
+              else
+                ''
+                  :
+                '';
+            rcSetupScriptIfDefaultFileOrStoreSymlink =
+              if manageGitoliteRc then
+                ''
+                  ln -sf "${rcDir}/gitolite.rc" "$GITOLITE_RC"
+                ''
+              else
+                ''
+                  [[ -L "$GITOLITE_RC" ]] && rm -f "$GITOLITE_RC"
+                '';
+          in
+          ''
+            if ( [[ ! -e "$GITOLITE_RC" ]] && [[ ! -L "$GITOLITE_RC" ]] ) ||
+               ( [[ -f "$GITOLITE_RC" ]] && diff -q "$GITOLITE_RC" "$GITOLITE_RC_DEFAULT" >/dev/null ) ||
+               ( [[ -L "$GITOLITE_RC" ]] && [[ "$(readlink "$GITOLITE_RC")" =~ ^/nix/store/ ]] )
+            then
+          ''
+          + rcSetupScriptIfDefaultFileOrStoreSymlink
+          + ''
+            else
+          ''
+          + rcSetupScriptIfCustomFile
+          + ''
+            fi
+
+            if [ ! -d repositories ]; then
+              gitolite setup -pk ${pubkeyFile}
+            fi
+
+            rm -rf   .gitolite/local/hooks/common/
+            mkdir -p .gitolite/local/hooks/common/
+            ${lib.concatStringsSep "\n" (
+              lib.mapAttrsToList (name: script: "ln -s ${script} .gitolite/local/hooks/common/${name}") hooks
+            )}
+
+            rm -rf .gitolite/local/triggers/
+            mkdir -p .gitolite/local/triggers/
+            ${lib.concatStringsSep "\n" (
+              lib.mapAttrsToList (name: script: "ln -s ${script} .gitolite/local/triggers/${name}") triggers
+            )}
+
+            rm -rf .gitolite/local/commands/
+            mkdir -p .gitolite/local/commands/
+            ${lib.concatStringsSep "\n" (
+              lib.mapAttrsToList (name: script: "ln -s ${script} .gitolite/local/commands/${name}") commands
+            )}
+
+            gitolite setup # Upgrade if needed
+          '';
+      };
+
+      environment.systemPackages = [
+        pkgs.gitolite
+        pkgs.git
+        pkgs.perl
+      ];
+    }
+  );
+
+}