Factor out option renaming

Option aliases/deprecations can now be declared in any NixOS module,
not just in nixos/modules/rename.nix. This is more modular (since it
allows for example grub-related aliases to be declared in the grub
module), and allows aliases outside of NixOS (e.g. in NixOps modules).

The syntax is a bit funky. Ideally we'd have something like:

  options = {
    foo.bar.newOption = mkOption { ... };
    foo.bar.oldOption = mkAliasOption [ "foo" "bar" "newOption" ];
  };

but that's not possible because options cannot define values in
*other* options - you need to have a "config" for that. So instead we
have functions that return a *module*: mkRemovedOptionModule,
mkRenamedOptionModule and mkAliasOptionModule. These can be used via
"imports", e.g.

  imports = [
    (mkAliasOptionModule [ "foo" "bar" "oldOption" ] [ "foo" "bar" "newOption" ]);
  ];

As an added bonus, deprecation warnings now show the file name of the
offending module.

Fixes #10385.
This commit is contained in:
Eelco Dolstra
2015-10-14 18:18:47 +02:00
parent 7b001ed68a
commit 5f077e2296
5 changed files with 155 additions and 150 deletions
+65
View File
@@ -469,6 +469,7 @@ rec {
mkBefore = mkOrder 500;
mkAfter = mkOrder 1500;
# Convenient property used to transfer all definitions and their
# properties from one option to another. This property is useful for
# renaming options, and also for including properties from another module
@@ -498,4 +499,68 @@ rec {
/* Compatibility. */
fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
/* Return a module that causes a warning to be shown if the
specified option is defined. For example,
mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ]
causes a warning if the user defines boot.loader.grub.bootDevice.
*/
mkRemovedOptionModule = optionName:
{ options, ... }:
{ options = setAttrByPath optionName (mkOption {
visible = false;
});
config.warnings =
let opt = getAttrFromPath optionName options; in
optional opt.isDefined
"The option definition `${showOption optionName}' in ${showFiles opt.files} no longer has any effect; please remove it.";
};
/* Return a module that causes a warning to be shown if the
specified "from" option is defined; the defined value is however
forwarded to the "to" option. This can be used to rename options
while providing backward compatibility. For example,
mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
forwards any definitions of boot.copyKernels to
boot.loader.grub.copyKernels while printing a warning.
*/
mkRenamedOptionModule = from: to: doRename {
inherit from to;
visible = false;
warn = true;
use = builtins.trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
};
/* Like mkRenamedOptionModule, but doesn't show a warning. */
mkAliasOptionModule = from: to: doRename {
inherit from to;
visible = true;
warn = false;
use = id;
};
doRename = { from, to, visible, warn, use }:
let
toOf = attrByPath to
(abort "Renaming error: option `${showOption to}' does not exists.");
in
{ config, options, ... }:
{ options = setAttrByPath from (mkOption {
description = "Alias of <option>${showOption to}</option>.";
apply = x: use (toOf config);
});
config = {
/*
warnings =
let opt = getAttrFromPath from options; in
optional (warn && opt.isDefined)
"The option `${showOption from}' defined in ${showFiles opt.files} has been renamed to `${showOption to}'.";
*/
} // setAttrByPath to (mkAliasDefinitions (getAttrFromPath from options));
};
}