!wfudwzqQUiJYJnqfSY:nixos.org

NixOS Module System

159 Members
32 Servers

You have reached the beginning of time (for this room).


SenderMessageTime
20 May 2025
@kongrooparadox:matrix.orgkongrooparadox joined the room.21:44:52
21 May 2025
@oddlama:matrix.orgoddlama changed their display name from Malte to oddlama.17:42:04
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) I see that nixos/lib and nixos/modules use normal path values in _file (except for modulesPath = toString ./eval-config.nix), but somehow in man configuration.nix we get relative paths without hashes? How does that happen 17:48:12
@mattsturg:matrix.orgMatt Sturgeon

path values only get copied to the store when used with string interpolation (e.g. "${./some/path}"). If you instead stringify them with toString, then they are not copied.

E.g.

"${./foo}"
=> "/nix/store/r1l6z113nnzx44iiqp728f50lpczp577-foo"

toString ./foo
=> "/home/matt/foo"

./foo
=> /home/matt/foo
17:53:58
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) Ohhh so nixos/modules actually does pass strings around and not paths? 18:00:37
@ss:someonex.netSomeoneSerge (Ever OOMed by Element)
nixos/lib/eval-config.nix
71-  pkgsModule = rec {
72:    _file = ./eval-config.nix;
73:    key = _file;
18:02:08
@ss:someonex.netSomeoneSerge (Ever OOMed by Element)This is 100% a "path"18:02:19
@ss:someonex.netSomeoneSerge (Ever OOMed by Element)
$ man configuration.nix
...
       nixpkgs.pkgs
...
           Declared by:
               <nixpkgs/nixos/modules/misc/nixpkgs.nix>
18:03:29
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) So there is some magic happening that makes this ./eval-config.nix into a string that is relative to.... hmmm parent of the checkout 18:03:57
@mattsturg:matrix.orgMatt Sturgeon IIRC specialArgs.modulesPath is removed if it is a prefix of the stringified _file. 18:05:42
@mattsturg:matrix.orgMatt Sturgeon

actually does pass strings around

No, but when rendering files in errors, docs, etc they are stringified using toString

18:06:40
@spaenny:tchncs.dePhilipp joined the room.18:21:49
23 May 2025
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) Btw that magic was in pkgs/ in nixosOptionsDoc 22:32:42
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) Next one! Given (evalModules {...}).options and a path in options, is there a ready tool to tell which definition (with location) won the priority? I see I can access definitionsWithLocations which is an unfiltered list, and, to further complicate things, in case of an attrsOf option there's just the top-level list, which doesn't directly relate paths under the option to definitions or locations. 22:36:26
@mattsturg:matrix.orgMatt Sturgeon

For simple/flat options, all the definition listed in the option are the ones that "won" the priority.

Specifically, all of opt.definitions and opt.definitionsWithLocations have opt.highestPrio.

That's because most wrappers like mkIf, mkMerge, mkOverride, and mkOrder are resolved before creating the option's definitions list.

However, this is only done for the option's definitions (i.e. the top-level). Wrappers on nested attrs are applied by the option's type when it merges the option's definitions.

I don't know of an "easy" way to filter for definitions of a specific attr on an attrsOf type.

There are some functions like lib.modules.mergeAttrDefinitionsWithPrio, so maybe something similar exists or could be written that exposes definition location for attrsOf sub-attrs?

If you were dealing with a submodule, and had an explicit suboption declared, then you could access the suboption's definitions within the submodule eval. E.g., you could expose them to the wider module eval by defining an internal option in the submodule.

22:48:40
24 May 2025
@jappie:jappie.devjappie

I'm trying to create a settings option for services.dovecot2 (https://github.com/NixOS/nixpkgs/pull/388463/) and running into some issues trying to use a submodule for the type of the settings option.

Dovecot allows you to do something like this:

# dovecot config format:
service imap-login {
  restart_request_count = 1
  inet_listener imaps {
    port = 993
    ssl = yes
  }
}

# Nix:
"service imap-login" = {
  restart_request_count = 1;
  "inet_listener imaps" = {
    port = 993;
    ssl = true;
  };
};

Technically the following works for options.settings.type:

type =
  let
    inherit (lib.types) bool int listOf nullOr oneOf str submodule;
    inherit (lib) elemAt singleton split;
    any = oneOf [ int str bool (lib.types.lazyAttrsOf configValueType) ];
    configValueType = nullOr (oneOf [
      any
      (listOf any)
    ]);
  in
  configValueType;

But a better solution would be to define the section type & section name (e.g. service & imap-login or inet_listener & imaps from above) in the options part of a submodule instead of hiding it in the parser that writes the config file:

