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 cleanSource sourceByRegex sourceFilesBySuffices 102 commitIdFromGitRepo cleanSourceWith pathHasContext 103 canCleanSource; 104 - inherit (modules) evalModules closeModules unifyModuleSyntax 105 applyIfFunction mergeModules 106 mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions 107 pushDownProperties dischargeProperties filterOverrides ··· 110 mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions 111 mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule 112 mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule 113 - mkAliasOptionModule doRename filterModules; 114 inherit (options) isOption mkEnableOption mkSinkUndeclaredOptions 115 mergeDefaultOption mergeOneOption mergeEqualOption getValues 116 getFiles optionAttrSetToDocList optionAttrSetToDocList'
··· 101 cleanSource sourceByRegex sourceFilesBySuffices 102 commitIdFromGitRepo cleanSourceWith pathHasContext 103 canCleanSource; 104 + inherit (modules) evalModules unifyModuleSyntax 105 applyIfFunction mergeModules 106 mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions 107 pushDownProperties dischargeProperties filterOverrides ··· 110 mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions 111 mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule 112 mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule 113 + mkAliasOptionModule doRename; 114 inherit (options) isOption mkEnableOption mkSinkUndeclaredOptions 115 mergeDefaultOption mergeOneOption mergeEqualOption getValues 116 getFiles optionAttrSetToDocList optionAttrSetToDocList'
+73 -25
lib/modules.nix
··· 59 }; 60 }; 61 62 - closed = closeModules (modules ++ [ internalModule ]) ({ inherit config options lib; } // specialArgs); 63 64 - options = mergeModules prefix (reverseList (filterModules (specialArgs.modulesPath or "") closed)); 65 66 # Traverse options and extract the option values into the final 67 # config set. At the same time, check whether all option ··· 87 result = { inherit options config; }; 88 in result; 89 90 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 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 - }; 115 116 /* Massage a module into canonical form, that is, a set consisting 117 of ‘options’, ‘config’ and ‘imports’ attributes. */
··· 59 }; 60 }; 61 62 + collected = collectModules 63 + (specialArgs.modulesPath or "") 64 + (modules ++ [ internalModule ]) 65 + ({ inherit config options lib; } // specialArgs); 66 67 + options = mergeModules prefix (reverseList collected); 68 69 # Traverse options and extract the option values into the final 70 # config set. At the same time, check whether all option ··· 90 result = { inherit options config; }; 91 in result; 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 98 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 107 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); 163 164 /* Massage a module into canonical form, that is, a set consisting 165 of ‘options’, ‘config’ and ‘imports’ attributes. */
+6
lib/tests/modules.sh
··· 177 # Temporarily disabled until https://github.com/NixOS/nixpkgs/pull/76861 178 #checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix 179 180 cat <<EOF 181 ====== module tests ====== 182 $pass Pass
··· 177 # Temporarily disabled until https://github.com/NixOS/nixpkgs/pull/76861 178 #checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix 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 + 186 cat <<EOF 187 ====== module tests ====== 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 <title>Replace Modules</title> 7 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 11 to take it's place. This can be used to import a set of modules from another 12 channel while keeping the rest of the system on a stable release. 13 </para>
··· 6 <title>Replace Modules</title> 7 8 <para> 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 to take it's place. This can be used to import a set of modules from another 12 channel while keeping the rest of the system on a stable release. 13 </para>
+5 -2
nixos/modules/misc/documentation.nix
··· 1 - { config, lib, pkgs, baseModules, extraModules, modules, ... }: 2 3 with lib; 4 ··· 22 scrubbedEval = evalModules { 23 modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules; 24 args = (config._module.args) // { modules = [ ]; }; 25 - specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; }; 26 }; 27 scrubDerivations = namePrefix: pkgSet: mapAttrs 28 (name: value:
··· 1 + { config, lib, pkgs, baseModules, extraModules, modules, modulesPath, ... }: 2 3 with lib; 4 ··· 22 scrubbedEval = evalModules { 23 modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules; 24 args = (config._module.args) // { modules = [ ]; }; 25 + specialArgs = { 26 + pkgs = scrubDerivations "pkgs" pkgs; 27 + inherit modulesPath; 28 + }; 29 }; 30 scrubDerivations = namePrefix: pkgSet: mapAttrs 31 (name: value: