From b7cc2466f1a695326ffc1a14040cd4d3b4358ea0 Mon Sep 17 00:00:00 2001 From: Aguirre Matteo Date: Sat, 30 Aug 2025 16:55:32 -0300 Subject: [PATCH] distrobox: add settings option and other general improvements --- modules/programs/distrobox.nix | 119 ++++++++++++------ .../assert-containers-systemd-unit.nix | 10 ++ .../distrobox/assert-package-systemd-unit.nix | 18 +++ .../{example-config.ini => containers.ini} | 0 tests/modules/programs/distrobox/default.nix | 3 + .../modules/programs/distrobox/distrobox.conf | 12 ++ .../programs/distrobox/example-config.nix | 23 +++- .../modules/programs/distrobox/no-asserts.nix | 6 + 8 files changed, 149 insertions(+), 42 deletions(-) create mode 100644 tests/modules/programs/distrobox/assert-containers-systemd-unit.nix create mode 100644 tests/modules/programs/distrobox/assert-package-systemd-unit.nix rename tests/modules/programs/distrobox/{example-config.ini => containers.ini} (100%) create mode 100644 tests/modules/programs/distrobox/distrobox.conf create mode 100644 tests/modules/programs/distrobox/no-asserts.nix diff --git a/modules/programs/distrobox.nix b/modules/programs/distrobox.nix index 990c682a6..ea48f0c92 100644 --- a/modules/programs/distrobox.nix +++ b/modules/programs/distrobox.nix @@ -14,56 +14,84 @@ let cfg = config.programs.distrobox; - formatter = pkgs.formats.ini { listsAsDuplicateKeys = true; }; + generateConfig = lib.generators.toKeyValue { + mkKeyValue = + name: value: + if lib.isString value then ''${name}="${value}"'' else "${name}=${builtins.toString value}"; + }; + + iniFormat = pkgs.formats.ini { listsAsDuplicateKeys = true; }; + iniAtomType = iniFormat.lib.types.atom; in { meta.maintainers = with lib.hm.maintainers; [ aguirre-matteo ]; options.programs.distrobox = { enable = mkEnableOption "distrobox"; - package = mkPackageOption pkgs "distrobox" { }; + package = mkPackageOption pkgs "distrobox" { nullable = true; }; enableSystemdUnit = mkOption { type = lib.types.bool; - default = true; + default = cfg.containers != { } && cfg.package != null; + defaultText = "config.programs.distrobox.containers != { } && config.programs.distrobox.package != null"; example = false; description = '' Whatever to enable a Systemd Unit that automatically rebuilds your containers when changes are detected. ''; }; - containers = mkOption { - type = formatter.type; + settings = mkOption { + type = lib.types.attrsOf iniAtomType; default = { }; - example = '' - { - python-project = { - image = "fedora:40"; - additional_packages = "python3 git"; - init_hooks = "pip3 install numpy pandas torch torchvision"; - }; - - common-debian = { - image = "debian:13"; - entry = true; - additional_packages = "git"; - init_hooks = [ - "ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker" - "ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker-compose" - ]; - }; - - office = { - clone = "common-debian"; - additional_packages = "libreoffice onlyoffice"; - entry = true; - }; - - random-things = { - clone = "common-debian"; - entry = false; - }; - } + example = { + container_always_pull = "1"; + container_generate_entry = 0; + container_manager = "docker"; + container_image_default = "registry.opensuse.org/opensuse/toolbox:latest"; + container_name_default = "test-name-1"; + container_user_custom_home = "$HOME/.local/share/container-home-test"; + container_init_hook = "~/.local/distrobox/a_custom_default_init_hook.sh"; + container_pre_init_hook = "~/a_custom_default_pre_init_hook.sh"; + container_manager_additional_flags = "--env-file /path/to/file --custom-flag"; + container_additional_volumes = "/example:/example1 /example2:/example3:ro"; + non_interactive = "1"; + skip_workdir = "0"; + }; + description = '' + Configuration settings for Distrobox. All the available options can be found here: + ''; + }; + containers = mkOption { + inherit (iniFormat) type; + default = { }; + example = { + python-project = { + image = "fedora:40"; + additional_packages = "python3 git"; + init_hooks = "pip3 install numpy pandas torch torchvision"; + }; + + common-debian = { + image = "debian:13"; + entry = true; + additional_packages = "git"; + init_hooks = [ + "ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker" + "ln -sf /usr/bin/distrobox-host-exec /usr/local/bin/docker-compose" + ]; + }; + + office = { + clone = "common-debian"; + additional_packages = "libreoffice onlyoffice"; + entry = true; + }; + + random-things = { + clone = "common-debian"; + entry = false; + }; + }; description = '' A set of containers and all its respective configurations. Each option can be either a bool, string or a list of strings. If passed a list, the option will be repeated for each element. @@ -76,15 +104,28 @@ in config = mkIf cfg.enable { assertions = [ (lib.hm.assertions.assertPlatform "programs.distrobox" pkgs lib.platforms.linux) + { + assertion = cfg.enableSystemdUnit -> (cfg.containers != { }); + message = "Cannot set `programs.distrobox.enableSystemdUnit` if `programs.distrobox.containers` is unset."; + } + { + assertion = cfg.enableSystemdUnit -> (cfg.package != null); + message = "Cannot set `programs.distrobox.enableSystemdUnit` if `programs.distrobox.package` is set to null."; + } ]; - home.packages = [ cfg.package ]; + home.packages = mkIf (cfg.package != null) [ cfg.package ]; - xdg.configFile."distrobox/containers.ini".source = ( - formatter.generate "containers.ini" cfg.containers - ); + xdg.configFile = { + "distrobox/containers.ini" = mkIf (cfg.containers != { }) { + source = iniFormat.generate "distrobox-containers.ini" cfg.containers; + }; + "distrobox/distrobox.conf" = mkIf (cfg.settings != { }) { + text = generateConfig cfg.settings; + }; + }; - systemd.user.services.distrobox-home-manager = mkIf cfg.enableSystemdUnit { + systemd.user.services.distrobox-home-manager = mkIf (cfg.enableSystemdUnit && cfg.package != null) { Unit.Description = "Build the containers declared in ~/.config/distrobox/containers.ini"; Install.WantedBy = [ "default.target" ]; diff --git a/tests/modules/programs/distrobox/assert-containers-systemd-unit.nix b/tests/modules/programs/distrobox/assert-containers-systemd-unit.nix new file mode 100644 index 000000000..55d5f533a --- /dev/null +++ b/tests/modules/programs/distrobox/assert-containers-systemd-unit.nix @@ -0,0 +1,10 @@ +{ + programs.distrobox = { + enable = true; + enableSystemdUnit = true; + }; + + test.asserts.assertions.expected = [ + "Cannot set `programs.distrobox.enableSystemdUnit` if `programs.distrobox.containers` is unset." + ]; +} diff --git a/tests/modules/programs/distrobox/assert-package-systemd-unit.nix b/tests/modules/programs/distrobox/assert-package-systemd-unit.nix new file mode 100644 index 000000000..4ff33bc06 --- /dev/null +++ b/tests/modules/programs/distrobox/assert-package-systemd-unit.nix @@ -0,0 +1,18 @@ +{ + programs.distrobox = { + enable = true; + package = null; + enableSystemdUnit = true; + containers = { + python-project = { + image = "fedora:40"; + additional_packages = "python3 git"; + init_hooks = "pip3 install numpy pandas torch torchvision"; + }; + }; + }; + + test.asserts.assertions.expected = [ + "Cannot set `programs.distrobox.enableSystemdUnit` if `programs.distrobox.package` is set to null." + ]; +} diff --git a/tests/modules/programs/distrobox/example-config.ini b/tests/modules/programs/distrobox/containers.ini similarity index 100% rename from tests/modules/programs/distrobox/example-config.ini rename to tests/modules/programs/distrobox/containers.ini diff --git a/tests/modules/programs/distrobox/default.nix b/tests/modules/programs/distrobox/default.nix index 6525760fb..d3e81edf7 100644 --- a/tests/modules/programs/distrobox/default.nix +++ b/tests/modules/programs/distrobox/default.nix @@ -1,4 +1,7 @@ { lib, pkgs, ... }: lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { distrobox-example-config = ./example-config.nix; + distrobox-no-asserts = ./no-asserts.nix; + distrobox-assert-package-systemd-unit = ./assert-package-systemd-unit.nix; + distrobox-assert-containers-systemd-unit = ./assert-containers-systemd-unit.nix; } diff --git a/tests/modules/programs/distrobox/distrobox.conf b/tests/modules/programs/distrobox/distrobox.conf new file mode 100644 index 000000000..76df347c7 --- /dev/null +++ b/tests/modules/programs/distrobox/distrobox.conf @@ -0,0 +1,12 @@ +container_additional_volumes="/example:/example1 /example2:/example3:ro" +container_always_pull="1" +container_generate_entry=0 +container_image_default="registry.opensuse.org/opensuse/toolbox:latest" +container_init_hook="~/.local/distrobox/a_custom_default_init_hook.sh" +container_manager="docker" +container_manager_additional_flags="--env-file /path/to/file --custom-flag" +container_name_default="test-name-1" +container_pre_init_hook="~/a_custom_default_pre_init_hook.sh" +container_user_custom_home="$HOME/.local/share/container-home-test" +non_interactive="1" +skip_workdir="0" diff --git a/tests/modules/programs/distrobox/example-config.nix b/tests/modules/programs/distrobox/example-config.nix index 6046d0f7f..0e5f7274b 100644 --- a/tests/modules/programs/distrobox/example-config.nix +++ b/tests/modules/programs/distrobox/example-config.nix @@ -1,8 +1,22 @@ { programs.distrobox = { enable = true; - containers = { + settings = { + container_always_pull = "1"; + container_generate_entry = 0; + container_manager = "docker"; + container_image_default = "registry.opensuse.org/opensuse/toolbox:latest"; + container_name_default = "test-name-1"; + container_user_custom_home = "$HOME/.local/share/container-home-test"; + container_init_hook = "~/.local/distrobox/a_custom_default_init_hook.sh"; + container_pre_init_hook = "~/a_custom_default_pre_init_hook.sh"; + container_manager_additional_flags = "--env-file /path/to/file --custom-flag"; + container_additional_volumes = "/example:/example1 /example2:/example3:ro"; + non_interactive = "1"; + skip_workdir = "0"; + }; + containers = { python-project = { image = "fedora:40"; additional_packages = "python3 git"; @@ -29,13 +43,16 @@ clone = "common-debian"; entry = false; }; - }; }; nmt.script = '' + assertFileExists home-files/.config/distrobox/distrobox.conf + assertFileContent home-files/.config/distrobox/distrobox.conf \ + ${./distrobox.conf} + assertFileExists home-files/.config/distrobox/containers.ini assertFileContent home-files/.config/distrobox/containers.ini \ - ${./example-config.ini} + ${./containers.ini} ''; } diff --git a/tests/modules/programs/distrobox/no-asserts.nix b/tests/modules/programs/distrobox/no-asserts.nix new file mode 100644 index 000000000..46c4dd271 --- /dev/null +++ b/tests/modules/programs/distrobox/no-asserts.nix @@ -0,0 +1,6 @@ +{ + programs.distrobox = { + enable = true; + package = null; + }; +}