Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions checkmate/modules/tests/aspect_assignment.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{ lib, targetLib, ... }:
{
# This test verifies that we can define aspects inside
# an scope and then merge them in another scope.
#
# This is important for Den social aspects, since people will
# try to merge aspects from different sources, local, and remote flakes.
flake.tests."test-assign-aspects-on-scopes" =
let
flake-aspects-lib = import targetLib lib;

first = lib.evalModules {
modules = [
# each scope creates a new <name>.aspects tree.
(flake-aspects-lib.new-scope "foo")
(flake-aspects-lib.new-scope "bar")
(flake-aspects-lib.new-scope "baz")
# create a._.b._.c aspect on each namespace
# we will be trying to merge them for this test.
{
foo.aspects.a._.b._.c.nixos.x = [ "foo" ];
}
{
bar.aspects.a._.b._.c.nixos.x = [ "bar" ];
}
{
baz.aspects.a._.b._.c.nixos.x = [ "baz" ];
}
(
{ config, ... }:
{
bar = config.foo; # bar merges all of foo
}
)
(
{ config, ... }:
{
baz = config.bar; # baz merges all of baz
}
)
];
};

second = lib.evalModules {
modules = [
# We evaluate the abc nixos module from baz
first.config.baz.aspects.a._.b._.c.modules.nixos
# create the options to merge all different values
{ options.x = lib.mkOption { type = lib.types.listOf lib.types.str; }; }
];
};

# Sort and dedupe for deterministic comparison - merged modules may
# produce duplicates and order is not guaranteed across merges.
expr = lib.sort (a: b: a < b) (lib.unique second.config.x);
expected = [
"bar"
"baz"
"foo"
];
in
{
inherit expected expr;
};

}
19 changes: 13 additions & 6 deletions nix/types.nix
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,16 @@ let
(x: lib.length x > 0)
];

ignoredType = lib.types.mkOptionType {
name = "ignored type";
description = "ignored values";
merge = _loc: _defs: null;
check = _: true;
};

aspectSubmodule = lib.types.submodule (
{
name,
aspect,
config,
...
}:
Expand Down Expand Up @@ -102,21 +108,22 @@ let
visible = false;
readOnly = true;
description = "resolved modules from this aspect";
type = lib.types.attrsOf lib.types.deferredModule;
default = lib.mapAttrs (class: _: aspect.resolve { inherit class; }) aspect;
type = ignoredType;
apply = _: lib.mapAttrs (class: _: config.resolve { inherit class; }) config;
};
options.resolve = lib.mkOption {
internal = true;
visible = false;
readOnly = true;
description = "function to resolve a module from this aspect";
type = lib.types.functionTo lib.types.deferredModule;
default =
type = ignoredType;
apply =
_:
{
class,
aspect-chain ? [ ],
}:
resolve class aspect-chain (aspect {
resolve class aspect-chain (config {
inherit class aspect-chain;
});
};
Expand Down