!wfudwzqQUiJYJnqfSY:nixos.org

NixOS Module System

81 Members
20 Servers

Load older messages


SenderMessageTime
17 Aug 2024
@mattsturg:matrix.orgMatt Sturgeon *

Anyone know why overriding an option-type's merge function seems to have no effect?

E.g. I have a submodule with a deprecated sub-option. Since the submodule's final value is often fully evaluated (e.g. printed to lua using lib.generators.toLua) I'd like to filter the deprecated option out of the final-merged value to prevent "used but not defined" errors.

I figured I could do something like:

fooType =
  let
    sub = types.submodule ({ config, options, ... }: {
      options.deprecatedOption = mkOption { };
    });
  in
    sub // {
      merge = loc: defs: builtins.removeAttrs (sub.merge loc defs) [
        "deprecatedOption"
      ];
    };

However this doesn't seem to have any effect, deprecatedOption is still present in fooType's final value.

For this specific example, I could use an option's apply function, but I'd like to understand the underlying issue. Implementing it in the type would also be better, as I may use it in several options.

I had a the same issue a few weeks ago when extending types.coercedTo to support deprecation warnings. I wanted to just override the merge attr, however I ended up having to copy the entire coercedTo implementation to get it working...

Seeing as mkOptionType just returns an attrset, I'm confused why overriding the merge attr seemingly doesn't affect how the type is merged in the module system.

22:32:23
@mattsturg:matrix.orgMatt Sturgeon *

Anyone know why overriding an option-type's merge function seems to have no effect?

E.g. I have a submodule with a deprecated sub-option. Since the submodule's final value is often fully evaluated (e.g. printed to lua using lib.generators.toLua) I'd like to filter the deprecated option out of the final-merged value to prevent "used but not defined" errors.

I figured I could do something like:

fooType =
  let
    sub = types.submodule ({ config, options, ... }: {
      options.deprecatedOption = mkOption { };
    });
  in
    sub // {
      merge = loc: defs: builtins.removeAttrs (sub.merge loc defs) [
        "deprecatedOption"
      ];
    };

However this doesn't seem to have any effect, deprecatedOption is still present in fooType's final value. Calling trace in the overridden merge function doesn't print anything either.

For this specific example, I could use an option's apply function, but I'd like to understand the underlying issue. Implementing it in the type would also be better, as I may use it in several options.

I had a the same issue a few weeks ago when extending types.coercedTo to support deprecation warnings. I wanted to just override the merge attr, however I ended up having to copy the entire coercedTo implementation to get it working...

Seeing as mkOptionType just returns an attrset, I'm confused why overriding the merge attr seemingly doesn't affect how the type is merged in the module system.

22:33:54
18 Aug 2024
@sebtm:lodere.esSebTM
In reply to @mattsturg:matrix.org

Another approach would be to check system outside of the module eval. E.g. if you're using lib.evalModules you could do:

lib.evalModules {
  modules = [
    ./common.nix
  ]
  ++ lib.optionals (system == "some-system") [
    ./system-specific.nix
  ];
}

(Same applies to wrappers, such as lib.nixosSystem)

Awesome thanks for explaining ✌🏻👌🏻🙏
07:38:58
@r3vx:matrix.orgr3vx joined the room.14:18:31
22 Aug 2024
@asmundesen:matrix.orgArtur Manuel joined the room.13:04:02
@asmundesen:matrix.orgArtur Manuel changed their profile picture.14:52:58
23 Aug 2024
@mr-qubo:matrix.orgmr-qubo

I'm trying to write nixos config where I can set nixos options from home-manager modules. But I can't get around infinite recursion errors.
I wrote this nixos module, I though this should work, but I'm still getting infinite recursion error, which I don't know how to debug.

{ lib, options, ... }:
with builtins; with lib;

let
  hmModuleBase = with options.home-manager.users.type.nestedTypes.elemType.functor.payload; evalModules {
    inherit class specialArgs;
    modules = modules ++ [{
      options.MrQubo = {
        osConfigs = {
          type = options.raw;
        };
      };
    }];
  };

  evalHmModule = module:
    hmModuleBase.extendModules { modules = [ module ]; };

  isImportableNV = { name, value }:
    (value == "regular" && match ".*\\.nix" name != null) || (value == "directory" && (readDir "${localOverlays}/${name}") ? "default.nix");

  parseNV = { name, value }: rec {
    username = removeSuffix ".nix" name;
    module = evalHmModule ../users/${name};
  };

  userModules = map parseNV (filter isImportableNV (attrsToList (readDir ../users)));

  osConfigs = flatten (map (attrs: attrs.module.MrQubo.osConfigs) userModules);

  hmUsersConfig = {
    home-manager.users = listToAttrs (map (attrs: { name = attrs.username; value = attrs.module; }) userModules);
  };

