lib.types: Introduce types.optionType
This type correctly merges multiple option types together while also annotating them with file information. In a future commit this will be used for `_module.freeformType`
This commit is contained in:
parent
891e65b0fa
commit
5cbeddfde4
6 changed files with 113 additions and 1 deletions
|
@ -299,6 +299,13 @@ checkConfigOutput "10" config.processedToplevel ./raw.nix
|
|||
checkConfigError "The option .multiple. is defined multiple times" config.multiple ./raw.nix
|
||||
checkConfigOutput "bar" config.priorities ./raw.nix
|
||||
|
||||
# Test that types.optionType merges types correctly
|
||||
checkConfigOutput '^10$' config.theOption.int ./optionTypeMerging.nix
|
||||
checkConfigOutput '^"hello"$' config.theOption.str ./optionTypeMerging.nix
|
||||
|
||||
# Test that types.optionType correctly annotates option locations
|
||||
checkConfigError 'The option .theOption.nested. in .other.nix. is already declared in .optionTypeFile.nix.' config.theOption.nested ./optionTypeFile.nix
|
||||
|
||||
cat <<EOF
|
||||
====== module tests ======
|
||||
$pass Pass
|
||||
|
|
28
lib/tests/modules/optionTypeFile.nix
Normal file
28
lib/tests/modules/optionTypeFile.nix
Normal file
|
@ -0,0 +1,28 @@
|
|||
{ config, lib, ... }: {
|
||||
|
||||
_file = "optionTypeFile.nix";
|
||||
|
||||
options.theType = lib.mkOption {
|
||||
type = lib.types.optionType;
|
||||
};
|
||||
|
||||
options.theOption = lib.mkOption {
|
||||
type = config.theType;
|
||||
default = {};
|
||||
};
|
||||
|
||||
config.theType = lib.mkMerge [
|
||||
(lib.types.submodule {
|
||||
options.nested = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
};
|
||||
})
|
||||
(lib.types.submodule {
|
||||
_file = "other.nix";
|
||||
options.nested = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
}
|
27
lib/tests/modules/optionTypeMerging.nix
Normal file
27
lib/tests/modules/optionTypeMerging.nix
Normal file
|
@ -0,0 +1,27 @@
|
|||
{ config, lib, ... }: {
|
||||
|
||||
options.theType = lib.mkOption {
|
||||
type = lib.types.optionType;
|
||||
};
|
||||
|
||||
options.theOption = lib.mkOption {
|
||||
type = config.theType;
|
||||
};
|
||||
|
||||
config.theType = lib.mkMerge [
|
||||
(lib.types.submodule {
|
||||
options.int = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 10;
|
||||
};
|
||||
})
|
||||
(lib.types.submodule {
|
||||
options.str = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
config.theOption.str = "hello";
|
||||
|
||||
}
|
|
@ -61,7 +61,11 @@ let
|
|||
boolToString
|
||||
;
|
||||
|
||||
inherit (lib.modules) mergeDefinitions;
|
||||
inherit (lib.modules)
|
||||
mergeDefinitions
|
||||
fixupOptionType
|
||||
mergeOptionDecls
|
||||
;
|
||||
outer_types =
|
||||
rec {
|
||||
isType = type: x: (x._type or "") == type;
|
||||
|
@ -525,6 +529,31 @@ rec {
|
|||
modules = toList modules;
|
||||
};
|
||||
|
||||
# The type of a type!
|
||||
optionType = mkOptionType {
|
||||
name = "optionType";
|
||||
description = "optionType";
|
||||
check = value: value._type or null == "option-type";
|
||||
merge = loc: defs:
|
||||
let
|
||||
# Prepares the type definitions for mergeOptionDecls, which
|
||||
# annotates submodules types with file locations
|
||||
optionModules = map ({ value, file }:
|
||||
{
|
||||
_file = file;
|
||||
# There's no way to merge types directly from the module system,
|
||||
# but we can cheat a bit by just declaring an option with the type
|
||||
options = lib.mkOption {
|
||||
type = value;
|
||||
};
|
||||
}
|
||||
) defs;
|
||||
# Merges all the types into a single one, including submodule merging.
|
||||
# This also propagates file information to all submodules
|
||||
mergedOption = fixupOptionType loc (mergeOptionDecls loc optionModules);
|
||||
in mergedOption.type;
|
||||
};
|
||||
|
||||
submoduleWith =
|
||||
{ modules
|
||||
, specialArgs ? {}
|
||||
|
|
|
@ -74,6 +74,13 @@ merging is handled.
|
|||
should only be used when checking, merging and nested evaluation are not
|
||||
desirable.
|
||||
|
||||
`types.optionType`
|
||||
|
||||
: The type of an option's type. Its merging operation ensures that nested
|
||||
options have the correct file location annotated, and that if possible,
|
||||
multiple option definitions are correctly merged together. The main use
|
||||
case is as the type of the `_module.freeformType` option.
|
||||
|
||||
`types.attrs`
|
||||
|
||||
: A free-form attribute set.
|
||||
|
|
|
@ -111,6 +111,20 @@
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.optionType</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The type of an option’s type. Its merging operation ensures
|
||||
that nested options have the correct file location
|
||||
annotated, and that if possible, multiple option definitions
|
||||
are correctly merged together. The main use case is as the
|
||||
type of the <literal>_module.freeformType</literal> option.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.attrs</literal>
|
||||
|
|
Loading…
Reference in a new issue