at 23.11-pre 8.2 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.gitolite; 7 # Use writeTextDir to not leak Nix store hash into file name 8 pubkeyFile = (pkgs.writeTextDir "gitolite-admin.pub" cfg.adminPubkey) + "/gitolite-admin.pub"; 9 hooks = lib.concatMapStrings (hook: "${hook} ") cfg.commonHooks; 10in 11{ 12 options = { 13 services.gitolite = { 14 enable = mkOption { 15 type = types.bool; 16 default = false; 17 description = lib.mdDoc '' 18 Enable gitolite management under the 19 `gitolite` user. After 20 switching to a configuration with Gitolite enabled, you can 21 then run `git clone gitolite@host:gitolite-admin.git` to manage it further. 22 ''; 23 }; 24 25 dataDir = mkOption { 26 type = types.str; 27 default = "/var/lib/gitolite"; 28 description = lib.mdDoc '' 29 The gitolite home directory used to store all repositories. If left as the default value 30 this directory will automatically be created before the gitolite server starts, otherwise 31 the sysadmin is responsible for ensuring the directory exists with appropriate ownership 32 and permissions. 33 ''; 34 }; 35 36 adminPubkey = mkOption { 37 type = types.str; 38 description = lib.mdDoc '' 39 Initial administrative public key for Gitolite. This should 40 be an SSH Public Key. Note that this key will only be used 41 once, upon the first initialization of the Gitolite user. 42 The key string cannot have any line breaks in it. 43 ''; 44 }; 45 46 enableGitAnnex = mkOption { 47 type = types.bool; 48 default = false; 49 description = lib.mdDoc '' 50 Enable git-annex support. Uses the `extraGitoliteRc` option 51 to apply the necessary configuration. 52 ''; 53 }; 54 55 commonHooks = mkOption { 56 type = types.listOf types.path; 57 default = []; 58 description = lib.mdDoc '' 59 A list of custom git hooks that get copied to `~/.gitolite/hooks/common`. 60 ''; 61 }; 62 63 extraGitoliteRc = mkOption { 64 type = types.lines; 65 default = ""; 66 example = literalExpression '' 67 ''' 68 $RC{UMASK} = 0027; 69 $RC{SITE_INFO} = 'This is our private repository host'; 70 push( @{$RC{ENABLE}}, 'Kindergarten' ); # enable the command/feature 71 @{$RC{ENABLE}} = grep { $_ ne 'desc' } @{$RC{ENABLE}}; # disable the command/feature 72 ''' 73 ''; 74 description = lib.mdDoc '' 75 Extra configuration to append to the default `~/.gitolite.rc`. 76 77 This should be Perl code that modifies the `%RC` 78 configuration variable. The default `~/.gitolite.rc` 79 content is generated by invoking `gitolite print-default-rc`, 80 and extra configuration from this option is appended to it. The result 81 is placed to Nix store, and the `~/.gitolite.rc` file 82 becomes a symlink to it. 83 84 If you already have a customized (or otherwise changed) 85 `~/.gitolite.rc` file, NixOS will refuse to replace 86 it with a symlink, and the `gitolite-init` initialization service 87 will fail. In this situation, in order to use this option, you 88 will need to take any customizations you may have in 89 `~/.gitolite.rc`, convert them to appropriate Perl 90 statements, add them to this option, and remove the file. 91 92 See also the `enableGitAnnex` option. 93 ''; 94 }; 95 96 user = mkOption { 97 type = types.str; 98 default = "gitolite"; 99 description = lib.mdDoc '' 100 Gitolite user account. This is the username of the gitolite endpoint. 101 ''; 102 }; 103 104 description = mkOption { 105 type = types.str; 106 default = "Gitolite user"; 107 description = lib.mdDoc '' 108 Gitolite user account's description. 109 ''; 110 }; 111 112 group = mkOption { 113 type = types.str; 114 default = "gitolite"; 115 description = lib.mdDoc '' 116 Primary group of the Gitolite user account. 117 ''; 118 }; 119 }; 120 }; 121 122 config = mkIf cfg.enable ( 123 let 124 manageGitoliteRc = cfg.extraGitoliteRc != ""; 125 rcDir = pkgs.runCommand "gitolite-rc" { preferLocalBuild = true; } rcDirScript; 126 rcDirScript = 127 '' 128 mkdir "$out" 129 export HOME=temp-home 130 mkdir -p "$HOME/.gitolite/logs" # gitolite can't run without it 131 '${pkgs.gitolite}'/bin/gitolite print-default-rc >>"$out/gitolite.rc.default" 132 cat <<END >>"$out/gitolite.rc" 133 # This file is managed by NixOS. 134 # Use services.gitolite options to control it. 135 136 END 137 cat "$out/gitolite.rc.default" >>"$out/gitolite.rc" 138 '' + 139 optionalString (cfg.extraGitoliteRc != "") '' 140 echo -n ${escapeShellArg '' 141 142 # Added by NixOS: 143 ${removeSuffix "\n" cfg.extraGitoliteRc} 144 145 # per perl rules, this should be the last line in such a file: 146 1; 147 ''} >>"$out/gitolite.rc" 148 ''; 149 in { 150 services.gitolite.extraGitoliteRc = optionalString cfg.enableGitAnnex '' 151 # Enable git-annex support: 152 push( @{$RC{ENABLE}}, 'git-annex-shell ua'); 153 ''; 154 155 users.users.${cfg.user} = { 156 description = cfg.description; 157 home = cfg.dataDir; 158 uid = config.ids.uids.gitolite; 159 group = cfg.group; 160 useDefaultShell = true; 161 }; 162 users.groups.${cfg.group}.gid = config.ids.gids.gitolite; 163 164 systemd.services.gitolite-init = { 165 description = "Gitolite initialization"; 166 wantedBy = [ "multi-user.target" ]; 167 unitConfig.RequiresMountsFor = cfg.dataDir; 168 169 environment = { 170 GITOLITE_RC = ".gitolite.rc"; 171 GITOLITE_RC_DEFAULT = "${rcDir}/gitolite.rc.default"; 172 }; 173 174 serviceConfig = mkMerge [ 175 (mkIf (cfg.dataDir == "/var/lib/gitolite") { 176 StateDirectory = "gitolite gitolite/.gitolite gitolite/.gitolite/logs"; 177 StateDirectoryMode = "0750"; 178 }) 179 { 180 Type = "oneshot"; 181 User = cfg.user; 182 Group = cfg.group; 183 WorkingDirectory = "~"; 184 RemainAfterExit = true; 185 } 186 ]; 187 188 path = [ pkgs.gitolite pkgs.git pkgs.perl pkgs.bash pkgs.diffutils config.programs.ssh.package ]; 189 script = 190 let 191 rcSetupScriptIfCustomFile = 192 if manageGitoliteRc then '' 193 cat <<END 194 <3>ERROR: NixOS can't apply declarative configuration 195 <3>to your .gitolite.rc file, because it seems to be 196 <3>already customized manually. 197 <3>See the services.gitolite.extraGitoliteRc option 198 <3>in "man configuration.nix" for more information. 199 END 200 # Not sure if the line below addresses the issue directly or just 201 # adds a delay, but without it our error message often doesn't 202 # show up in `systemctl status gitolite-init`. 203 journalctl --flush 204 exit 1 205 '' else '' 206 : 207 ''; 208 rcSetupScriptIfDefaultFileOrStoreSymlink = 209 if manageGitoliteRc then '' 210 ln -sf "${rcDir}/gitolite.rc" "$GITOLITE_RC" 211 '' else '' 212 [[ -L "$GITOLITE_RC" ]] && rm -f "$GITOLITE_RC" 213 ''; 214 in 215 '' 216 if ( [[ ! -e "$GITOLITE_RC" ]] && [[ ! -L "$GITOLITE_RC" ]] ) || 217 ( [[ -f "$GITOLITE_RC" ]] && diff -q "$GITOLITE_RC" "$GITOLITE_RC_DEFAULT" >/dev/null ) || 218 ( [[ -L "$GITOLITE_RC" ]] && [[ "$(readlink "$GITOLITE_RC")" =~ ^/nix/store/ ]] ) 219 then 220 '' + rcSetupScriptIfDefaultFileOrStoreSymlink + 221 '' 222 else 223 '' + rcSetupScriptIfCustomFile + 224 '' 225 fi 226 227 if [ ! -d repositories ]; then 228 gitolite setup -pk ${pubkeyFile} 229 fi 230 if [ -n "${hooks}" ]; then 231 cp -f ${hooks} .gitolite/hooks/common/ 232 chmod +x .gitolite/hooks/common/* 233 fi 234 gitolite setup # Upgrade if needed 235 ''; 236 }; 237 238 environment.systemPackages = [ pkgs.gitolite pkgs.git ] 239 ++ optional cfg.enableGitAnnex pkgs.git-annex; 240 }); 241}