forked from mirrors/nixpkgs
Merge pull request #163617 from hercules-ci/lib-types-deferredModule
lib.types: Add deferredModule
This commit is contained in:
commit
8f8db59c0e
|
@ -462,6 +462,7 @@ rec {
|
|||
config = addFreeformType (addMeta (m.config or {}));
|
||||
}
|
||||
else
|
||||
lib.throwIfNot (isAttrs m) "module ${file} (${key}) does not look like a module."
|
||||
{ _file = toString m._file or file;
|
||||
key = toString m.key or key;
|
||||
disabledModules = m.disabledModules or [];
|
||||
|
|
|
@ -194,6 +194,13 @@ 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
|
||||
|
||||
## deferredModule
|
||||
# default module is merged into nodes.foo
|
||||
checkConfigOutput '"beta"' config.nodes.foo.settingsDict.c ./deferred-module.nix
|
||||
# errors from the default module are reported with accurate location
|
||||
checkConfigError 'In `the-file-that-contains-the-bad-config.nix, via option default'\'': "bogus"' config.nodes.foo.bottom ./deferred-module.nix
|
||||
checkConfigError '.*lib/tests/modules/deferred-module-error.nix, via option deferred [(]:anon-1:anon-1:anon-1[)] does not look like a module.' config.result ./deferred-module-error.nix
|
||||
|
||||
# Check the file location information is propagated into submodules
|
||||
checkConfigOutput the-file.nix config.submodule.internalFiles.0 ./submoduleFiles.nix
|
||||
|
||||
|
|
20
lib/tests/modules/deferred-module-error.nix
Normal file
20
lib/tests/modules/deferred-module-error.nix
Normal file
|
@ -0,0 +1,20 @@
|
|||
{ config, lib, ... }:
|
||||
let
|
||||
inherit (lib) types mkOption setDefaultModuleLocation evalModules;
|
||||
inherit (types) deferredModule lazyAttrsOf submodule str raw enum;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
deferred = mkOption {
|
||||
type = deferredModule;
|
||||
};
|
||||
result = mkOption {
|
||||
default = (evalModules { modules = [ config.deferred ]; }).config.result;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
deferred = { ... }:
|
||||
# this should be an attrset, so this fails
|
||||
true;
|
||||
};
|
||||
}
|
58
lib/tests/modules/deferred-module.nix
Normal file
58
lib/tests/modules/deferred-module.nix
Normal file
|
@ -0,0 +1,58 @@
|
|||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib) types mkOption setDefaultModuleLocation;
|
||||
inherit (types) deferredModule lazyAttrsOf submodule str raw enum;
|
||||
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 = {}; };
|
||||
options.bottom = lib.mkOption { type = enum []; };
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
_file = "default-a-is-b.nix";
|
||||
default = ./define-settingsDict-a-is-b.nix;
|
||||
}
|
||||
|
||||
{
|
||||
_file = "nodes-foo.nix";
|
||||
nodes.foo.settingsDict.b = "beta";
|
||||
}
|
||||
|
||||
{
|
||||
_file = "the-file-that-contains-the-bad-config.nix";
|
||||
default.bottom = "bogus";
|
||||
}
|
||||
|
||||
{
|
||||
_file = "nodes-foo-c-is-a.nix";
|
||||
nodes.foo = { config, ... }: {
|
||||
settingsDict.c = config.settingsDict.a;
|
||||
};
|
||||
}
|
||||
|
||||
];
|
||||
}
|
3
lib/tests/modules/define-settingsDict-a-is-b.nix
Normal file
3
lib/tests/modules/define-settingsDict-a-is-b.nix
Normal file
|
@ -0,0 +1,3 @@
|
|||
{ config, ... }: {
|
||||
settingsDict.a = config.settingsDict.b;
|
||||
}
|
|
@ -539,6 +539,36 @@ rec {
|
|||
modules = toList modules;
|
||||
};
|
||||
|
||||
# A module to be imported in some other part of the configuration.
|
||||
deferredModule = deferredModuleWith { };
|
||||
|
||||
# A module to be imported in some other part of the configuration.
|
||||
# `staticModules`' options will be added to the documentation, unlike
|
||||
# options declared via `config`.
|
||||
deferredModuleWith = attrs@{ staticModules ? [] }: mkOptionType {
|
||||
name = "deferredModule";
|
||||
description = "module";
|
||||
check = x: isAttrs x || isFunction x || path.check x;
|
||||
merge = loc: defs: {
|
||||
imports = staticModules ++ map (def: lib.setDefaultModuleLocation "${def.file}, via option ${showOption loc}" def.value) defs;
|
||||
};
|
||||
inherit (submoduleWith { modules = staticModules; })
|
||||
getSubOptions
|
||||
getSubModules;
|
||||
substSubModules = m: deferredModuleWith (attrs // {
|
||||
staticModules = m;
|
||||
});
|
||||
functor = defaultFunctor "deferredModuleWith" // {
|
||||
type = types.deferredModuleWith;
|
||||
payload = {
|
||||
inherit staticModules;
|
||||
};
|
||||
binOp = lhs: rhs: {
|
||||
staticModules = lhs.staticModules ++ rhs.staticModules;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# 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 in `imports`, in `submoduleWith`'s `modules`
|
||||
or in `evalModules`' `modules` parameter, among other places.
|
||||
|
||||
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.
|
||||
|
||||
## Composed Types {#sec-option-types-composed}
|
||||
|
||||
Composed types are types that take a type as parameter. `listOf
|
||||
|
|
|
@ -427,6 +427,43 @@
|
|||
</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 in
|
||||
<literal>imports</literal>, in
|
||||
<literal>submoduleWith</literal><quote>s
|
||||
<literal>modules</literal> or in
|
||||
<literal>evalModules</literal></quote>
|
||||
<literal>modules</literal> parameter, among other places.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
<section xml:id="sec-option-types-composed">
|
||||
|
|
Loading…
Reference in a new issue