diff options
author | github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> | 2021-11-01 12:01:00 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-01 12:01:00 +0000 |
commit | cc41bb585179fca8d8443e0ffb58c3a24458564d (patch) | |
tree | 51d1967cfd81307013894b4126ba8fdd5cee3946 /lib | |
parent | 2b9973012c1d1f7f3e3457f2569f0517a97b1b81 (diff) | |
parent | 4559160c4f4eb55f9eee0cb6015e2a0f3fa80462 (diff) | |
download | nixpkgs-cc41bb585179fca8d8443e0ffb58c3a24458564d.tar nixpkgs-cc41bb585179fca8d8443e0ffb58c3a24458564d.tar.gz nixpkgs-cc41bb585179fca8d8443e0ffb58c3a24458564d.tar.bz2 nixpkgs-cc41bb585179fca8d8443e0ffb58c3a24458564d.tar.lz nixpkgs-cc41bb585179fca8d8443e0ffb58c3a24458564d.tar.xz nixpkgs-cc41bb585179fca8d8443e0ffb58c3a24458564d.tar.zst nixpkgs-cc41bb585179fca8d8443e0ffb58c3a24458564d.zip |
Merge master into staging-next
Diffstat (limited to 'lib')
-rw-r--r-- | lib/modules.nix | 62 | ||||
-rw-r--r-- | lib/options.nix | 10 | ||||
-rwxr-xr-x | lib/tests/modules.sh | 7 | ||||
-rw-r--r-- | lib/tests/modules/declare-submodule-via-evalModules.nix | 28 | ||||
-rw-r--r-- | lib/types.nix | 56 |
5 files changed, 123 insertions, 40 deletions
diff --git a/lib/modules.nix b/lib/modules.nix index 46ae3f13631..d9b4000e56b 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -52,15 +52,39 @@ in rec { - /* Evaluate a set of modules. The result is a set of two - attributes: ‘options’: the nested set of all option declarations, - and ‘config’: the nested set of all option values. + /* + Evaluate a set of modules. The result is a set with the attributes: + + ‘options’: The nested set of all option declarations, + + ‘config’: The nested set of all option values. + + ‘type’: A module system type representing the module set as a submodule, + to be extended by configuration from the containing module set. + + ‘extendModules’: A function similar to ‘evalModules’ but building on top + of the module set. Its arguments, ‘modules’ and ‘specialArgs’ are + added to the existing values. + + Using ‘extendModules’ a few times has no performance impact as long + as you only reference the final ‘options’ and ‘config’. + If you do reference multiple ‘config’ (or ‘options’) from before and + after ‘extendModules’, performance is the same as with multiple + ‘evalModules’ invocations, because the new modules' ability to + override existing configuration fundamentally requires a new + fixpoint to be constructed. + + ‘_module’: A portion of the configuration tree which is elided from + ‘config’. It contains some values that are mostly internal to the + module system implementation. + !!! Please think twice before adding to this argument list! The more that is specified here instead of in the modules themselves the harder it is to transparently move a set of modules to be a submodule of another config (as the proper arguments need to be replicated at each call to evalModules) and the less declarative the module set is. */ - evalModules = { modules + evalModules = evalModulesArgs@ + { modules , prefix ? [] , # This should only be used for special arguments that need to be evaluated # when resolving module structure (like in imports). For everything else, @@ -120,7 +144,9 @@ rec { }; config = { - _module.args = args; + _module.args = { + inherit extendModules; + } // args; }; }; @@ -183,10 +209,28 @@ rec { else throw baseMsg else null; - result = builtins.seq checkUnmatched { - inherit options; - config = removeAttrs config [ "_module" ]; - inherit (config) _module; + checked = builtins.seq checkUnmatched; + + extendModules = extendArgs@{ + modules ? [], + specialArgs ? {}, + prefix ? [], + }: + evalModules (evalModulesArgs // { + modules = evalModulesArgs.modules ++ modules; + specialArgs = evalModulesArgs.specialArgs or {} // specialArgs; + prefix = extendArgs.prefix or evalModulesArgs.prefix; + }); + + type = lib.types.submoduleWith { + inherit modules specialArgs; + }; + + result = { + options = checked options; + config = checked (removeAttrs config [ "_module" ]); + _module = checked (config._module); + inherit extendModules type; }; in result; diff --git a/lib/options.nix b/lib/options.nix index b3164181312..5d52f065af0 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -74,7 +74,7 @@ rec { apply ? null, # Whether the option is for NixOS developers only. internal ? null, - # Whether the option shows up in the manual. + # Whether the option shows up in the manual. Default: true. Use false to hide the option and any sub-options from submodules. Use "shallow" to hide only sub-options. visible ? null, # Whether the option can be set only once readOnly ? null, @@ -180,7 +180,10 @@ rec { description = opt.description or (lib.warn "Option `${name}' has no description." "This option has no description."); declarations = filter (x: x != unknownModule) opt.declarations; internal = opt.internal or false; - visible = opt.visible or true; + visible = + if (opt?visible && opt.visible == "shallow") + then true + else opt.visible or true; readOnly = opt.readOnly or false; type = opt.type.description or null; } @@ -192,8 +195,9 @@ rec { subOptions = let ss = opt.type.getSubOptions opt.loc; in if ss != {} then optionAttrSetToDocList' opt.loc ss else []; + subOptionsVisible = docOption.visible && opt.visible or null != "shallow"; in - [ docOption ] ++ optionals docOption.visible subOptions) (collect isOption options); + [ docOption ] ++ optionals subOptionsVisible subOptions) (collect isOption options); /* This function recursively removes all derivation attributes from diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index b51db91f6b0..49fc8bcbafc 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -179,6 +179,13 @@ checkConfigOutput "true" config.submodule.outer ./declare-submoduleWith-modules. # which evaluates all the modules defined by the type) checkConfigOutput "submodule" options.submodule.type.description ./declare-submoduleWith-modules.nix +## submodules can be declared using (evalModules {...}).type +checkConfigOutput "true" config.submodule.inner ./declare-submodule-via-evalModules.nix +checkConfigOutput "true" config.submodule.outer ./declare-submodule-via-evalModules.nix +# Should also be able to evaluate the type name (which evaluates freeformType, +# which evaluates all the modules defined by the type) +checkConfigOutput "submodule" options.submodule.type.description ./declare-submodule-via-evalModules.nix + ## Paths should be allowed as values and work as expected checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix diff --git a/lib/tests/modules/declare-submodule-via-evalModules.nix b/lib/tests/modules/declare-submodule-via-evalModules.nix new file mode 100644 index 00000000000..2841c64a073 --- /dev/null +++ b/lib/tests/modules/declare-submodule-via-evalModules.nix @@ -0,0 +1,28 @@ +{ lib, ... }: { + options.submodule = lib.mkOption { + inherit (lib.evalModules { + modules = [ + { + options.inner = lib.mkOption { + type = lib.types.bool; + default = false; + }; + } + ]; + }) type; + default = {}; + }; + + config.submodule = lib.mkMerge [ + ({ lib, ... }: { + options.outer = lib.mkOption { + type = lib.types.bool; + default = false; + }; + }) + { + inner = true; + outer = true; + } + ]; +} diff --git a/lib/types.nix b/lib/types.nix index c2532065d7e..244cbb6b535 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -505,17 +505,36 @@ rec { then setFunctionArgs (args: unify (value args)) (functionArgs value) else unify (if shorthandOnlyDefinesConfig then { config = value; } else value); - allModules = defs: modules ++ imap1 (n: { value, file }: + allModules = defs: 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 ) defs; - freeformType = (evalModules { - inherit modules specialArgs; - args.name = "‹name›"; - })._module.freeformType; + base = evalModules { + inherit specialArgs; + modules = [{ + # This is a work-around for the fact that some sub-modules, + # such as the one included in an attribute set, expects an "args" + # attribute to be given to the sub-module. As the option + # evaluation does not have any specific attribute name yet, we + # provide a default for the documentation and the freeform type. + # + # This is necessary as some option declaration might use the + # "name" attribute given as argument of the submodule and use it + # as the default of option declarations. + # + # We use lookalike unicode single angle quotation marks because + # of the docbook transformation the options receive. In all uses + # > and < wouldn't be encoded correctly so the encoded values + # would be used, and use of `<` and `>` would break the XML document. + # It shouldn't cause an issue since this is cosmetic for the manual. + _module.args.name = lib.mkOptionDefault "‹name›"; + }] ++ modules; + }; + + freeformType = base._module.freeformType; in mkOptionType rec { @@ -523,32 +542,13 @@ rec { description = freeformType.description or name; check = x: isAttrs x || isFunction x || path.check x; merge = loc: defs: - (evalModules { - modules = allModules defs; - inherit specialArgs; - args.name = last loc; + (base.extendModules { + modules = [ { _module.args.name = last loc; } ] ++ allModules defs; prefix = loc; }).config; emptyValue = { value = {}; }; - getSubOptions = prefix: (evalModules - { inherit modules prefix specialArgs; - # This is a work-around due to the fact that some sub-modules, - # such as the one included in an attribute set, expects a "args" - # attribute to be given to the sub-module. As the option - # evaluation does not have any specific attribute name, we - # provide a default one for the documentation. - # - # This is mandatory as some option declaration might use the - # "name" attribute given as argument of the submodule and use it - # as the default of option declarations. - # - # Using lookalike unicode single angle quotation marks because - # of the docbook transformation the options receive. In all uses - # > and < wouldn't be encoded correctly so the encoded values - # would be used, and use of `<` and `>` would break the XML document. - # It shouldn't cause an issue since this is cosmetic for the manual. - args.name = "‹name›"; - }).options // optionalAttrs (freeformType != null) { + getSubOptions = prefix: (base.extendModules + { inherit prefix; }).options // optionalAttrs (freeformType != null) { # Expose the sub options of the freeform type. Note that the option # discovery doesn't care about the attribute name used here, so this # is just to avoid conflicts with potential options from the submodule |