diff --git a/modules/context/perHost-perUser.nix b/modules/context/perHost-perUser.nix index 01f439c1..ee4aa26f 100644 --- a/modules/context/perHost-perUser.nix +++ b/modules/context/perHost-perUser.nix @@ -7,9 +7,9 @@ let inherit (config.den.lib) take parametric; fixed = ctx: aspect: parametric.fixedTo ctx { includes = [ aspect ]; }; - perHost = aspect: take.exactly ({ host }@ctx: fixed ctx aspect); - perUser = aspect: take.exactly ({ host, user }@ctx: fixed ctx aspect); - perHome = aspect: take.exactly ({ home }@ctx: fixed ctx aspect); + perHost = aspect: { includes = [ (take.exactly ({ host }@ctx: fixed ctx aspect)) ]; }; + perUser = aspect: { includes = [ (take.exactly ({ host, user }@ctx: fixed ctx aspect)) ]; }; + perHome = aspect: { includes = [ (take.exactly ({ home }@ctx: fixed ctx aspect)) ]; }; in { den.lib = { inherit perHome perUser perHost; }; diff --git a/nix/lib/aspects/types.nix b/nix/lib/aspects/types.nix index ee4a238c..030ecacb 100644 --- a/nix/lib/aspects/types.nix +++ b/nix/lib/aspects/types.nix @@ -154,7 +154,19 @@ let } ); - aspectsType = cnf: lib.types.submodule { freeformType = lib.types.lazyAttrsOf (providerType cnf); }; + # Wrap non-module functions into { includes = [fn] } so they don't get + # treated as module functions by aspectType's submodule merge. + coercedProviderType = + cnf: + let + pt = providerType cnf; + in + lib.types.coercedTo (lib.types.addCheck lib.types.raw ( + v: builtins.isFunction v && !isSubmoduleFn v + )) (fn: { includes = [ fn ]; }) pt; + + aspectsType = + cnf: lib.types.submodule { freeformType = lib.types.lazyAttrsOf (coercedProviderType cnf); }; in { diff --git a/nix/lib/take.nix b/nix/lib/take.nix index 022b4cd9..7e222248 100644 --- a/nix/lib/take.nix +++ b/nix/lib/take.nix @@ -3,6 +3,15 @@ let asIs = _: lib.id; upTo = f: builtins.intersectAttrs (lib.functionArgs f); + # Carry name from the function to its result when the result doesn't + # already have one. This preserves aspect identity through take calls. + carryAttrs = + fn: result: + if builtins.isAttrs result then + result // lib.optionalAttrs ((fn.name or null) != null && !(result ? name)) { inherit (fn) name; } + else + result; + take.unused = _unused: used: used; take.exactly = take den.lib.canTake.exactly asIs; @@ -14,6 +23,6 @@ let let ctx = argAdapter fn args; in - if canTake ctx fn then fn ctx else { }; + if canTake ctx fn then carryAttrs fn (fn ctx) else { }; in take diff --git a/templates/ci/modules/features/aspect-path.nix b/templates/ci/modules/features/aspect-path.nix index f921cc3c..4bbc94cd 100644 --- a/templates/ci/modules/features/aspect-path.nix +++ b/templates/ci/modules/features/aspect-path.nix @@ -195,5 +195,33 @@ } ); + # perHost parametric aspects should appear in trace by name + test-perHost-visible-in-trace = denTest ( + { den, ... }: + { + den.aspects.role.includes = with den.aspects; [ + leaf + param + ]; + den.aspects.leaf.nixos = { }; + den.aspects.param = den.lib.perHost ( + { host }: + { + nixos = { }; + } + ); + + expr = with den.lib.aspects; resolve.withAdapter adapters.trace "nixos" den.aspects.role; + expected.trace = [ + "role" + [ "leaf" ] + [ + "param" + [ "[definition 1-entry 1]" ] + ] + ]; + } + ); + }; } diff --git a/templates/ci/modules/features/deadbugs/issue-408-bare-function-aspect.nix b/templates/ci/modules/features/deadbugs/issue-408-bare-function-aspect.nix new file mode 100644 index 00000000..43c864fd --- /dev/null +++ b/templates/ci/modules/features/deadbugs/issue-408-bare-function-aspect.nix @@ -0,0 +1,43 @@ +# Bare function aspect merged with static config. +# https://github.com/vic/den/pull/408 +{ denTest, lib, ... }: +{ + flake.tests.deadbugs-issue-408 = { + test-function-aspect-with-static-merge = denTest ( + { den, igloo, ... }: + { + den.hosts.x86_64-linux.igloo.users.tux = { }; + den.aspects.igloo.includes = [ den.aspects.foo ]; + + imports = + let + one = { + den.aspects.foo = + { host, ... }: + { + nixos.environment.sessionVariables.FOO = host.name; + }; + }; + two = { + den.aspects.foo.nixos = + { pkgs, ... }: + { + environment.systemPackages = [ pkgs.hello ]; + }; + }; + in + [ + one + two + ]; + + expr = { + hello = lib.elem "hello" (map lib.getName igloo.environment.systemPackages); + FOO = igloo.environment.sessionVariables.FOO; + }; + expected.FOO = "igloo"; + expected.hello = true; + } + ); + }; +}