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

nixos

1262 readers
8 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" 
};

}
you are viewing a single comment's thread
view the rest of the comments
[–] [email protected] 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

[–] [email protected] 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.

[–] [email protected] 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.

[–] [email protected] 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) {};

  };

}