nix-config/modules/git-pull-timer.nix

158 lines
4.4 KiB
Nix

{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.services.git-pull-timer;
in
{
options.services.git-pull-timer = {
enable = mkEnableOption "git pull timer service";
onCalendar = mkOption {
type = types.listOf types.str;
default = [ "daily" ];
description = "OnCalendar options for the timer (systemd calendar format)";
example = [
"hourly"
"daily"
"*:0/30"
];
};
onBoot = mkOption {
type = types.bool;
default = false;
description = "Enable OnBootSec = 5min option for the timer";
};
persistent = mkOption {
type = types.bool;
default = true;
description = "Persistent option for the timer (catch up missed runs)";
};
remoteAddresses = mkOption {
type = types.listOf types.str;
default = null;
description = "List of git remote addresses to try in order";
example = [
"git@github.com:user/repo.git"
"https://github.com/user/repo.git"
];
};
directory = mkOption {
type = types.str;
default = "/etc/nixos";
description = "Directory where the git repository should be located";
};
user = mkOption {
type = types.str;
default = null;
description = "User to run the git operations as";
};
group = mkOption {
type = types.str;
default = null;
description = "Group to run the git operations as";
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.remoteAddresses != null && cfg.remoteAddresses != [ ];
message = "services.git-pull-timer.remoteAddresses must be set and non-empty";
}
{
assertion = cfg.user != null;
message = "services.git-pull-timer.user must be set";
}
{
assertion = cfg.group != null;
message = "services.git-pull-timer.group must be set";
}
];
systemd.services.git-pull-timer = {
description = "Pull git repository";
serviceConfig = {
Type = "oneshot";
ExecStartPre = [
"+${pkgs.coreutils}/bin/mkdir -p ${cfg.directory}"
"+${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} ${cfg.directory}"
];
ExecStart = pkgs.writeShellScript "git-pull-script" ''
set -e
cd ${cfg.directory}
# Check if this is a git repository
if ! ${pkgs.git}/bin/git rev-parse --git-dir > /dev/null 2>&1; then
echo "No git repository found, attempting to clone..."
# Try each remote address in order
success=false
${concatMapStringsSep "\n" (addr: ''
if [ "$success" = "false" ]; then
echo "Trying to clone from: ${addr}"
if ${pkgs.git}/bin/git clone ${addr} . 2>/dev/null; then
echo "Successfully cloned from: ${addr}"
success=true
else
echo "Failed to clone from: ${addr}"
fi
fi
'') cfg.remoteAddresses}
if [ "$success" = "false" ]; then
echo "All clone attempts failed"
exit 1
fi
else
echo "Git repository exists, pulling updates..."
# Check if there are unstaged changes
if ! ${pkgs.git}/bin/git diff --quiet; then
echo "Unstaged changes detected, stashing..."
${pkgs.git}/bin/git stash push -m "Auto-stash before pull $(date)"
fi
# Check if there are staged changes
if ! ${pkgs.git}/bin/git diff --cached --quiet; then
echo "Staged changes detected, pulling with rebase..."
${pkgs.git}/bin/git pull --rebase
else
echo "No staged changes, doing regular pull..."
${pkgs.git}/bin/git pull
fi
fi
'';
User = cfg.user;
Group = cfg.group;
};
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
};
systemd.timers.git-pull-timer = {
description = "Timer for git pull service";
timerConfig =
{
OnCalendar = cfg.onCalendar;
Persistent = cfg.persistent;
}
// optionalAttrs cfg.onBoot {
OnBootSec = "5min";
};
wantedBy = [ "timers.target" ];
};
};
}