From 8a677091830176ba5e820f5421e7d6f7eb938f8c Mon Sep 17 00:00:00 2001 From: Nicolas Pierron Date: Sun, 15 Apr 2012 23:31:48 +0000 Subject: [PATCH] Add mkMerge and obsolete mkThenElse. svn path=/nixpkgs/trunk/; revision=33796 --- pkgs/lib/modules.nix | 44 +++++++++++++++++++++++++++++------------ pkgs/lib/properties.nix | 31 ++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/pkgs/lib/modules.nix b/pkgs/lib/modules.nix index 8ecb04156e78..eb528f141fe2 100644 --- a/pkgs/lib/modules.nix +++ b/pkgs/lib/modules.nix @@ -41,29 +41,31 @@ rec { # attributes. unifyModuleSyntax = m: let - getImports = m: + delayedModule = delayProperties m; + getImports = if m ? config || m ? options then attrByPath ["imports"] [] m else - toList (rmProperties (attrByPath ["require"] [] (delayProperties m))); + toList (rmProperties (attrByPath ["require"] [] delayedModule)); - getImportedPaths = m: filter isPath (getImports m); - getImportedSets = m: filter (x: !isPath x) (getImports m); + getImportedPaths = filter isPath getImports; + getImportedSets = filter (x: !isPath x) getImports; + + getConfig = + removeAttrs delayedModule ["require" "key"]; - getConfig = m: - removeAttrs (delayProperties m) ["require" "key"]; in if isModule m then { key = ""; } // m else { key = ""; - imports = getImportedPaths m; - config = getConfig m; + imports = getImportedPaths; + config = getConfig; } // ( - if getImportedSets m != [] then - assert tail (getImportedSets m) == []; - { options = head (getImportedSets m); } + if getImportedSets != [] then + assert tail getImportedSets == []; + { options = head getImportedSets; } else {} ); @@ -124,9 +126,25 @@ rec { value ) module; + # Handle mkMerge function left behind after a delay property. + moduleFlattenMerge = module: + if module ? config && + isProperty module.config && + isMerge module.config.property + then + (map (cfg: { key = module.key; config = cfg; }) module.config.content) + ++ [ (module // { config = {}; }) ] + else + [ module ]; + # Handle mkMerge attributes which are left behind by previous delay + # properties and convert them into a list of modules. Delay properties + # inside the config attribute of a module and create a second module if a + # mkMerge attribute was left behind. + # + # Module -> [ Module ] delayModule = module: - moduleApply { config = delayProperties; } module; + map (moduleApply { config = delayProperties; }) (moduleFlattenMerge module); evalDefinitions = opt: values: if opt ? type && opt.type.delayOnGlobalEval then @@ -170,7 +188,7 @@ rec { addName = name: if path == "" then name else path + "." + name; - modules = map delayModule modules_; + modules = concatLists (map delayModule modules_); modulesOf = name: filterModules name modules; declarationsOf = name: filter (m: m ? options) (modulesOf name); diff --git a/pkgs/lib/properties.nix b/pkgs/lib/properties.nix index d7df14f716f5..0d864b0c553c 100644 --- a/pkgs/lib/properties.nix +++ b/pkgs/lib/properties.nix @@ -82,7 +82,19 @@ rec { attrs; delayProperties = # implicit attrs argument. - delayPropertiesWithIter (f: p: v: lib.mapAttrs f v) ""; + let + # mapAttrs except that it also recurse into potential mkMerge + # functions. This may cause a strictness issue because looking the + # type of a string implies evaluating it. + iter = fun: path: value: + lib.mapAttrs (attr: val: + if isProperty val && isMerge val.property then + val // { content = map (fun attr) val.content; } + else + fun attr val + ) value; + in + delayPropertiesWithIter iter ""; # Call onDelay functions. triggerPropertiesDelay = name: attrs: @@ -179,6 +191,22 @@ rec { copyProperties = attrs: newAttrs: foldProperty id (x: newAttrs) attrs; + /* Merge. */ + + # Create "merge" statement which is skipped by the delayProperty function + # and interpreted by the underlying system using properties (modules). + + # Create a "Merge" property which only contains a condition. + isMerge = attrs: (typeOf attrs) == "merge"; + mkMerge = content: mkProperty { + property = { + _type = "merge"; + onDelay = name: val: throw "mkMerge is not the first of the list of properties."; + onEval = val: throw "mkMerge is not allowed on option definitions."; + }; + inherit content; + }; + /* If. ThenElse. Always. */ # create "if" statement that can be delayed on sets until a "then-else" or @@ -202,6 +230,7 @@ rec { isThenElse = attrs: (typeOf attrs) == "then-else"; mkThenElse = attrs: assert attrs ? thenPart && attrs ? elsePart; + __trace "Obsolete usage of mkThenElse, replace it by mkMerge." mkProperty { property = { _type = "then-else";