in mkMerge (osConfigs ++ [ hmUsersConfig ])
13:15:22
25 Aug 2024
@mattsturg:matrix.orgMatt Sturgeon

Robert Hensing (roberth) thanks for your thoughts here, I figured I'd reply here to save derailing that PR's discussion 😁

I just had a quick look in the repl, and highestPrio seems to be 1500 when an option is undefined such that it is using it's default value.

So we could have an isOptionDefault, but it wouldn't be able to distinguish between a default passed to mkOption and a config definition wrapped using mkOptionDefault.

Maybe that'd be the intended behavior though? 🤔

This also begs the question of how an override priority above 1500 should be handled, though I guess that's off-topic!

14:53:57
@mattsturg:matrix.orgMatt Sturgeon *

Robert Hensing (roberth) thanks for your thoughts here, I figured I'd reply here to save derailing that PR's discussion 😁

An isDefinedExplicitly option attr, true when isDefined, but without using the default.

This can also be achieved with a function from option to bool, by looking at the highestPrio attribute.

I just had a quick look in the repl, and highestPrio seems to be 1500 when an option is undefined such that it is using it's default value.

So we could have an isOptionDefault, but it wouldn't be able to distinguish between a default passed to mkOption and a config definition wrapped using mkOptionDefault.

Maybe that'd be the intended behavior though? 🤔

This also begs the question of how an override priority above 1500 should be handled, though I guess that's off-topic!

14:54:18
26 Aug 2024
@nbp:mozilla.orgnbp

The infinite recursion comes from the fact that osConfigs might contain home-manager user configurations.

I suggest to explicitly the top-level attributes that can be set to exclude users;

  osConfigs' = flatten …;
  # Generate an error if `users` is set.
  osConfigs = ({programs? {}, services? {}}: {
    inherit programs services;
  }) osConfigs';
09:46:27
@nbp:mozilla.orgnbp *

The infinite recursion comes from the fact that osConfigs might contain home-manager user configurations.

I suggest to explicitly the top-level attributes that can be set to exclude users;

  osConfigs' = flatten …;
  # Generate an error if `users` is set.
  osConfigs = ({programs? {}, services? {}}: {
    inherit programs services;
  }) osConfigs';
09:46:35
@nbp:mozilla.orgnbp *

The infinite recursion comes from the fact that osConfigs might contain home-manager user configurations.

I suggest to explicit the top-level attributes that can be set to exclude users;

  osConfigs' = flatten …;
  # Generate an error if `users` is set.
  osConfigs = ({programs? {}, services? {}}: {
    inherit programs services;
  }) osConfigs';
