From 9255c48a06913a064da4e103e6b7c1d94fb4fb90 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Thu, 1 May 2014 17:29:30 -0400 Subject: [PATCH] Move property processing, type checking, and merge code into a function This makes the relationship between property types clearer, and more importantly will let option types parameterized by other option types reuse the code for delegated type checking and merging. --- lib/modules.nix | 58 ++++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/lib/modules.nix b/lib/modules.nix index d0b8f90e5ce6..8bf8016b431f 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -106,12 +106,9 @@ rec { else [] ) configs); nrOptions = count (m: isOption m.options) decls; - # Process mkMerge and mkIf properties. - defns' = concatMap (m: - if m.config ? ${name} - then map (m': { inherit (m) file; value = m'; }) (dischargeProperties m.config.${name}) - else [] - ) configs; + # Extract the definitions for this loc + defns' = map (m: { inherit (m) file; value = m.config.${name}; }) + (filter (m: m.config ? ${name}) configs); in if nrOptions == length decls then let opt = fixupOptionType loc (mergeOptionDecls loc decls); @@ -177,27 +174,17 @@ rec { config value. */ evalOptionValue = loc: opt: defs: let - # Process mkOverride properties, adding in the default - # value specified in the option declaration (if any). - defsFinal' = filterOverrides - ((if opt ? default then [{ file = head opt.declarations; value = mkOptionDefault opt.default; }] else []) ++ defs); - # Sort mkOrder properties. - defsFinal = - # Avoid sorting if we don't have to. - if any (def: def.value._type or "" == "order") defsFinal' - then sortProperties defsFinal' - else defsFinal'; + # Add in the default value for this option, if any. + defs' = (optional (opt ? default) + { file = head opt.declarations; value = mkOptionDefault opt.default; }) ++ defs; + # Handle properties, check types, and merge everything together + inherit (mergeDefinitions loc opt.type defs') defsFinal mergedValue; files = map (def: def.file) defsFinal; - # Type-check the remaining definitions, and merge them if - # possible. merged = if defsFinal == [] then throw "The option `${showOption loc}' is used but not defined." else - fold (def: res: - if opt.type.check def.value then res - else throw "The option value `${showOption loc}' in `${def.file}' is not a ${opt.type.name}.") - (opt.type.merge loc defsFinal) defsFinal; + mergedValue; # Finally, apply the ‘apply’ function to the merged # value. This allows options to yield a value computed # from the definitions. @@ -209,6 +196,33 @@ rec { inherit files; }; + # Merge definitions of a value of a given type + mergeDefinitions = loc: type: defs: rec { + defsFinal = + let + # Process mkMerge and mkIf properties + discharged = concatMap (m: + map (value: { inherit (m) file; inherit value; }) (dischargeProperties m.value) + ) defs; + + # Process mkOverride properties + overridden = filterOverrides discharged; + + # Sort mkOrder properties + sorted = + # Avoid sorting if we don't have to. + if any (def: def.value._type or "" == "order") overridden + then sortProperties overridden + else overridden; + in sorted; + + # Type-check the remaining definitions, and merge them + mergedValue = fold (def: res: + if type.check def.value then res + else throw "The option value `${showOption loc}' in `${def.file}' is not a ${type.name}.") + (type.merge loc defsFinal) defsFinal; + }; + /* Given a config set, expand mkMerge properties, and push down the other properties into the children. The result is a list of config sets that do not have properties at top-level. For