factor mergeOptionSets and filterOptionSets into the function handleOptionSets.

svn path=/nixpkgs/trunk/; revision=13838
This commit is contained in:
Nicolas Pierron 2009-01-25 00:31:23 +00:00
parent db7f0d3ef5
commit 13d5c8923d

View file

@ -485,11 +485,11 @@ rec {
else if all __isAttrs list then mergeAttrs list else if all __isAttrs list then mergeAttrs list
else if all (x: true == x || false == x) list then fold logicalOR false list else if all (x: true == x || false == x) list then fold logicalOR false list
else if all (x: x == toString x) list then concatStrings list else if all (x: x == toString x) list then concatStrings list
else abort "${name}: Cannot merge values."; else throw "Cannot merge values.";
mergeTypedOption = typeName: predicate: merge: name: list: mergeTypedOption = typeName: predicate: merge: name: list:
if all predicate list then merge list if all predicate list then merge list
else abort "${name}: Expect a ${typeName}."; else throw "Expect a ${typeName}.";
mergeEnableOption = mergeTypedOption "boolean" mergeEnableOption = mergeTypedOption "boolean"
(x: true == x || false == x) (fold logicalOR false); (x: true == x || false == x) (fold logicalOR false);
@ -501,38 +501,59 @@ rec {
(x: if builtins ? isString then builtins.isString x else x + "") (x: if builtins ? isString then builtins.isString x else x + "")
concatStrings; concatStrings;
# Merge sets of options and bindings.
# noOption: function to call if no option is declared.
mergeOptionSets = noOption: path: opts:
if all __isAttrs opts then
zip (attr: opts:
let
name = if path == "" then attr else path + "." + attr;
test = partition isOption opts;
opt = ({ merge = mergeDefaultOption; apply = id; } // head test.right);
in
if test.right == [] then mergeOptionSets noOption name (map delayIf test.wrong)
else if tail test.right != [] then throw "Multiple options for '${name}'."
else if test.wrong == [] then opt.apply opt.default
else opt.apply (opt.merge name (map evalIf test.wrong))
) opts
else noOption path opts;
# Keep all option declarations and add an attribute "name" inside # Handle the traversal of option sets. All sets inside 'opts' are zipped
# each option which contains the path that has to be followed to # and options declaration and definition are separated. If no option are
# access it. # declared at a specific depth, then the function recurse into the values.
filterOptionSets = path: opts: # Other cases are handled by the optionHandler which contains two
# functions that are used to defined your goal.
# - export is a function which takes two arguments which are the option
# and the list of values.
# - notHandle is a function which takes the list of values are not handle
# by this function.
handleOptionSets = optionHandler@{export, notHandle, ...}: path: opts:
if all __isAttrs opts then if all __isAttrs opts then
zip (attr: opts: zip (attr: opts:
let let
name = if path == "" then attr else path + "." + attr; name = if path == "" then attr else path + "." + attr;
test = partition isOption opts; test = partition isOption opts;
opt = {
inherit name;
merge = mergeDefaultOption;
apply = id;
} // (head test.right);
in in
if test.right == [] then filterOptionSets name (map delayIf test.wrong) if test.right == [] then handleOptionSets optionHandler name (map delayIf test.wrong)
else if tail test.right != [] then throw "Multiple options for '${name}'." else addLocation "while evaluating the option ${name}:" (
else { inherit name; } // (head test.right) if tail test.right != [] then throw "Multiple options."
else export opt (map evalIf test.wrong)
)
) opts ) opts
else {}; else addLocation "while evaluating ${path}:" (notHandle opts);
# Merge option sets and produce a set of values which is the merging of
# all options declare and defined. If no values are defined for an
# option, then the default value is used otherwise it use the merge
# function of each option to get the result.
mergeOptionSets = noOption: newMergeOptionSets; # ignore argument
newMergeOptionSets =
handleOptionSets {
export = opt: values:
opt.apply (
if values == [] then
if opt ? default then opt.default
else throw "Not defined."
else opt.merge (opt.name) values
);
notHandle = throw "Used without option declaration.";
};
# Keep all option declarations.
filterOptionSets =
handleOptionSets {
export = opt: values: opt;
notHandle = {};
};
# Evaluate a list of option sets that would be merged with the # Evaluate a list of option sets that would be merged with the
# function "merge" which expects two arguments. The attribute named # function "merge" which expects two arguments. The attribute named
@ -550,11 +571,11 @@ rec {
# call configuration "files" with one of the existing convention. # call configuration "files" with one of the existing convention.
optionSet = config: configFun: optionSet = config: configFun:
if __isFunction configFun then if __isFunction configFun then
let result = configFun { inherit pkgs config; }; in let result = configFun { inherit pkgs config merge; }; in
# {pkgs, config, ...}: {..} # {pkgs, config, merge, ...}: {..}
if builtins.isAttrs result then result if builtins.isAttrs result then result
# pkgs: config: {..} # pkgs: config: {..}
else configFun pkgs config else builtins.trace "obsolete:" (configFun {} {})
# {..} # {..}
else configFun; else configFun;
@ -592,6 +613,8 @@ rec {
innerModifySumArgs f x (a // b); innerModifySumArgs f x (a // b);
modifySumArgs = f: x: innerModifySumArgs f x {}; modifySumArgs = f: x: innerModifySumArgs f x {};
addLocation = if builtins ? addLocation then builtins.addLocation else msg: val: val;
debugVal = if builtins ? trace then x: (builtins.trace x x) else x: x; debugVal = if builtins ? trace then x: (builtins.trace x x) else x: x;
debugXMLVal = if builtins ? trace then x: (builtins.trace (builtins.toXML x) x) else x: x; debugXMLVal = if builtins ? trace then x: (builtins.trace (builtins.toXML x) x) else x: x;