From 1b0478e165bfbbc666e4cd60124be35db3881798 Mon Sep 17 00:00:00 2001 From: Lin Yinfeng Date: Mon, 1 Sep 2025 17:18:43 +0800 Subject: [PATCH] angrr: init at 0.1.1 Also add a nixos module and a nixos test. --- .../manual/release-notes/rl-2511.section.md | 2 + nixos/modules/module-list.nix | 1 + nixos/modules/services/misc/angrr.nix | 128 ++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/angrr.nix | 63 +++++++++ pkgs/by-name/an/angrr/package.nix | 50 +++++++ 6 files changed, 245 insertions(+) create mode 100644 nixos/modules/services/misc/angrr.nix create mode 100644 nixos/tests/angrr.nix create mode 100644 pkgs/by-name/an/angrr/package.nix diff --git a/nixos/doc/manual/release-notes/rl-2511.section.md b/nixos/doc/manual/release-notes/rl-2511.section.md index 4727bdd8e785..a9602f7afd68 100644 --- a/nixos/doc/manual/release-notes/rl-2511.section.md +++ b/nixos/doc/manual/release-notes/rl-2511.section.md @@ -82,6 +82,8 @@ - [dwl](https://codeberg.org/dwl/dwl), a compact, hackable compositor for Wayland based on wlroots. Available as [programs.dwl](#opt-programs.dwl.enable). +- [angrr](https://github.com/linyinfeng/angrr), a service that automatically cleans up old auto GC roots. Available as [services.angrr](#opt-services.angrr.enable). + - [Sharkey](https://joinsharkey.org), a Sharkish microblogging platform. Available as [services.sharkey](#opt-services.sharkey.enable). - [fw-fanctrl](https://github.com/TamtamHero/fw-fanctrl), a simple systemd service to better control Framework Laptop's fan(s). Available as [hardware.fw-fanctrl](#opt-hardware.fw-fanctrl.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 50679a014efc..5f03ed380891 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -788,6 +788,7 @@ ./services/misc/airsonic.nix ./services/misc/amazon-ssm-agent.nix ./services/misc/ananicy.nix + ./services/misc/angrr.nix ./services/misc/anki-sync-server.nix ./services/misc/apache-kafka.nix ./services/misc/atuin.nix diff --git a/nixos/modules/services/misc/angrr.nix b/nixos/modules/services/misc/angrr.nix new file mode 100644 index 000000000000..dbecc7e76fbb --- /dev/null +++ b/nixos/modules/services/misc/angrr.nix @@ -0,0 +1,128 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.angrr; +in +{ + meta.maintainers = pkgs.angrr.meta.maintainers; + options = { + services.angrr = { + enable = lib.mkEnableOption "angrr"; + package = lib.mkPackageOption pkgs "angrr" { }; + period = lib.mkOption { + type = lib.types.str; + default = "7d"; + example = "2weeks"; + description = '' + The retention period of auto GC roots. + ''; + }; + removeRoot = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to pass the `--remove-root` option to angrr. + ''; + }; + ownedOnly = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Control the `--remove-root=` option of angrr. + ''; + apply = b: if b then "true" else "false"; + }; + logLevel = lib.mkOption { + type = + with lib.types; + enum [ + "off" + "error" + "warn" + "info" + "debug" + "trace" + ]; + default = "info"; + description = '' + Set the log level of angrr. + ''; + }; + extraArgs = lib.mkOption { + type = with lib.types; listOf str; + default = [ ]; + description = '' + Extra command-line arguments pass to angrr. + ''; + }; + enableNixGcIntegration = lib.mkOption { + type = lib.types.bool; + description = '' + Whether to enable nix-gc.service integration + ''; + }; + timer = { + enable = lib.mkEnableOption "angrr timer"; + dates = lib.mkOption { + type = lib.types.str; + default = "03:00"; + description = '' + How often or when the retention policy is performed. + ''; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + assertions = [ + { + assertion = cfg.enableNixGcIntegration -> config.nix.gc.automatic; + message = "angrr nix-gc.service integration requires `nix.gc.automatic = true`"; + } + ]; + services.angrr.enableNixGcIntegration = lib.mkDefault config.nix.gc.automatic; + } + + { + systemd.services.angrr = { + description = "Auto Nix GC Roots Retention"; + script = '' + ${lib.getExe cfg.package} run \ + --log-level "${cfg.logLevel}" \ + --period "${cfg.period}" \ + ${lib.optionalString cfg.removeRoot "--remove-root"} \ + --owned-only="${cfg.ownedOnly}" \ + --no-prompt ${lib.escapeShellArgs cfg.extraArgs} + ''; + serviceConfig = { + Type = "oneshot"; + }; + }; + } + + (lib.mkIf cfg.timer.enable { + systemd.timers.angrr = { + timerConfig = { + OnCalendar = cfg.timer.dates; + }; + wantedBy = [ "timers.target" ]; + }; + }) + + (lib.mkIf cfg.enableNixGcIntegration { + systemd.services.angrr = { + wantedBy = [ "nix-gc.service" ]; + before = [ "nix-gc.service" ]; + }; + }) + ] + ); +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 3c6f89dcb2ae..6854525656ff 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -210,6 +210,7 @@ in amd-sev = runTest ./amd-sev.nix; android-translation-layer = runTest ./android-translation-layer.nix; angie-api = runTest ./angie-api.nix; + angrr = runTest ./angrr.nix; anki-sync-server = runTest ./anki-sync-server.nix; anubis = runTest ./anubis.nix; anuko-time-tracker = runTest ./anuko-time-tracker.nix; diff --git a/nixos/tests/angrr.nix b/nixos/tests/angrr.nix new file mode 100644 index 000000000000..7e57e071390a --- /dev/null +++ b/nixos/tests/angrr.nix @@ -0,0 +1,63 @@ +{ ... }: +{ + name = "angrr"; + nodes = { + machine = { + services.angrr = { + enable = true; + period = "7d"; + }; + # `angrr.service` integrates to `nix-gc.service` by default + nix.gc.automatic = true; + + # Create a normal nix user for test + users.users.normal.isNormalUser = true; + # For `nix build /run/current-system --out-link`, + # `nix-build` does not support this use case. + nix.settings.experimental-features = [ "nix-command" ]; + }; + }; + + testScript = '' + start_all() + + machine.wait_for_unit("default.target") + + machine.systemctl("stop nix-gc.timer") + + # Creates some auto gc roots + # Use /run/current-system so that we do not need to build anything new + machine.succeed("nix build /run/current-system --out-link /tmp/root-auto-gc-root-1") + machine.succeed("nix build /run/current-system --out-link /tmp/root-auto-gc-root-2") + machine.succeed("su normal --command 'nix build /run/current-system --out-link /tmp/user-auto-gc-root-1'") + machine.succeed("su normal --command 'nix build /run/current-system --out-link /tmp/user-auto-gc-root-2'") + + machine.systemctl("start nix-gc.service") + # Not auto gc root will be removed + machine.succeed("readlink /tmp/root-auto-gc-root-1") + machine.succeed("readlink /tmp/root-auto-gc-root-2") + machine.succeed("readlink /tmp/user-auto-gc-root-1") + machine.succeed("readlink /tmp/user-auto-gc-root-2") + + # Change time to 8 days after (greater than 7d) + machine.succeed("date -s '8 days'") + + # Touch GC roots `-2` + machine.succeed("touch /tmp/root-auto-gc-root-2 --no-dereference") + machine.succeed("touch /tmp/user-auto-gc-root-2 --no-dereference") + + machine.systemctl("start nix-gc.service") + # Only GC roots `-1` are removed + machine.succeed("test ! -f /tmp/root-auto-gc-root-1") + machine.succeed("readlink /tmp/root-auto-gc-root-2") + machine.succeed("test ! -f /tmp/user-auto-gc-root-1") + machine.succeed("readlink /tmp/user-auto-gc-root-2") + + # Change time again + machine.succeed("date -s '8 days'") + machine.systemctl("start nix-gc.service") + # All auto GC roots are removed + machine.succeed("test ! -f /tmp/root-auto-gc-root-2") + machine.succeed("test ! -f /tmp/user-auto-gc-root-2") + ''; +} diff --git a/pkgs/by-name/an/angrr/package.nix b/pkgs/by-name/an/angrr/package.nix new file mode 100644 index 000000000000..6a2f32ca4df3 --- /dev/null +++ b/pkgs/by-name/an/angrr/package.nix @@ -0,0 +1,50 @@ +{ + lib, + rustPlatform, + fetchFromGitHub, + installShellFiles, + nixosTests, + testers, + nix-update-script, +}: + +rustPlatform.buildRustPackage (finalAttrs: { + pname = "angrr"; + version = "0.1.1"; + + src = fetchFromGitHub { + owner = "linyinfeng"; + repo = "angrr"; + tag = "v${finalAttrs.version}"; + hash = "sha256-SL4UBDoD0pvpCKokQvKLAcS9cQJaFiA+IjswFARswdM="; + }; + + cargoHash = "sha256-lo9JpsHkvyrEqFnIiGlU2o4rREeQeqWpe9WMwisvw+4="; + + nativeBuildInputs = [ installShellFiles ]; + postInstall = '' + installShellCompletion --cmd angrr \ + --bash <($out/bin/angrr completion bash) \ + --fish <($out/bin/angrr completion fish) \ + --zsh <($out/bin/angrr completion zsh) + ''; + + passthru = { + tests = { + module = nixosTests.angrr; + version = testers.testVersion { + package = finalAttrs.finalPackage; + }; + }; + updateScript = nix-update-script { }; + }; + + meta = { + description = "Tool for auto Nix GC roots retention"; + homepage = "https://github.com/linyinfeng/angrr"; + license = [ lib.licenses.mit ]; + maintainers = with lib.maintainers; [ yinfeng ]; + platforms = with lib.platforms; linux ++ darwin; + mainProgram = "angrr"; + }; +})