diff --git a/flake.nix b/flake.nix index fc1c8be..a6309e0 100644 --- a/flake.nix +++ b/flake.nix @@ -79,6 +79,7 @@ impermanence.nixosModules.impermanence nix-flatpak.nixosModules.nix-flatpak stylix.nixosModules.stylix + self.nixosModules.git-pull-timer { nixpkgs.overlays = [ agenix.overlays.default @@ -200,6 +201,7 @@ nixosModules = { qbittorrent = import ./modules/qbittorrent.nix; + git-pull-timer = import ./modules/git-pull-timer.nix; }; }; } diff --git a/hosts/modules/services.nix b/hosts/modules/services.nix index 85939f7..a63e75d 100644 --- a/hosts/modules/services.nix +++ b/hosts/modules/services.nix @@ -18,6 +18,15 @@ enable = true; settings.PermitRootLogin = "no"; }; + git-pull-timer = { + enable = true; + remoteAddresses = [ + "git@github.com:baduhai/nix-config.git" + "https://github.com/baduhai/nix-config.git" + ]; + user = "user"; + group = "users"; + }; fwupd.enable = true; fstrim.enable = true; }; diff --git a/modules/git-pull-timer.nix b/modules/git-pull-timer.nix new file mode 100644 index 0000000..69efd8b --- /dev/null +++ b/modules/git-pull-timer.nix @@ -0,0 +1,158 @@ +{ + 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" ]; + }; + }; +}