2014-06-26 04:32:45 +01:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.gitolite;
|
2017-09-12 09:44:21 +01:00
|
|
|
# Use writeTextDir to not leak Nix store hash into file name
|
|
|
|
pubkeyFile = (pkgs.writeTextDir "gitolite-admin.pub" cfg.adminPubkey) + "/gitolite-admin.pub";
|
2014-09-16 07:33:29 +01:00
|
|
|
hooks = lib.concatMapStrings (hook: "${hook} ") cfg.commonHooks;
|
2014-06-26 04:32:45 +01:00
|
|
|
in
|
|
|
|
{
|
|
|
|
options = {
|
|
|
|
services.gitolite = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
Enable gitolite management under the
|
2014-11-01 23:24:41 +00:00
|
|
|
<literal>gitolite</literal> user. After
|
2014-06-26 04:32:45 +01:00
|
|
|
switching to a configuration with Gitolite enabled, you can
|
|
|
|
then run <literal>git clone
|
2014-06-26 04:55:43 +01:00
|
|
|
gitolite@host:gitolite-admin.git</literal> to manage it further.
|
2014-06-26 04:32:45 +01:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2014-11-01 23:24:41 +00:00
|
|
|
dataDir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "/var/lib/gitolite";
|
|
|
|
description = ''
|
|
|
|
Gitolite home directory (used to store all the repositories).
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2014-06-26 04:32:45 +01:00
|
|
|
adminPubkey = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
Initial administrative public key for Gitolite. This should
|
|
|
|
be an SSH Public Key. Note that this key will only be used
|
|
|
|
once, upon the first initialization of the Gitolite user.
|
2015-01-13 05:49:33 +00:00
|
|
|
The key string cannot have any line breaks in it.
|
2014-06-26 04:32:45 +01:00
|
|
|
'';
|
|
|
|
};
|
2014-09-16 07:33:29 +01:00
|
|
|
|
2017-09-23 08:56:26 +01:00
|
|
|
enableGitAnnex = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = ''
|
|
|
|
Enable git-annex support. Uses the <literal>extraGitoliteRc</literal> option
|
|
|
|
to apply the necessary configuration.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2014-09-16 07:33:29 +01:00
|
|
|
commonHooks = mkOption {
|
|
|
|
type = types.listOf types.path;
|
|
|
|
default = [];
|
|
|
|
description = ''
|
|
|
|
A list of custom git hooks that get copied to <literal>~/.gitolite/hooks/common</literal>.
|
|
|
|
'';
|
|
|
|
};
|
2014-11-14 15:07:17 +00:00
|
|
|
|
2017-09-22 03:16:36 +01:00
|
|
|
extraGitoliteRc = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = "";
|
|
|
|
example = literalExample ''
|
|
|
|
$RC{UMASK} = 0027;
|
|
|
|
$RC{SITE_INFO} = 'This is our private repository host';
|
|
|
|
push( @{$RC{ENABLE}}, 'Kindergarten' ); # enable the command/feature
|
|
|
|
@{$RC{ENABLE}} = grep { $_ ne 'desc' } @{$RC{ENABLE}}; # disable the command/feature
|
|
|
|
'';
|
|
|
|
description = ''
|
|
|
|
Extra configuration to append to the default <literal>~/.gitolite.rc</literal>.
|
|
|
|
|
|
|
|
This should be Perl code that modifies the <literal>%RC</literal>
|
|
|
|
configuration variable. The default <literal>~/.gitolite.rc</literal>
|
|
|
|
content is generated by invoking <literal>gitolite print-default-rc</literal>,
|
|
|
|
and extra configuration from this option is appended to it. The result
|
|
|
|
is placed to Nix store, and the <literal>~/.gitolite.rc</literal> file
|
|
|
|
becomes a symlink to it.
|
|
|
|
|
|
|
|
If you already have a customized (or otherwise changed)
|
|
|
|
<literal>~/.gitolite.rc</literal> file, NixOS will refuse to replace
|
|
|
|
it with a symlink, and the `gitolite-init` initialization service
|
|
|
|
will fail. In this situation, in order to use this option, you
|
|
|
|
will need to take any customizations you may have in
|
|
|
|
<literal>~/.gitolite.rc</literal>, convert them to appropriate Perl
|
|
|
|
statements, add them to this option, and remove the file.
|
2017-09-23 08:56:26 +01:00
|
|
|
|
|
|
|
See also the <literal>enableGitAnnex</literal> option.
|
2017-09-22 03:16:36 +01:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2014-11-14 15:07:17 +00:00
|
|
|
user = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "gitolite";
|
|
|
|
description = ''
|
|
|
|
Gitolite user account. This is the username of the gitolite endpoint.
|
|
|
|
'';
|
|
|
|
};
|
2017-09-12 10:31:29 +01:00
|
|
|
|
|
|
|
group = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "gitolite";
|
|
|
|
description = ''
|
|
|
|
Primary group of the Gitolite user account.
|
|
|
|
'';
|
|
|
|
};
|
2014-06-26 04:32:45 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2017-09-22 03:16:36 +01:00
|
|
|
config = mkIf cfg.enable (
|
|
|
|
let
|
|
|
|
manageGitoliteRc = cfg.extraGitoliteRc != "";
|
2018-11-08 10:59:03 +00:00
|
|
|
rcDir = pkgs.runCommand "gitolite-rc" { preferLocalBuild = true; } rcDirScript;
|
2017-09-22 03:16:36 +01:00
|
|
|
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"
|
|
|
|
'' +
|
|
|
|
optionalString (cfg.extraGitoliteRc != "") ''
|
|
|
|
echo -n ${escapeShellArg ''
|
|
|
|
|
|
|
|
# Added by NixOS:
|
|
|
|
${removeSuffix "\n" cfg.extraGitoliteRc}
|
|
|
|
|
|
|
|
# per perl rules, this should be the last line in such a file:
|
|
|
|
1;
|
|
|
|
''} >>"$out/gitolite.rc"
|
|
|
|
'';
|
|
|
|
in {
|
2017-09-23 08:56:26 +01:00
|
|
|
services.gitolite.extraGitoliteRc = optionalString cfg.enableGitAnnex ''
|
|
|
|
# Enable git-annex support:
|
|
|
|
push( @{$RC{ENABLE}}, 'git-annex-shell ua');
|
|
|
|
'';
|
|
|
|
|
2018-06-30 00:58:35 +01:00
|
|
|
users.users.${cfg.user} = {
|
2014-06-26 04:32:45 +01:00
|
|
|
description = "Gitolite user";
|
2014-11-01 23:24:41 +00:00
|
|
|
home = cfg.dataDir;
|
2014-06-26 04:32:45 +01:00
|
|
|
uid = config.ids.uids.gitolite;
|
2017-09-12 10:31:29 +01:00
|
|
|
group = cfg.group;
|
2014-06-26 04:32:45 +01:00
|
|
|
useDefaultShell = true;
|
|
|
|
};
|
2018-06-30 00:58:35 +01:00
|
|
|
users.groups."${cfg.group}".gid = config.ids.gids.gitolite;
|
2014-06-26 04:32:45 +01:00
|
|
|
|
2019-06-22 18:18:51 +01:00
|
|
|
systemd.tmpfiles.rules = [
|
|
|
|
"d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.dataDir}'/.gitolite - ${cfg.user} ${cfg.group} - -"
|
|
|
|
"d '${cfg.dataDir}'/.gitolite/logs - ${cfg.user} ${cfg.group} - -"
|
|
|
|
|
|
|
|
"Z ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -"
|
|
|
|
];
|
|
|
|
|
2014-06-26 04:32:45 +01:00
|
|
|
systemd.services."gitolite-init" = {
|
|
|
|
description = "Gitolite initialization";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
2017-09-11 20:03:51 +01:00
|
|
|
unitConfig.RequiresMountsFor = cfg.dataDir;
|
2014-06-26 04:32:45 +01:00
|
|
|
|
2019-06-22 18:18:51 +01:00
|
|
|
environment = {
|
|
|
|
GITOLITE_RC = ".gitolite.rc";
|
|
|
|
GITOLITE_RC_DEFAULT = "${rcDir}/gitolite.rc.default";
|
|
|
|
};
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
User = cfg.user;
|
|
|
|
Group = cfg.group;
|
|
|
|
WorkingDirectory = "~";
|
|
|
|
RemainAfterExit = true;
|
|
|
|
};
|
2014-06-26 04:32:45 +01:00
|
|
|
|
2017-09-22 03:16:36 +01:00
|
|
|
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
|
|
|
|
if [ -n "${hooks}" ]; then
|
2017-12-19 16:06:26 +00:00
|
|
|
cp -f ${hooks} .gitolite/hooks/common/
|
2017-09-22 03:16:36 +01:00
|
|
|
chmod +x .gitolite/hooks/common/*
|
|
|
|
fi
|
|
|
|
gitolite setup # Upgrade if needed
|
|
|
|
'';
|
2014-06-26 04:32:45 +01:00
|
|
|
};
|
|
|
|
|
2017-09-23 08:56:26 +01:00
|
|
|
environment.systemPackages = [ pkgs.gitolite pkgs.git ]
|
|
|
|
++ optional cfg.enableGitAnnex pkgs.gitAndTools.git-annex;
|
2017-09-22 03:16:36 +01:00
|
|
|
});
|
2014-06-26 04:32:45 +01:00
|
|
|
}
|