From 5cbeddfde486ca5524baeaf3da6e8944075cf463 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Wed, 8 Dec 2021 19:02:29 +0100 Subject: [PATCH 1/2] lib.types: Introduce `types.optionType` This type correctly merges multiple option types together while also annotating them with file information. In a future commit this will be used for `_module.freeformType` --- lib/tests/modules.sh | 7 +++++ lib/tests/modules/optionTypeFile.nix | 28 +++++++++++++++++ lib/tests/modules/optionTypeMerging.nix | 27 ++++++++++++++++ lib/types.nix | 31 ++++++++++++++++++- .../development/option-types.section.md | 7 +++++ .../development/option-types.section.xml | 14 +++++++++ 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 lib/tests/modules/optionTypeFile.nix create mode 100644 lib/tests/modules/optionTypeMerging.nix diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index a1c592cf4ef0..d11f32e59964 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -299,6 +299,13 @@ checkConfigOutput "10" config.processedToplevel ./raw.nix checkConfigError "The option .multiple. is defined multiple times" config.multiple ./raw.nix checkConfigOutput "bar" config.priorities ./raw.nix +# Test that types.optionType merges types correctly +checkConfigOutput '^10$' config.theOption.int ./optionTypeMerging.nix +checkConfigOutput '^"hello"$' config.theOption.str ./optionTypeMerging.nix + +# Test that types.optionType correctly annotates option locations +checkConfigError 'The option .theOption.nested. in .other.nix. is already declared in .optionTypeFile.nix.' config.theOption.nested ./optionTypeFile.nix + cat < + + + types.optionType + + + + The type of an option’s type. Its merging operation ensures + that nested options have the correct file location + annotated, and that if possible, multiple option definitions + are correctly merged together. The main use case is as the + type of the _module.freeformType option. + + + types.attrs From 023fa7b9239e645f7dfcbbe3ee82ab0093f9978d Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Wed, 8 Dec 2021 19:13:14 +0100 Subject: [PATCH 2/2] lib.modules: Use types.optionType for _module.freeformType This ensures that the module file locations are propagated to the freeform type, which makes it so that submodules in freeform types now have their declaration location shown in the manual, fixing https://github.com/NixOS/nixpkgs/issues/132085. In addition, this also newly allows freeformTypes to be declared multiple times and all declarations being merged together according to normal option merging. This also removes some awkwardness regarding the type of `freeformType` --- lib/modules.nix | 3 +-- lib/tests/modules.sh | 5 +++++ lib/tests/modules/freeform-submodules.nix | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 lib/tests/modules/freeform-submodules.nix diff --git a/lib/modules.nix b/lib/modules.nix index e9fc1007fc20..79d54e4a5387 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -151,8 +151,7 @@ rec { }; _module.freeformType = mkOption { - # Disallow merging for now, but could be implemented nicely with a `types.optionType` - type = types.nullOr (types.uniq types.attrs); + type = types.nullOr types.optionType; internal = true; default = null; description = '' diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index d11f32e59964..e4bb7ad21900 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -240,6 +240,11 @@ checkConfigOutput '^"24"$' config.foo ./freeform-attrsOf.nix ./freeform-str-dep- checkConfigError 'infinite recursion encountered' config.foo ./freeform-attrsOf.nix ./freeform-unstr-dep-str.nix checkConfigError 'The option .* is used but not defined' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix checkConfigOutput '^"24"$' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix ./define-value-string.nix +# submodules in freeformTypes should have their locations annotated +checkConfigOutput '/freeform-submodules.nix"$' config.fooDeclarations.0 ./freeform-submodules.nix +# freeformTypes can get merged using `types.type`, including submodules +checkConfigOutput '^10$' config.free.xxx.foo ./freeform-submodules.nix +checkConfigOutput '^10$' config.free.yyy.bar ./freeform-submodules.nix ## types.anything # Check that attribute sets are merged recursively diff --git a/lib/tests/modules/freeform-submodules.nix b/lib/tests/modules/freeform-submodules.nix new file mode 100644 index 000000000000..3910435a7b5c --- /dev/null +++ b/lib/tests/modules/freeform-submodules.nix @@ -0,0 +1,22 @@ +{ lib, options, ... }: with lib.types; { + + options.fooDeclarations = lib.mkOption { + default = (options.free.type.getSubOptions [])._freeformOptions.foo.declarations; + }; + + options.free = lib.mkOption { + type = submodule { + config._module.freeformType = lib.mkMerge [ + (attrsOf (submodule { + options.foo = lib.mkOption {}; + })) + (attrsOf (submodule { + options.bar = lib.mkOption {}; + })) + ]; + }; + }; + + config.free.xxx.foo = 10; + config.free.yyy.bar = 10; +}