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