| 31 Jan 2024 |
infinisil | djacu: Yeah that's not possible, probably best to have a function with that parameter that returns a new option, like lib.mkPackageOption | 16:03:53 |
@djacu:matrix.org | In reply to @infinisil:matrix.org djacu: Yeah that's not possible, probably best to have a function with that parameter that returns a new option, like lib.mkPackageOption Yeah I figured. Thank infinisil ! | 17:37:10 |
| 1 Feb 2024 |
@djacu:matrix.org | Hi all. I have a question about merging user defined options with default options. I am trying to design a module with the following attributes.
- It has a
user and default options that are attrs of something. user defaults to {} and default defaults to some non-empty set.
- There is a
useDefault option that will control whether or not the default values get used.
- There is an
out option that merges the user and default options.
- (where i have trouble) The user can enable the defaults but also override them.
I have a working example below. default is set to {a = 1; b = 2}. With useDefault = true;, I can set some other key-value like c=3 and ever override it with mkOverride or mkForce. However, I cannot override anything that was set by default. You can see in userOptions all the things I tried to get the config to evaluate properly but nothing worked.
Have I missed something or is this not possible? Thanks
let
pkgs = import <nixpkgs> {};
inherit (pkgs) lib;
inherit (lib) types;
testDefaults = {
lib,
config,
...
}: {
options = {
user = lib.mkOption {
description = "Test default things.";
type = types.attrsOf types.int;
default = {};
};
useDefault = lib.mkEnableOption "Enables default.";
default = lib.mkOption {
description = "The defaults";
type = types.attrsOf types.int;
default = {
a = 1;
b = 2;
};
};
out = lib.mkOption {
description = "The output.";
type = types.attrsOf types.int;
default = {};
};
};
config = lib.mkMerge [
(
lib.mkIf config.useDefault {
out = config.default;
}
)
{
out = config.user;
}
];
};
userOptions = [
({...}: {useDefault = true;})
# NONE OF THESE WORK; conflicting definitions
# ({...}: {user = {b = 3;};})
# ({...}: {user = {b = lib.mkOverride 1 3;};})
# ({...}: {user = {b = lib.mkDefault 3;};})
# ({...}: {user = {b = lib.mkForce 3;};})
# ({...}: {user = lib.mkForce {b = 3;};})
# I can set an option not in default.
({...}: {user = {c = 3;};})
# And I can override my own option using mkOVerride (<100).
({...}: {user = {c = lib.mkOverride 99 4;};})
# Or just mkForce which is mkOverride 50.
# ({...}: {user = {c = lib.mkForce 4;};})
];
in (
(lib.evalModules {
modules =
[
testDefaults
]
++ userOptions;
})
.config
)
| 19:45:53 |
guangtao | is it possible to solve your problem through the apply option? I mean you can set the defualt to be {}, use apply instead
apply = cfg: lib.recursiveUpdate {<default>} cfg;
| 20:12:04 |
guangtao | * is it possible to solve your problem through the apply option? I mean you can set the defualt to be {}, use apply instead
| 20:12:13 |
guangtao | * is it possible to solve your problem through the apply option? I mean you can set the defualt to be {}, use apply instead
apply = cfg: lib.recursiveUpdate {<default>} cfg;
| 20:12:42 |
guangtao | Yeah, if I understand your problem correctly. | 20:13:50 |
infinisil | Oh don't use apply, that's generally an anti-pattern | 20:14:12 |
infinisil | I'll take a closer look at the code | 20:14:22 |
@djacu:matrix.org | apply also generally wouldn't work because this module wouldn't necessarily be at the top level. I mean it could work but would be messy. Also, it breaks out of the module ecosystem and isn't very user friendly. | 20:16:08 |
infinisil | Oh so it doesn't work because to the module system, all definitions have the same priority | 20:16:57 |
infinisil | You set them both with out = <attrset>, no mkDefault or so | 20:17:16 |
infinisil | But out = mkDefault config.default wouldn't work because then the entire attribute set gets overridden by the users one, therefore not using any defaults | 20:18:00 |
infinisil | What you need is out = mapAttrs (name: mkDefault) config.default | 20:18:26 |
@djacu:matrix.org | I'm a little lost. Which line would I inject this:
out = mapAttrs (name: mkDefault) config.default
Also doesn't mapAttrs a function of 2 variables?
| 20:21:09 |
infinisil | The line out = config.default; | 20:21:48 |
@djacu:matrix.org | * I'm a little lost. Which line would I inject this:
out = mapAttrs (name: mkDefault) config.default
Also isn't mapAttrs a function of 2 variables?
| 20:22:09 |
infinisil | Currying function arguments :) | 20:22:12 |
guangtao | that makes sense; set all attrts of default to having order. | 20:23:54 |
@djacu:matrix.org | What is this deep magic!? It works | 20:26:24 |
@djacu:matrix.org | Oh did you just apply mkDefault to all the values set in default?? | 20:27:02 |