summary refs log tree commit diff
path: root/pkgs
diff options
context:
space:
mode:
authorNicolas Pierron <nicolas.b.pierron@gmail.com>2009-07-13 16:18:52 +0000
committerNicolas Pierron <nicolas.b.pierron@gmail.com>2009-07-13 16:18:52 +0000
commitb09382fcd1baa62df37253594a65cef6dfb4fa48 (patch)
tree72f24ceeff20dd0f28f6c8c0d2586a2b03c76dcf /pkgs
parent9cd30e68e314f1aab8676cdb07182e913e784284 (diff)
downloadnixpkgs-b09382fcd1baa62df37253594a65cef6dfb4fa48.tar
nixpkgs-b09382fcd1baa62df37253594a65cef6dfb4fa48.tar.gz
nixpkgs-b09382fcd1baa62df37253594a65cef6dfb4fa48.tar.bz2
nixpkgs-b09382fcd1baa62df37253594a65cef6dfb4fa48.tar.lz
nixpkgs-b09382fcd1baa62df37253594a65cef6dfb4fa48.tar.xz
nixpkgs-b09382fcd1baa62df37253594a65cef6dfb4fa48.tar.zst
nixpkgs-b09382fcd1baa62df37253594a65cef6dfb4fa48.zip
Extract properties.nix and modules.nix from options.nix.
svn path=/nixpkgs/trunk/; revision=16339
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/lib/default.nix6
-rw-r--r--pkgs/lib/modules.nix71
-rw-r--r--pkgs/lib/options.nix419
-rw-r--r--pkgs/lib/properties.nix371
4 files changed, 448 insertions, 419 deletions
diff --git a/pkgs/lib/default.nix b/pkgs/lib/default.nix
index f3682f9f365..01f01d5cb16 100644
--- a/pkgs/lib/default.nix
+++ b/pkgs/lib/default.nix
@@ -6,7 +6,9 @@ let
   stringsWithDeps = import ./strings-with-deps.nix;
   attrsets = import ./attrsets.nix;
   sources = import ./sources.nix;
+  modules = import ./modules.nix;
   options = import ./options.nix;
+  properties = import ./properties.nix;
   types = import ./types.nix;
   meta = import ./meta.nix;
   debug = import ./debug.nix;
@@ -15,9 +17,9 @@ let
 
 in
   { inherit trivial lists strings stringsWithDeps attrsets sources options
-      types meta debug maintainers;
+      properties modules types meta debug maintainers;
   }
   # !!! don't include everything at top-level; perhaps only the most
   # commonly used functions.
   // trivial // lists // strings // stringsWithDeps // attrsets // sources
-  // options // types // meta // debug // misc
+  // properties // options // types // meta // debug // misc
diff --git a/pkgs/lib/modules.nix b/pkgs/lib/modules.nix
new file mode 100644
index 00000000000..0b92462ee3e
--- /dev/null
+++ b/pkgs/lib/modules.nix
@@ -0,0 +1,71 @@
+# NixOS module handling.
+
+let lib = import ./default.nix; in
+
+with { inherit (builtins) head tail; };
+with import ./trivial.nix;
+with import ./lists.nix;
+with import ./misc.nix;
+with import ./attrsets.nix;
+with import ./properties.nix;
+
+rec {
+
+  # Unfortunately this can also be a string.
+  isPath = x: !(
+     builtins.isFunction x
+  || builtins.isAttrs x
+  || builtins.isInt x
+  || builtins.isBool x
+  || builtins.isList x
+  );
+
+  importIfPath = path:
+    if isPath path then
+      import path
+    else
+      path;
+
+  applyIfFunction = f: arg:
+    if builtins.isFunction f then
+      f arg
+    else
+      f;
+
+  moduleClosure = initModules: args:
+    let
+      moduleImport = m:
+        (applyIfFunction (importIfPath m) args) // {
+          # used by generic closure to avoid duplicated imports.
+          key = m;
+        };
+
+      removeKeys = list: map (m: removeAttrs m ["key"]) list;
+
+      getImports = m:
+        if m ? config || m ? options then
+          attrByPath ["imports"] [] m
+        else
+          toList (rmProperties (attrByPath ["require"] [] (delayProperties m)));
+
+      getImportedPaths = m: filter isPath (getImports m);
+      getImportedSets = m: filter (x: !isPath x) (getImports m);
+
+      inlineImportedSets = list:
+        lib.concatMap (m:[m] ++ map moduleImport (getImportedSets m)) list;
+    in
+      removeKeys (inlineImportedSets (lazyGenericClosure {
+        startSet = map moduleImport initModules;
+        operator = m: map moduleImport (getImportedPaths m);
+      }));
+
+  selectDeclsAndDefs = modules:
+    lib.concatMap (m:
+      if m ? config || m ? options then
+         attrByPath ["options"] [] m
+      ++ attrByPath ["config"] [] m
+      else
+        [ m ]
+    ) modules;
+
+}
\ No newline at end of file
diff --git a/pkgs/lib/options.nix b/pkgs/lib/options.nix
index f674b399415..34492b289df 100644
--- a/pkgs/lib/options.nix
+++ b/pkgs/lib/options.nix
@@ -7,6 +7,8 @@ with import ./trivial.nix;
 with import ./lists.nix;
 with import ./misc.nix;
 with import ./attrsets.nix;
