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