Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow submodules to use custom lib/evalModules #98952

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/tests/modules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ checkConfigOutput "true" config.submodule.outer ./declare-submoduleWith-modules.
## Paths should be allowed as values and work as expected
checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix

## evalModules should be settable
checkConfigOutput 10 config.submodule.value ./submoduleWithLib.nix

# Check the file location information is propagated into submodules
checkConfigOutput the-file.nix config.submodule.internalFiles.0 ./submoduleFiles.nix


# Check that disabledModules works recursively and correctly
checkConfigOutput "true" config.enable ./disable-recursive/main.nix
checkConfigOutput "true" config.enable ./disable-recursive/{main.nix,disable-foo.nix}
Expand Down
21 changes: 21 additions & 0 deletions lib/tests/modules/submoduleFiles.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{ lib, ... }: {
options.submodule = lib.mkOption {
default = {};
type = lib.types.submoduleWith {
modules = [ ({ options, ... }: {
options.value = lib.mkOption {};

options.internalFiles = lib.mkOption {
default = options.value.files;
};
})];
};
};

imports = [
{
_file = "the-file.nix";
submodule.value = 10;
}
];
}
13 changes: 13 additions & 0 deletions lib/tests/modules/submoduleWithLib.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{ lib, ... }: {
options.submodule = lib.mkOption {
default = {};
type = lib.types.submoduleWith {
evalModules = ((import ../..).extend (self: super: { value = 10; })).evalModules;
modules = [ ({ lib, ... }: {
options.value = lib.mkOption {
default = lib.value;
};
})];
};
};
}
24 changes: 14 additions & 10 deletions lib/types.nix
Original file line number Diff line number Diff line change
Expand Up @@ -408,27 +408,23 @@ rec {

submoduleWith =
{ modules
, evalModules ? lib.modules.evalModules
, specialArgs ? {}
, shorthandOnlyDefinesConfig ? false
}@attrs:
let
inherit (lib.modules) evalModules;

coerce = unify: value: if isFunction value
then setFunctionArgs (args: unify (value args)) (functionArgs value)
else unify (if shorthandOnlyDefinesConfig then { config = value; } else value);

allModules = defs: modules ++ imap1 (n: { value, file }:
if isAttrs value || isFunction value then
# Annotate the value with the location of its definition for better error messages
coerce (lib.modules.unifyModuleSyntax file "${toString file}-${toString n}") value
else value
if isAttrs value && shorthandOnlyDefinesConfig
then { _file = file; config = value; }
else { _file = file; imports = [ value ]; }
) defs;

freeformType = (evalModules {
inherit modules specialArgs;
args.name = "‹name›";
})._module.freeformType;
})._module.freeformType or null;
# `or null` in case the given evalModules doesn't have that attribute yet

in
mkOptionType rec {
Expand Down Expand Up @@ -477,6 +473,10 @@ rec {
modules = modules;
specialArgs = specialArgs;
shorthandOnlyDefinesConfig = shorthandOnlyDefinesConfig;
} // optionalAttrs (attrs ? evalModules) {
# We need to be able to detect whether evalModules was set or not in
# the binOp function, to throw an error if it was set multiple times
inherit (attrs) evalModules;
};
binOp = lhs: rhs: {
modules = lhs.modules ++ rhs.modules;
Expand All @@ -489,6 +489,10 @@ rec {
if lhs.shorthandOnlyDefinesConfig == rhs.shorthandOnlyDefinesConfig
then lhs.shorthandOnlyDefinesConfig
else throw "A submoduleWith option is declared multiple times with conflicting shorthandOnlyDefinesConfig values";
} // optionalAttrs (lhs ? evalModules || rhs ? evalModules) {
evalModules = if lhs ? evalModules && rhs ? evalModules
then throw "A submoduleWith option is declared multiple times with conflicting evalModules values"
else lhs.evalModules or rhs.evalModules;
};
};
};
Expand Down
9 changes: 9 additions & 0 deletions nixos/doc/manual/development/option-types.xml
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@
<term>
<varname>types.submoduleWith</varname> {
<replaceable>modules</replaceable>,
<replaceable>evalModules</replaceable> ? lib.evalModules,
<replaceable>specialArgs</replaceable> ? {},
<replaceable>shorthandOnlyDefinesConfig</replaceable> ? false }
</term>
Expand All @@ -335,6 +336,14 @@
Only options defined with this argument are included in rendered documentation.
</para></note>
</para></listitem>
<listitem><para>
<replaceable>evalModules</replaceable>
The function used to evaluate the given modules. This can be set to a
<literal>lib.evalModules</literal> from another nixpkgs version if
the modules require that version for evaluation. This also causes
the <literal>lib</literal> module argument for the submodules to
point to the <literal>lib</literal> from <literal>evalModules</literal>.
</para></listitem>
<listitem><para>
<replaceable>specialArgs</replaceable>
An attribute set of extra arguments to be passed to the module functions.
Expand Down