!wfudwzqQUiJYJnqfSY:nixos.org

NixOS Module System

121 Members
23 Servers

Load older messages


SenderMessageTime
16 Apr 2025
@alexandrutocar:matrix.orgAlexandru Tocar joined the room.11:47:32
18 Apr 2025
@cirnolovetech:matrix.org@cirnolovetech:matrix.org joined the room.01:05:05
@fabaff:matrix.orgfabaff joined the room.18:03:01
19 Apr 2025
@jopejoe1:matrix.orgjopejoe1 (4094@GPN23) changed their display name from jopejoe1 to jopejoe1 (4094@eh22).13:01:33
@nam3l33ss:matrix.org·☽•Nameless☆•777 · ± changed their profile picture.14:32:34
@accelbread:matrix.org@accelbread:matrix.org left the room.20:30:31
22 Apr 2025
@cirnolovetech:matrix.org@cirnolovetech:matrix.org left the room.09:31:37
25 Apr 2025
@creepinson:matrix.org@creepinson:matrix.org joined the room.23:38:39
29 Apr 2025
@n8henrie:matrix.orgn8henrie joined the room.18:04:14
1 May 2025
@rosariopulella:matrix.orgRosuavio changed their display name from Rosario Pulella to Rosuavio.20:08:44
8 May 2025
@isabel:isabelroses.comisabel changed their profile picture.08:57:53
@isabel:isabelroses.comisabel changed their profile picture.08:57:59
@nam3l33ss:matrix.org·☽•Nameless☆•777 · ± changed their profile picture.13:26:34
16 May 2025
@ss:someonex.netSomeoneSerge (Ever OOMed by Element)

I never acquainted with types.nix, is there some fundamental reason that either of two freeform submodules couldn't work when left and right have disjoint explicit options?

with import <nixpkgs/lib>;

evalModules {
  modules = [
    {
      options.foo = mkOption {
        type =
          types.either
            (types.submodule {
              freeformType = types.attrsOf types.str;
              options.marker_a = mkOption {
                type = types.str;
              };
            })
            (
              types.submodule {
                freeformType = types.attrsOf types.str;
                options.marker_b = mkOption {
                  type = types.str;
                };
              }
            );
      };
      config.foo = {
        marker_b = "bar";
      };
    }
  ];
}

{ foo = { marker_a = «error: The option `foo.marker_a' was accessed but has no value defined. Try setting 
the option.»; marker_b = "bar"; }; }
19:49:57
@mattsturg:matrix.orgMatt Sturgeon

I believe the issue is the left and right type's check function.

either will use whichever type fist passes check value, and iirc submodules just use something like check = isAttrs

19:52:25
@h7x4:nani.wtfh7x4 Some of the "container types" don't really check what's inside before being evaluated at a later stage. I believe this is the case for submodules, listOf and attrsOf. As a hack, you can add those checks with lib.types.addCheck. Same scenario with either and oneOf. 19:53:46
@mattsturg:matrix.orgMatt Sturgeon It's intentional that the submodule-type's check function is not very restrictive, since you can assign any module to a submodule and it is down to the submodule's configuration to evaluate and merge its own definitions internally. 19:53:58
@mattsturg:matrix.orgMatt Sturgeon E.g. foo = {} is a vaild definition, as is foo = { config, ... }: { }, as is foo = ./someModule.nix 19:54:55
@h7x4:nani.wtfh7x4
nix-repl> with lib.types; (listOf int).check [ true false "hello" ]
true

nix-repl> with lib.types; (addCheck (listOf int) (builtins.all builtins.isInt)).check [ true false "hello" ]
false
19:57:21
@mattsturg:matrix.orgMatt Sturgeon

The other issue with marker options (marker_a, marker_b) is how should definitions be merged that don't include the marker? E.g.

foo = lib.mkMerge [
  { something_freeform = "hi"; }
  { marker_a = "there"; }
]

You don't know which marker is defined until all merging is done.

In a simple case like this, you could refactor this as one submodule with both markers, and then add some extra logic/conditions within the submodule and/or in the optinon's final apply function.

20:02:16
@h7x4:nani.wtfh7x4Also ref https://discourse.nixos.org/t/problems-with-types-oneof-and-submodules/1519720:03:59
@mattsturg:matrix.orgMatt Sturgeon

One way you could work around this is to add an internal final option within the submodule and then map to it in the apply function:

foo = mkOption {
  type = types.submodule (
    { config, options, ... }:
    {
      freeformType = types.attrsOf types.str;
      options.marker_a = mkOption {
        type = types.str;
      };
      options.marker_b = mkOption {
        type = types.str;
      };
      options.__result = mkOption {
        type = config._module.freeformType;
        internal = true;
      };

      config.__result =
        let
          cfg = builtins.removeAttrs config [
            "_module"
            "marker_a"
            "marker_b"
            "__result"
          ];
        in
        if options.marker_a.isDefined then
          cfg // { inherit (config) marker_a; } # TODO
        else if options.marker_b.isDefined then
          cfg // { inherit (config) marker_b; } # TODO
        else
          cfg # TODO: (empty? no marker?)
          ;
    }
  );

  apply = value: value.__result;
}
20:16:10
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) Yeah, thought about that. One'd need access to all defs at once... 20:18:26
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) H'm, do I get a merged value as an input if I addCheck (submodule ...) (def: def?marker_a)?
I just tried adding { foo = { }; } before and after { foo.marker_b = ...; } and it still seems to work
20:28:37
@h7x4:nani.wtfh7x4 I believe the attrs are merged before being typechecked. I suppose you could try adding a lib.trace inside the typecheck to verify? 20:32:31
@ss:someonex.netSomeoneSerge (Ever OOMed by Element)
trace: { below = "_"; }                                                                                                                                                                                              
trace: { marker_b = "bar"; }                                                                                                                                                                                         
trace: { above = "_"; }                                                                                                                                                                                              
trace: { below = "_"; }                                                                                                                                                                                              
{ foo = { above = "_"; below = "_"; marker_b = "bar"; }; } 

For modules:

    { foo = { above = "_"; }; }
    {
      foo.marker_b = "bar";
    }
    { foo = { below = "_"; }; }

20:37:22
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) *
trace: { below = "_"; }                                                                                                                                                                                              
trace: { marker_b = "bar"; }                                                                                                                                                                                         
trace: { above = "_"; }                                                                                                                                                                                              
trace: { below = "_"; }                                                                                                                                                                                              
{ foo = { above = "_"; below = "_"; marker_b = "bar"; }; } 

For modules:

    { foo = { above = "_"; }; }
    {
      foo.marker_b = "bar";
    }
    { foo = { below = "_"; }; }

20:37:32
@mattsturg:matrix.orgMatt Sturgeon

This won't support foo = { config,...}: { marker_b = "bar"; }.

Type checking is done before merging, but after resolving mkIf (etc) wrappers.

Type checking is used to determine which type to use for merging.

20:39:18
@h7x4:nani.wtfh7x4Aha, that makes sense 👍️20:41:25
@ss:someonex.netSomeoneSerge (Ever OOMed by Element) Sounds like __result is least wrong? 20:50:51

Show newer messages


Back to Room ListRoom Version: 10