Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)

Merge pull request #76857 from Infinisil/recursive-disableModules

Apply `disabledModules` recursively

authored by

Silvan Mosberger and committed by
GitHub
e9c16ec1 4052aa37

+120 -31
+2 -2
lib/default.nix
··· 101 101 cleanSource sourceByRegex sourceFilesBySuffices 102 102 commitIdFromGitRepo cleanSourceWith pathHasContext 103 103 canCleanSource; 104 - inherit (modules) evalModules closeModules unifyModuleSyntax 104 + inherit (modules) evalModules unifyModuleSyntax 105 105 applyIfFunction mergeModules 106 106 mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions 107 107 pushDownProperties dischargeProperties filterOverrides ··· 110 110 mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions 111 111 mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule 112 112 mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule 113 - mkAliasOptionModule doRename filterModules; 113 + mkAliasOptionModule doRename; 114 114 inherit (options) isOption mkEnableOption mkSinkUndeclaredOptions 115 115 mergeDefaultOption mergeOneOption mergeEqualOption getValues 116 116 getFiles optionAttrSetToDocList optionAttrSetToDocList'
+73 -25
lib/modules.nix
··· 59 59 }; 60 60 }; 61 61 62 - closed = closeModules (modules ++ [ internalModule ]) ({ inherit config options lib; } // specialArgs); 62 + collected = collectModules 63 + (specialArgs.modulesPath or "") 64 + (modules ++ [ internalModule ]) 65 + ({ inherit config options lib; } // specialArgs); 63 66 64 - options = mergeModules prefix (reverseList (filterModules (specialArgs.modulesPath or "") closed)); 67 + options = mergeModules prefix (reverseList collected); 65 68 66 69 # Traverse options and extract the option values into the final 67 70 # config set. At the same time, check whether all option ··· 87 90 result = { inherit options config; }; 88 91 in result; 89 92 93 + # collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ] 94 + # 95 + # Collects all modules recursively through `import` statements, filtering out 96 + # all modules in disabledModules. 97 + collectModules = let 90 98 91 - # Filter disabled modules. Modules can be disabled allowing 92 - # their implementation to be replaced. 93 - filterModules = modulesPath: modules: 94 - let 95 - moduleKey = m: if isString m then toString modulesPath + "/" + m else toString m; 96 - disabledKeys = map moduleKey (concatMap (m: m.disabledModules) modules); 97 - in 98 - filter (m: !(elem m.key disabledKeys)) modules; 99 + # Like unifyModuleSyntax, but also imports paths and calls functions if necessary 100 + loadModule = args: fallbackFile: fallbackKey: m: 101 + if isFunction m || isAttrs m then 102 + unifyModuleSyntax fallbackFile fallbackKey (applyIfFunction fallbackKey m args) 103 + else unifyModuleSyntax (toString m) (toString m) (applyIfFunction (toString m) (import m) args); 104 + 105 + /* 106 + Collects all modules recursively into the form 99 107 100 - /* Close a set of modules under the ‘imports’ relation. */ 101 - closeModules = modules: args: 102 - let 103 - toClosureList = file: parentKey: imap1 (n: x: 104 - if isAttrs x || isFunction x then 105 - let key = "${parentKey}:anon-${toString n}"; in 106 - unifyModuleSyntax file key (applyIfFunction key x args) 107 - else 108 - let file = toString x; key = toString x; in 109 - unifyModuleSyntax file key (applyIfFunction key (import x) args)); 110 - in 111 - builtins.genericClosure { 112 - startSet = toClosureList unknownModule "" modules; 113 - operator = m: toClosureList m._file m.key m.imports; 114 - }; 108 + { 109 + disabled = [ <list of disabled modules> ]; 110 + # All modules of the main module list 111 + modules = [ 112 + { 113 + key = <key1>; 114 + module = <module for key1>; 115 + # All modules imported by the module for key1 116 + modules = [ 117 + { 118 + key = <key1-1>; 119 + module = <module for key1-1>; 120 + # All modules imported by the module for key1-1 121 + modules = [ ... ]; 122 + } 123 + ... 124 + ]; 125 + } 126 + ... 127 + ]; 128 + } 129 + */ 130 + collectStructuredModules = 131 + let 132 + collectResults = modules: { 133 + disabled = concatLists (catAttrs "disabled" modules); 134 + inherit modules; 135 + }; 136 + in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x: 137 + let 138 + module = loadModule args parentFile "${parentKey}:anon-${toString n}" x; 139 + collectedImports = collectStructuredModules module._file module.key module.imports args; 140 + in { 141 + key = module.key; 142 + module = module; 143 + modules = collectedImports.modules; 144 + disabled = module.disabledModules ++ collectedImports.disabled; 145 + }) initialModules); 146 + 147 + # filterModules :: String -> { disabled, modules } -> [ Module ] 148 + # 149 + # Filters a structure as emitted by collectStructuredModules by removing all disabled 150 + # modules recursively. It returns the final list of unique-by-key modules 151 + filterModules = modulesPath: { disabled, modules }: 152 + let 153 + moduleKey = m: if isString m then toString modulesPath + "/" + m else toString m; 154 + disabledKeys = listToAttrs (map (k: nameValuePair (moduleKey k) null) disabled); 155 + keyFilter = filter (attrs: ! disabledKeys ? ${attrs.key}); 156 + in map (attrs: attrs.module) (builtins.genericClosure { 157 + startSet = keyFilter modules; 158 + operator = attrs: keyFilter attrs.modules; 159 + }); 160 + 161 + in modulesPath: initialModules: args: 162 + filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args); 115 163 116 164 /* Massage a module into canonical form, that is, a set consisting 117 165 of ‘options’, ‘config’ and ‘imports’ attributes. */
+6
lib/tests/modules.sh
··· 177 177 # Temporarily disabled until https://github.com/NixOS/nixpkgs/pull/76861 178 178 #checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix 179 179 180 + # Check that disabledModules works recursively and correctly 181 + checkConfigOutput "true" config.enable ./disable-recursive/main.nix 182 + checkConfigOutput "true" config.enable ./disable-recursive/{main.nix,disable-foo.nix} 183 + checkConfigOutput "true" config.enable ./disable-recursive/{main.nix,disable-bar.nix} 184 + checkConfigError 'The option .* defined in .* does not exist' config.enable ./disable-recursive/{main.nix,disable-foo.nix,disable-bar.nix} 185 + 180 186 cat <<EOF 181 187 ====== module tests ====== 182 188 $pass Pass
+5
lib/tests/modules/disable-recursive/bar.nix
··· 1 + { 2 + imports = [ 3 + ../declare-enable.nix 4 + ]; 5 + }
+7
lib/tests/modules/disable-recursive/disable-bar.nix
··· 1 + { 2 + 3 + disabledModules = [ 4 + ./bar.nix 5 + ]; 6 + 7 + }
+7
lib/tests/modules/disable-recursive/disable-foo.nix
··· 1 + { 2 + 3 + disabledModules = [ 4 + ./foo.nix 5 + ]; 6 + 7 + }
+5
lib/tests/modules/disable-recursive/foo.nix
··· 1 + { 2 + imports = [ 3 + ../declare-enable.nix 4 + ]; 5 + }
+8
lib/tests/modules/disable-recursive/main.nix
··· 1 + { 2 + imports = [ 3 + ./foo.nix 4 + ./bar.nix 5 + ]; 6 + 7 + enable = true; 8 + }
+2 -2
nixos/doc/manual/development/replace-modules.xml
··· 6 6 <title>Replace Modules</title> 7 7 8 8 <para> 9 - Modules that are imported can also be disabled. The option declarations and 10 - config implementation of a disabled module will be ignored, allowing another 9 + Modules that are imported can also be disabled. The option declarations, 10 + config implementation and the imports of a disabled module will be ignored, allowing another 11 11 to take it's place. This can be used to import a set of modules from another 12 12 channel while keeping the rest of the system on a stable release. 13 13 </para>
+5 -2
nixos/modules/misc/documentation.nix
··· 1 - { config, lib, pkgs, baseModules, extraModules, modules, ... }: 1 + { config, lib, pkgs, baseModules, extraModules, modules, modulesPath, ... }: 2 2 3 3 with lib; 4 4 ··· 22 22 scrubbedEval = evalModules { 23 23 modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules; 24 24 args = (config._module.args) // { modules = [ ]; }; 25 - specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; }; 25 + specialArgs = { 26 + pkgs = scrubDerivations "pkgs" pkgs; 27 + inherit modulesPath; 28 + }; 26 29 }; 27 30 scrubDerivations = namePrefix: pkgSet: mapAttrs 28 31 (name: value: