Skip to content
Closed
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
11 changes: 11 additions & 0 deletions lib/options.nix
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ let
;
inherit (lib.attrsets)
optionalAttrs
recursiveUpdateUntil
;
inherit (lib.strings)
concatMapStrings
Expand Down Expand Up @@ -147,6 +148,16 @@ rec {
else
first) (head defs) (tail defs)).value;

/* Merge attribute sets of non-conflicting values. */
mergeAttrSetOptions = loc: defs:
foldl' (val: def: recursiveUpdateUntil (path: lhs: rhs:
if isAttrs lhs && isAttrs rhs then
false
else if lhs != rhs then
throw ''The option `${showOption loc}' has conflicting definition values in '${concatStringsSep "." path}':${showFiles (getFiles defs)}.''
else
true) val def.value) {} defs;

/* Extracts values of all "value" keys of the given list.

Type: getValues :: [ { value :: a } ] -> [a]
Expand Down
4 changes: 4 additions & 0 deletions lib/tests/modules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ checkConfigError 'A definition for option .fun.\[function body\]. is not of type
checkConfigOutput '^"b a"$' config.result ./functionTo/list-order.nix
checkConfigOutput '^"a c"$' config.result ./functionTo/merging-attrs.nix

## types.attrs
checkConfigError 'The option .* has conflicting definition values in .*foo.bar.*' config.value.foo.bar ./define-conflicting-attrs.nix
checkConfigOutput '^42$' config.value.foo.baz ./define-merging-attrs.nix

# moduleType
checkConfigOutput '^"a b"$' config.resultFoo ./declare-variants.nix ./define-variant.nix
checkConfigOutput '^"a y z"$' config.resultFooBar ./declare-variants.nix ./define-variant.nix
Expand Down
5 changes: 5 additions & 0 deletions lib/tests/modules/declare-attrs.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{ lib, ... }: {
options.value = lib.mkOption {
type = lib.types.attrs;
};
}
7 changes: 7 additions & 0 deletions lib/tests/modules/define-conflicting-attrs.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
imports = [
./declare-attrs.nix
{ value = { foo = { bar = false; }; }; }
{ value = { foo = { bar = true; }; }; }
];
}
7 changes: 7 additions & 0 deletions lib/tests/modules/define-merging-attrs.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
imports = [
./declare-attrs.nix
{ value = { foo = { bar = true; }; }; }
{ value = { foo = { bar = true; baz = 42; }; }; }
];
}
3 changes: 2 additions & 1 deletion lib/types.nix
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ let
mergeDefaultOption
mergeEqualOption
mergeOneOption
mergeAttrSetOptions
showFiles
showOption
;
Expand Down Expand Up @@ -340,7 +341,7 @@ rec {
name = "attrs";
description = "attribute set";
check = isAttrs;
merge = loc: foldl' (res: def: res // def.value) {};
merge = mergeAttrSetOptions;
emptyValue = { value = {}; };
};

Expand Down