+with import ./properties.nix;
+with import ./modules.nix;
 
 rec {
 
@@ -253,64 +255,6 @@ rec {
     };
 
 
-  # Unfortunately this can also be a string.
-  isPath = x: !(
-     builtins.isFunction x
-  || builtins.isAttrs x
-  || builtins.isInt x
-  || builtins.isBool x
-  || builtins.isList x
-  );
-
-  importIfPath = path:
-    if isPath path then
-      import path
-    else
-      path;
-
-  applyIfFunction = f: arg:
-    if builtins.isFunction f then
-      f arg
-    else
-      f;
-
-  moduleClosure = initModules: args:
-    let
-      moduleImport = m:
-        (applyIfFunction (importIfPath m) args) // {
-          # used by generic closure to avoid duplicated imports.
-          key = m;
-        };
-
-      removeKeys = list: map (m: removeAttrs m ["key"]) list;
-
-      getImports = m:
-        if m ? config || m ? options then
-          attrByPath ["imports"] [] m
-        else
-          toList (rmProperties (attrByPath ["require"] [] (delayProperties m)));
-
-      getImportedPaths = m: filter isPath (getImports m);
-      getImportedSets = m: filter (x: !isPath x) (getImports m);
-
-      inlineImportedSets = list:
-        lib.concatMap (m:[m] ++ map moduleImport (getImportedSets m)) list;
-    in
-      removeKeys (inlineImportedSets (lazyGenericClosure {
-        startSet = map moduleImport initModules;
-        operator = m: map moduleImport (getImportedPaths m);
-      }));
-
-  selectDeclsAndDefs = modules:
-    lib.concatMap (m:
-      if m ? config || m ? options then
-         attrByPath ["options"] [] m
-      ++ attrByPath ["config"] [] m
-      else
-        [ m ]
-    ) modules;
-
-
   fixableMergeFun = merge: f: config:
     merge (
       # remove require because this is not an option.
@@ -384,363 +328,4 @@ rec {
       ) [] options;
 
 
-  /* Option Properties */
-  # Generalize the problem of delayable properties.  Any property can be created
-
-
-  # Tell that nothing is defined.  When properties are evaluated, this type
-  # is used to remove an entry.  Thus if your property evaluation semantic
-  # implies that you have to mute the content of an attribute, then your
-  # property should produce this value.
-  isNotdef = attrs: (typeOf attrs) == "notdef";
-  mkNotdef = {_type = "notdef";};
-
-  # General property type, it has a property attribute and a content
-  # attribute.  The property attribute refer to an attribute set which
-  # contains a _type attribute and a list of functions which are used to
-  # evaluate this property.  The content attribute is used to stack property
-  # on top of each other.
-  # 
-  # The optional functions which may be contained in the property attribute
-  # are:
-  #  - onDelay: run on a copied property.
-  #  - onGlobalDelay: run on all copied properties.
-  #  - onEval: run on an evaluated property.
-  #  - onGlobalEval: run on a list of property stack on top of their values.
-  isProperty = attrs: (typeOf attrs) == "property";
-  mkProperty = p@{property, content, ...}: p // {
-    _type = "property";
-  };
-
-  # Go throw the stack of properties and apply the function `op' on all
-  # property and call the function `nul' on the final value which is not a
-  # property.  The stack is traversed in reversed order.  The `op' function
-  # should expect a property with a content which have been modified.
-  # 
-  # Warning: The `op' function expects only one argument in order to avoid
-  # calls to mkProperties as the argument is already a valid property which
-  # contains the result of the folding inside the content attribute.
-  foldProperty = op: nul: attrs:
-    if isProperty attrs then
-      op (attrs // {
-        content = foldProperty op nul attrs.content;
-      })
-    else
-      nul attrs;
-
-  # Simple function which can be used as the `op' argument of the
-  # foldProperty function.  Properties that you don't want to handle can be
-  # ignored with the `id' function.  `isSearched' is a function which should
-  # check the type of a property and return a boolean value.  `thenFun' and
-  # `elseFun' are functions which behave as the `op' argument of the
-  # foldProperty function.
-  foldFilter = isSearched: thenFun: elseFun: attrs:
-    if isSearched attrs.property then
-      thenFun attrs
-    else
-      elseFun attrs;
-
-
-  # Move properties from the current attribute set to the attribute
-  # contained in this attribute set.  This trigger property handlers called
-  # `onDelay' and `onGlobalDelay'.
-  delayProperties = attrs:
-    let cleanAttrs = rmProperties attrs; in
-    if isProperty attrs then
-      lib.mapAttrs (a: v:
-        lib.addErrorContext "while moving properties on the attribute `${a}'." (
-          triggerPropertiesGlobalDelay a (
-            triggerPropertiesDelay a (
-              copyProperties attrs v
-      )))) cleanAttrs
-    else
-      attrs;
-
-  # Call onDelay functions.
-  triggerPropertiesDelay = name: attrs:
-    let
-      callOnDelay = p@{property, ...}:
-        lib.addErrorContext "while calling a onDelay function." (
-          if property ? onDelay then
-            property.onDelay name p
-          else
-            p
-        );
-    in
-      foldProperty callOnDelay id attrs;
-
-  # Call onGlobalDelay functions.
-  triggerPropertiesGlobalDelay = name: attrs:
-    let
-      globalDelayFuns = uniqListExt {
-        getter = property: property._type;
-        inputList = foldProperty (p@{property, content, ...}:
-          if property ? onGlobalDelay then
-            [ property ] ++ content
-          else
-            content
-        ) (a: []) attrs;
-      };
-
-      callOnGlobalDelay = property: content:
-        lib.addErrorContext "while calling a onGlobalDelay function." (
-          property.onGlobalDelay name content
-        );
-    in
-      fold callOnGlobalDelay attrs globalDelayFuns;
-
-  # Expect a list of values which may have properties and return the same
-  # list of values where all properties have been evaluated and where all
-  # ignored values are removed.  This trigger property handlers called
-  # `onEval' and `onGlobalEval'.
-  evalProperties = valList:
-    if valList != [] then
-      filter (x: !isNotdef x) (
-        lib.addErrorContext "while evaluating properties an attribute." (
-          triggerPropertiesGlobalEval (
-            map triggerPropertiesEval valList
-      )))
-    else
-      valList;
-
-  # Call onEval function
-  triggerPropertiesEval = val:
-    foldProperty (p@{property, ...}:
-      lib.addErrorContext "while calling a onEval function." (
-        if property ? onEval then
-          property.onEval p
-        else
-          p
-      )
-    ) id val;
-
-  # Call onGlobalEval function
-  triggerPropertiesGlobalEval = valList:
-    let
-      globalEvalFuns = uniqListExt {
-        getter = property: property._type;
-        inputList =
-          fold (attrs: list:
-            foldProperty (p@{property, content, ...}:
-              if property ? onGlobalEval then
-                [ property ] ++ content
-              else
-                content
-            ) (a: list) attrs
-          ) [] valList;
-      };
-
-      callOnGlobalEval = property: valList:
-        lib.addErrorContext "while calling a onGlobalEval function." (
-          property.onGlobalEval valList
-        );
-    in
-      fold callOnGlobalEval valList globalEvalFuns;
-
-  # Remove all properties on top of a value and return the value.
-  rmProperties =
-    foldProperty (p@{content, ...}: content) id;
-
-  # Copy properties defined on a value on another value.
-  copyProperties = attrs: newAttrs:
-    foldProperty id (x: newAttrs) attrs;
-
-  /* If. ThenElse. Always. */
-
-  # create "if" statement that can be delayed on sets until a "then-else" or
-  # "always" set is reached.  When an always set is reached the condition
-  # is ignore.
-
-  # Create a "If" property which only contains a condition.
-  isIf = attrs: (typeOf attrs) == "if";
-  mkIf = condition: content: mkProperty {
-    property = {
-      _type = "if";
-      onGlobalDelay = onIfGlobalDelay;
-      onEval = onIfEval;
-      inherit condition;
-    };
-    inherit content;
-  };
-
-  # Create a "ThenElse" property which contains choices which can choosed by
-  # the evaluation of an "If" statement.
-  isThenElse = attrs: (typeOf attrs) == "then-else";
-  mkThenElse = attrs:
-    assert attrs ? thenPart && attrs ? elsePart;
-    mkProperty {
-      property = {
-        _type = "then-else";
-        onEval = val: throw "Missing mkIf statement.";
-        inherit (attrs) thenPart elsePart;
-      };
-      content = mkNotdef;
-    };
-
-  # Create an "Always" property remove ignore all "If" statement.
-  isAlways = attrs: (typeOf attrs) == "always";
-  mkAlways = value:
-    mkProperty {
-      property = {
-        _type = "always";
-        onEval = p@{content, ...}: content;
-        inherit value;
-      };
-      content = mkNotdef;
-    };
-
-  # Remove all "If" statement defined on a value.
-  rmIf = foldProperty (
-      foldFilter isIf
-        ({content, ...}: content)
-        id
-    ) id;
-
-  # Evaluate the "If" statements when either "ThenElse" or "Always"
-  # statement is encounter.  Otherwise it remove multiple If statement and
-  # replace them by one "If" staement where the condition is the list of all
-  # conditions joined with a "and" operation.
-  onIfGlobalDelay = name: content:
-    let
-      # extract if statements and non-if statements and repectively put them
-      # in the attribute list and attrs.
-      ifProps =
-        foldProperty
-          (foldFilter (p: isIf p || isThenElse p || isAlways p)
-            # then, push the codition inside the list list
-            (p@{property, content, ...}:
-              { inherit (content) attrs;
-                list = [property] ++ content.list;
-              }
-            )
-            # otherwise, add the propertie.
-            (p@{property, content, ...}:
-              { inherit (content) list;
-                attrs = p // { content = content.attrs; };
-              }
-            )
-          )
-          (attrs: { list = []; inherit attrs; })
-          content;
-
-      # compute the list of if statements.
-      evalIf = content: condition: list:
-        if list == [] then
-          mkIf condition content
-        else
-          let p = head list; in
-
-          # evaluate the condition.
-          if isThenElse p then
-            if condition then
-              copyProperties content p.thenPart
-            else
-              copyProperties content p.elsePart
-          # ignore the condition.
-          else if isAlways p then
-            copyProperties content p.value
-          # otherwise (isIf)
-          else
-            evalIf content (condition && p.condition) (tail list);
-    in
-      evalIf ifProps.attrs true ifProps.list;
-
-  # Evaluate the condition of the "If" statement to either get the value or
-  # to ignore the value.
-  onIfEval = p@{property, content, ...}:
-    if property.condition then
-      content
-    else
-      mkNotdef;
-
-  /* mkOverride */
-
-  # Create an "Override" statement which allow the user to define
-  # prioprities between values.  The default priority is 100 and the lowest
-  # priorities are kept.  The template argument must reproduce the same
-  # attribute set hierachy to override leaves of the hierarchy.
-  isOverride = attrs: (typeOf attrs) == "override";
-  mkOverride = priority: template: content: mkProperty {
-    property = {
-      _type = "override";
-      onDelay = onOverrideDelay;
-      onGlobalEval = onOverrideGlobalEval;
-      inherit priority template;
-    };
-    inherit content;
-  };
-
-  # Sugar to override the default value of the option by making a new
-  # default value based on the configuration.
-  mkDefaultValue = content: mkOverride 1000 {} content;
-
-  # Make the template traversal in function of the property traversal.  If
-  # the template define a non-empty attribute set, then the property is
-  # copied only on all mentionned attributes inside the template.
-  # Otherwise, the property is kept on all sub-attribute definitions.
-  onOverrideDelay = name: p@{property, content, ...}:
-    let inherit (property) template; in
-    if isAttrs template && template != {} then
-      if hasAttr name template then
-        p // {
-          property = p.property // {
-            template = builtins.getAttr name template;
-          };
-        }
-      # Do not override the attribute \name\
-      else
-        content
-    # Override values defined inside the attribute \name\.
-    else
-      p;
-
-  # Ignore all values which have a higher value of the priority number.
-  onOverrideGlobalEval = valList:
-    let
-      defaultPrio = 100;
-
-      inherit (builtins) lessThan;
-
-      getPrioVal =
-        foldProperty
-          (foldFilter isOverride
-            (p@{property, content, ...}:
-              if content ? priority && lessThan content.priority property.priority then
-                content
-              else
-                content // {
-                  inherit (property) priority;
-                }
-            )
-            (p@{property, content, ...}:
-              content // {
-                value = p // { content = content.value; };
-              }
-            )
-          ) (value: { inherit value; });
-
-      addDefaultPrio = x:
-        if x ? priority then x
-        else x // { priority = defaultPrio; };
-
-      prioValList = map (x: addDefaultPrio (getPrioVal x)) valList;
-
-      higherPrio =
-        if prioValList == [] then
-          defaultPrio
-        else
-          fold (x: min:
-            if lessThan x.priority min then
-              x.priority
-            else
-              min
-          ) (head prioValList).priority (tail prioValList);
-    in
-      map (x:
-        if x.priority == higherPrio then
-          x.value
-        else
-          mkNotdef
-      ) prioValList;
-
 }
