Commit 834a83c
Changed files (3)
modules
users
modules/users/schema.nix
@@ -2,43 +2,82 @@
lib,
config,
...
-}: {
+}: let
+ # Identity fields other than `displayName`, whose default differs between the
+ # shared registry (the registry key) and the entity (the injected value).
+ identityFields = {
+ options = {
+ email = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ description = "Email address for the user";
+ };
+ avatar = lib.mkOption {
+ type = lib.types.nullOr lib.types.path;
+ default = null;
+ description = "Avatar for the user";
+ };
+ sshKeys = lib.mkOption {
+ type = lib.types.listOf lib.types.str;
+ default = [];
+ };
+ gpgKeys = lib.mkOption {
+ type = lib.types.listOf (lib.types.either lib.types.path lib.types.str);
+ default = [];
+ description = "OpenPGP public keys (paths or armored key text) for this user";
+ };
+ };
+ };
+
+ identityType = lib.types.submodule {
+ imports = [identityFields];
+ options.displayName = lib.mkOption {
+ type = lib.types.str;
+ description = "Display name for the user";
+ };
+ };
+
+ sharedIdentity = lib.mkOptionType {
+ name = "den-shared-user-identity";
+ check = v: builtins.isAttrs v;
+ merge = loc: defs: let
+ shared =
+ if builtins.length loc < 2
+ then {}
+ else let
+ username = lib.elemAt loc (builtins.length loc - 2);
+ in
+ (config.den.users.${username} or {}).identity or {displayName = username;};
+ in
+ identityType.merge loc ([
+ {
+ file = "<den.users>";
+ value = lib.mkDefault shared;
+ }
+ ]
+ ++ defs);
+ };
+in {
# Shared user schema across every host
options.den.users = lib.mkOption {
type = lib.types.attrsOf (
- lib.types.submodule ({name, ...}: {
+ lib.types.submodule {
freeformType = lib.types.attrsOf lib.types.anything;
options = {
admin = lib.mkEnableOption "Whether to add user to admin user";
identity = lib.mkOption {
- type = lib.types.submodule {
- options = {
- displayName = lib.mkOption {
+ type = lib.types.submodule (
+ {name, ...}: let
+ userName = name;
+ in {
+ imports = [identityFields];
+ options.displayName = lib.mkOption {
type = lib.types.str;
- default = name;
+ default = userName;
description = "Display name for the user";
};
- email = lib.mkOption {
- type = lib.types.nullOr lib.types.str;
- default = null;
- description = "Email address for the user";
- };
- avatar = lib.mkOption {
- type = lib.types.nullOr lib.types.path;
- default = null;
- description = "Avatar for the user";
- };
- sshKeys = lib.mkOption {
- type = lib.types.listOf lib.types.str;
- default = [];
- };
- gpgKeys = lib.mkOption {
- type = lib.types.listOf (lib.types.either lib.types.path lib.types.str);
- default = [];
- description = "OpenPGP public keys (paths or armored key text) for this user";
- };
- };
- };
+ }
+ );
default = {};
};
system = lib.mkOption {
@@ -56,7 +95,7 @@
default = {};
};
};
- })
+ }
);
default = {};
description = ''
@@ -67,23 +106,12 @@
'';
};
- config.den.schema.user = {
- # Per-user name is only recoverable from the freeform merge's option path.
- options._module.freeformType = lib.mkOption {
- apply = t:
- if t == null
- then null
- else
- lib.mkOptionType {
- name = "den-shared-user-freeform";
- check = builtins.isAttrs;
- # Freeform merge never runs without any definitions.
- merge = loc: defs:
- lib.removeAttrs (
- lib.recursiveUpdate (config.den.users.${lib.last loc} or {}) (t.merge loc defs)
- ) ["ixSharedSentinel"];
- };
- };
- config.ixSharedSentinel = true;
+ config.den.schema.user.options.identity = lib.mkOption {
+ type = sharedIdentity;
+ default = {};
+ description = ''
+ User identity fields, merged with the shared `den.users.<name>.identity`
+ registry entry as a lowest-priority definition.
+ '';
};
}
modules/users/theme.nix
@@ -19,22 +19,22 @@
"themes"
];
- # Navigated refs lack name/meta; derive them from __provider so
+ # Navigated refs lack name/meta; derive them from __aspectChain so
# guard-time hasAspect matches what the walker assigns.
normalizeRef = v:
if
builtins.isAttrs v
&& !(v ? name)
- && builtins.isList (v.__provider or [])
- && v.__provider != []
+ && builtins.isList (v.__aspectChain or [])
+ && v.__aspectChain != []
then
v
// {
- name = lib.last v.__provider;
+ name = lib.last v.__aspectChain;
meta =
(v.meta or {})
// {
- provider = lib.init v.__provider;
+ aspect-chain = lib.init v.__aspectChain;
};
}
else v;
flake.lock
@@ -17,11 +17,11 @@
},
"den": {
"locked": {
- "lastModified": 1786475005,
- "narHash": "sha256-gp7Q7rMEjsqAyW4Uwz+sms8j+XegD5P/lzRCuMW2fNI=",
+ "lastModified": 1790179224,
+ "narHash": "sha256-dxUKiY5abOjTkazki74sA39yJxq0o1Aprh1lsQKNqPY=",
"owner": "denful",
"repo": "den",
- "rev": "e8e8de1e32646456cfc613f152175a7a548508ec",
+ "rev": "ba9ee3a5e8ad1f77ba8e0341b224c4a1d5999787",
"type": "github"
},
"original": {