Modular, context-aware and aspect-oriented dendritic Nix configurations. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ den.oeiuwq.com
configurations den dendritic nix aspect oriented
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(namespaces): fix missing reflection information on imported providers from a namespace (#353)

Fixes #352

## Summary
Providers when imported through a namespace get pass through a functor
transformation in `nix/lib/namespace/nix:functorModules` which fails to
propagate its `__functionArgs` for the reflection needing in the context
propagation system. Adding this alone is not enough because then this
triggers the freeformType part of the aspect type definition resulting
in a `__functionArgs` like this. The fix as far as I can tell also
requires registering the `__functionArgs` type with the aspect type.

```nix
__functionArgs = {
imports = [
{
_file = "<unknown-file>, via option den.ful.test.aspect.provides.host.__functionArgs";
imports = [
{ host = false; }
];
}
];
};
```

---------

Co-authored-by: Victor Borja <vborja@apache.org>

authored by

Dylan R. Johnston
Victor Borja
and committed by
GitHub
892a94fa 067282ff

+103 -82
-2
README.md
··· 16 16 These configurations become specific when applied to your particular infra entities (hosts/users), 17 17 while allowing re-usable aspects to be shared between hosts, users, or across other flakes and non-flake projects. 18 18 19 - 20 - 21 19 <table> 22 20 <tr> 23 21 <td>
+3 -2
nix/lib/aspects/default.nix
··· 4 4 ... 5 5 }: 6 6 let 7 + rawTypes = import ./types.nix { inherit den lib; }; 8 + resolve = import ./resolve.nix { inherit den lib; }; 9 + 7 10 defaultFunctor = (den.lib.parametric { }).__functor; 8 11 typesConf = { inherit defaultFunctor; }; 9 - rawTypes = import ./types.nix lib; 10 12 types = lib.mapAttrs (_: v: v typesConf) rawTypes; 11 - resolve = import ./resolve.nix lib; 12 13 in 13 14 { 14 15 inherit types resolve;
+1 -1
nix/lib/aspects/resolve.nix
··· 1 - lib: 1 + { lib, ... }: 2 2 let 3 3 4 4 resolve =
+5 -24
nix/lib/aspects/types.nix
··· 1 - lib: 1 + { lib, den, ... }: 2 2 let 3 - functorType = lib.types.mkOptionType { 4 - name = "aspectFunctor"; 5 - description = "aspect functor function"; 6 - check = lib.isFunction; 7 - merge = 8 - _loc: defs: 9 - let 10 - lastDef = lib.last defs; 11 - in 12 - { 13 - __functionArgs = lib.functionArgs lastDef.value; 14 - __functor = 15 - _: callerArgs: 16 - let 17 - result = lastDef.value callerArgs; 18 - in 19 - if builtins.isFunction result then result else _: result; 20 - }; 21 - }; 3 + inherit (den.lib) lastFunctionTo; 22 4 23 5 isSubmoduleFn = 24 6 m: ··· 44 26 in 45 27 names != [ ] && builtins.all (n: builtins.elem n providerArgNames) names; 46 28 47 - directProviderFn = 48 - cnf: lib.types.addCheck (lib.types.functionTo (aspectSubmodule cnf)) isProviderFn; 29 + directProviderFn = cnf: lib.types.addCheck (lastFunctionTo (aspectSubmodule cnf)) isProviderFn; 49 30 50 31 curriedProviderFn = 51 32 cnf: 52 - lib.types.addCheck (lib.types.functionTo (providerType cnf)) ( 33 + lib.types.addCheck (lastFunctionTo (providerType cnf)) ( 53 34 f: 54 35 builtins.isFunction f 55 36 || ··· 109 90 internal = true; 110 91 visible = false; 111 92 description = "Functor to default provider"; 112 - type = functorType; 93 + type = lastFunctionTo (providerType cnf); 113 94 default = cnf.defaultFunctor or lib.const; 114 95 }; 115 96 };
+1
nix/lib/default.nix
··· 31 31 parametric = ./parametric.nix; 32 32 statics = ./statics.nix; 33 33 take = ./take.nix; 34 + lastFunctionTo = ./last-function-to.nix; 34 35 }; 35 36 in 36 37 den-lib
+8
nix/lib/last-function-to.nix
··· 1 + { lib, ... }: 2 + elemType: 3 + lib.types.mkOptionType { 4 + name = "lastFunctionTo"; 5 + description = "last function to ${elemType.description}"; 6 + check = (lib.types.functionTo elemType).check; 7 + merge = _loc: defs: (lib.last defs).value; 8 + }
+3 -52
nix/lib/namespace.nix
··· 8 8 name 9 9 ]) (builtins.filter builtins.isAttrs from); 10 10 11 - internals = [ 12 - "_" 13 - "_module" 14 - "__functor" 15 - "__functionArgs" 16 - ]; 17 - 18 - stripAspect = 19 - v: 20 - if !builtins.isAttrs v then 21 - v 22 - else 23 - lib.mapAttrs ( 24 - n: child: 25 - if n == "provides" then 26 - lib.mapAttrs (_: stripAspect) child 27 - else if builtins.isAttrs child then 28 - builtins.removeAttrs child internals 29 - else 30 - child 31 - ) (builtins.removeAttrs v internals); 32 - 33 - stripNamespace = lib.mapAttrs (_: stripAspect); 34 - 35 - functorModules = 36 - aspectPath: v: 37 - lib.optionals (builtins.isAttrs v) ( 38 - lib.optional (v ? __functor) { 39 - config = lib.setAttrByPath aspectPath { __functor = v.__functor; }; 40 - } 41 - ++ lib.concatMap ( 42 - pname: 43 - functorModules ( 44 - aspectPath 45 - ++ [ 46 - "provides" 47 - pname 48 - ] 49 - ) v.provides.${pname} 50 - ) (lib.attrNames (v.provides or { })) 51 - ); 52 - 53 - namespaceFunctorModules = 54 - ns: lib.concatMap (aname: functorModules [ "den" "ful" name aname ] ns.${aname}) (lib.attrNames ns); 55 - 56 - sourceModule = { 57 - config.den.ful.${name} = lib.mkMerge (map stripNamespace denfuls); 58 - }; 11 + sourceModules = map (denful: { config.den.ful.${name} = denful; }) denfuls; 59 12 60 13 aliasModule = lib.mkAliasOptionModule [ name ] [ "den" "ful" name ]; 61 14 ··· 68 21 { }; 69 22 in 70 23 { 71 - imports = [ 72 - sourceModule 24 + imports = sourceModules ++ [ 73 25 aliasModule 74 26 outputModule 75 - ] 76 - ++ lib.concatMap namespaceFunctorModules denfuls; 27 + ]; 77 28 config._module.args.${name} = config.den.ful.${name}; 78 29 }
+5 -1
nix/lib/parametric.nix
··· 17 17 provided 18 18 // { 19 19 includes = map ( 20 - include: if include ? includes then parametric.deep functor ctx include else include 20 + include: 21 + if include ? includes then 22 + if include ? __functor then include else parametric.deep functor ctx include 23 + else 24 + include 21 25 ) (provided.includes or [ ]); 22 26 }; 23 27
+77
templates/ci/modules/features/deadbugs/issue-352-exported-providers-function-arg-reflection.nix
··· 1 + { denTest, ... }: 2 + { 3 + flake.tests.deadbugs-issue-352 = 4 + let 5 + module = 6 + { inputs, ... }: 7 + { 8 + imports = [ 9 + inputs.den.flakeModule 10 + (inputs.den.namespace "test" true) 11 + ]; 12 + 13 + test.aspect._.host = 14 + { host, ... }: 15 + { 16 + nixos.environment.sessionVariables.TEST_HOST = host.name; 17 + }; 18 + }; 19 + internal = module; 20 + external = 21 + inputs: 22 + (inputs.nixpkgs.lib.evalModules { 23 + specialArgs = { inherit inputs; }; 24 + modules = [ module ]; 25 + }).config.flake; 26 + in 27 + { 28 + test-internal-exported-providers-function-arg-reflection = denTest ( 29 + { 30 + lib, 31 + test, 32 + ... 33 + }: 34 + { 35 + imports = [ internal ]; 36 + 37 + expr = lib.functionArgs test.aspect._.host; 38 + expected = { 39 + host = false; 40 + }; 41 + } 42 + ); 43 + 44 + test-raw-exported-providers-function-arg-reflection = denTest ( 45 + { 46 + inputs, 47 + lib, 48 + test, 49 + ... 50 + }: 51 + { 52 + expr = lib.functionArgs (external inputs).denful.test.aspect._.host; 53 + expected = { 54 + host = false; 55 + }; 56 + } 57 + ); 58 + 59 + test-external-exported-providers-function-arg-reflection = denTest ( 60 + { 61 + inputs, 62 + test, 63 + lib, 64 + ... 65 + }: 66 + 67 + { 68 + imports = [ (inputs.den.namespace "test" [ (external inputs) ]) ]; 69 + 70 + expr = lib.functionArgs test.aspect._.host; 71 + expected = { 72 + host = false; 73 + }; 74 + } 75 + ); 76 + }; 77 + }