lib/types: Introduce types.anything
This new type has unsurprising merge behavior: Only attribute sets are merged together (recursively), and only if they don't conflict. This is in contrast to the existing types: - types.attrs is problematic because later definitions completely override attributes of earlier definitions, and it doesn't support mkIf and co. - types.unspecified is very similar to types.attrs, but it has smart merging behavior that often doesn't make sense, and it doesn't support all types
This commit is contained in:
parent
6e7bc2c6c9
commit
67551f46fb
|
@ -101,6 +101,42 @@ rec {
|
||||||
# When adding new types don't forget to document them in
|
# When adding new types don't forget to document them in
|
||||||
# nixos/doc/manual/development/option-types.xml!
|
# nixos/doc/manual/development/option-types.xml!
|
||||||
types = rec {
|
types = rec {
|
||||||
|
|
||||||
|
anything = mkOptionType {
|
||||||
|
name = "anything";
|
||||||
|
description = "anything";
|
||||||
|
check = value: true;
|
||||||
|
merge = loc: defs:
|
||||||
|
let
|
||||||
|
getType = value:
|
||||||
|
if isAttrs value && isCoercibleToString value
|
||||||
|
then "stringCoercibleSet"
|
||||||
|
else builtins.typeOf value;
|
||||||
|
|
||||||
|
# Returns the common type of all definitions, throws an error if they
|
||||||
|
# don't have the same type
|
||||||
|
commonType = foldl' (type: def:
|
||||||
|
if getType def.value == type
|
||||||
|
then type
|
||||||
|
else throw "The option `${showOption loc}' has conflicting option types in ${showFiles (getFiles defs)}"
|
||||||
|
) (getType (head defs).value) defs;
|
||||||
|
|
||||||
|
mergeFunction = {
|
||||||
|
# Recursively merge attribute sets
|
||||||
|
set = (attrsOf anything).merge;
|
||||||
|
# Safe and deterministic behavior for lists is to only accept one definition
|
||||||
|
# listOf only used to apply mkIf and co.
|
||||||
|
list =
|
||||||
|
if length defs > 1
|
||||||
|
then throw "The option `${showOption loc}' has conflicting definitions, in ${showFiles (getFiles defs)}."
|
||||||
|
else (listOf anything).merge;
|
||||||
|
# This is the type of packages, only accept a single definition
|
||||||
|
stringCoercibleSet = mergeOneOption;
|
||||||
|
# Otherwise fall back to only allowing all equal definitions
|
||||||
|
}.${commonType} or mergeEqualOption;
|
||||||
|
in mergeFunction loc defs;
|
||||||
|
};
|
||||||
|
|
||||||
unspecified = mkOptionType {
|
unspecified = mkOptionType {
|
||||||
name = "unspecified";
|
name = "unspecified";
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue