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
This commit is contained in:
parent
bb9a37a2a5
commit
d88721e440
@ -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
|
||||
|
@ -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.*:' "$@"
|
||||
|
@ -3,5 +3,6 @@
|
||||
{
|
||||
inherit (lib.evalModules {
|
||||
inherit modules;
|
||||
specialArgs.modulesPath = ./.;
|
||||
}) config options;
|
||||
}
|
||||
|
5
lib/tests/modules/disable-declare-enable.nix
Normal file
5
lib/tests/modules/disable-declare-enable.nix
Normal file
@ -0,0 +1,5 @@
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
disabledModules = [ ./declare-enable.nix ];
|
||||
}
|
5
lib/tests/modules/disable-define-enable.nix
Normal file
5
lib/tests/modules/disable-define-enable.nix
Normal file
@ -0,0 +1,5 @@
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
disabledModules = [ ./define-enable.nix ];
|
||||
}
|
5
lib/tests/modules/disable-enable-modules.nix
Normal file
5
lib/tests/modules/disable-enable-modules.nix
Normal file
@ -0,0 +1,5 @@
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
disabledModules = [ "define-enable.nix" "declare-enable.nix" ];
|
||||
}
|
75
nixos/doc/manual/development/replace-modules.xml
Normal file
75
nixos/doc/manual/development/replace-modules.xml
Normal file
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user