Correct way to disable submodules with top module enable option

Hi all,

I’m trying to figure out how to best organize my modules in my config, I have a main module mySystem and a myHome(for home manager) that I import into my hosts and use to toggle certain features on or off so the interface looks like:

  myHome = {
    enable = true; # if false, all below options and sub module options should be disabled even if they're set to true
    # All the options
    user = "yeshey";
    plasma.enable = true;
    gnome.enable = false;
    homeApps = {
      enable = true; # if false, all home apps should be disabled
      cli = {
        enable = false; # if false, all cli apps should be disabled
        general.enable = true;
        git = {
          enable = true; # if false, git should be disabled
          personalGit = {
            enable = true;
            userName = "Yeshey";
            userEmail = "yesheysangpo@hotmail.com";
          };
        };
      };
      libreoffice.enable = true;
    };
   };

The way to implement this gets a little messy, the myHome module imports all others:

  imports = [
    ./gnome/default.nix
    ./plasma/default.nix
    ./homeApps/default.nix
    [...]
  ];

So, in the plasma nix file I need to check if the enable option of myHome and if myHome.plasma.enable are both set:

  config = lib.mkIf (config.myHome.enable && cfg.enable) {

This is all fine and great, but with nested options in gets increasingly hellish, my git module is like:

  config = lib.mkIf (config.myHome.enable && config.myHome.homeApps.enable && config.myHome.homeApps.cli.enable && cfg.enable) {

This could maybe be solved with conditional imports, where it would only import the homeApps submodule if myHome was enabled, maybe like home-manager does/did, but I’ve read here that conditional imports are discouraged and lead to problems in nix.

I tried to look at the submodules type, but either it wouldn’t help me or I missed something. Or maybe I’m going about this the wrong way, and this is not the way nested enable options should be used?

Thanks in advance!

I think you are using nested enable options in the right way. But in NixOS we don’t often see deeply nested options submodules.

Maybe you could make a library function? Something like this:

config = let
  inherit (lib) length getAttr head tail;
  isModuleEnabled = config: attrPath:
      if length attrPath == 0
      then config.enable
      else (config.enable or true) &&
        isModuleEnabled
          (getAttr (head attrPath) config)
          (tail attrPath);

in
  lib.mkIf (isModuleEnabled config ["myHome" "homeApps" "cli" "git" "personalGit"]) {
    # ...
  }
1 Like

wow, you’re going down on nix in a way I didnt even know was possible :upside_down_face:.
Thank you for the suggestion!! I mostly wanted to know if I wasn’t doing something stupid or missing something obvious, which looks like i wasn’t, so, cool

Would this override the config keyword in all the files? Where would I do that :thinking:, sorry I’m still not rly comfortable with nix, im having trouble understanding and making use of the snippet, to me it looks like it’s equaling config to lib.mkIf with special parameters config = let ... in lib.mkIf ... is it some top level override?

The isModuleEnabled function would need to be moved into the place where you put your library of functions. This place could be an overlay which extends lib for example. Or it could be a NixOS/home-manager module which defines functions under config.lib (this way might be easier).