09:46:57
27 Aug 2024
@mattsturg:matrix.orgMatt Sturgeon removeAttrs osConfigs [ "users" ] may also work? 21:00:47
30 Aug 2024
@artur:glasgow.social(artur 'manuel) joined the room.08:11:32
@mr-qubo:matrix.orgmr-qubo
In reply to @mr-qubo:matrix.org

I'm trying to write nixos config where I can set nixos options from home-manager modules. But I can't get around infinite recursion errors.
I wrote this nixos module, I though this should work, but I'm still getting infinite recursion error, which I don't know how to debug.

{ lib, options, ... }:
with builtins; with lib;

let
  hmModuleBase = with options.home-manager.users.type.nestedTypes.elemType.functor.payload; evalModules {
    inherit class specialArgs;
    modules = modules ++ [{
      options.MrQubo = {
        osConfigs = {
          type = options.raw;
        };
      };
    }];
  };

  evalHmModule = module:
    hmModuleBase.extendModules { modules = [ module ]; };

  isImportableNV = { name, value }:
    (value == "regular" && match ".*\\.nix" name != null) || (value == "directory" && (readDir "${localOverlays}/${name}") ? "default.nix");

  parseNV = { name, value }: rec {
    username = removeSuffix ".nix" name;
    module = evalHmModule ../users/${name};
  };

  userModules = map parseNV (filter isImportableNV (attrsToList (readDir ../users)));

  osConfigs = flatten (map (attrs: attrs.module.MrQubo.osConfigs) userModules);

  hmUsersConfig = {
    home-manager.users = listToAttrs (map (attrs: { name = attrs.username; value = attrs.module; }) userModules);
  };

in mkMerge (osConfigs ++ [ hmUsersConfig ])

My second attempt:

{ lib, ... }:
with builtins; with lib;

let

  isImportable = { name, value }:
    (value == "regular" && match ".*\\.nix" name != null) || (value == "directory" && (readDir "${localOverlays}/${name}") ? "default.nix");

  parseUser = { name, value }: rec {
    username = removeSuffix ".nix" name;
    module = ../users/${name};
  };

  users = map parseUser (filter isImportable (attrsToList (readDir ../users)));

  evalHmModule = { username, module, config, pkgs, ... }:
    (import <home-manager/modules> {
      configuration = {
        options.MrQubo = {
          osConfig.services = mkOption {
            type = types.raw;
          };
        };
        config = {
          submoduleSupport.enable = true;
          submoduleSupport.externalPackageInstall = false;

          home.username = config.users.users.${username}.name;
          home.homeDirectory = config.users.users.${username}.home;

          # Make activation script use same version of Nix as system as a whole.
          # This avoids problems with Nix not being in PATH.
          nix.package = config.nix.package;
        };
      };
      inherit pkgs;
    }).extendModules {
      modules = [
        {
          MrQubo.osConfig.services = config.services;
        }
        module
      ];
    };

  osConfigModules = flip map users (user: { pkgs, config, ... }:
    { config.services = (evalHmModule ({ inherit pkgs config; } // user)).config.MrQubo.osConfig.services; }
  );

in {
  imports = osConfigModules;
}

It still doesn't work, even with just "services" option.
I get

       … while evaluating the option `services.sftpgo.user':

       error: infinite recursion encountered
11:26:33
@nbp:mozilla.orgnbp mr-qubo: I do not have enough information with what you copied to give you any answer, apart that I do not see any reasons for an infinite recursion in this file. 12:47:17
@mr-qubo:matrix.orgmr-qubo
In reply to @nbp:mozilla.org
mr-qubo: I do not have enough information with what you copied to give you any answer, apart that I do not see any reasons for an infinite recursion in this file.

I run it with nixos-rebuild -I nixos-config=$(pwd)/users-impl.nix dry-build --show-trace. ./user-impl.nix is the name of the file contents which I pasted. You also need to put some file in ../users/ dir. I have nix.nix file with those contents:

{
  home.stateVersion = "23.11";
}

home.stateVersion is needed, otherwise there's a different error from home-manager.

16:33:27
@mr-qubo:matrix.orgmr-qubo
In reply to @nbp:mozilla.org
mr-qubo: I do not have enough information with what you copied to give you any answer, apart that I do not see any reasons for an infinite recursion in this file.
*

I run it with nixos-rebuild -I nixos-config=$(pwd)/users-impl.nix dry-build --show-trace. ./user-impl.nix is the name of the file contents which I pasted. You also need to put some file in ../users/ dir. I have nix.nix file with those contents:

{
  home.stateVersion = "23.11";
}

home.stateVersion is needed, otherwise there's a different error from home-manager.
And you also need <home-manager> channel.

16:34:21
@mr-qubo:matrix.orgmr-qubo *

I run it with nixos-rebuild -I nixos-config=$(pwd)/users-impl.nix dry-build --show-trace. ./user-impl.nix is the name of the file, contents which I pasted. You also need to put some file in ../users/ dir. I have nix.nix file with those contents:

{
  home.stateVersion = "23.11";
}

home.stateVersion is needed, otherwise there's a different error from home-manager.
And you also need <home-manager> channel.

16:37:23
@mr-qubo:matrix.orgmr-qubo *

I run it with nixos-rebuild -I nixos-config=$(pwd)/users-impl.nix dry-build --show-trace. ./user-impl.nix is the name of the file, contents which I pasted. You also need to put some file in ../users/ dir. I have nix.nix file with those contents:

{
  home.stateVersion = "23.11";
}

home.stateVersion is needed, otherwise there's a different error from home-manager.
And you also need <home-manager> channel (nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager).

16:39:46
@mr-qubo:matrix.orgmr-qubo *

I've made more minimal example:

{ lib, ... }:

let

  users = [
    {
      username = "nix";
      module = {
        home.stateVersion = "23.11";
	# MrQubo.osConfig.services.logrotate.enable = false;
      };
    }
  ];

  evalHmModule = { username, module, config, pkgs, ... }:
    (import <home-manager/modules> {
      configuration = {
        options.MrQubo = {
          osConfig.services = lib.mkOption {
            type = lib.types.raw;
          };
        };
        config = {
          submoduleSupport.enable = true;
          submoduleSupport.externalPackageInstall = false;

          home.username = config.users.users.${username}.name;
          home.homeDirectory = config.users.users.${username}.home;

          # Make activation script use same version of Nix as system as a whole.
          # This avoids problems with Nix not being in PATH.
          nix.package = config.nix.package;
        };
      };
      inherit pkgs;
    }).extendModules {
      modules = [
        {
          MrQubo.osConfig.services = config.services;
        }
        module
      ];
    };

  osConfigModules = lib.flip map users (user: { pkgs, config, ... }:
    { config.services = (evalHmModule ({ inherit pkgs config; } // user)).config.MrQubo.osConfig.services; }
  );

in {
  imports = osConfigModules;
}


# vim: sts=2 sw=2 ts=60 et:

You also need <home-manager> channel, which can be added with nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager.
The configuration can be run with nixos-rebuild -I nixos-config=$(pwd)/users.nix dry-build --show-trace.

16:47:04
@mr-qubo:matrix.orgmr-qubo *

I've made more minimal example:

{ lib, ... }:

let

  users = [
    {
      username = "nix";
      module = {
        home.stateVersion = "23.11";
	# MrQubo.osConfig.services.logrotate.enable = false;
      };
    }
  ];

  evalHmModule = { username, module, config, pkgs, ... }:
    (import <home-manager/modules> {
      configuration = {
        options.MrQubo = {
          osConfig.services = lib.mkOption {
            type = lib.types.raw;
          };
        };
        config = {
          submoduleSupport.enable = true;
          submoduleSupport.externalPackageInstall = false;

          home.username = config.users.users.${username}.name;
          home.homeDirectory = config.users.users.${username}.home;

          # Make activation script use same version of Nix as system as a whole.
          # This avoids problems with Nix not being in PATH.
          nix.package = config.nix.package;
        };
      };
      inherit pkgs;
    }).extendModules {
      modules = [
        {
          MrQubo.osConfig.services = config.services;
        }
        module
      ];
    };

  osConfigModules = lib.flip map users (user: { pkgs, config, ... }:
    { config.services = (evalHmModule ({ inherit pkgs config; } // user)).config.MrQubo.osConfig.services; }
  );

in {
  imports = osConfigModules;
}

You also need <home-manager> channel, which can be added with nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager.
The configuration can be run with nixos-rebuild -I nixos-config=$(pwd)/users.nix dry-build --show-trace.

16:47:19
@mr-qubo:matrix.orgmr-qubo *

I've made more minimal example:

users.nix:

{ lib, ... }:

let

  users = [
    {
      username = "nix";
      module = {
        home.stateVersion = "23.11";
	# MrQubo.osConfig.services.logrotate.enable = false;
      };
    }
  ];

  evalHmModule = { username, module, config, pkgs, ... }:
    (import <home-manager/modules> {
      configuration = {
        options.MrQubo = {
          osConfig.services = lib.mkOption {
            type = lib.types.raw;
          };
        };
        config = {
          submoduleSupport.enable = true;
          submoduleSupport.externalPackageInstall = false;

          home.username = config.users.users.${username}.name;
          home.homeDirectory = config.users.users.${username}.home;

          # Make activation script use same version of Nix as system as a whole.
          # This avoids problems with Nix not being in PATH.
          nix.package = config.nix.package;
        };
      };
      inherit pkgs;
    }).extendModules {
      modules = [
        {
          MrQubo.osConfig.services = config.services;
        }
        module
      ];
    };

  osConfigModules = lib.flip map users (user: { pkgs, config, ... }:
    { config.services = (evalHmModule ({ inherit pkgs config; } // user)).config.MrQubo.osConfig.services; }
  );

in {
  imports = osConfigModules;
}

You also need <home-manager> channel, which can be added with nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager.
The configuration can be run with nixos-rebuild -I nixos-config=$(pwd)/users.nix dry-build --show-trace.

16:47:45
3 Sep 2024
@djacu:matrix.org@djacu:matrix.org left the room.23:29:30
4 Sep 2024
@ss:someonex.netSomeoneSerge (utc+3) changed their display name from SomeoneSerge (UTC+3) to SomeoneSerge (nix.camp).21:49:17
5 Sep 2024
@lingo5080:matrix.orglingo5080 joined the room.15:56:06
7 Sep 2024
@throwachimera:matrix.orgthrowachimera joined the room.11:56:03
@kamillaova:matrix.orgKamilla 'ova joined the room.12:21:15
8 Sep 2024
@jakehamilton:matrix.orgjakehamilton joined the room.01:02:45
@cafkafk:gitter.imcafkafk joined the room.05:21:48

Show newer messages


Back to Room ListRoom Version: 10