diff --git a/modules/modules.nix b/modules/modules.nix index 6504bc42..d798147e 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -308,6 +308,7 @@ let ./services/muchsync.nix ./services/network-manager-applet.nix ./services/nextcloud-client.nix + ./services/nix-gc.nix ./services/notify-osd.nix ./services/opensnitch-ui.nix ./services/osmscout-server.nix diff --git a/modules/services/nix-gc.nix b/modules/services/nix-gc.nix new file mode 100644 index 00000000..01fe5ac5 --- /dev/null +++ b/modules/services/nix-gc.nix @@ -0,0 +1,120 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.nix.gc; + + mkCalendarInterval = frequency: + let + freq = { + "hourly" = [{ Minute = 0; }]; + "weekly" = [{ + Weekday = 1; + Hour = 0; + Minute = 0; + }]; + "monthly" = [{ + Day = 1; + Hour = 0; + Minute = 0; + }]; + "semiannually" = [ + { + Month = 1; + Day = 1; + Hour = 0; + Minute = 0; + } + { + Month = 7; + Day = 1; + Hour = 0; + Minute = 0; + } + ]; + "annually" = [{ + Month = 1; + Day = 1; + Hour = 0; + Minute = 0; + }]; + }; + in freq.${frequency}; + + nixPackage = if config.nix.enable && config.nix.package != null then + config.nix.package + else + pkgs.nix; +in { + meta.maintainers = [ maintainers.shivaraj-bh ]; + + options = { + nix.gc = { + automatic = mkOption { + type = types.bool; + default = false; + description = '' + Automatically run the garbage collector at a specific time. + + Note: This will only garbage collect the current user's profiles. + ''; + }; + + frequency = mkOption { + type = + types.enum [ "hourly" "weekly" "monthly" "semiannually" "annually" ]; + default = "weekly"; + example = "monthly"; + description = '' + The frequency at which to run the garbage collector. + + These enums are based on special expressions from the + {manpage}`systemd.time(7)` + ''; + }; + + options = mkOption { + type = types.nullOr types.str; + default = null; + example = "--max-freed $((64 * 1024**3))"; + description = '' + Options given to {file}`nix-collect-garbage` when the + garbage collector is run automatically. + ''; + }; + }; + }; + + config = lib.mkIf cfg.automatic (mkMerge [ + (mkIf pkgs.stdenv.isLinux { + systemd.user.services.nix-gc = { + Unit = { Description = "Nix Garbage Collector"; }; + Service = { + ExecStart = "${nixPackage}/bin/nix-collect-garbage ${ + lib.optionalString (cfg.options != null) cfg.options + }"; + }; + }; + systemd.user.timers.nix-gc = { + Unit = { Description = "Nix Garbage Collector"; }; + Timer = { + OnCalendar = "${cfg.frequency}"; + Unit = "nix-gc.service"; + }; + Install = { WantedBy = [ "timers.target" ]; }; + }; + }) + + (mkIf pkgs.stdenv.isDarwin { + launchd.agents.nix-gc = { + enable = true; + config = { + ProgramArguments = [ "${nixPackage}/bin/nix-collect-garbage" ] + ++ lib.optional (cfg.options != null) cfg.options; + StartCalendarInterval = mkCalendarInterval cfg.frequency; + }; + }; + }) + ]); +} diff --git a/tests/default.nix b/tests/default.nix index ff1373de..be4d8f40 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -161,6 +161,7 @@ in import nmtSrc { ./modules/launchd ./modules/services/git-sync-darwin ./modules/services/imapnotify-darwin + ./modules/services/nix-gc-darwin ./modules/targets-darwin ] ++ lib.optionals isLinux [ ./modules/config/i18n @@ -234,6 +235,7 @@ in import nmtSrc { ./modules/services/mpd ./modules/services/mpd-mpris ./modules/services/mpdris2 + ./modules/services/nix-gc ./modules/services/osmscout-server ./modules/services/pantalaimon ./modules/services/parcellite diff --git a/tests/modules/services/nix-gc-darwin/basic.nix b/tests/modules/services/nix-gc-darwin/basic.nix new file mode 100644 index 00000000..f09309fe --- /dev/null +++ b/tests/modules/services/nix-gc-darwin/basic.nix @@ -0,0 +1,19 @@ +{ ... }: + +{ + nix.gc = { + automatic = true; + frequency = "monthly"; + options = "--delete-older-than 30d"; + }; + + test.stubs.nix = { name = "nix"; }; + + nmt.script = '' + serviceFile=LaunchAgents/org.nix-community.home.nix-gc.plist + + assertFileExists "$serviceFile" + + assertFileContent "$serviceFile" ${./expected-agent.plist} + ''; +} diff --git a/tests/modules/services/nix-gc-darwin/default.nix b/tests/modules/services/nix-gc-darwin/default.nix new file mode 100644 index 00000000..f2fc20aa --- /dev/null +++ b/tests/modules/services/nix-gc-darwin/default.nix @@ -0,0 +1 @@ +{ nix-gc = ./basic.nix; } diff --git a/tests/modules/services/nix-gc-darwin/expected-agent.plist b/tests/modules/services/nix-gc-darwin/expected-agent.plist new file mode 100644 index 00000000..13b16c16 --- /dev/null +++ b/tests/modules/services/nix-gc-darwin/expected-agent.plist @@ -0,0 +1,24 @@ + + + + + Label + org.nix-community.home.nix-gc + ProgramArguments + + @nix@/bin/nix-collect-garbage + --delete-older-than 30d + + StartCalendarInterval + + + Day + 1 + Hour + 0 + Minute + 0 + + + + \ No newline at end of file diff --git a/tests/modules/services/nix-gc/basic.nix b/tests/modules/services/nix-gc/basic.nix new file mode 100644 index 00000000..d6511a17 --- /dev/null +++ b/tests/modules/services/nix-gc/basic.nix @@ -0,0 +1,29 @@ +{ ... }: + +{ + nix.gc = { + automatic = true; + frequency = "monthly"; + options = "--delete-older-than 30d"; + }; + + test.stubs.nix = { name = "nix"; }; + + nmt.script = '' + serviceFile=home-files/.config/systemd/user/nix-gc.service + + assertFileExists $serviceFile + + serviceFile=$(normalizeStorePaths $serviceFile) + + assertFileContent $serviceFile ${./expected.service} + + timerFile=home-files/.config/systemd/user/nix-gc.timer + + assertFileExists $timerFile + + timerFile=$(normalizeStorePaths $timerFile) + + assertFileContent $timerFile ${./expected.timer} + ''; +} diff --git a/tests/modules/services/nix-gc/default.nix b/tests/modules/services/nix-gc/default.nix new file mode 100644 index 00000000..f2fc20aa --- /dev/null +++ b/tests/modules/services/nix-gc/default.nix @@ -0,0 +1 @@ +{ nix-gc = ./basic.nix; } diff --git a/tests/modules/services/nix-gc/expected.service b/tests/modules/services/nix-gc/expected.service new file mode 100644 index 00000000..4aafd6af --- /dev/null +++ b/tests/modules/services/nix-gc/expected.service @@ -0,0 +1,5 @@ +[Service] +ExecStart=@nix@/bin/nix-collect-garbage --delete-older-than 30d + +[Unit] +Description=Nix Garbage Collector diff --git a/tests/modules/services/nix-gc/expected.timer b/tests/modules/services/nix-gc/expected.timer new file mode 100644 index 00000000..2b0c6603 --- /dev/null +++ b/tests/modules/services/nix-gc/expected.timer @@ -0,0 +1,9 @@ +[Install] +WantedBy=timers.target + +[Timer] +OnCalendar=monthly +Unit=nix-gc.service + +[Unit] +Description=Nix Garbage Collector