diff options
author | Daiderd Jordan <daiderd@gmail.com> | 2017-02-14 23:18:44 +0100 |
---|---|---|
committer | Vladimír Čunát <vcunat@gmail.com> | 2017-03-03 13:45:22 +0100 |
commit | d88721e4408988202a0ae3cea3f5551ebfa13168 (patch) | |
tree | 5eca06d1133b1615b7c6e667ba7c42f7e97548b3 | |
parent | bb9a37a2a56249483cd98ef09c254b78e736af1a (diff) |
modules: add support for module replacement with disabledModules
This is based on a prototype Nicolas B. Pierron worked on during a discussion we had at FOSDEM. A new version with a workaround for problems of the reverted original. Discussion: https://github.com/NixOS/nixpkgs/commit/3f2566689
-rw-r--r-- | lib/modules.nix | 24 | ||||
-rwxr-xr-x | lib/tests/modules.sh | 8 | ||||
-rw-r--r-- | lib/tests/modules/default.nix | 1 | ||||
-rw-r--r-- | lib/tests/modules/disable-declare-enable.nix | 5 | ||||
-rw-r--r-- | lib/tests/modules/disable-define-enable.nix | 5 | ||||
-rw-r--r-- | lib/tests/modules/disable-enable-modules.nix | 5 | ||||
-rw-r--r-- | nixos/doc/manual/development/replace-modules.xml | 75 | ||||
-rw-r--r-- | nixos/doc/manual/development/writing-modules.xml | 1 | ||||
-rw-r--r-- | nixos/doc/manual/release-notes/rl-1703.xml | 10 |
9 files changed, 127 insertions, 7 deletions
diff --git a/lib/modules.nix b/lib/modules.nix index 4eee41306cd7f..a7c397d2cf433 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -20,7 +20,8 @@ rec { , prefix ? [] , # This should only be used for special arguments that need to be evaluated # when resolving module structure (like in imports). For everything else, - # there's _module.args. + # there's _module.args. If specialArgs.modulesPath is defined it will be + # used as the base path for disabledModules. specialArgs ? {} , # This would be remove in the future, Prefer _module.args option instead. args ? {} @@ -58,10 +59,7 @@ rec { closed = closeModules (modules ++ [ internalModule ]) ({ inherit config options; lib = import ./.; } // specialArgs); - # Note: the list of modules is reversed to maintain backward - # compatibility with the old module system. Not sure if this is - # the most sensible policy. - options = mergeModules prefix (reverseList closed); + options = mergeModules prefix (reverseList (filterModules (specialArgs.modulesPath or "") closed)); # Traverse options and extract the option values into the final # config set. At the same time, check whether all option @@ -87,6 +85,16 @@ rec { result = { inherit options config; }; in result; + + # Filter disabled modules. Modules can be disabled allowing + # their implementation to be replaced. + filterModules = modulesPath: modules: + let + moduleKey = m: if isString m then toString modulesPath + "/" + m else toString m; + 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: let @@ -111,12 +119,13 @@ rec { else {}; in if m ? config || m ? options then - let badAttrs = removeAttrs m ["imports" "options" "config" "key" "_file" "meta"]; in + let badAttrs = removeAttrs m ["_file" "key" "disabledModules" "imports" "options" "config" "meta"]; in if badAttrs != {} then throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by assignments to the top-level attributes `config' or `options'." else { file = m._file or file; key = toString m.key or key; + disabledModules = m.disabledModules or []; imports = m.imports or []; options = m.options or {}; config = mkMerge [ (m.config or {}) metaSet ]; @@ -124,9 +133,10 @@ rec { else { file = m._file or file; key = toString m.key or key; + disabledModules = m.disabledModules or []; imports = m.require or [] ++ m.imports or []; options = {}; - config = mkMerge [ (removeAttrs m ["key" "_file" "require" "imports"]) metaSet ]; + config = mkMerge [ (removeAttrs m ["_file" "key" "disabledModules" "require" "imports"]) metaSet ]; }; applyIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index 8b476a5d3dcc4..ba0c67fb7d421 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -99,6 +99,14 @@ checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-if-foo-enabl checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-foo-if-enable.nix checkConfigOutput 'true' "$@" ./define-enable.nix ./define-loaOfSub-foo-enable-if.nix +# Check disabledModules with config definitions and option declarations. +set -- config.enable ./define-enable.nix ./declare-enable.nix +checkConfigOutput "true" "$@" +checkConfigOutput "false" "$@" ./disable-define-enable.nix +checkConfigError "The option .*enable.* defined in .* does not exist" "$@" ./disable-declare-enable.nix +checkConfigError "attribute .*enable.* in selection path .*config.enable.* not found" "$@" ./disable-define-enable.nix ./disable-declare-enable.nix +checkConfigError "attribute .*enable.* in selection path .*config.enable.* not found" "$@" ./disable-enable-modules.nix + # Check _module.args. set -- config.enable ./declare-enable.nix ./define-enable-with-custom-arg.nix checkConfigError 'while evaluating the module argument .*custom.* in .*define-enable-with-custom-arg.nix.*:' "$@" diff --git a/lib/tests/modules/default.nix b/lib/tests/modules/default.nix index c5ce9cb3e3b80..5b0947104198c 100644 --- a/lib/tests/modules/default.nix +++ b/lib/tests/modules/default.nix @@ -3,5 +3,6 @@ { inherit (lib.evalModules { inherit modules; + specialArgs.modulesPath = ./.; }) config options; } diff --git a/lib/tests/modules/disable-declare-enable.nix b/lib/tests/modules/disable-declare-enable.nix new file mode 100644 index 0000000000000..a373ee7e550eb --- /dev/null +++ b/lib/tests/modules/disable-declare-enable.nix @@ -0,0 +1,5 @@ +{ lib, ... }: + +{ + disabledModules = [ ./declare-enable.nix ]; +} diff --git a/lib/tests/modules/disable-define-enable.nix b/lib/tests/modules/disable-define-enable.nix new file mode 100644 index 0000000000000..0d84a7c3cb6c8 --- /dev/null +++ b/lib/tests/modules/disable-define-enable.nix @@ -0,0 +1,5 @@ +{ lib, ... }: + +{ + disabledModules = [ ./define-enable.nix ]; +} diff --git a/lib/tests/modules/disable-enable-modules.nix b/lib/tests/modules/disable-enable-modules.nix new file mode 100644 index 0000000000000..c325f4e074318 --- /dev/null +++ b/lib/tests/modules/disable-enable-modules.nix @@ -0,0 +1,5 @@ +{ lib, ... }: + +{ + disabledModules = [ "define-enable.nix" "declare-enable.nix" ]; +} diff --git a/nixos/doc/manual/development/replace-modules.xml b/nixos/doc/manual/development/replace-modules.xml new file mode 100644 index 0000000000000..cc0539ec51092 --- /dev/null +++ b/nixos/doc/manual/development/replace-modules.xml @@ -0,0 +1,75 @@ +<section xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="sec-replace-modules"> + +<title>Replace Modules</title> + +<para>Modules that are imported can also be disabled. The option + declarations and config implementation 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 channel while keeping the rest + of the system on a stable release.</para> +<para><literal>disabledModules</literal> is a top level attribute like + <literal>imports</literal>, <literal>options</literal> and + <literal>config</literal>. It contains a list of modules that will + be disabled. This can either be the full path to the module or a + string with the filename relative to the modules path + (eg. <nixpkgs/nixos/modules> for nixos). + </para> + +<para>This example will replace the existing postgresql module with + the version defined in the nixos-unstable channel while keeping the + rest of the modules and packages from the original nixos channel. + This only overrides the module definition, this won't use postgresql + from nixos-unstable unless explicitly configured to do so.</para> + +<programlisting> +{ config, lib, pkgs, ... }: + +{ + disabledModules = [ "services/databases/postgresql.nix" ]; + + imports = + [ # Use postgresql service from nixos-unstable channel. + # sudo nix-channel --add http://nixos.org/channels/nixos-unstable nixos-unstable + <nixos-unstable/nixos/modules/services/databases/postgresql.nix> + ]; + + services.postgresql.enable = true; +} +</programlisting> + +<para>This example shows how to define a custom module as a + replacement for an existing module. Importing this module will + disable the original module without having to know it's + implementation details.</para> + +<programlisting> +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.man; +in + +{ + disabledModules = [ "services/programs/man.nix" ]; + + options = { + programs.man.enable = mkOption { + type = types.bool; + default = true; + description = "Whether to enable manual pages."; + }; + }; + + config = mkIf cfg.enabled { + warnings = [ "disabled manpages for production deployments." ]; + }; +} +</programlisting> + +</section> diff --git a/nixos/doc/manual/development/writing-modules.xml b/nixos/doc/manual/development/writing-modules.xml index ef6920160e6db..5bdcad5ceb574 100644 --- a/nixos/doc/manual/development/writing-modules.xml +++ b/nixos/doc/manual/development/writing-modules.xml @@ -179,5 +179,6 @@ in { <xi:include href="option-types.xml" /> <xi:include href="option-def.xml" /> <xi:include href="meta-attributes.xml" /> +<xi:include href="replace-modules.xml" /> </chapter> diff --git a/nixos/doc/manual/release-notes/rl-1703.xml b/nixos/doc/manual/release-notes/rl-1703.xml index fda46217144cb..f40b03ec9b992 100644 --- a/nixos/doc/manual/release-notes/rl-1703.xml +++ b/nixos/doc/manual/release-notes/rl-1703.xml @@ -271,6 +271,16 @@ following incompatible changes:</para> </para> </listitem> + <listitem> + <para> + Modules can now be disabled by using <link + xlink:href="https://nixos.org/nixpkgs/manual/#sec-replace-modules"> + disabledModules</link>, allowing 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. + </para> + </listitem> + </itemizedlist> |