diff --git a/pkgs/lib/properties.nix b/pkgs/lib/properties.nix
new file mode 100644
index 00000000000..91f65c448ec
--- /dev/null
+++ b/pkgs/lib/properties.nix
@@ -0,0 +1,371 @@
+# Nixpkgs/NixOS properties.  Generalize the problem of delayable (not yet
+# evaluable) properties like mkIf.
+
+let lib = import ./default.nix; in
+
+with { inherit (builtins) head tail; };
+with import ./trivial.nix;
+with import ./lists.nix;
+with import ./misc.nix;
+with import ./attrsets.nix;
+
+rec {
+
+  inherit (lib) typeOf;
+
+  # Tell that nothing is defined.  When properties are evaluated, this type
+  # is used to remove an entry.  Thus if your property evaluation semantic
+  # implies that you have to mute the content of an attribute, then your
+  # property should produce this value.
+  isNotdef = attrs: (typeOf attrs) == "notdef";
+  mkNotdef = {_type = "notdef";};
+
+  # General property type, it has a property attribute and a content
+  # attribute.  The property attribute refer to an attribute set which
+  # contains a _type attribute and a list of functions which are used to
+  # evaluate this property.  The content attribute is used to stack property
+  # on top of each other.
+  # 
+  # The optional functions which may be contained in the property attribute
+  # are:
+  #  - onDelay: run on a copied property.
+  #  - onGlobalDelay: run on all copied properties.
+  #  - onEval: run on an evaluated property.
+  #  - onGlobalEval: run on a list of property stack on top of their values.
+  isProperty = attrs: (typeOf attrs) == "property";
+  mkProperty = p@{property, content, ...}: p // {
+    _type = "property";
+  };
+
+  # Go through the stack of properties and apply the function `op' on all
+  # property and call the function `nul' on the final value which is not a
+  # property.  The stack is traversed in reversed order.  The `op' function
+  # should expect a property with a content which have been modified.
+  # 
+  # Warning: The `op' function expects only one argument in order to avoid
+  # calls to mkProperties as the argument is already a valid property which
+  # contains the result of the folding inside the content attribute.
+  foldProperty = op: nul: attrs:
+    if isProperty attrs then
+      op (attrs // {
+        content = foldProperty op nul attrs.content;
+      })
+    else
+      nul attrs;
+
+  # Simple function which can be used as the `op' argument of the
+  # foldProperty function.  Properties that you don't want to handle can be
+  # ignored with the `id' function.  `isSearched' is a function which should
+  # check the type of a property and return a boolean value.  `thenFun' and
+  # `elseFun' are functions which behave as the `op' argument of the
+  # foldProperty function.
+  foldFilter = isSearched: thenFun: elseFun: attrs:
+    if isSearched attrs.property then
+      thenFun attrs
+    else
+      elseFun attrs;
+
+
+  # Move properties from the current attribute set to the attribute
+  # contained in this attribute set.  This trigger property handlers called
+  # `onDelay' and `onGlobalDelay'.
+  delayProperties = attrs:
+    let cleanAttrs = rmProperties attrs; in
+    if isProperty attrs then
+      lib.mapAttrs (a: v:
+        lib.addErrorContext "while moving properties on the attribute `${a}'." (
+          triggerPropertiesGlobalDelay a (
+            triggerPropertiesDelay a (
+              copyProperties attrs v
+      )))) cleanAttrs
+    else
+      attrs;
+
+  # Call onDelay functions.
+  triggerPropertiesDelay = name: attrs:
+    let
+      callOnDelay = p@{property, ...}:
+        lib.addErrorContext "while calling a onDelay function." (
+          if property ? onDelay then
+            property.onDelay name p
+          else
+            p
+        );
+    in
+      foldProperty callOnDelay id attrs;
+
+  # Call onGlobalDelay functions.
+  triggerPropertiesGlobalDelay = name: attrs:
+    let
+      globalDelayFuns = uniqListExt {
+        getter = property: property._type;
+        inputList = foldProperty (p@{property, content, ...}:
+          if property ? onGlobalDelay then
+            [ property ] ++ content
+          else
+            content
+        ) (a: []) attrs;
+      };
+
+      callOnGlobalDelay = property: content:
+        lib.addErrorContext "while calling a onGlobalDelay function." (
+          property.onGlobalDelay name content
+        );
+    in
+      fold callOnGlobalDelay attrs globalDelayFuns;
+
+  # Expect a list of values which may have properties and return the same
+  # list of values where all properties have been evaluated and where all
+  # ignored values are removed.  This trigger property handlers called
+  # `onEval' and `onGlobalEval'.
+  evalProperties = valList:
+    if valList != [] then
+      filter (x: !isNotdef x) (
+        lib.addErrorContext "while evaluating properties an attribute." (
+          triggerPropertiesGlobalEval (
+            map triggerPropertiesEval valList
+      )))
+    else
+      valList;
+
+  # Call onEval function
+  triggerPropertiesEval = val:
+    foldProperty (p@{property, ...}:
+      lib.addErrorContext "while calling a onEval function." (
+        if property ? onEval then
+          property.onEval p
+        else
+          p
+      )
+    ) id val;
+
+  # Call onGlobalEval function
+  triggerPropertiesGlobalEval = valList:
+    let
+      globalEvalFuns = uniqListExt {
+        getter = property: property._type;
+        inputList =
+          fold (attrs: list:
+            foldProperty (p@{property, content, ...}:
+              if property ? onGlobalEval then
+                [ property ] ++ content
+              else
+                content
+            ) (a: list) attrs
+          ) [] valList;
+      };
+
+      callOnGlobalEval = property: valList:
+        lib.addErrorContext "while calling a onGlobalEval function." (
+          property.onGlobalEval valList
+        );
+    in
+      fold callOnGlobalEval valList globalEvalFuns;
+
+  # Remove all properties on top of a value and return the value.
+  rmProperties =
+    foldProperty (p@{content, ...}: content) id;
+
+  # Copy properties defined on a value on another value.
+  copyProperties = attrs: newAttrs:
+    foldProperty id (x: newAttrs) attrs;
+
+  /* If. ThenElse. Always. */
+
+  # create "if" statement that can be delayed on sets until a "then-else" or
+  # "always" set is reached.  When an always set is reached the condition
+  # is ignore.
+
+  # Create a "If" property which only contains a condition.
+  isIf = attrs: (typeOf attrs) == "if";
+  mkIf = condition: content: mkProperty {
+    property = {
+      _type = "if";
+      onGlobalDelay = onIfGlobalDelay;
+      onEval = onIfEval;
+      inherit condition;
+    };
+    inherit content;
+  };
+
+  # Create a "ThenElse" property which contains choices which can choosed by
+  # the evaluation of an "If" statement.
+  isThenElse = attrs: (typeOf attrs) == "then-else";
+  mkThenElse = attrs:
+    assert attrs ? thenPart && attrs ? elsePart;
+    mkProperty {
+      property = {
+        _type = "then-else";
+        onEval = val: throw "Missing mkIf statement.";
+        inherit (attrs) thenPart elsePart;
+      };
+      content = mkNotdef;
+    };
+
+  # Create an "Always" property remove ignore all "If" statement.
+  isAlways = attrs: (typeOf attrs) == "always";
+  mkAlways = value:
+    mkProperty {
+      property = {
+        _type = "always";
+        onEval = p@{content, ...}: content;
+        inherit value;
+      };
+      content = mkNotdef;
+    };
+
+  # Remove all "If" statement defined on a value.
+  rmIf = foldProperty (
+      foldFilter isIf
+        ({content, ...}: content)
+        id
+    ) id;
+
+  # Evaluate the "If" statements when either "ThenElse" or "Always"
+  # statement is encounter.  Otherwise it remove multiple If statement and
+  # replace them by one "If" staement where the condition is the list of all
+  # conditions joined with a "and" operation.
+  onIfGlobalDelay = name: content:
+    let
+      # extract if statements and non-if statements and repectively put them
+      # in the attribute list and attrs.
+      ifProps =
+        foldProperty
+          (foldFilter (p: isIf p || isThenElse p || isAlways p)
+            # then, push the codition inside the list list
+            (p@{property, content, ...}:
+              { inherit (content) attrs;
+                list = [property] ++ content.list;
+              }
+            )
+            # otherwise, add the propertie.
+            (p@{property, content, ...}:
+              { inherit (content) list;
+                attrs = p // { content = content.attrs; };
+              }
+            )
+          )
+          (attrs: { list = []; inherit attrs; })
+          content;
+
+      # compute the list of if statements.
+      evalIf = content: condition: list:
+        if list == [] then
+          mkIf condition content
+        else
+          let p = head list; in
+
+          # evaluate the condition.
+          if isThenElse p then
+            if condition then
+              copyProperties content p.thenPart
+            else
+              copyProperties content p.elsePart
+          # ignore the condition.
+          else if isAlways p then
+            copyProperties content p.value
+          # otherwise (isIf)
+          else
+            evalIf content (condition && p.condition) (tail list);
+    in
+      evalIf ifProps.attrs true ifProps.list;
+
+  # Evaluate the condition of the "If" statement to either get the value or
+  # to ignore the value.
+  onIfEval = p@{property, content, ...}:
+    if property.condition then
+      content
+    else
+      mkNotdef;
+
+  /* mkOverride */
+
+  # Create an "Override" statement which allow the user to define
+  # prioprities between values.  The default priority is 100 and the lowest
+  # priorities are kept.  The template argument must reproduce the same
+  # attribute set hierachy to override leaves of the hierarchy.
+  isOverride = attrs: (typeOf attrs) == "override";
+  mkOverride = priority: template: content: mkProperty {
+    property = {
+      _type = "override";
+      onDelay = onOverrideDelay;
+      onGlobalEval = onOverrideGlobalEval;
+      inherit priority template;
+    };
+    inherit content;
+  };
+
+  # Sugar to override the default value of the option by making a new
+  # default value based on the configuration.
+  mkDefaultValue = content: mkOverride 1000 {} content;
+
+  # Make the template traversal in function of the property traversal.  If
+  # the template define a non-empty attribute set, then the property is
+  # copied only on all mentionned attributes inside the template.
+  # Otherwise, the property is kept on all sub-attribute definitions.
+  onOverrideDelay = name: p@{property, content, ...}:
+    let inherit (property) template; in
+    if isAttrs template && template != {} then
+      if hasAttr name template then
+        p // {
+          property = p.property // {
+            template = builtins.getAttr name template;
+          };
+        }
+      # Do not override the attribute \name\
+      else
+        content
+    # Override values defined inside the attribute \name\.
+    else
+      p;
+
+  # Ignore all values which have a higher value of the priority number.
+  onOverrideGlobalEval = valList:
+    let
+      defaultPrio = 100;
+
+      inherit (builtins) lessThan;
+
+      getPrioVal =
+        foldProperty
+          (foldFilter isOverride
+            (p@{property, content, ...}:
+              if content ? priority && lessThan content.priority property.priority then
+                content
+              else
+                content // {
+                  inherit (property) priority;
+                }
+            )
+            (p@{property, content, ...}:
+              content // {
+                value = p // { content = content.value; };
+              }
+            )
+          ) (value: { inherit value; });
+
+      addDefaultPrio = x:
+        if x ? priority then x
+        else x // { priority = defaultPrio; };
+
+      prioValList = map (x: addDefaultPrio (getPrioVal x)) valList;
+
+      higherPrio =
+        if prioValList == [] then
+          defaultPrio
+        else
+          fold (x: min:
+            if lessThan x.priority min then
+              x.priority
+            else
+              min
+          ) (head prioValList).priority (tail prioValList);
+    in
+      map (x:
+        if x.priority == higherPrio then
+          x.value
+        else
+          mkNotdef
+      ) prioValList;
+
+}
\ No newline at end of file