{ 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 <>"$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.filesystem.impermanence.system.dirs = [ { directory = cfg.dataDir; mode = "0755"; user = cfg.user; group = cfg.group; } ]; 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; packages = [ pkgs.gitolite pkgs.git pkgs.perl ]; }; 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 <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 ''; }; } ); }