diff options
-rw-r--r-- | lib/modules.nix | 164 | ||||
-rw-r--r-- | lib/options.nix | 2 | ||||
-rw-r--r-- | lib/tests/misc.nix | 2 | ||||
-rwxr-xr-x | lib/tests/modules.sh | 78 | ||||
-rw-r--r-- | lib/tests/modules/assertions/condition-true.nix | 8 | ||||
-rw-r--r-- | lib/tests/modules/assertions/enable-false.nix | 9 | ||||
-rw-r--r-- | lib/tests/modules/assertions/multi.nix | 23 | ||||
-rw-r--r-- | lib/tests/modules/assertions/simple.nix | 6 | ||||
-rw-r--r-- | lib/tests/modules/assertions/submodule-attrsOf-attrsOf.nix | 13 | ||||
-rw-r--r-- | lib/tests/modules/assertions/submodule-attrsOf.nix | 13 | ||||
-rw-r--r-- | lib/tests/modules/assertions/submodule.nix | 13 | ||||
-rw-r--r-- | lib/tests/modules/assertions/underscore-attributes.nix | 8 | ||||
-rw-r--r-- | lib/tests/modules/assertions/warning.nix | 9 | ||||
-rw-r--r-- | nixos/doc/manual/development/assertions.xml | 159 | ||||
-rw-r--r-- | nixos/modules/misc/assertions.nix | 15 | ||||
-rw-r--r-- | nixos/modules/system/activation/top-level.nix | 10 |
16 files changed, 93 insertions, 439 deletions
diff --git a/lib/modules.nix b/lib/modules.nix index 5548c5f7049c3..3f2bfd478b0df 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -46,7 +46,6 @@ let showFiles showOption unknownModule - literalExample ; in @@ -73,20 +72,14 @@ rec { check ? true }: let - # An internal module that's always added, defining special options which - # change the behavior of the module evaluation itself. This is under a - # `_`-prefixed namespace in order to prevent name clashes with - # user-defined options + # This internal module declare internal options under the `_module' + # attribute. These options are fragile, as they are used by the + # module system to change the interpretation of modules. internalModule = rec { - # FIXME: Using ./modules.nix directly breaks the doc for some reason - _file = "lib/modules.nix"; + _file = ./modules.nix; key = _file; - # Most of these options are set to be internal only for prefix != [], - # aka it's a submodule evaluation. This way their docs are displayed - # only once as a top-level NixOS option, but will be hidden for all - # submodules, even though they are available there too options = { _module.args = mkOption { # Because things like `mkIf` are entirely useless for @@ -96,7 +89,7 @@ rec { # a `_module.args.pkgs = import (fetchTarball { ... }) {}` won't # start a download when `pkgs` wasn't evaluated. type = types.lazyAttrsOf types.unspecified; - internal = prefix != []; + internal = true; description = "Arguments passed to each module."; }; @@ -104,19 +97,13 @@ rec { type = types.bool; internal = true; default = check; - 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 - ''; + description = "Whether to check whether all option definitions have matching declarations."; }; _module.freeformType = mkOption { # Disallow merging for now, but could be implemented nicely with a `types.optionType` type = types.nullOr (types.uniq types.attrs); - internal = prefix != []; + internal = true; default = null; description = '' If set, merge all definitions that don't have an associated option @@ -129,75 +116,6 @@ rec { turned off. ''; }; - - _module.checks = mkOption { - description = '' - Evaluation checks to trigger during module evaluation. The - attribute name will be displayed when it is triggered, allowing - users to disable/change these checks if necessary. See - the section on Warnings and Assertions in the manual for more - information. - ''; - example = literalExample '' - { - gpgSshAgent = { - enable = config.programs.gnupg.agent.enableSSHSupport && config.programs.ssh.startAgent; - message = "You can't use ssh-agent and GnuPG agent with SSH support enabled at the same time!"; - }; - - grafanaPassword = { - enable = config.services.grafana.database.password != ""; - message = "Grafana passwords will be stored as plaintext in the Nix store!"; - type = "warning"; - }; - } - ''; - default = {}; - internal = prefix != []; - type = types.attrsOf (types.submodule { - options.enable = mkOption { - description = '' - Whether to enable this check. Set this to false to not trigger - any errors or warning messages. This is useful for ignoring a - check in case it doesn't make sense in certain scenarios. - ''; - default = true; - type = types.bool; - }; - - options.check = mkOption { - description = '' - The condition that must succeed in order for this check to be - successful and not trigger a warning or error. - ''; - readOnly = true; - type = types.bool; - }; - - options.type = mkOption { - description = '' - 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. - ''; - type = types.enum [ "error" "warning" ]; - default = "error"; - example = "warning"; - }; - - options.message = mkOption { - description = '' - 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>. - ''; - type = types.str; - example = "Enabling both \${options.services.foo.enable} and \${options.services.bar.enable} is not possible."; - }; - }); - }; }; config = { @@ -236,35 +154,6 @@ rec { # paths, meaning recursiveUpdate will never override any value else recursiveUpdate freeformConfig declaredConfig; - # Triggers all checks defined by _module.checks before returning its argument - triggerChecks = let - - handleCheck = errors: name: - let - value = config._module.checks.${name}; - show = - # Assertions with a _ prefix aren't meant to be configurable - if lib.hasPrefix "_" name then value.message - else "[${showOption prefix}${optionalString (prefix != []) "/"}${name}] ${value.message}"; - in - if value.enable -> value.check then errors - else if value.type == "warning" then lib.warn show errors - else if value.type == "error" then errors ++ [ show ] - else abort "Unknown check type ${value.type}"; - - errors = lib.foldl' handleCheck [] (lib.attrNames config._module.checks); - - errorMessage = '' - Failed checks: - ${lib.concatMapStringsSep "\n" (a: "- ${a}") errors} - ''; - - trigger = if errors == [] then null else throw errorMessage; - - in builtins.seq trigger; - - finalConfig = triggerChecks (removeAttrs config [ "_module" ]); - checkUnmatched = if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then let @@ -284,7 +173,7 @@ rec { result = builtins.seq checkUnmatched { inherit options; - config = finalConfig; + config = removeAttrs config [ "_module" ]; inherit (config) _module; }; in result; @@ -625,8 +514,6 @@ rec { definitions = map (def: def.value) res.defsFinal; files = map (def: def.file) res.defsFinal; inherit (res) isDefined; - # This allows options to be correctly displayed using `${options.path.to.it}` - __toString = _: showOption loc; }; # Merge definitions of a value of a given type. @@ -886,15 +773,14 @@ rec { visible = false; apply = x: throw "The option `${showOption optionName}' can no longer be used since it's been removed. ${replacementInstructions}"; }); - config._module.checks = - let opt = getAttrFromPath optionName options; in { - ${"removed-" + showOption optionName} = lib.mkIf opt.isDefined { + config.assertions = + let opt = getAttrFromPath optionName options; in [{ + assertion = !opt.isDefined; message = '' The option definition `${showOption optionName}' in ${showFiles opt.files} no longer has any effect; please remove it. ${replacementInstructions} ''; - }; - }; + }]; }; /* Return a module that causes a warning to be shown if the @@ -955,18 +841,14 @@ rec { })) from); config = { - _module.checks = - let warningMessages = map (f: - let val = getAttrFromPath f config; - opt = getAttrFromPath f options; - in { - ${"merged" + showOption f} = lib.mkIf (val != "_mkMergedOptionModule") { - type = "warning"; - message = "The option `${showOption f}' defined in ${showFiles opt.files} has been changed to `${showOption to}' that has a different type. Please read `${showOption to}' documentation and update your configuration accordingly."; - }; - } - ) from; - in mkMerge warningMessages; + warnings = filter (x: x != "") (map (f: + let val = getAttrFromPath f config; + opt = getAttrFromPath f options; + in + optionalString + (val != "_mkMergedOptionModule") + "The option `${showOption f}' defined in ${showFiles opt.files} has been changed to `${showOption to}' that has a different type. Please read `${showOption to}' documentation and update your configuration accordingly." + ) from); } // setAttrByPath to (mkMerge (optional (any (f: (getAttrFromPath f config) != "_mkMergedOptionModule") from) @@ -1025,10 +907,8 @@ rec { }); config = mkMerge [ { - _module.checks.${"renamed-" + showOption from} = mkIf (warn && fromOpt.isDefined) { - type = "warning"; - message = "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'."; - }; + warnings = optional (warn && fromOpt.isDefined) + "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'."; } (if withPriority then mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt diff --git a/lib/options.nix b/lib/options.nix index 5c042a6c6f29e..87cd8b797969c 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -192,7 +192,7 @@ rec { let ss = opt.type.getSubOptions opt.loc; in if ss != {} then optionAttrSetToDocList' opt.loc ss else []; in - [ docOption ] ++ optionals (docOption.visible && ! docOption.internal) subOptions) (collect isOption options); + [ docOption ] ++ optionals docOption.visible subOptions) (collect isOption options); /* This function recursively removes all derivation attributes from diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 2d53ed81176da..35a5801c724fe 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -655,7 +655,7 @@ runTests { modules = [ module ]; }).options; - locs = filter (o: ! o.internal) (optionAttrSetToDocList (removeAttrs options [ "_module" ])); + locs = filter (o: ! o.internal) (optionAttrSetToDocList options); in map (o: o.loc) locs; expected = [ [ "foo" ] [ "foo" "<name>" "bar" ] [ "foo" "bar" ] ]; }; diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index 775be9f7209bc..309c5311361c1 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -27,50 +27,37 @@ reportFailure() { fail=$((fail + 1)) } -checkConfigCodeOutErr() { - local expectedExit=$1 - shift; +checkConfigOutput() { local outputContains=$1 shift; - local errorContains=$1 - shift; - out=$(mktemp) - err=$(mktemp) - evalConfig "$@" 1>"$out" 2>"$err" - if [[ "$?" -ne "$expectedExit" ]]; then - echo 2>&1 "error: Expected exit code $expectedExit while evaluating" - reportFailure "$@" - return 1 - fi - - if [[ -n "$outputContains" ]] && ! grep -zP --silent "$outputContains" "$out"; then - echo 2>&1 "error: Expected output matching '$outputContains', while evaluating" + if evalConfig "$@" 2>/dev/null | grep --silent "$outputContains" ; then + pass=$((pass + 1)) + return 0; + else + echo 2>&1 "error: Expected result matching '$outputContains', while evaluating" reportFailure "$@" return 1 fi - - if [[ -n "$errorContains" ]] && ! grep -zP --silent "$errorContains" "$err"; then - echo 2>&1 "error: Expected error matching '$errorContains', while evaluating" - reportFailure "$@" - return 1 - fi - - pass=$((pass + 1)) - - # Clean up temp files - rm "$out" "$err" -} - -checkConfigOutput() { - local outputContains=$1 - shift; - checkConfigCodeOutErr 0 "$outputContains" "" "$@" } checkConfigError() { local errorContains=$1 + local err="" shift; - checkConfigCodeOutErr 1 "" "$errorContains" "$@" + if err==$(evalConfig "$@" 2>&1 >/dev/null); then + echo 2>&1 "error: Expected error code, got exit code 0, while evaluating" + reportFailure "$@" + return 1 + else + if echo "$err" | grep -zP --silent "$errorContains" ; then + pass=$((pass + 1)) + return 0; + else + echo 2>&1 "error: Expected error matching '$errorContains', while evaluating" + reportFailure "$@" + return 1 + fi + fi } # Check boolean option. @@ -275,29 +262,6 @@ checkConfigOutput true config.value.mkbefore ./types-anything/mk-mods.nix checkConfigOutput 1 config.value.nested.foo ./types-anything/mk-mods.nix 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 checks:\n- \[test\] Assertion failed' config ./assertions/simple.nix - -# Assertion is not triggered when enable is false or condition is true -checkConfigOutput '{ }' config ./assertions/condition-true.nix -checkConfigOutput '{ }' config ./assertions/enable-false.nix - -# Warnings should be displayed on standard error -checkConfigCodeOutErr 0 '{ }' 'warning: \[test\] Warning message' config ./assertions/warning.nix - -# Check that multiple assertions and warnings can be triggered at once -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 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 with an attribute starting with _ shouldn't have their name displayed -checkConfigError 'Failed checks:\n- Assertion failed' config ./assertions/underscore-attributes.nix - cat <<EOF ====== module tests ====== $pass Pass diff --git a/lib/tests/modules/assertions/condition-true.nix b/lib/tests/modules/assertions/condition-true.nix deleted file mode 100644 index 7ca0817a23971..0000000000000 --- a/lib/tests/modules/assertions/condition-true.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ - - _module.checks.test = { - check = true; - message = "Assertion failed"; - }; - -} diff --git a/lib/tests/modules/assertions/enable-false.nix b/lib/tests/modules/assertions/enable-false.nix deleted file mode 100644 index 11f753bb32e81..0000000000000 --- a/lib/tests/modules/assertions/enable-false.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ - - _module.checks.test = { - enable = false; - check = false; - message = "Assertion failed"; - }; - -} diff --git a/lib/tests/modules/assertions/multi.nix b/lib/tests/modules/assertions/multi.nix deleted file mode 100644 index 1e2e14b8643a4..0000000000000 --- a/lib/tests/modules/assertions/multi.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ - - _module.checks = { - test1 = { - check = false; - message = "Assertion 1 failed"; - }; - test2 = { - check = false; - message = "Assertion 2 failed"; - }; - test3 = { - check = false; - message = "Warning 3 failed"; - type = "warning"; - }; - test4 = { - check = false; - message = "Warning 4 failed"; - type = "warning"; - }; - }; -} diff --git a/lib/tests/modules/assertions/simple.nix b/lib/tests/modules/assertions/simple.nix deleted file mode 100644 index 115d89a303622..0000000000000 --- a/lib/tests/modules/assertions/simple.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ - _module.checks.test = { - check = false; - message = "Assertion failed"; - }; -} diff --git a/lib/tests/modules/assertions/submodule-attrsOf-attrsOf.nix b/lib/tests/modules/assertions/submodule-attrsOf-attrsOf.nix deleted file mode 100644 index 27a63d1e4329c..0000000000000 --- a/lib/tests/modules/assertions/submodule-attrsOf-attrsOf.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ lib, ... }: { - - options.foo = lib.mkOption { - default = { bar.baz = {}; }; - type = lib.types.attrsOf (lib.types.attrsOf (lib.types.submodule { - _module.checks.test = { - check = false; - message = "Assertion failed"; - }; - })); - }; - -} diff --git a/lib/tests/modules/assertions/submodule-attrsOf.nix b/lib/tests/modules/assertions/submodule-attrsOf.nix deleted file mode 100644 index aac5937cf7e59..0000000000000 --- a/lib/tests/modules/assertions/submodule-attrsOf.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ lib, ... }: { - - options.foo = lib.mkOption { - default = { bar = {}; }; - type = lib.types.attrsOf (lib.types.submodule { - _module.checks.test = { - check = false; - message = "Assertion failed"; - }; - }); - }; - -} diff --git a/lib/tests/modules/assertions/submodule.nix b/lib/tests/modules/assertions/submodule.nix deleted file mode 100644 index 4e7e0b1bd61e9..0000000000000 --- a/lib/tests/modules/assertions/submodule.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ lib, ... }: { - - options.foo = lib.mkOption { - default = {}; - type = lib.types.submodule { - _module.checks.test = { - check = false; - message = "Assertion failed"; - }; - }; - }; - -} diff --git a/lib/tests/modules/assertions/underscore-attributes.nix b/lib/tests/modules/assertions/underscore-attributes.nix deleted file mode 100644 index f9ee5c5787b08..0000000000000 --- a/lib/tests/modules/assertions/underscore-attributes.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ - - _module.checks._test = { - check = false; - message = "Assertion failed"; - }; - -} diff --git a/lib/tests/modules/assertions/warning.nix b/lib/tests/modules/assertions/warning.nix deleted file mode 100644 index 72598ba3fdd55..0000000000000 --- a/lib/tests/modules/assertions/warning.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ - - _module.checks.test = { - check = false; - type = "warning"; - message = "Warning message"; - }; - -} diff --git a/nixos/doc/manual/development/assertions.xml b/nixos/doc/manual/development/assertions.xml index 31d09f958af58..32f90cf2e7c47 100644 --- a/nixos/doc/manual/development/assertions.xml +++ b/nixos/doc/manual/development/assertions.xml @@ -3,155 +3,72 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="sec-assertions"> - <title>Evaluation Checks</title> + <title>Warnings and Assertions</title> <para> When configuration problems are detectable in a module, it is a good idea to - write a check for catching it early. Doing so can provide clear feedback to - the user and can prevent errors before the build. + write an assertion or warning. Doing so provides clear feedback to the user + and prevents errors after the build. </para> <para> Although Nix has the <literal>abort</literal> and <literal>builtins.trace</literal> <link xlink:href="https://nixos.org/nix/manual/#ssec-builtins">functions</link> - to perform such tasks generally, they are not ideally suited for NixOS - modules. Instead of these functions, you can declare your evaluation checks - using the NixOS module system. + to perform such tasks, they are not ideally suited for NixOS modules. Instead + of these functions, you can declare your warnings and assertions using the + NixOS module system. </para> - <section xml:id="sec-assertions-define"> - <title>Defining Checks</title> + <section xml:id="sec-assertions-warnings"> + <title>Warnings</title> <para> - Checks can be defined using the <xref linkend="opt-_module.checks"/> option. - Each check needs an attribute name, under which you can define a trigger - assertion using <xref linkend="opt-_module.checks._name_.check"/> and a - message using <xref linkend="opt-_module.checks._name_.message"/>. - For the message, you can add - <literal>options</literal> to the module arguments and use - <literal>${options.path.to.option}</literal> to print a context-aware string - representation of an option path. Here is an example showing how this can be - done. - </para> - -<programlisting> -{ config, options, ... }: { - _module.checks.gpgSshAgent = { - check = config.programs.gnupg.agent.enableSSHSupport -> !config.programs.ssh.startAgent; - message = "If you have ${options.programs.gnupg.agent.enableSSHSupport} enabled," - + " you can't enable ${options.programs.ssh.startAgent} as well!"; - }; - - _module.checks.grafanaPassword = { - check = config.services.grafana.database.password == ""; - message = "The grafana password defined with ${options.services.grafana.database.password}" - + " will be stored as plaintext in the Nix store!"; - # This is a non-fatal warning - type = "warning"; - }; -} -</programlisting> - - </section> - - <section xml:id="sec-assertions-ignoring"> - <title>Ignoring Checks</title> - - <para> - Sometimes you can get failing checks that don't apply to your specific case - and you wish to ignore them, or at least make errors non-fatal. You can do so - for all checks defined using <xref linkend="opt-_module.checks"/> by - using the attribute name of the definition, which is conveniently printed - using <literal>[...]</literal> when the check is triggered. For above - example, the evaluation output when the checks are triggered looks as - follows: - </para> - -<programlisting> -trace: warning: [grafanaPassword] The grafana password defined with - services.grafana.database.password will be stored as plaintext in the Nix store! -error: Failed checks: -- [gpgSshAgent] If you have programs.gnupg.agent.enableSSHSupport - enabled, you can't enable programs.ssh.startAgent as well! -</programlisting> - - <para> - The <literal>[grafanaPassword]</literal> and <literal>[gpgSshAgent]</literal> - strings tell you that these were defined under the <literal>grafanaPassword - </literal> and <literal>gpgSshAgent</literal> attributes of - <xref linkend="opt-_module.checks"/> respectively. With this knowledge - you can adjust them to your liking: + This is an example of using <literal>warnings</literal>. </para> <programlisting> +<![CDATA[ +{ config, lib, ... }: { - # Change the error into a non-fatal warning - _module.checks.gpgSshAgent.type = "warning"; - - # We don't care about this warning, disable it - _module.checks.grafanaPassword.enable = false; + config = lib.mkIf config.services.foo.enable { + warnings = + if config.services.foo.bar + then [ ''You have enabled the bar feature of the foo service. + This is known to cause some specific problems in certain situations. + '' ] + else []; + } } +]]> </programlisting> - - </section> - <section xml:id="sec-assertions-submodules"> - <title>Checks in Submodules</title> - <para> - Evaluation checks can be defined within submodules in the same way. Here is an example: - </para> - -<programlisting> -{ lib, ... }: { - - options.myServices = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({ config, options, ... }: { - options.port = lib.mkOption {}; - - config._module.checks.portConflict = { - check = config.port != 80; - message = "Port ${toString config.port} defined using" - + " ${options.port} is usually used for HTTP"; - type = "warning"; - }; - })); - }; - -} -</programlisting> + <section xml:id="sec-assertions-assertions"> + <title>Assertions</title> <para> - When this check is triggered, it shows both the submodule path along with - the check attribute within that submodule, joined by a - <literal>/</literal>. Note also how <literal>${options.port}</literal> - correctly shows the context of the option. - </para> - -<programlisting> -trace: warning: [myServices.foo/portConflict] Port 80 defined using - myServices.foo.port is usually used for HTTP -</programlisting> - - <para> - Therefore to disable such a check, you can do so by changing the - <xref linkend="opt-_module.checks"/> option within the - <literal>myServices.foo</literal> submodule: + This example, extracted from the + <link xlink:href="https://github.com/NixOS/nixpkgs/blob/release-17.09/nixos/modules/services/logging/syslogd.nix"> + <literal>syslogd</literal> module </link> shows how to use + <literal>assertions</literal>. Since there can only be one active syslog + daemon at a time, an assertion is useful to prevent such a broken system + from being built. </para> <programlisting> +<![CDATA[ +{ config, lib, ... }: { - myServices.foo._module.checks.portConflict.enable = false; + config = lib.mkIf config.services.syslogd.enable { + assertions = + [ { assertion = !config.services.rsyslogd.enable; + message = "rsyslogd conflicts with syslogd"; + } + ]; + } } +]]> </programlisting> - -<note> - <para> - Checks defined in submodules under <literal>types.listOf</literal> can't be - ignored, since there's no way to change previously defined list items. - </para> -</note> - </section> </section> diff --git a/nixos/modules/misc/assertions.nix b/nixos/modules/misc/assertions.nix index d7cdb32491d3c..550b3ac97f6a8 100644 --- a/nixos/modules/misc/assertions.nix +++ b/nixos/modules/misc/assertions.nix @@ -1,4 +1,4 @@ -{ lib, config, ... }: +{ lib, ... }: with lib; @@ -30,18 +30,5 @@ with lib; }; }; - - config._module.checks = lib.listToAttrs (lib.imap1 (n: value: - let - name = "_${toString n}"; - isWarning = lib.isString value; - result = { - check = if isWarning then false else value.assertion; - type = if isWarning then "warning" else "error"; - message = if isWarning then value else value.message; - }; - in nameValuePair name result - ) (config.assertions ++ config.warnings)); - # impl of assertions is in <nixpkgs/nixos/modules/system/activation/top-level.nix> } diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 17b62ad9569b1..03d7e7493230b 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -117,10 +117,18 @@ let perl = "${pkgs.perl}/bin/perl " + (concatMapStringsSep " " (lib: "-I${lib}/${pkgs.perl.libPrefix}") (with pkgs.perlPackages; [ FileSlurp NetDBus XMLParser XMLTwig ])); }; + # Handle assertions and warnings + + failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions); + + baseSystemAssertWarn = if failedAssertions != [] + then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" + else showWarnings config.warnings baseSystem; + # Replace runtime dependencies system = fold ({ oldDependency, newDependency }: drv: pkgs.replaceDependency { inherit oldDependency newDependency drv; } - ) baseSystem config.system.replaceRuntimeDependencies; + ) baseSystemAssertWarn config.system.replaceRuntimeDependencies; in |