this post was submitted on 08 Sep 2023
5 points (100.0% liked)

nixos

1262 readers
6 users here now

All about NixOS - https://nixos.org/

founded 4 years ago
 

I'd like to set a "global" option from within a submodule, but the config I return is grafted into the "global" under the submodule "path" rather than at the root... any idea if it's somehow possible?

Er... I guess I didn't make a great job at explaining what I want to do... Some code will hopefully help.

In mymodule.nix I have:

{ lib, config, ... }: {

  options.myoption = lib.mkOption {
      type = lib.types.attrsOf (lib.types.submodule (
        import ./mysubmodule.nix
      ));
  };

}

and mysubmodule.nix is:

{ name, lib, config, ... }: {

options.mysubmoduleoption = {
  type = lib.types.str;
};

config = {
  # here I want to set a "global" option, say "systemd.mounts"
  # based on the value of "mymodule.name.mysubmoduleoption"
  # but it seems I can only set values under "mymodule.name" 
};

}
top 4 comments
sorted by: hot top controversial new old
[–] Atemu@lemmy.ml 1 points 1 year ago (1 children)

Could you provide a more concrete example? There"s nothing preventing what I think you're trying to do.

Write what you are trying to do and then the accompyaning error.

Here's my btrfs module for reference:

https://github.com/Atemu/nixos-config/blob/431d76e67219a37f1e2e06042141df417530200b/btrfs.nix

[–] gomp@lemmy.ml 1 points 1 year ago* (last edited 1 year ago) (1 children)

Your module only defines the option inside types.submodule - I'd (ideally, to better organize the code) want to also put the config section in the submodule.

Ie. your code is structured similar to:

options = {
    fileSystems = mkOption {
    type = types.attrsOf (types.submodule {
        options = {
          # bla bla
        };           
    };
    };
};

config = {
  # set options here
};

while what I would like to do is more like

options = {
  fileSystems = mkOption {
    type = types.attrsOf (types.submodule {
      options = {
        # bla bla
      };
      config = {
        # set options here
      };
  };
};

The reason why I'm trying to do so is purely to restructure my code (which right now does has the config logic at the module, rather than submodule, level) in order to make it more readable/manageable, since it currently has jems like:

config.services.restic.backups = builtins.listToAttrs (
  builtins.concatLists (lib.attrsets.mapAttrsToList (v-name: v-cfg: (
    builtins.concatLists (lib.attrsets.mapAttrsToList (s-name: s-cfg: (
      builtins.concatLists (lib.attrsets.mapAttrsToList (r-name: r-cfg: (

I know I can restructure the code in other ways (eg. let .. in) - I just wanted to put the options definitions together with the code that uses them.

[–] Atemu@lemmy.ml 1 points 1 year ago (1 children)

It doesn't work like that. Submodules are for defining the type, so the only thing you get is interface (options), not implementation.

I know I can restructure the code in other ways (eg. let .. in)

Do that.

Also be aware that some use-cases might be covered by library functions such as lib.flatMap or lib.pipe.

[–] gomp@lemmy.ml 1 points 1 year ago

Submodules are for defining the type, so the only thing you get is interface (options), not implementation.

You do get a functional config in submodules... try this (it doesn't do anything so you can just import into any configuration.nix):

{ config, lib, pkgs, modulesPath, specialArgs, options, ... }: {

  options.mynamespace = lib.mkOption {
    type = lib.types.attrsOf (lib.types.submodule ({name, config, ...}:{
      options = {
        option1 = lib.mkOption { type = lib.types.str; default = ""; };
        option2 = lib.mkOption { type = lib.types.str; default = ""; };
      };
      config = {
        option2 = "derived from value of option1: '${config.option1}'";
      };
    }));
  };

  config = {

    mynamespace.submodule1.option1 = "value of option1";

    fileSystems = builtins.trace (builtins.toJSON config.mynamespace) {};

  };

}