summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/modules.nix21
-rw-r--r--lib/types.nix21
2 files changed, 35 insertions, 7 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index 31134c66276b..1d428311cd19 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -144,7 +144,8 @@ rec {
opt.options ? example && res ? example ||
opt.options ? description && res ? description ||
opt.options ? apply && res ? apply ||
- opt.options ? type && res ? type
+ # Accept to merge options which have identical types.
+ opt.options ? type && res ? type && opt.options.type.name != res.type.name
then
throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}."
else
@@ -155,12 +156,16 @@ rec {
current option declaration as the file use for the submodule. If the
submodule defines any filename, then we ignore the enclosing option file. */
options' = toList opt.options.options;
+ addModuleFile = m:
+ if isFunction m then args: { _file = opt.file; } // (m args)
+ else { _file = opt.file; } // m;
coerceOption = file: opt:
if isFunction opt then args: { _file = file; } // (opt args)
- else args: { _file = file; options = opt; };
+ else { _file = file; options = opt; };
+ getSubModules = opt.options.type.getSubModules or null;
submodules =
- if opt.options ? options
- then map (coerceOption opt.file) options' ++ res.options
+ if getSubModules != null then map addModuleFile getSubModules ++ res.options
+ else if opt.options ? options then map (coerceOption opt.file) options' ++ res.options
else res.options;
in opt.options // res //
{ declarations = [opt.file] ++ res.declarations;
@@ -292,7 +297,8 @@ rec {
in sort compare defs';
/* Hack for backward compatibility: convert options of type
- optionSet to configOf. FIXME: remove eventually. */
+ optionSet to options of type submodule. FIXME: remove
+ eventually. */
fixupOptionType = loc: opt:
let
options = opt.options or
@@ -305,7 +311,10 @@ rec {
else if tp.name == "list of option sets" then types.listOf (types.submodule options)
else if tp.name == "null or option set" then types.nullOr (types.submodule options)
else tp;
- in opt // { type = f (opt.type or types.unspecified); };
+ in
+ if opt.type.getSubModules or null == null
+ then opt // { type = f (opt.type or types.unspecified); }
+ else opt // { type = opt.type.substSubModules opt.options; options = []; };
/* Properties. */
diff --git a/lib/types.nix b/lib/types.nix
index 0e2b6515e165..783e07cdc721 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -33,9 +33,14 @@ rec {
, # Return a flat list of sub-options. Used to generate
# documentation.
getSubOptions ? prefix: {}
+ , # List of modules if any, or null if none.
+ getSubModules ? null
+ , # Function for building the same option type with a different list of
+ # modules.
+ substSubModules ? m: null
}:
{ _type = "option-type";
- inherit name check merge getSubOptions;
+ inherit name check merge getSubOptions getSubModules substSubModules;
};
@@ -110,6 +115,8 @@ rec {
elemType.merge (loc ++ ["[${toString n}-${toString m}]"])
[{ inherit (def) file; value = def'; }]) def.value) defs);
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
+ getSubModules = elemType.getSubModules;
+ substSubModules = m: listOf (elemType.substSubModules m);
};
attrsOf = elemType: mkOptionType {
@@ -121,6 +128,8 @@ rec {
(map (def: listToAttrs (mapAttrsToList (n: def':
{ name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs);
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
+ getSubModules = elemType.getSubModules;
+ substSubModules = m: attrsOf (elemType.substSubModules m);
};
# List or attribute set of ...
@@ -147,12 +156,16 @@ rec {
else false;
merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
+ getSubModules = elemType.getSubModules;
+ substSubModules = m: loaOf (elemType.substSubModules m);
};
uniq = elemType: mkOptionType {
inherit (elemType) name check;
merge = mergeOneOption;
getSubOptions = elemType.getSubOptions;
+ getSubModules = elemType.getSubModules;
+ substSubModules = m: uniq (elemType.substSubModules m);
};
nullOr = elemType: mkOptionType {
@@ -165,6 +178,8 @@ rec {
throw "The option `${showOption loc}' is defined both null and not null, in ${showFiles (getFiles defs)}."
else elemType.merge loc defs;
getSubOptions = elemType.getSubOptions;
+ getSubModules = elemType.getSubModules;
+ substSubModules = m: nullOr (elemType.substSubModules m);
};
functionTo = elemType: mkOptionType {
@@ -173,6 +188,8 @@ rec {
merge = loc: defs:
fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
getSubOptions = elemType.getSubOptions;
+ getSubModules = elemType.getSubModules;
+ substSubModules = m: functionTo (elemType.substSubModules m);
};
submodule = opts:
@@ -192,6 +209,8 @@ rec {
{ modules = opts'; inherit prefix;
# FIXME: hack to get shit to evaluate.
args = { name = ""; }; }).options;
+ getSubModules = opts';
+ substSubModules = m: submodule m;
};
enum = values: mkOptionType {