type =
  let
    inherit (lib.types) attrsOf bool int listOf nullOr oneOf str submodule;
    inherit (lib) elemAt singleton split;
    section = submodule (
      { name, config, ... }:
      let
        # split on first space
        splits = elemAt (elemAt (split "^([^ ]+)( +(.+))?$" name) 1);
        typeDefault = splits 0;
        nameDefault = splits 1; # 2;
      in
      {
        options = {
          section = {
            type = mkOption {
              description = "...";
              type = str;
              default = typeDefault;
            };
            name = mkOption {
              description = "...";
              type = nullOr str;
              default = nameDefault;
            };
          };
        };
        freeformType = configValueType;
      }
    );
    any = oneOf [ int str bool (lib.types.lazyAttrsOf section) ];
    configValueType = nullOr (oneOf [
      any
      (listOf any)
    ]);
  in
  configValueType;

However this throws and then infrecs trying to evaluate description:

       … from call site
         at /nix/store/iarry5sq6zg1wm91f4dn68a91nqs369w-source/nixos/modules/services/mail/dovecot.nix:794:65:
          793|       }
          794|       // optionalAttrs (cfg.settings ? mail_uid && cfg.settings.mail_uid != null && cfg.createMailUser) {
             |                                                                 ^
          795|         ${cfg.settings.mail_uid} =

       … while calling anonymous lambda
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:818:27:
          817|                   (
          818|                     name: defs:
             |                           ^
          819|                     let

       … while evaluating the attribute 'optionalValue.value'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/modules.nix:1148:41:
         1147|
         1148|     optionalValue = if isDefined then { value = mergedValue; } else { };
             |                                         ^
         1149|   };

       … while calling the 'throw' builtin
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/modules.nix:1139:11:
         1138|           in
         1139|           throw "A definition for option `${showOption loc}' is not of type `${type.description}'. Definition values:${showDefs allInvalid}"
             |           ^
         1140|       else

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … while evaluating the attribute '_module.freeformType.description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … from call site
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:1026:13:
         1025|           description = "null or ${
         1026|             optionDescriptionPhrase (class: class == "noun" || class == "conjunction") elemType
             |             ^
         1027|           }";

       … while calling 'optionDescriptionPhrase'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:290:23:
          289|     optionDescriptionPhrase =
          290|       unparenthesize: t:
             |                       ^
          291|       if unparenthesize (t.descriptionClass or null) then t.description else "(${t.description})";

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … from call site
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:1383:18:
         1382|             else
         1383|               "${optionDescriptionPhrase (class: class == "noun" || class == "conjunction") t1} or ${
             |                  ^
         1384|                 optionDescriptionPhrase (

       … while calling 'optionDescriptionPhrase'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:290:23:
          289|     optionDescriptionPhrase =
          290|       unparenthesize: t:
             |                       ^
          291|       if unparenthesize (t.descriptionClass or null) then t.description else "(${t.description})";

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … from call site
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:1384:17:
         1383|               "${optionDescriptionPhrase (class: class == "noun" || class == "conjunction") t1} or ${
         1384|                 optionDescriptionPhrase (
             |                 ^
         1385|                   class: class == "noun" || class == "conjunction" || class == "composite"

       … while calling 'optionDescriptionPhrase'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:290:23:
          289|     optionDescriptionPhrase =
          290|       unparenthesize: t:
             |                       ^
          291|       if unparenthesize (t.descriptionClass or null) then t.description else "(${t.description})";

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … from call site
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:808:22:
          807|             (if lazy then "lazy attribute set" else "attribute set")
          808|             + " of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
             |                      ^
          809|           descriptionClass = "composite";

       … while calling 'optionDescriptionPhrase'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:290:23:
          289|     optionDescriptionPhrase =
          290|       unparenthesize: t:
             |                       ^
          291|       if unparenthesize (t.descriptionClass or null) then t.description else "(${t.description})";

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       error: infinite recursion encountered
       at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

Is what I'm trying to do here not possible with submodules due to the recursion or am I missing something?

12:06:15
@jappie:jappie.devjappie *

I'm trying to create a settings option for services.dovecot2 (https://github.com/NixOS/nixpkgs/pull/388463/) and running into some issues trying to use a submodule for the type of the settings option.

Dovecot allows you to do something like this:

# dovecot config format:
service imap-login {
  restart_request_count = 1
  inet_listener imaps {
    port = 993
    ssl = yes
  }
}

# Nix:
"service imap-login" = {
  restart_request_count = 1;
  "inet_listener imaps" = {
    port = 993;
    ssl = true;
  };
};

Technically the following works for options.settings.type:

type =
  let
    inherit (lib.types) bool int listOf nullOr oneOf str submodule;
    inherit (lib) elemAt singleton split;
    any = oneOf [ int str bool (lib.types.lazyAttrsOf configValueType) ];
    configValueType = nullOr (oneOf [
      any
      (listOf any)
    ]);
  in
  configValueType;

But a better solution would be to define the section type & section name (e.g. service & imap-login or inet_listener & imaps from above) in the options part of a submodule instead of hiding it in the parser that writes the config file:

type =
  let
    inherit (lib.types) attrsOf bool int listOf nullOr oneOf str submodule;
    inherit (lib) elemAt singleton split;
    section = submodule (
      { name, config, ... }:
      let
        # split on first space
        splits = elemAt (elemAt (split "^([^ ]+)( +(.+))?$" name) 1);
        typeDefault = splits 0;
        nameDefault = splits 1;
      in
      {
        options = {
          section = {
            type = mkOption {
              description = "...";
              type = str;
              default = typeDefault;
            };
            name = mkOption {
              description = "...";
              type = nullOr str;
              default = nameDefault;
            };
          };
        };
        freeformType = configValueType;
      }
    );
    any = oneOf [ int str bool (lib.types.lazyAttrsOf section) ];
    configValueType = nullOr (oneOf [
      any
      (listOf any)
    ]);
  in
  configValueType;

However this throws and then infrecs trying to evaluate description:

       … from call site
         at /nix/store/iarry5sq6zg1wm91f4dn68a91nqs369w-source/nixos/modules/services/mail/dovecot.nix:794:65:
          793|       }
          794|       // optionalAttrs (cfg.settings ? mail_uid && cfg.settings.mail_uid != null && cfg.createMailUser) {
             |                                                                 ^
          795|         ${cfg.settings.mail_uid} =

       … while calling anonymous lambda
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:818:27:
          817|                   (
          818|                     name: defs:
             |                           ^
          819|                     let

       … while evaluating the attribute 'optionalValue.value'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/modules.nix:1148:41:
         1147|
         1148|     optionalValue = if isDefined then { value = mergedValue; } else { };
             |                                         ^
         1149|   };

       … while calling the 'throw' builtin
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/modules.nix:1139:11:
         1138|           in
         1139|           throw "A definition for option `${showOption loc}' is not of type `${type.description}'. Definition values:${showDefs allInvalid}"
             |           ^
         1140|       else

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … while evaluating the attribute '_module.freeformType.description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … from call site
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:1026:13:
         1025|           description = "null or ${
         1026|             optionDescriptionPhrase (class: class == "noun" || class == "conjunction") elemType
             |             ^
         1027|           }";

       … while calling 'optionDescriptionPhrase'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:290:23:
          289|     optionDescriptionPhrase =
          290|       unparenthesize: t:
             |                       ^
          291|       if unparenthesize (t.descriptionClass or null) then t.description else "(${t.description})";

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … from call site
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:1383:18:
         1382|             else
         1383|               "${optionDescriptionPhrase (class: class == "noun" || class == "conjunction") t1} or ${
             |                  ^
         1384|                 optionDescriptionPhrase (

       … while calling 'optionDescriptionPhrase'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:290:23:
          289|     optionDescriptionPhrase =
          290|       unparenthesize: t:
             |                       ^
          291|       if unparenthesize (t.descriptionClass or null) then t.description else "(${t.description})";

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … from call site
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:1384:17:
         1383|               "${optionDescriptionPhrase (class: class == "noun" || class == "conjunction") t1} or ${
         1384|                 optionDescriptionPhrase (
             |                 ^
         1385|                   class: class == "noun" || class == "conjunction" || class == "composite"

       … while calling 'optionDescriptionPhrase'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:290:23:
          289|     optionDescriptionPhrase =
          290|       unparenthesize: t:
             |                       ^
          291|       if unparenthesize (t.descriptionClass or null) then t.description else "(${t.description})";

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       … while evaluating description
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:26:
          265|             functor;
          266|         description = if description == null then name else description;
             |                          ^
          267|       };

       … from call site
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:808:22:
          807|             (if lazy then "lazy attribute set" else "attribute set")
          808|             + " of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
             |                      ^
          809|           descriptionClass = "composite";

       … while calling 'optionDescriptionPhrase'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:290:23:
          289|     optionDescriptionPhrase =
          290|       unparenthesize: t:
             |                       ^
          291|       if unparenthesize (t.descriptionClass or null) then t.description else "(${t.description})";

       … while evaluating the attribute 'description'
         at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

       error: infinite recursion encountered
       at /nix/store/p893dkrzm5rxvhnqh092prgi1a7dzmcy-source/lib/types.nix:266:9:
          265|             functor;
          266|         description = if description == null then name else description;
             |         ^
          267|       };

Is what I'm trying to do here not possible with submodules due to the recursion or am I missing something?

12:06:55
25 May 2025
@mattsturg:matrix.orgMatt Sturgeon

lazyAttrsOf

Slightly off topic, but this probably isn't what you want in a freeform settings type; if a use does settings.foo = mkIf false {}, then foo will be defined, but as an "empty value" stub; usually an empty value is a throw expression throwing something like "option settings.foo is used but not defined". This will be a problem when you later want to serialize settings into the program's config format.

00:06:33

Show newer messages


Back to Room ListRoom Version: 10