lib.types: Add deferredModule

main
Robert Hensing 2 years ago
parent 9ef09e0680
commit 4746f6d03e
  1. 3
      lib/tests/modules.sh
  2. 54
      lib/tests/modules/deferred-module.nix
  3. 8
      lib/types.nix
  4. 19
      nixos/doc/manual/development/option-types.section.md
  5. 34
      nixos/doc/manual/from_md/development/option-types.section.xml

@ -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

@ -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;
};
}
];
}

@ -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";

@ -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

@ -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">

Loading…
Cancel
Save