[SOLVED] How do I build options and config from a list?

Im configuring custom modules and options for my systems (thanks to those who helped HERE and sorry for not responding, fell out of the loop for a while) and am trying to pass a list to build options from to relieve the tedium of manually writing out each one, like so:

{

let
    appName = with pkgs; [guiapp1 guiapp2 guiapp3];
in

options = {
    myDomain.programs.${appName}.enable = lib.mkOption {
        type = lib.types.bool;
        default = true;
    };
};

config = lib.mkIf config.myDomain.system.hasGUI {
  environment.systemPackages = with pkgs; lib.mkIf config.myDomain.programs.${appName}.enable [ ${appName} ];
  };
}

The above code doesnt work, but maybe that gives you an idea of what I am trying to accomplish. I found how to iterate through a list with a function HERE with the AI generated example but it doesnt seem to work with “options = { …”.

appName is a list containing guiapp1, guiapp2, and guiapp3 at the same time. You can use map to transform this into a list of pairs of names and values, which you can further turn into an attribute set than you can then assign to, e.g., options.myDomain.programs. Putting that all together, something like the following should work:

let apps = with pkgs; [ … ];
in { 
  options = {
    myDomain.programs = lib.listToAttrs (
      map (app: let appName = app.pname;
                in lib.nameValuePair appName {
                  enable = lib.mkEnableOption appName;
                }) apps
    );
  };  

  config = lib.mkIf config.myDomain.system.hasGUI {
    environment.systemPackages = lib.mkMerge (
      map (app: lib.mkIf config.myDomain."${app.pname}".enable [
        app
      ]) apps
    );
  };
}
2 Likes

Thanks for the response. It seems to want to work but gives me:

error: attribute 'mc' missing

It doesnt seem to recognize the package names as packages. I tried quoting them but environment.systemPackages doesnt accept strings and removing the “with pkgs” and explicitly specifying “pkgs.mc” doesnt change the error.

Full code block:

{ config, pkgs, lib, ... }:
let apps = with pkgs; [ mc nnn ranger ];
in {
  options = {
    tekslice.programs = lib.listToAttrs (
      map (app: let appName = app.pname;
                in lib.nameValuePair appName {
                  enable = lib.mkEnableOption appName;
                }) apps
    );
  };

  config = lib.mkIf config.tekslice.system.hasGUI {
    environment.systemPackages = lib.mkMerge (
      map (app: lib.mkIf config.tekslice.programs."${app.pname}".enable [
        app
      ]) apps
    );
  };
}

Note: im just using mc nnn and ranger as test programs for this.

The snippet you posted works for me. If you do get the error with mc, then there is something wrong with the pkgs the module gets passed. If it’s actually a different package name that is the problem, it might just be misspelled.

Ok, not sure what the glitch was. Sat down today, ran a nix flake update and it started working. I finally settled on:

{ config, pkgs, lib, ... }:
let apps = with pkgs; [ mc nnn ranger ];
in {
  options = {
    tekslice.programs = lib.listToAttrs (
      map (app: let appName = app.pname;
        in lib.nameValuePair appName {
          enable = lib.mkOption {
          type = lib.types.bool;
          default = true;
          };
        }) apps
    );
  };

  config = lib.mkIf config.tekslice.system.hasGUI {
    environment.systemPackages = lib.mkMerge (
      map (app: lib.mkIf config.tekslice.programs."${app.pname}".enable [
        app
      ]) apps
    );
  };
}

…and it works perfectly. Thank you

2 Likes