lib/modules: Rename _module.assertions to _module.checks

This commit is contained in:
Silvan Mosberger
2020-11-30 20:04:03 +01:00
parent 3e39d6efdf
commit c9cc8969b4
16 changed files with 108 additions and 76 deletions

View File

@@ -103,7 +103,13 @@ rec {
type = types.bool;
internal = prefix != [];
default = check;
description = "Whether to check whether all option definitions have matching declarations.";
description = ''
Whether to check whether all option definitions have matching
declarations.
Note that this has nothing to do with the similarly named
<option>_module.checks</option> option
'';
};
_module.freeformType = mkOption {
@@ -123,11 +129,11 @@ rec {
'';
};
_module.assertions = mkOption {
_module.checks = mkOption {
description = ''
Assertions and warnings to trigger during module evaluation. The
Evaluation checks to trigger during module evaluation. The
attribute name will be displayed when it is triggered, allowing
users to disable/change these assertions again if necessary. See
users to disable/change these checks if necessary. See
the section on Warnings and Assertions in the manual for more
information.
'';
@@ -151,7 +157,7 @@ rec {
# TODO: Rename to assertion? Or allow also setting assertion?
options.enable = mkOption {
description = ''
Whether to enable this assertion.
Whether to enable this check.
<note><para>
This is the inverse of asserting a condition: If a certain
condition should be <literal>true</literal>, then this
@@ -164,7 +170,7 @@ rec {
options.type = mkOption {
description = ''
The type of the assertion. The default
The type of the check. The default
<literal>"error"</literal> type will cause evaluation to fail,
while the <literal>"warning"</literal> type will only show a
warning.
@@ -176,7 +182,7 @@ rec {
options.message = mkOption {
description = ''
The assertion message to display if this assertion triggers.
The message to display if this check triggers.
To display option names in the message, add
<literal>options</literal> to the module function arguments
and use <literal>''${options.path.to.option}</literal>.
@@ -190,24 +196,24 @@ rec {
options.triggerPath = mkOption {
description = ''
The <literal>config</literal> path which when evaluated should
trigger this assertion. By default this is
trigger this check. By default this is
<literal>[]</literal>, meaning evaluating
<literal>config</literal> at all will trigger the assertion.
<literal>config</literal> at all will trigger the check.
On NixOS this default is changed to
<literal>[ "system" "build" "toplevel"</literal> such that
only a system evaluation triggers the assertions.
only a system evaluation triggers the checks.
<warning><para>
Evaluating <literal>config</literal> from within the current
module evaluation doesn't cause a trigger. Only accessing it
from outside will do that. This means it's easy to miss
assertions if this option doesn't have an externally-accessed
failing checks if this option doesn't have an externally-accessed
value.
</para></warning>
'';
# Mark as internal as it's easy to misuse it
internal = true;
type = types.uniq (types.listOf types.str);
# Default to [], causing assertions to be triggered when
# Default to [], causing checks to be triggered when
# anything is evaluated. This is a safe and convenient default.
default = [];
example = [ "system" "build" "vm" ];
@@ -253,13 +259,13 @@ rec {
else recursiveUpdate freeformConfig declaredConfig;
/*
Inject a list of assertions into a config value, corresponding to their
Inject a list of checks into a config value, corresponding to their
triggerPath (meaning when that path is accessed from the result of this
function, the assertion triggers).
function, the check triggers).
*/
injectAssertions = assertions: config: let
# Partition into assertions that are triggered on this level and ones that aren't
parted = lib.partition (a: length a.triggerPath == 0) assertions;
injectChecks = checks: config: let
# Partition into checks that are triggered on this level and ones that aren't
parted = lib.partition (a: length a.triggerPath == 0) checks;
# From the ones that are triggered, filter out ones that aren't enabled
# and group into warnings/errors
@@ -270,45 +276,45 @@ rec {
errorTrigger = value:
if byType.error or [] == [] then value else
throw ''
Failed assertions:
Failed checks:
${lib.concatMapStringsSep "\n" (a: "- ${a.show}") byType.error}
'';
# Trigger for both warnings and errors
trigger = value: warningTrigger (errorTrigger value);
# From the non-triggered assertions, split off the first element of triggerPath
# to get a mapping from nested attributes to a list of assertions for that attribute
# From the non-triggered checks, split off the first element of triggerPath
# to get a mapping from nested attributes to a list of checks for that attribute
nested = lib.zipAttrs (map (a: {
${head a.triggerPath} = a // {
triggerPath = lib.tail a.triggerPath;
};
}) parted.wrong);
# Recursively inject assertions if config is an attribute set and we
# have assertions under its attributes
# Recursively inject checks if config is an attribute set and we
# have checks under its attributes
result =
if isAttrs config
then
mapAttrs (name: value:
if nested ? ${name}
then injectAssertions nested.${name} value
then injectChecks nested.${name} value
else value
) config
else config;
in trigger result;
# List of assertions for this module evaluation, where each assertion also
# List of checks for this module evaluation, where each check also
# has a `show` attribute for how to show it if triggered
assertions = mapAttrsToList (name: value:
checks = mapAttrsToList (name: value:
let id =
if lib.hasPrefix "_" name then ""
else "[${showOption prefix}${optionalString (prefix != []) "/"}${name}] ";
in value // {
show = "${id}${value.message}";
}
) config._module.assertions;
) config._module.checks;
finalConfig = injectAssertions assertions (removeAttrs config [ "_module" ]);
finalConfig = injectChecks checks (removeAttrs config [ "_module" ]);
checkUnmatched =
if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
@@ -931,7 +937,7 @@ rec {
visible = false;
apply = x: throw "The option `${showOption optionName}' can no longer be used since it's been removed. ${replacementInstructions}";
});
config._module.assertions =
config._module.checks =
let opt = getAttrFromPath optionName options; in {
${showOption optionName} = {
enable = mkDefault opt.isDefined;
@@ -1001,7 +1007,7 @@ rec {
})) from);
config = {
_module.assertions =
_module.checks =
let warningMessages = map (f:
let val = getAttrFromPath f config;
opt = getAttrFromPath f options;
@@ -1072,7 +1078,7 @@ rec {
});
config = mkMerge [
{
_module.assertions.${showOption from} = {
_module.checks.${showOption from} = {
enable = mkDefault (warn && fromOpt.isDefined);
type = "warning";
message = "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'.";

View File

@@ -277,9 +277,9 @@ checkConfigOutput baz config.value.nested.bar.baz ./types-anything/mk-mods.nix
## Module assertions
# Check that assertions are triggered by default for just evaluating config
checkConfigError 'Failed assertions:\n- \[test\] Assertion failed' config ./assertions/simple.nix
checkConfigError 'Failed checks:\n- \[test\] Assertion failed' config ./assertions/simple.nix
# Check that assertions are only triggered if they have a triggerPath that's evaluated
checkConfigError 'Failed assertions:\n- \[test\] Assertion failed' config.foo ./assertions/trigger-lazy.nix
checkConfigError 'Failed checks:\n- \[test\] Assertion failed' config.foo ./assertions/trigger-lazy.nix
checkConfigOutput true config.bar ./assertions/trigger-lazy.nix
# The assertions enable condition should only be evaluated if the trigger is evaluated
@@ -294,23 +294,23 @@ checkConfigCodeOutErr 0 '{ }' 'warning: \[test\] Warning message' config ./asser
# A triggerPath can be set to a submodule path
checkConfigOutput '{ baz = <CODE>; }' config.foo.bar ./assertions/trigger-submodule.nix
checkConfigError 'Failed assertions:\n- \[test\] Assertion failed' config.foo.bar.baz ./assertions/trigger-submodule.nix
checkConfigError 'Failed checks:\n- \[test\] Assertion failed' config.foo.bar.baz ./assertions/trigger-submodule.nix
# Check that multiple assertions and warnings can be triggered at once
checkConfigError 'Failed assertions:\n- \[test1\] Assertion 1 failed\n- \[test2\] Assertion 2 failed' config ./assertions/multi.nix
checkConfigError 'Failed checks:\n- \[test1\] Assertion 1 failed\n- \[test2\] Assertion 2 failed' config ./assertions/multi.nix
checkConfigError 'trace: warning: \[test3\] Warning 3 failed\ntrace: warning: \[test4\] Warning 4 failed' config ./assertions/multi.nix
# Submodules should be able to trigger assertions and display the submodule prefix in their error
checkConfigError 'Failed assertions:\n- \[foo/test\] Assertion failed' config.foo ./assertions/submodule.nix
checkConfigError 'Failed assertions:\n- \[foo.bar/test\] Assertion failed' config.foo.bar ./assertions/submodule-attrsOf.nix
checkConfigError 'Failed assertions:\n- \[foo.bar.baz/test\] Assertion failed' config.foo.bar.baz ./assertions/submodule-attrsOf-attrsOf.nix
checkConfigError 'Failed checks:\n- \[foo/test\] Assertion failed' config.foo ./assertions/submodule.nix
checkConfigError 'Failed checks:\n- \[foo.bar/test\] Assertion failed' config.foo.bar ./assertions/submodule-attrsOf.nix
checkConfigError 'Failed checks:\n- \[foo.bar.baz/test\] Assertion failed' config.foo.bar.baz ./assertions/submodule-attrsOf-attrsOf.nix
# Assertions aren't triggered when the trigger path is only evaluated from within the same module evaluation
# This behavior is necessary to allow assertions to depend on config values. This could potentially be changed in the future if all of NixOS' assertions are rewritten to not depend on any config values
checkConfigOutput true config.bar ./assertions/non-cascading.nix
# Assertions with an attribute starting with _ shouldn't have their name displayed
checkConfigError 'Failed assertions:\n- Assertion failed' config ./assertions/underscore-attributes.nix
checkConfigError 'Failed checks:\n- Assertion failed' config ./assertions/underscore-attributes.nix
cat <<EOF
====== module tests ======

View File

@@ -1,6 +1,6 @@
{
_module.assertions.test = {
_module.checks.test = {
enable = false;
message = "Assertion failed";
};

View File

@@ -8,7 +8,7 @@
default = true;
};
config._module.assertions.test = {
config._module.checks.test = {
enable = throw "enable evaluated";
message = "Assertion failed";
triggerPath = [ "foo" ];

View File

@@ -1,6 +1,6 @@
{
_module.assertions = {
_module.checks = {
test1 = {
enable = true;
message = "Assertion 1 failed";

View File

@@ -8,7 +8,7 @@
default = config.foo;
};
config._module.assertions.foo = {
config._module.checks.foo = {
enable = true;
message = "Foo assertion";
triggerPath = [ "foo" ];

View File

@@ -1,5 +1,5 @@
{
_module.assertions.test = {
_module.checks.test = {
enable = true;
message = "Assertion failed";
};

View File

@@ -3,7 +3,7 @@
options.foo = lib.mkOption {
default = { bar.baz = {}; };
type = lib.types.attrsOf (lib.types.attrsOf (lib.types.submodule {
_module.assertions.test = {
_module.checks.test = {
enable = true;
message = "Assertion failed";
};

View File

@@ -3,7 +3,7 @@
options.foo = lib.mkOption {
default = { bar = {}; };
type = lib.types.attrsOf (lib.types.submodule {
_module.assertions.test = {
_module.checks.test = {
enable = true;
message = "Assertion failed";
};

View File

@@ -3,7 +3,7 @@
options.foo = lib.mkOption {
default = {};
type = lib.types.submodule {
_module.assertions.test = {
_module.checks.test = {
enable = true;
message = "Assertion failed";
};

View File

@@ -7,7 +7,7 @@
default = true;
};
config._module.assertions.test = {
config._module.checks.test = {
enable = true;
message = "Assertion failed";
triggerPath = [ "foo" ];

View File

@@ -9,7 +9,7 @@
});
};
config._module.assertions.test = {
config._module.checks.test = {
enable = true;
message = "Assertion failed";
triggerPath = [ "foo" "bar" "baz" ];

View File

@@ -1,6 +1,6 @@
{
_module.assertions._test = {
_module.checks._test = {
enable = true;
message = "Assertion failed";
};

View File

@@ -1,6 +1,6 @@
{
_module.assertions.test = {
_module.checks.test = {
enable = true;
type = "warning";
message = "Warning message";