···1+{ den, lib, ... }:
2+let
3+ inherit (den.lib)
4+ parametric
5+ take
6+ ;
7+8+ description = ''
9+ This is a private aspect always included in den.default.
10+11+ It adds a module option that gathers all packages defined
12+ in den._.unfree usages and declares a
13+ nixpkgs.config.allowUnfreePredicate for each class.
14+15+ '';
16+17+ unfreeComposableModule.options.unfree = {
18+ packages = lib.mkOption {
19+ type = lib.types.listOf lib.types.str;
20+ default = [ ];
21+ };
22+ };
23+24+ nixosAspect =
25+ { config, ... }:
26+ {
27+ nixpkgs.config.allowUnfreePredicate = (pkg: builtins.elem (lib.getName pkg) config.unfree.packages);
28+ };
29+30+ homeManagerAspect =
31+ { config, osConfig, ... }:
32+ {
33+ nixpkgs = lib.mkIf (!osConfig.home-manager.useGlobalPkgs) {
34+ config.allowUnfreePredicate = (pkg: builtins.elem (lib.getName pkg) config.unfree.packages);
35+ };
36+ };
37+38+ aspect = parametric.exactly {
39+ inherit description;
40+ includes = [
41+ (
42+ { OS, host }:
43+ let
44+ unused = take.unused OS;
45+ in
46+ {
47+ ${host.class}.imports = unused [
48+ unfreeComposableModule
49+ nixosAspect
50+ ];
51+ }
52+ )
53+ (
54+ {
55+ OS,
56+ HM,
57+ user,
58+ host,
59+ }:
60+ let
61+ unused = take.unused [
62+ OS
63+ HM
64+ host
65+ ];
66+ in
67+ {
68+ ${user.class}.imports = unused [
69+ unfreeComposableModule
70+ homeManagerAspect
71+ ];
72+ }
73+ )
74+ (
75+ { HM, home }:
76+ let
77+ unused = take.unused HM;
78+ in
79+ {
80+ ${home.class}.imports = unused [
81+ unfreeComposableModule
82+ nixosAspect
83+ ];
84+ }
85+ )
86+ ];
87+ };
88+in
89+{
90+ den.default.includes = [ aspect ];
91+}
+21
modules/aspects/provides/unfree/unfree.nix
···000000000000000000000
···1+{ den, ... }:
2+{
3+ den.provides.unfree.description = ''
4+ A class generic aspect that enables unfree packages by name.
5+6+ Works for any class (nixos/darwin/homeManager,etc) on any host/user/home context.
7+8+ ## Usage
9+10+ den.aspects.my-laptop.includes = [ (den._.unfree [ "code" ]) ];
11+12+ It will dynamically provide a module for each class when accessed.
13+ '';
14+15+ den.provides.unfree.__functor =
16+ _self: allowed-names:
17+ { class, aspect-chain }:
18+ den.lib.take.unused aspect-chain {
19+ ${class}.unfree.packages = allowed-names;
20+ };
21+}
-21
modules/aspects/provides/unfree.nix
···1-{ lib, den, ... }:
2-{
3- den.provides.unfree.description = ''
4- A class generic aspect that enables unfree packages by name.
5-6- Works for any class (nixos/darwin/homeManager,etc) on any host/user/home context.
7-8- ## Usage
9-10- den.aspects.my-laptop.includes = [ (den._.unfree [ "code" ]) ];
11-12- It will dynamically provide a module for each class when accessed.
13- '';
14-15- den.provides.unfree.__functor =
16- _self: allowed-names:
17- { class, aspect-chain }:
18- den.lib.take.unused aspect-chain {
19- ${class}.nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) allowed-names;
20- };
21-}
···000000000000000000000
+6-50
nix/namespace.nix
···3let
4 from = lib.flatten [ sources ];
5 isOutput = builtins.any (x: x == true) from;
6- attrs = builtins.filter builtins.isAttrs from;
7-8- # Strip module system metadata to get clean raw values
9- stripMeta = value:
10- if builtins.isList value then
11- map stripMeta value
12- else if builtins.isAttrs value then
13- let
14- # Remove module system special attributes
15- cleaned = builtins.removeAttrs value [
16- "__functor"
17- "__functionArgs"
18- "_module"
19- "config"
20- ];
21- in
22- lib.mapAttrs (_: stripMeta) cleaned
23- else
24- value;
25-26- # Deep merge that concatenates lists instead of overwriting them
27- deepMergeWith = lhs: rhs:
28- if builtins.isList lhs && builtins.isList rhs then
29- lhs ++ rhs
30- else if builtins.isAttrs lhs && builtins.isAttrs rhs then
31- let
32- allKeys = lib.unique (builtins.attrNames lhs ++ builtins.attrNames rhs);
33- mergedAttrs = builtins.listToAttrs (map (name: {
34- inherit name;
35- value =
36- if lhs ? ${name} && rhs ? ${name} then
37- deepMergeWith lhs.${name} rhs.${name}
38- else if lhs ? ${name} then
39- lhs.${name}
40- else
41- rhs.${name};
42- }) allKeys);
43- in
44- mergedAttrs
45- else
46- rhs;
47-48- # Extract denful values, strip metadata, and merge them deeply before passing to module system
49- deepMerge = builtins.foldl' (acc: x:
50- deepMergeWith acc (stripMeta (lib.getAttrFromPath [ "denful" name ] x))
51- ) { } attrs;
5253 sourceModule = {
54- config.den.ful.${name} = deepMerge;
55 };
5657 aliasModule = lib.mkAliasOptionModule [ name ] [ "den" "ful" name ];
···59 outputModule =
60 if isOutput then
61 {
62- # Use mkOptionDefault to ensure this assignment has lower priority
63- # This prevents re-evaluation and duplication issues
64- config.flake.denful.${name} = lib.mkOptionDefault config.den.ful.${name};
65 }
66 else
67 { };
···9 den.base.host =
10 { host, ... }:
11 {
12- options.capabilities.ssh-server = lib.mkEnableOption "Does host ${host.name} provides ssh?";
13 };
1415 # This module is base for all user configs.
···9 den.base.host =
10 { host, ... }:
11 {
12+ options.capabilities.ssh-server = lib.mkEnableOption "Does host ${host.name} provide ssh?";
13 };
1415 # This module is base for all user configs.