Merge pull request #76857 from Infinisil/recursive-disableModules

Apply `disabledModules` recursively
This commit is contained in:
Silvan Mosberger 2020-01-09 18:20:12 +01:00 committed by GitHub
commit e9c16ec186
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 120 additions and 31 deletions

View file

@ -101,7 +101,7 @@ let
cleanSource sourceByRegex sourceFilesBySuffices cleanSource sourceByRegex sourceFilesBySuffices
commitIdFromGitRepo cleanSourceWith pathHasContext commitIdFromGitRepo cleanSourceWith pathHasContext
canCleanSource; canCleanSource;
inherit (modules) evalModules closeModules unifyModuleSyntax inherit (modules) evalModules unifyModuleSyntax
applyIfFunction mergeModules applyIfFunction mergeModules
mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
pushDownProperties dischargeProperties filterOverrides pushDownProperties dischargeProperties filterOverrides
@ -110,7 +110,7 @@ let
mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions
mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule
mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule
mkAliasOptionModule doRename filterModules; mkAliasOptionModule doRename;
inherit (options) isOption mkEnableOption mkSinkUndeclaredOptions inherit (options) isOption mkEnableOption mkSinkUndeclaredOptions
mergeDefaultOption mergeOneOption mergeEqualOption getValues mergeDefaultOption mergeOneOption mergeEqualOption getValues
getFiles optionAttrSetToDocList optionAttrSetToDocList' getFiles optionAttrSetToDocList optionAttrSetToDocList'

View file

