···99 catAttrs
1010 concatLists
1111 concatMap
1212- count
1212+ concatStringsSep
1313 elem
1414 filter
1515 findFirst
···4747 showOption
4848 unknownModule
4949 ;
5050+5151+ showDeclPrefix = loc: decl: prefix:
5252+ " - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
5353+ showRawDecls = loc: decls:
5454+ concatStringsSep "\n"
5555+ (sort (a: b: a < b)
5656+ (concatMap
5757+ (decl: map
5858+ (showDeclPrefix loc decl)
5959+ (attrNames decl.options)
6060+ )
6161+ decls
6262+ ));
6363+5064in
51655266rec {
···474488 [{ inherit (module) file; inherit value; }]
475489 ) configs;
476490491491+ # Convert an option tree decl to a submodule option decl
492492+ optionTreeToOption = decl:
493493+ if isOption decl.options
494494+ then decl
495495+ else decl // {
496496+ options = mkOption {
497497+ type = types.submoduleWith {
498498+ modules = [ { options = decl.options; } ];
499499+ # `null` is not intended for use by modules. It is an internal
500500+ # value that means "whatever the user has declared elsewhere".
501501+ # This might become obsolete with https://github.com/NixOS/nixpkgs/issues/162398
502502+ shorthandOnlyDefinesConfig = null;
503503+ };
504504+ };
505505+ };
506506+477507 resultsByName = mapAttrs (name: decls:
478508 # We're descending into attribute ‘name’.
479509 let
480510 loc = prefix ++ [name];
481511 defns = defnsByName.${name} or [];
482512 defns' = defnsByName'.${name} or [];
483483- nrOptions = count (m: isOption m.options) decls;
513513+ optionDecls = filter (m: isOption m.options) decls;
484514 in
485485- if nrOptions == length decls then
515515+ if length optionDecls == length decls then
486516 let opt = fixupOptionType loc (mergeOptionDecls loc decls);
487517 in {
488518 matchedOptions = evalOptionValue loc opt defns';
489519 unmatchedDefns = [];
490520 }
491491- else if nrOptions != 0 then
492492- let
493493- firstOption = findFirst (m: isOption m.options) "" decls;
494494- firstNonOption = findFirst (m: !isOption m.options) "" decls;
495495- in
496496- throw "The option `${showOption loc}' in `${firstOption._file}' is a prefix of options in `${firstNonOption._file}'."
521521+ else if optionDecls != [] then
522522+ if all (x: x.options.type.name == "submodule") optionDecls
523523+ # Raw options can only be merged into submodules. Merging into
524524+ # attrsets might be nice, but ambiguous. Suppose we have
525525+ # attrset as a `attrsOf submodule`. User declares option
526526+ # attrset.foo.bar, this could mean:
527527+ # a. option `bar` is only available in `attrset.foo`
528528+ # b. option `foo.bar` is available in all `attrset.*`
529529+ # c. reject and require "<name>" as a reminder that it behaves like (b).
530530+ # d. magically combine (a) and (c).
531531+ # All of the above are merely syntax sugar though.
532532+ then
533533+ let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
534534+ in {
535535+ matchedOptions = evalOptionValue loc opt defns';
536536+ unmatchedDefns = [];
537537+ }
538538+ else
539539+ let
540540+ firstNonOption = findFirst (m: !isOption m.options) "" decls;
541541+ nonOptions = filter (m: !isOption m.options) decls;
542542+ in
543543+ throw "The option `${showOption loc}' in module `${(lib.head optionDecls)._file}' would be a parent of the following options, but its type `${(lib.head optionDecls).options.type.description or "<no description>"}' does not support nested options.\n${
544544+ showRawDecls loc nonOptions
545545+ }"
497546 else
498547 mergeModules' loc decls defns) declsByName;
499548···753802 compare = a: b: (a.priority or 1000) < (b.priority or 1000);
754803 in sort compare defs';
755804756756- /* Hack for backward compatibility: convert options of type
757757- optionSet to options of type submodule. FIXME: remove
758758- eventually. */
759805 fixupOptionType = loc: opt:
760806 let
761807 options = opt.options or
762808 (throw "Option `${showOption loc}' has type optionSet but has no option attribute, in ${showFiles opt.declarations}.");
809809+810810+ # Hack for backward compatibility: convert options of type
811811+ # optionSet to options of type submodule. FIXME: remove
812812+ # eventually.
763813 f = tp:
764814 if tp.name == "option set" || tp.name == "submodule" then
765815 throw "The option ${showOption loc} uses submodules without a wrapping type, in ${showFiles opt.declarations}."
+1-1
lib/options.nix
···231231 then true
232232 else opt.visible or true;
233233 readOnly = opt.readOnly or false;
234234- type = opt.type.description or null;
234234+ type = opt.type.description or "unspecified";
235235 }
236236 // optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
237237 // optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
+13
lib/tests/modules.sh
···6262checkConfigOutput '^false$' config.enable ./declare-enable.nix
6363checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*: true' config.enable ./define-enable.nix
64646565+checkConfigOutput '^1$' config.bare-submodule.nested ./declare-bare-submodule.nix ./declare-bare-submodule-nested-option.nix
6666+checkConfigOutput '^2$' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-deep-option.nix
6767+checkConfigOutput '^42$' config.bare-submodule.nested ./declare-bare-submodule.nix ./declare-bare-submodule-nested-option.nix ./declare-bare-submodule-deep-option.nix ./define-bare-submodule-values.nix
6868+checkConfigOutput '^420$' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-nested-option.nix ./declare-bare-submodule-deep-option.nix ./define-bare-submodule-values.nix
6969+checkConfigOutput '^2$' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-deep-option.nix ./define-shorthandOnlyDefinesConfig-true.nix
7070+checkConfigError 'The option .bare-submodule.deep. in .*/declare-bare-submodule-deep-option.nix. is already declared in .*/declare-bare-submodule-deep-option-duplicate.nix' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-deep-option.nix ./declare-bare-submodule-deep-option-duplicate.nix
7171+6572# Check integer types.
6673# unsigned
6774checkConfigOutput '^42$' config.value ./declare-int-unsigned-value.nix ./define-value-int-positive.nix
···303310checkConfigOutput "10" config.processedToplevel ./raw.nix
304311checkConfigError "The option .multiple. is defined multiple times" config.multiple ./raw.nix
305312checkConfigOutput "bar" config.priorities ./raw.nix
313313+314314+## Option collision
315315+checkConfigError \
316316+ 'The option .set. in module .*/declare-set.nix. would be a parent of the following options, but its type .attribute set of signed integers. does not support nested options.\n\s*- option[(]s[)] with prefix .set.enable. in module .*/declare-enable-nested.nix.' \
317317+ config.set \
318318+ ./declare-set.nix ./declare-enable-nested.nix
306319307320# Test that types.optionType merges types correctly
308321checkConfigOutput '^10$' config.theOption.int ./optionTypeMerging.nix
···572572 let
573573 inherit (lib.modules) evalModules;
574574575575- coerce = unify: value: if isFunction value
576576- then setFunctionArgs (args: unify (value args)) (functionArgs value)
577577- else unify (if shorthandOnlyDefinesConfig then { config = value; } else value);
575575+ shorthandToModule = if shorthandOnlyDefinesConfig == false
576576+ then value: value
577577+ else value: { config = value; };
578578579579 allModules = defs: imap1 (n: { value, file }:
580580- if isAttrs value || isFunction value then
581581- # Annotate the value with the location of its definition for better error messages
582582- coerce (lib.modules.unifyModuleSyntax file "${toString file}-${toString n}") value
580580+ if isFunction value
581581+ then setFunctionArgs
582582+ (args: lib.modules.unifyModuleSyntax file "${toString file}-${toString n}" (value args))
583583+ (functionArgs value)
584584+ else if isAttrs value
585585+ then
586586+ lib.modules.unifyModuleSyntax file "${toString file}-${toString n}" (shorthandToModule value)
583587 else value
584588 ) defs;
585589···647651 then lhs.specialArgs // rhs.specialArgs
648652 else throw "A submoduleWith option is declared multiple times with the same specialArgs \"${toString (attrNames intersecting)}\"";
649653 shorthandOnlyDefinesConfig =
650650- if lhs.shorthandOnlyDefinesConfig == rhs.shorthandOnlyDefinesConfig
654654+ if lhs.shorthandOnlyDefinesConfig == null
655655+ then rhs.shorthandOnlyDefinesConfig
656656+ else if rhs.shorthandOnlyDefinesConfig == null
657657+ then lhs.shorthandOnlyDefinesConfig
658658+ else if lhs.shorthandOnlyDefinesConfig == rhs.shorthandOnlyDefinesConfig
651659 then lhs.shorthandOnlyDefinesConfig
652660 else throw "A submoduleWith option is declared multiple times with conflicting shorthandOnlyDefinesConfig values";
653661 };
···27272828`type`
29293030-: The type of the option (see [](#sec-option-types)). It may be
3131- omitted, but that's not advisable since it may lead to errors that
3232- are hard to diagnose.
3030+: The type of the option (see [](#sec-option-types)). This
3131+ argument is mandatory for nixpkgs modules. Setting this is highly
3232+ recommended for the sake of documentation and type checking. In case it is
3333+ not set, a fallback type with unspecified behavior is used.
33343435`default`
3536
···3838 <listitem>
3939 <para>
4040 The type of the option (see
4141- <xref linkend="sec-option-types" />). It may be omitted, but
4242- that’s not advisable since it may lead to errors that are hard
4343- to diagnose.
4141+ <xref linkend="sec-option-types" />). This argument is
4242+ mandatory for nixpkgs modules. Setting this is highly
4343+ recommended for the sake of documentation and type checking.
4444+ In case it is not set, a fallback type with unspecified
4545+ behavior is used.
4446 </para>
4547 </listitem>
4648 </varlistentry>
···13451345 </listitem>
13461346 <listitem>
13471347 <para>
13481348+ ORY Kratos was updated to version 0.8.3-alpha.1.pre.0, which
13491349+ introduces some breaking changes:
13501350+ </para>
13511351+ <itemizedlist spacing="compact">
13521352+ <listitem>
13531353+ <para>
13541354+ If you are relying on the SQLite images, update your
13551355+ Docker Pull commands as follows:
13561356+ </para>
13571357+ <itemizedlist spacing="compact">
13581358+ <listitem>
13591359+ <para>
13601360+ <literal>docker pull oryd/kratos:{version}</literal>
13611361+ </para>
13621362+ </listitem>
13631363+ </itemizedlist>
13641364+ </listitem>
13651365+ <listitem>
13661366+ <para>
13671367+ Additionally, all passwords now have to be at least 8
13681368+ characters long.
13691369+ </para>
13701370+ </listitem>
13711371+ <listitem>
13721372+ <para>
13731373+ For more details, see:
13741374+ </para>
13751375+ <itemizedlist spacing="compact">
13761376+ <listitem>
13771377+ <para>
13781378+ <link xlink:href="https://github.com/ory/kratos/releases/tag/v0.8.1-alpha.1">Release
13791379+ Notes for v0.8.1-alpha-1</link>
13801380+ </para>
13811381+ </listitem>
13821382+ <listitem>
13831383+ <para>
13841384+ <link xlink:href="https://github.com/ory/kratos/releases/tag/v0.8.2-alpha.1">Release
13851385+ Notes for v0.8.2-alpha-1</link>
13861386+ </para>
13871387+ </listitem>
13881388+ </itemizedlist>
13891389+ </listitem>
13901390+ </itemizedlist>
13911391+ </listitem>
13921392+ <listitem>
13931393+ <para>
13481394 <literal>fetchFromSourcehut</literal> now allows fetching
13491395 repositories recursively using <literal>fetchgit</literal> or
13501396 <literal>fetchhg</literal> if the argument
+8
nixos/doc/manual/release-notes/rl-2205.section.md
···499499500500- `nixos-generate-config` now puts the dhcp configuration in `hardware-configuration.nix` instead of `configuration.nix`.
501501502502+- ORY Kratos was updated to version 0.8.3-alpha.1.pre.0, which introduces some breaking changes:
503503+ - If you are relying on the SQLite images, update your Docker Pull commands as follows:
504504+ - `docker pull oryd/kratos:{version}`
505505+ - Additionally, all passwords now have to be at least 8 characters long.
506506+ - For more details, see:
507507+ - [Release Notes for v0.8.1-alpha-1](https://github.com/ory/kratos/releases/tag/v0.8.1-alpha.1)
508508+ - [Release Notes for v0.8.2-alpha-1](https://github.com/ory/kratos/releases/tag/v0.8.2-alpha.1)
509509+502510- `fetchFromSourcehut` now allows fetching repositories recursively
503511 using `fetchgit` or `fetchhg` if the argument `fetchSubmodules`
504512 is set to `true`.
+8-1
nixos/lib/make-options-doc/mergeJSON.py
···6666 elif ov is not None or cur.get(ok, None) is None:
6767 cur[ok] = ov
68686969+severity = "error" if warningsAreErrors else "warning"
7070+6971# check that every option has a description
7072hasWarnings = False
7173for (k, v) in options.items():
7274 if v.value.get('description', None) is None:
7373- severity = "error" if warningsAreErrors else "warning"
7475 hasWarnings = True
7576 print(f"\x1b[1;31m{severity}: option {v.name} has no description\x1b[0m", file=sys.stderr)
7677 v.value['description'] = "This option has no description."
7878+ if v.value.get('type', "unspecified") == "unspecified":
7979+ hasWarnings = True
8080+ print(
8181+ f"\x1b[1;31m{severity}: option {v.name} has no type. Please specify a valid type, see " +
8282+ "https://nixos.org/manual/nixos/stable/index.html#sec-option-types\x1b[0m", file=sys.stderr)
8383+7784if hasWarnings and warningsAreErrors:
7885 print(
7986 "\x1b[1;31m" +
···183183184184 pruneNames = mkOption {
185185 type = listOf str;
186186- default = [ ".bzr" ".cache" ".git" ".hg" ".svn" ];
186186+ default = lib.optionals (!isFindutils) [ ".bzr" ".cache" ".git" ".hg" ".svn" ];
187187+ defaultText = literalDocBook ''
188188+ <literal>[ ".bzr" ".cache" ".git" ".hg" ".svn" ]</literal>, if
189189+ supported by the locate implementation (i.e. mlocate or plocate).
190190+ '';
187191 description = ''
188192 Directory components which should exclude paths containing them from indexing
189193 '';
+8-12
nixos/modules/services/networking/nsd.nix
···194194 zone.children
195195 );
196196197197- # fighting infinite recursion
198198- zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true;
199199- zoneOptions1 = zoneOptionsRaw // childConfig zoneOptions2 false;
200200- zoneOptions2 = zoneOptionsRaw // childConfig zoneOptions3 false;
201201- zoneOptions3 = zoneOptionsRaw // childConfig zoneOptions4 false;
202202- zoneOptions4 = zoneOptionsRaw // childConfig zoneOptions5 false;
203203- zoneOptions5 = zoneOptionsRaw // childConfig zoneOptions6 false;
204204- zoneOptions6 = zoneOptionsRaw // childConfig null false;
205205-206206- childConfig = x: v: { options.children = { type = types.attrsOf x; visible = v; }; };
207207-208197 # options are ordered alphanumerically
209209- zoneOptionsRaw = types.submodule {
198198+ zoneOptions = types.submodule {
210199 options = {
211200212201 allowAXFRFallback = mkOption {
···246235 };
247236248237 children = mkOption {
238238+ # TODO: This relies on the fact that `types.anything` doesn't set any
239239+ # values of its own to any defaults, because in the above zoneConfigs',
240240+ # values from children override ones from parents, but only if the
241241+ # attributes are defined. Because of this, we can't replace the element
242242+ # type here with `zoneConfigs`, since that would set all the attributes
243243+ # to default values, breaking the parent inheriting function.
244244+ type = types.attrsOf types.anything;
249245 default = {};
250246 description = ''
251247 Children zones inherit all options of their parents. Attributes
+1
nixos/modules/services/networking/unbound.nix
···6262 };
63636464 stateDir = mkOption {
6565+ type = types.path;
6566 default = "/var/lib/unbound";
6667 description = "Directory holding all state for unbound to run.";
6768 };
···601601 else "gzip"
602602 );
603603 defaultText = literalDocBook "<literal>zstd</literal> if the kernel supports it (5.9+), <literal>gzip</literal> if not";
604604- type = types.unspecified; # We don't have a function type...
604604+ type = types.either types.str (types.functionTo types.str);
605605 description = ''
606606 The compressor to use on the initrd image. May be any of:
607607
···11-WGET_ARGS=( https://download.kde.org/stable/release-service/21.12.2/src -A '*.tar.xz' )
11+WGET_ARGS=( https://download.kde.org/stable/release-service/21.12.3/src -A '*.tar.xz' )