Merge pull request #242812 from hercules-ci/modules-remove-byName-obfuscation

module system: Clean up and improve an error message

authored by

Silvan Mosberger and committed by
GitHub
0b339c82 4d8e3794

+65 -50
+64 -49
lib/modules.nix
··· 539 539 540 540 mergeModules' = prefix: options: configs: 541 541 let 542 - /* byName is like foldAttrs, but will look for attributes to merge in the 543 - specified attribute name. 544 - 545 - byName "foo" (module: value: ["module.hidden=${module.hidden},value=${value}"]) 546 - [ 547 - { 548 - hidden="baz"; 549 - foo={qux="bar"; gla="flop";}; 550 - } 551 - { 552 - hidden="fli"; 553 - foo={qux="gne"; gli="flip";}; 554 - } 555 - ] 556 - ===> 557 - { 558 - gla = [ "module.hidden=baz,value=flop" ]; 559 - gli = [ "module.hidden=fli,value=flip" ]; 560 - qux = [ "module.hidden=baz,value=bar" "module.hidden=fli,value=gne" ]; 561 - } 562 - */ 563 - byName = attr: f: modules: 564 - zipAttrsWith (n: concatLists) 565 - (map (module: let subtree = module.${attr}; in 542 + # an attrset 'name' => list of submodules that declare ‘name’. 543 + declsByName = 544 + zipAttrsWith 545 + (n: concatLists) 546 + (map 547 + (module: let subtree = module.options; in 566 548 if !(builtins.isAttrs subtree) then 567 - throw (if attr == "config" then '' 568 - You're trying to define a value of type `${builtins.typeOf subtree}' 569 - rather than an attribute set for the option 570 - `${builtins.concatStringsSep "." prefix}'! 571 - 572 - This usually happens if `${builtins.concatStringsSep "." prefix}' has option 573 - definitions inside that are not matched. Please check how to properly define 574 - this option by e.g. referring to `man 5 configuration.nix'! 575 - '' else '' 549 + throw '' 576 550 An option declaration for `${builtins.concatStringsSep "." prefix}' has type 577 551 `${builtins.typeOf subtree}' rather than an attribute set. 578 552 Did you mean to define this outside of `options'? 579 - '') 553 + '' 580 554 else 581 - mapAttrs (n: f module) subtree 582 - ) modules); 583 - # an attrset 'name' => list of submodules that declare ‘name’. 584 - declsByName = byName "options" (module: option: 585 - [{ inherit (module) _file; options = option; }] 586 - ) options; 555 + mapAttrs 556 + (n: option: 557 + [{ inherit (module) _file; options = option; }] 558 + ) 559 + subtree 560 + ) 561 + options); 562 + 563 + # The root of any module definition must be an attrset. 564 + checkedConfigs = 565 + assert 566 + lib.all 567 + (c: 568 + # TODO: I have my doubts that this error would occur when option definitions are not matched. 569 + # The implementation of this check used to be tied to a superficially similar check for 570 + # options, so maybe that's why this is here. 571 + isAttrs c.config || throw '' 572 + In module `${c.file}', you're trying to define a value of type `${builtins.typeOf c.config}' 573 + rather than an attribute set for the option 574 + `${builtins.concatStringsSep "." prefix}'! 575 + 576 + This usually happens if `${builtins.concatStringsSep "." prefix}' has option 577 + definitions inside that are not matched. Please check how to properly define 578 + this option by e.g. referring to `man 5 configuration.nix'! 579 + '' 580 + ) 581 + configs; 582 + configs; 583 + 587 584 # an attrset 'name' => list of submodules that define ‘name’. 588 - defnsByName = byName "config" (module: value: 589 - map (config: { inherit (module) file; inherit config; }) (pushDownProperties value) 590 - ) configs; 585 + pushedDownDefinitionsByName = 586 + zipAttrsWith 587 + (n: concatLists) 588 + (map 589 + (module: 590 + mapAttrs 591 + (n: value: 592 + map (config: { inherit (module) file; inherit config; }) (pushDownProperties value) 593 + ) 594 + module.config 595 + ) 596 + checkedConfigs); 591 597 # extract the definitions for each loc 592 - defnsByName' = byName "config" (module: value: 593 - [{ inherit (module) file; inherit value; }] 594 - ) configs; 598 + rawDefinitionsByName = 599 + zipAttrsWith 600 + (n: concatLists) 601 + (map 602 + (module: 603 + mapAttrs 604 + (n: value: 605 + [{ inherit (module) file; inherit value; }] 606 + ) 607 + module.config 608 + ) 609 + checkedConfigs); 595 610 596 611 # Convert an option tree decl to a submodule option decl 597 612 optionTreeToOption = decl: ··· 613 628 # We're descending into attribute ‘name’. 614 629 let 615 630 loc = prefix ++ [name]; 616 - defns = defnsByName.${name} or []; 617 - defns' = defnsByName'.${name} or []; 631 + defns = pushedDownDefinitionsByName.${name} or []; 632 + defns' = rawDefinitionsByName.${name} or []; 618 633 optionDecls = filter (m: isOption m.options) decls; 619 634 in 620 635 if length optionDecls == length decls then ··· 657 672 # Propagate all unmatched definitions from nested option sets 658 673 mapAttrs (n: v: v.unmatchedDefns) resultsByName 659 674 # Plus the definitions for the current prefix that don't have a matching option 660 - // removeAttrs defnsByName' (attrNames matchedOptions); 675 + // removeAttrs rawDefinitionsByName (attrNames matchedOptions); 661 676 in { 662 677 inherit matchedOptions; 663 678
+1 -1
lib/tests/modules.sh
··· 207 207 ## shorthandOnlyDefines config behaves as expected 208 208 checkConfigOutput '^true$' config.submodule.config ./declare-submoduleWith-shorthand.nix ./define-submoduleWith-shorthand.nix 209 209 checkConfigError 'is not of type `boolean' config.submodule.config ./declare-submoduleWith-shorthand.nix ./define-submoduleWith-noshorthand.nix 210 - checkConfigError "You're trying to define a value of type \`bool'\n\s*rather than an attribute set for the option" config.submodule.config ./declare-submoduleWith-noshorthand.nix ./define-submoduleWith-shorthand.nix 210 + checkConfigError "In module ..*define-submoduleWith-shorthand.nix., you're trying to define a value of type \`bool'\n\s*rather than an attribute set for the option" config.submodule.config ./declare-submoduleWith-noshorthand.nix ./define-submoduleWith-shorthand.nix 211 211 checkConfigOutput '^true$' config.submodule.config ./declare-submoduleWith-noshorthand.nix ./define-submoduleWith-noshorthand.nix 212 212 213 213 ## submoduleWith should merge all modules in one swoop