@ -59,9 +59,12 @@ rec {
}; };
}; };
closed = closeModules (modules ++ [ internalModule ]) ({ inherit config options lib; } // specialArgs); collected = collectModules
(specialArgs.modulesPath or "")
(modules ++ [ internalModule ])
({ inherit config options lib; } // specialArgs);
options = mergeModules prefix (reverseList (filterModules (specialArgs.modulesPath or "") closed)); options = mergeModules prefix (reverseList collected);
# Traverse options and extract the option values into the final # Traverse options and extract the option values into the final
# config set. At the same time, check whether all option # config set. At the same time, check whether all option
@ -87,31 +90,76 @@ rec {
result = { inherit options config; }; result = { inherit options config; };
in result; in result;
# collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
#
# Collects all modules recursively through `import` statements, filtering out
# all modules in disabledModules.
collectModules = let
# Filter disabled modules. Modules can be disabled allowing # Like unifyModuleSyntax, but also imports paths and calls functions if necessary
# their implementation to be replaced. loadModule = args: fallbackFile: fallbackKey: m:
filterModules = modulesPath: modules: if isFunction m || isAttrs m then
let unifyModuleSyntax fallbackFile fallbackKey (applyIfFunction fallbackKey m args)
moduleKey = m: if isString m then toString modulesPath + "/" + m else toString m; else unifyModuleSyntax (toString m) (toString m) (applyIfFunction (toString m) (import m) args);
disabledKeys = map moduleKey (concatMap (m: m.disabledModules) modules);
in
filter (m: !(elem m.key disabledKeys)) modules;
/* Close a set of modules under the imports relation. */ /*
closeModules = modules: args: Collects all modules recursively into the form
let
toClosureList = file: parentKey: imap1 (n: x: {
if isAttrs x || isFunction x then disabled = [ <list of disabled modules> ];
let key = "${parentKey}:anon-${toString n}"; in # All modules of the main module list
unifyModuleSyntax file key (applyIfFunction key x args) modules = [
else {
let file = toString x; key = toString x; in key = <key1>;
unifyModuleSyntax file key (applyIfFunction key (import x) args)); module = <module for key1>;
in # All modules imported by the module for key1
builtins.genericClosure { modules = [
startSet = toClosureList unknownModule "" modules; {
operator = m: toClosureList m._file m.key m.imports; key = <key1-1>;
}; module = <module for key1-1>;
# All modules imported by the module for key1-1
modules = [ ... ];
}
...
];
}
...
];
}
*/
collectStructuredModules =
let
collectResults = modules: {
disabled = concatLists (catAttrs "disabled" modules);
inherit modules;
};
in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x:
let
module = loadModule args parentFile "${parentKey}:anon-${toString n}" x;
collectedImports = collectStructuredModules module._file module.key module.imports args;
in {
key = module.key;
module = module;
modules = collectedImports.modules;
disabled = module.disabledModules ++ collectedImports.disabled;
}) initialModules);
# filterModules :: String -> { disabled, modules } -> [ Module ]
#
# Filters a structure as emitted by collectStructuredModules by removing all disabled
# modules recursively. It returns the final list of unique-by-key modules
filterModules = modulesPath: { disabled, modules }:
let
moduleKey = m: if isString m then toString modulesPath + "/" + m else toString m;
disabledKeys = listToAttrs (map (k: nameValuePair (moduleKey k) null) disabled);
keyFilter = filter (attrs: ! disabledKeys ? ${attrs.key});
in map (attrs: attrs.module) (builtins.genericClosure {
startSet = keyFilter modules;
operator = attrs: keyFilter attrs.modules;
});
in modulesPath: initialModules: args:
filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
/* Massage a module into canonical form, that is, a set consisting /* Massage a module into canonical form, that is, a set consisting
of options, config and imports attributes. */ of options, config and imports attributes. */

View file

@ -177,6 +177,12 @@ checkConfigOutput "true" config.submodule.outer ./declare-submoduleWith-modules.
# Temporarily disabled until https://github.com/NixOS/nixpkgs/pull/76861 # Temporarily disabled until https://github.com/NixOS/nixpkgs/pull/76861
#checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix #checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix
# Check that disabledModules works recursively and correctly
checkConfigOutput "true" config.enable ./disable-recursive/main.nix
checkConfigOutput "true" config.enable ./disable-recursive/{main.nix,disable-foo.nix}
checkConfigOutput "true" config.enable ./disable-recursive/{main.nix,disable-bar.nix}
checkConfigError 'The option .* defined in .* does not exist' config.enable ./disable-recursive/{main.nix,disable-foo.nix,disable-bar.nix}
cat <<EOF cat <<EOF
====== module tests ====== ====== module tests ======
$pass Pass $pass Pass

View file

@ -0,0 +1,5 @@
{
imports = [
../declare-enable.nix
];
}

View file

@ -0,0 +1,7 @@
{
disabledModules = [
./bar.nix
];
}

View file

@ -0,0 +1,7 @@
{
disabledModules = [
./foo.nix
];
}

View file

@ -0,0 +1,5 @@
{
imports = [
../declare-enable.nix
];
}

View file

@ -0,0 +1,8 @@
{
imports = [
./foo.nix
./bar.nix
];
enable = true;
}

View file

@ -6,8 +6,8 @@
<title>Replace Modules</title> <title>Replace Modules</title>
<para> <para>
Modules that are imported can also be disabled. The option declarations and Modules that are imported can also be disabled. The option declarations,
config implementation of a disabled module will be ignored, allowing another config implementation and the imports of a disabled module will be ignored, allowing another
to take it's place. This can be used to import a set of modules from another to take it's place. This can be used to import a set of modules from another
channel while keeping the rest of the system on a stable release. channel while keeping the rest of the system on a stable release.
</para> </para>

View file

@ -1,4 +1,4 @@
{ config, lib, pkgs, baseModules, extraModules, modules, ... }: { config, lib, pkgs, baseModules, extraModules, modules, modulesPath, ... }:
with lib; with lib;
@ -22,7 +22,10 @@ let
scrubbedEval = evalModules { scrubbedEval = evalModules {
modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules; modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules;
args = (config._module.args) // { modules = [ ]; }; args = (config._module.args) // { modules = [ ]; };
specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; }; specialArgs = {
pkgs = scrubDerivations "pkgs" pkgs;
inherit modulesPath;
};
}; };
scrubDerivations = namePrefix: pkgSet: mapAttrs scrubDerivations = namePrefix: pkgSet: mapAttrs
(name: value: (name: value: