In my configuration, I am trying to build a “GUI enabled” module that will provide me with a single ‘enable’ switch to specify whether a machine has a GUI/Desktop or not. Then all my other modules can specify submodules to be included only if that single flag is enabled.
To be clear, the interface I’m trying to create is something like this:
# Somewhere in my top-level configuration file...
my.gui.enable = true;
# In another module managing command-line utilities...
environment.systemPackages = with pkgs; [ fish fzf htop tmux ];
# I want to add a terminal emulator, enable Flatpak, and set some nix options,
# but only if this is machine has a GUI
my.gui.modules = [{
envrionment.systemPackages = with; pkgs [ alacritty ];
services.flatpak.enable = true;
nix.gc.automatic = true;
}];
To this very similar to how I use home-manager’s ‘sharedModules’ option, so I tried following their code to inspire my ‘my.gui’ module:
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.my.gui;
in
{
options.my.gui = {
enable = mkEnableOption "GUI configurations";
modules = mkOption {
type = with type; listOf raw;
default = [];
};
guiConfig = mkOption = {
type = types.submoduleWith {
modules = cfg.modules;
};
default = {};
};
};
config = mkIf cfg.enable cfg.guiConfig;
}
This results in a recursion error, naturally. I’ve tried just about every permutation of mkIf
and mkMerge
that I could think of. I get that this is because one of the included modules could potentially set my.gui.enable = false;
, which would cause a contradiction. Is there any work-around for this? For example, a way to enforce with types that the assembled guiConfig
module can contain whatever attrs, but never a my.gui
attribute?
I am currently using a setup where modules uses a mkIf
and mkMerge
like so:
config = mkMerge [
{
# Non-gui config...
}
( mkIf config.my.gui.enable {
# gui config...
})
];
This works, but it looks messy, and for the sake of cleanliness I am trying to refactor my configuration so that no module depends on the configuration of other modules (that is, the module’s output configuration can be entirely determined based on the values of its options).
Is there any way I can achieve the UX I am hoping for with these modules?