lib.types: Add deferredModule

This commit is contained in:
Robert Hensing 2022-03-10 22:45:41 +01:00
parent 9ef09e0680
commit 4746f6d03e
5 changed files with 118 additions and 0 deletions

View file

@ -194,6 +194,9 @@ checkConfigOutput '^"submodule"$' options.submodule.type.description ./declare-s
## Paths should be allowed as values and work as expected
checkConfigOutput '^true$' config.submodule.enable ./declare-submoduleWith-path.nix
## Deferred module
checkConfigOutput '"beta"' config.nodes.foo.settingsDict.c ./deferred-module.nix
# Check the file location information is propagated into submodules
checkConfigOutput the-file.nix config.submodule.internalFiles.0 ./submoduleFiles.nix

View file

@ -0,0 +1,54 @@
{ lib, ... }:
let
inherit (lib) types mkOption setDefaultModuleLocation;
inherit (types) deferredModule lazyAttrsOf submodule str raw;
in
{
imports = [
# generic module, declaring submodules:
# - nodes.<name>
# - default
# where all nodes include the default
({ config, ... }: {
_file = "generic.nix";
options.nodes = mkOption {
type = lazyAttrsOf (submodule { imports = config.default; });
default = {};
};
options.default = mkOption {
type = deferredModule;
default = { };
description = ''
Module that is included in all nodes.
'';
};
})
{
_file = "default-1.nix";
default = { config, ... }: {
options.settingsDict = lib.mkOption { type = lazyAttrsOf str; default = {}; };
};
}
{
_file = "default-a-is-b.nix";
default = { config, ... }: {
settingsDict.a = config.settingsDict.b;
};
}
{
_file = "nodes-foo.nix";
nodes.foo.settingsDict.b = "beta";
}
{
_file = "nodes-foo-c-is-a.nix";
nodes.foo = { config, ... }: {
settingsDict.c = config.settingsDict.a;
};
}
];
}

View file

@ -539,6 +539,14 @@ rec {
modules = toList modules;
};
# A module to be imported in some other part of the configuration.
deferredModule = mkOptionType {
name = "deferredModule";
description = "module";
check = t: isAttrs t || isFunction t;
merge = loc: defs: map (def: lib.setDefaultModuleLocation "${showOption loc} from ${def.file}" def.value) defs;
};
# The type of a type!
optionType = mkOptionType {
name = "optionType";

View file

@ -220,6 +220,25 @@ Value types are types that take a value parameter.
requires using a function:
`the-submodule = { ... }: { options = { ... }; }`.
`types.deferredModule`
: Whereas `submodule` represents an option tree, `deferredModule` represents
a module value, such as a module file or a configuration.
It can be set multiple times.
Module authors can use its value, which is always a list of module values,
in `imports` or in `submoduleWith`'s `modules` parameter.
Note that `imports` must be evaluated before the module fixpoint. Because
of this, deferred modules can only be imported into "other" fixpoints, such
as submodules.
One use case for this type is the type of a "default" module that allow the
user to affect all submodules in an `attrsOf submodule` at once. This is
more convenient and discoverable than expecting the module user to
type-merge with the `attrsOf submodule` option. NixOps uses this type in
`network.defaults`.
## Composed Types {#sec-option-types-composed}
Composed types are types that take a type as parameter. `listOf

View file

@ -427,6 +427,40 @@
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.deferredModule</literal>
</term>
<listitem>
<para>
Whereas <literal>submodule</literal> represents an option
tree, <literal>deferredModule</literal> represents a module
value, such as a module file or a configuration.
</para>
<para>
It can be set multiple times.
</para>
<para>
Module authors can use its value, which is always a list of
module values, in <literal>imports</literal> or in
<literal>submoduleWith</literal>s
<literal>modules</literal> parameter. Note that
<literal>imports</literal> must be evaluated before the
module fixpoint. Because of this, deferred modules can only
be imported into <quote>other</quote> fixpoints, such as
submodules.
</para>
<para>
One use case for this type is the type of a
<quote>default</quote> module that allow the user to affect
all submodules in an <literal>attrsOf submodule</literal> at
once. This is more convenient and discoverable than
expecting the module user to type-merge with the
<literal>attrsOf submodule</literal> option. NixOps uses
this type in <literal>network.defaults</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sec-option-types-composed">