Skip to content

Commit 30601bd

Browse files
authored
feat: parent parameter (#53)
* lib/attrset: add splitStrPath * lib/attrset: add mkModuleArgs though getAttrByStrPath is used, it is used only in `delib.module` for the user's api. with this function i tried to cover `delib.host` and `delib.rice` as well. * lib/configurations/module: rename wrap argument to x for consistency with other configuration modules. also "object" doesn't make much sense in a semantic way, but 'x' is short and easy on the eyes * lib/configurations/hosts: change todo to note i think that's more appropriate * docs/src/modules/structure: add parent argument also change cfg's description to a more readable one. i think using an approach like "literally describe what the code does" in the documentation is pointless, because the code is just available and the users can find it by themselves * docs/src/modules/structure: 'equal' typo as i remember, "to" is not used for "equals", but for "equal" * docs/src/hosts/structure: parent argument a funny issue was discovered: name in the modules was split by dots, but not in the hosts. i updated the documentation to chase the current working state of the branch, so i added a disclaimer for the usage of dot characters in the name. i don't actually know what should be done here. parent is probably not very useful to the hosts, but host function by itself is almost a wrapper around the module function, so should it provide less functionality? maybe the user defined the hosts module by themselves and some useful values were defined here. the current logic is likely broken if host contains dots. a single string is used in lib/configuration/host.nix to define config (see the note), but the name is split in mkModuleArgs. the situation is identical for rices. i see two resolutions here: - use parent argument only for the modules and rollback the changes of using mkModuleArgs - preserve previous behaviour - add an additional argument to mkModuleArgs to not split the name - just fixing the issue as an edgecase aside from that, in either way, the library results in a bit inconsistent behaviour, because dots are used as split characters for the modules, but not for the hosts or rices. for the hosts, i see no reason to use the dots, because host is just a host. host is a singular entity and nesting hosts seems unlikely. maybe allowing dots is actually good, because gives freedom to the user for the naming. but for the rices, i don't know. maybe nesting rices could be cool, because you can have a main "flavour" and nested "subflavours". and these subflavours would automatically inherit options from the parent. this seems like a cool application of the parent argument as a whole. but hosts and rices use assertions for the names, and right now the data structure for the assertions is a plain list, because the names cannot be nested. if nesting would be allowed, then a tree-like structure of attributes should be converted to a list. and the issue with infinite recursion should be resolved as well, if we want to allow nesting. i, personally, would stick with the second resolution to fix this issue and provide parent to hosts and rices, because i see no harm in it. the matter with the nesting can be handled later. * Revert "docs/src/hosts/structure: parent argument" This reverts commit b8c6afe. * lib/configurations/host!: don't use mkModuleArgs essentially, reverts the functionality to the original state personally, i really don't like the repetition here, but refactoring of the logic that's not tied to the parent argument is not in the scope for this branch, if the parent argument is not implemented here * lib/configurations/rice!: don't use mkModuleArgs the reasoning is the same as for the hosts * lib/attrset!: -mkModuleArgs, +splitStrPath splitStrPath is minimal, and used for other exported functions, so it's pretty safe to export. but mkModuleArgs is only used in one place, so it's been moved to the lib/configurations/module. and without the category functionality, because it's not needed anymore. * docs/src/ru/modules/structure: parent argument chase english docs
1 parent e90b670 commit 30601bd

File tree

4 files changed

+59
-41
lines changed

4 files changed

+59
-41
lines changed

docs/src/modules/structure.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,41 @@ This section uses the variables `myconfigName`, `moduleSystem`, and `homeManager
1717
A list of arguments passed to `options` and `[myconfig|nixos|home|darwin].[ifEnabled|ifDisabled|always]`, if their type is a `lambda`:
1818
- `name`: the same [name](#function-arguments-name) from the `delib.module` arguments.
1919
- `myconfig`: equals `config.${myConfigName}`.
20-
- `cfg`{#passed-arguments-cfg}: equals the result of the expression `delib.getAttrByStrPath name config.${myConfigName} {}`, where `name` is the [argument](#function-arguments-name) from `delib.module`, and `{}` is the value returned if the attribute is not found.
20+
- `cfg`{#passed-arguments-cfg}: essentially, the config values (assigned options) of the current module. In other words, equals `config.${myConfigName}.${name}`, where `name` is the [argument](#function-arguments-name) from `delib.module` and is "expanded" (converted to a valid attribute path).
21+
- `parent`: equal to the "parent" module (attribute set) of `cfg`. Example: `parent` is `config.${myConfigName}.programs` if `cfg` is `config.${myConfigName}.programs.example`.
2122

2223
## Pseudocode {#pseudocode}
2324
```nix
2425
delib.module {
2526
name = "";
2627
2728
# options.${myConfigName} = ...
28-
options = {name, cfg, myconfig, ...}: {};
29+
options = {name, cfg, parent, myconfig, ...}: {};
2930
3031
# config.${myConfigName} = ...
31-
myconfig.ifEnabled = {name, cfg, myconfig, ...}: {};
32-
myconfig.ifDisabled = {name, cfg, myconfig, ...}: {};
33-
myconfig.always = {name, cfg, myconfig, ...}: {};
32+
myconfig.ifEnabled = {name, cfg, parent, myconfig, ...}: {};
33+
myconfig.ifDisabled = {name, cfg, parent, myconfig, ...}: {};
34+
myconfig.always = {name, cfg, parent, myconfig, ...}: {};
3435
3536
# if moduleSystem == "nixos"
3637
# then {config = ...;}
3738
# else {}
38-
nixos.ifEnabled = {name, cfg, myconfig, ...}: {};
39-
nixos.ifDisabled = {name, cfg, myconfig, ...}: {};
40-
nixos.always = {name, cfg, myconfig, ...}: {};
39+
nixos.ifEnabled = {name, cfg, parent, myconfig, ...}: {};
40+
nixos.ifDisabled = {name, cfg, parent, myconfig, ...}: {};
41+
nixos.always = {name, cfg, parent, myconfig, ...}: {};
4142
4243
# if moduleSystem == "home"
4344
# then {config = ...;}
4445
# else {config.home-manager.users.${homeManagerUser} = ...;}
45-
home.ifEnabled = {name, cfg, myconfig, ...}: {};
46-
home.ifDisabled = {name, cfg, myconfig, ...}: {};
47-
home.always = {name, cfg, myconfig, ...}: {};
46+
home.ifEnabled = {name, cfg, parent, myconfig, ...}: {};
47+
home.ifDisabled = {name, cfg, parent, myconfig, ...}: {};
48+
home.always = {name, cfg, parent, myconfig, ...}: {};
4849
4950
# if moduleSystem == "darwin"
5051
# then {config = ...;}
5152
# else {}
52-
darwin.ifEnabled = {name, cfg, myconfig, ...}: {};
53-
darwin.ifDisabled = {name, cfg, myconfig, ...}: {};
54-
darwin.always = {name, cfg, myconfig, ...}: {};
53+
darwin.ifEnabled = {name, cfg, parent, myconfig, ...}: {};
54+
darwin.ifDisabled = {name, cfg, parent, myconfig, ...}: {};
55+
darwin.always = {name, cfg, parent, myconfig, ...}: {};
5556
}
5657
```

docs/src/ru/modules/structure.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,41 @@
1717
Список аргументов, которые передаются в `options` и `[myconfig|nixos|home|darwin].[ifEnabled|ifDisabled|always]`, если их тип - это `lambda`:
1818
- `name`: тот же [name](#function-arguments-name) из аргументов `delib.module`.
1919
- `myconfig`: равен `config.${myConfigName}`.
20-
- `cfg`{#passed-arguments-cfg}: равен результату выражения `delib.getAttrByStrPath name config.${myConfigName} {}`, где `name` - это [аргумент](#function-arguments-name) `delib.module`, а `{}` - значение, которое возвращается, если атрибут не найден.
20+
- `cfg`{#passed-arguments-cfg}: по сути, значения (присвоенные) из конфигурации текущего модуля. Другими словами, равняется `config.${myConfigName}.${name}`, где `name` это [аргумент](#function-arguments-name) из `delib.module`, "раскрывающийся" (конвертируется в валидный путь как атрибут) при этом.
21+
- `parent`: равняется модулю-"родителю" (набору атрибутов) `cfg`. Пример: `parent` это `config.${myConfigName}.programs`, если `cfg` это `config.${myConfigName}.programs.example`.
2122

2223
## Псевдокод {#pseudocode}
2324
```nix
2425
delib.module {
2526
name = "";
2627
2728
# options.${myConfigName} = ...
28-
options = {name, cfg, myconfig, ...}: {};
29+
options = {name, cfg, parent, myconfig, ...}: {};
2930
3031
# config.${myConfigName} = ...
31-
myconfig.ifEnabled = {name, cfg, myconfig, ...}: {};
32-
myconfig.ifDisabled = {name, cfg, myconfig, ...}: {};
33-
myconfig.always = {name, cfg, myconfig, ...}: {};
32+
myconfig.ifEnabled = {name, cfg, parent, myconfig, ...}: {};
33+
myconfig.ifDisabled = {name, cfg, parent, myconfig, ...}: {};
34+
myconfig.always = {name, cfg, parent, myconfig, ...}: {};
3435
3536
# если moduleSystem == "nixos"
3637
# то {config = ...;}
3738
# иначе {}
38-
nixos.ifEnabled = {name, cfg, myconfig, ...}: {};
39-
nixos.ifDisabled = {name, cfg, myconfig, ...}: {};
40-
nixos.always = {name, cfg, myconfig, ...}: {};
39+
nixos.ifEnabled = {name, cfg, parent, myconfig, ...}: {};
40+
nixos.ifDisabled = {name, cfg, parent, myconfig, ...}: {};
41+
nixos.always = {name, cfg, parent, myconfig, ...}: {};
4142
4243
# если moduleSystem == "home"
4344
# то {config = ...;}
4445
# иначе {config.home-manager.users.${homeManagerUser} = ...;}
45-
home.ifEnabled = {name, cfg, myconfig, ...}: {};
46-
home.ifDisabled = {name, cfg, myconfig, ...}: {};
47-
home.always = {name, cfg, myconfig, ...}: {};
46+
home.ifEnabled = {name, cfg, parent, myconfig, ...}: {};
47+
home.ifDisabled = {name, cfg, parent, myconfig, ...}: {};
48+
home.always = {name, cfg, parent, myconfig, ...}: {};
4849
4950
# если moduleSystem == "darwin"
5051
# то {config = ...;}
5152
# иначе {}
52-
darwin.ifEnabled = {name, cfg, myconfig, ...}: {};
53-
darwin.ifDisabled = {name, cfg, myconfig, ...}: {};
54-
darwin.always = {name, cfg, myconfig, ...}: {};
53+
darwin.ifEnabled = {name, cfg, parent, myconfig, ...}: {};
54+
darwin.ifDisabled = {name, cfg, parent, myconfig, ...}: {};
55+
darwin.always = {name, cfg, parent, myconfig, ...}: {};
5556
}
5657
```

lib/attrset.nix

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
{ lib, ... }:
1+
{ lib, delib, ... }:
22
{
3+
splitStrPath = lib.splitString ".";
4+
35
getAttrByStrPath =
46
strPath: attrset: default:
5-
lib.attrByPath (lib.splitString "." strPath) default attrset;
7+
lib.attrByPath (delib.splitStrPath strPath) default attrset;
68

7-
setAttrByStrPath = strPath: value: lib.setAttrByPath (lib.splitString "." strPath) value;
9+
setAttrByStrPath = strPath: value: lib.setAttrByPath (delib.splitStrPath strPath) value;
810

911
hasAttrs =
1012
attrs: attrset:

lib/configurations/module.nix

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,31 @@
2020
(
2121
{ config, ... }:
2222
let
23-
cfg = delib.attrset.getAttrByStrPath name config.${myconfigName} { };
23+
args =
24+
let
25+
# instance of the user's config attrset, not the
26+
# same as myconfig in the outer scope
27+
myconfig = config.${myconfigName};
2428

25-
wrap =
26-
object:
27-
if builtins.typeOf object == "lambda" then
28-
object {
29-
inherit name cfg;
30-
myconfig = config.${myconfigName};
31-
}
32-
else
33-
object;
29+
cfgPath = delib.attrset.splitStrPath name;
30+
31+
fromPath = with lib; path: if (length path) > 0 then attrByPath path { } myconfig else myconfig;
32+
33+
cfg = fromPath cfgPath;
34+
parent = fromPath (lib.dropEnd 1 cfgPath);
35+
in
36+
{
37+
inherit
38+
name
39+
myconfig
40+
cfg
41+
parent
42+
;
43+
};
44+
45+
inherit (args) cfg;
46+
47+
wrap = x: if builtins.typeOf x == "lambda" then x args else x;
3448

3549
defaults =
3650
{

0 commit comments

Comments
 (0)