Merge pull request #3856 from nbp/submodule-declarations
Annotate option-set options with the file in which they are declared.
This commit is contained in:
commit
388b7baa73
@ -132,20 +132,44 @@ rec {
|
|||||||
The exception is the ‘options’ attribute, which specifies
|
The exception is the ‘options’ attribute, which specifies
|
||||||
sub-options. These can be specified multiple times to allow one
|
sub-options. These can be specified multiple times to allow one
|
||||||
module to add sub-options to an option declared somewhere else
|
module to add sub-options to an option declared somewhere else
|
||||||
(e.g. multiple modules define sub-options for ‘fileSystems’). */
|
(e.g. multiple modules define sub-options for ‘fileSystems’).
|
||||||
|
|
||||||
|
'loc' is the list of attribute names where the option is located.
|
||||||
|
|
||||||
|
'opts' is a list of modules. Each module has an options attribute which
|
||||||
|
correspond to the definition of 'loc' in 'opt.file'. */
|
||||||
mergeOptionDecls = loc: opts:
|
mergeOptionDecls = loc: opts:
|
||||||
fold (opt: res:
|
fold (opt: res:
|
||||||
if opt.options ? default && res ? default ||
|
if opt.options ? default && res ? default ||
|
||||||
opt.options ? example && res ? example ||
|
opt.options ? example && res ? example ||
|
||||||
opt.options ? description && res ? description ||
|
opt.options ? description && res ? description ||
|
||||||
opt.options ? apply && res ? apply ||
|
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
|
then
|
||||||
throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}."
|
throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}."
|
||||||
else
|
else
|
||||||
opt.options // res //
|
let
|
||||||
|
/* Add the modules of the current option to the list of modules
|
||||||
|
already collected. The options attribute except either a list of
|
||||||
|
submodules or a submodule. For each submodule, we add the file of the
|
||||||
|
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 { _file = file; options = opt; };
|
||||||
|
getSubModules = opt.options.type.getSubModules or null;
|
||||||
|
submodules =
|
||||||
|
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;
|
{ declarations = [opt.file] ++ res.declarations;
|
||||||
options = if opt.options ? options then [(toList opt.options.options ++ res.options)] else [];
|
options = submodules;
|
||||||
}
|
}
|
||||||
) { inherit loc; declarations = []; options = []; } opts;
|
) { inherit loc; declarations = []; options = []; } opts;
|
||||||
|
|
||||||
@ -273,15 +297,12 @@ rec {
|
|||||||
in sort compare defs';
|
in sort compare defs';
|
||||||
|
|
||||||
/* Hack for backward compatibility: convert options of type
|
/* 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:
|
fixupOptionType = loc: opt:
|
||||||
let
|
let
|
||||||
options' = opt.options or
|
options = opt.options or
|
||||||
(throw "Option `${showOption loc'}' has type optionSet but has no option attribute, in ${showFiles opt.declarations}.");
|
(throw "Option `${showOption loc'}' has type optionSet but has no option attribute, in ${showFiles opt.declarations}.");
|
||||||
coerce = x:
|
|
||||||
if isFunction x then x
|
|
||||||
else { config, ... }: { options = x; };
|
|
||||||
options = map coerce (flatten options');
|
|
||||||
f = tp:
|
f = tp:
|
||||||
if tp.name == "option set" || tp.name == "submodule" then
|
if tp.name == "option set" || tp.name == "submodule" then
|
||||||
throw "The option ${showOption loc} uses submodules without a wrapping type, in ${showFiles opt.declarations}."
|
throw "The option ${showOption loc} uses submodules without a wrapping type, in ${showFiles opt.declarations}."
|
||||||
@ -290,7 +311,10 @@ rec {
|
|||||||
else if tp.name == "list of option sets" then types.listOf (types.submodule options)
|
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 if tp.name == "null or option set" then types.nullOr (types.submodule options)
|
||||||
else tp;
|
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. */
|
/* Properties. */
|
||||||
|
|||||||
@ -33,9 +33,14 @@ rec {
|
|||||||
, # Return a flat list of sub-options. Used to generate
|
, # Return a flat list of sub-options. Used to generate
|
||||||
# documentation.
|
# documentation.
|
||||||
getSubOptions ? prefix: {}
|
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";
|
{ _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}]"])
|
elemType.merge (loc ++ ["[${toString n}-${toString m}]"])
|
||||||
[{ inherit (def) file; value = def'; }]) def.value) defs);
|
[{ inherit (def) file; value = def'; }]) def.value) defs);
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
|
||||||
|
getSubModules = elemType.getSubModules;
|
||||||
|
substSubModules = m: listOf (elemType.substSubModules m);
|
||||||
};
|
};
|
||||||
|
|
||||||
attrsOf = elemType: mkOptionType {
|
attrsOf = elemType: mkOptionType {
|
||||||
@ -121,6 +128,8 @@ rec {
|
|||||||
(map (def: listToAttrs (mapAttrsToList (n: def':
|
(map (def: listToAttrs (mapAttrsToList (n: def':
|
||||||
{ name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs);
|
{ name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs);
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
||||||
|
getSubModules = elemType.getSubModules;
|
||||||
|
substSubModules = m: attrsOf (elemType.substSubModules m);
|
||||||
};
|
};
|
||||||
|
|
||||||
# List or attribute set of ...
|
# List or attribute set of ...
|
||||||
@ -147,12 +156,16 @@ rec {
|
|||||||
else false;
|
else false;
|
||||||
merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
|
merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
|
||||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
|
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
|
||||||
|
getSubModules = elemType.getSubModules;
|
||||||
|
substSubModules = m: loaOf (elemType.substSubModules m);
|
||||||
};
|
};
|
||||||
|
|
||||||
uniq = elemType: mkOptionType {
|
uniq = elemType: mkOptionType {
|
||||||
inherit (elemType) name check;
|
inherit (elemType) name check;
|
||||||
merge = mergeOneOption;
|
merge = mergeOneOption;
|
||||||
getSubOptions = elemType.getSubOptions;
|
getSubOptions = elemType.getSubOptions;
|
||||||
|
getSubModules = elemType.getSubModules;
|
||||||
|
substSubModules = m: uniq (elemType.substSubModules m);
|
||||||
};
|
};
|
||||||
|
|
||||||
nullOr = elemType: mkOptionType {
|
nullOr = elemType: mkOptionType {
|
||||||
@ -165,6 +178,8 @@ rec {
|
|||||||
throw "The option `${showOption loc}' is defined both null and not null, in ${showFiles (getFiles defs)}."
|
throw "The option `${showOption loc}' is defined both null and not null, in ${showFiles (getFiles defs)}."
|
||||||
else elemType.merge loc defs;
|
else elemType.merge loc defs;
|
||||||
getSubOptions = elemType.getSubOptions;
|
getSubOptions = elemType.getSubOptions;
|
||||||
|
getSubModules = elemType.getSubModules;
|
||||||
|
substSubModules = m: nullOr (elemType.substSubModules m);
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTo = elemType: mkOptionType {
|
functionTo = elemType: mkOptionType {
|
||||||
@ -173,6 +188,8 @@ rec {
|
|||||||
merge = loc: defs:
|
merge = loc: defs:
|
||||||
fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
|
fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
|
||||||
getSubOptions = elemType.getSubOptions;
|
getSubOptions = elemType.getSubOptions;
|
||||||
|
getSubModules = elemType.getSubModules;
|
||||||
|
substSubModules = m: functionTo (elemType.substSubModules m);
|
||||||
};
|
};
|
||||||
|
|
||||||
submodule = opts:
|
submodule = opts:
|
||||||
@ -192,6 +209,8 @@ rec {
|
|||||||
{ modules = opts'; inherit prefix;
|
{ modules = opts'; inherit prefix;
|
||||||
# FIXME: hack to get shit to evaluate.
|
# FIXME: hack to get shit to evaluate.
|
||||||
args = { name = ""; }; }).options;
|
args = { name = ""; }; }).options;
|
||||||
|
getSubModules = opts';
|
||||||
|
substSubModules = m: submodule m;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum = values: mkOptionType {
|
enum = values: mkOptionType {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user