summary refs log tree commit diff
path: root/pkgs/lib/properties.nix
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/lib/properties.nix')
-rw-r--r--pkgs/lib/properties.nix464
1 files changed, 0 insertions, 464 deletions
diff --git a/pkgs/lib/properties.nix b/pkgs/lib/properties.nix
deleted file mode 100644
index 22aa8d891d8a..000000000000
--- a/pkgs/lib/properties.nix
+++ /dev/null
@@ -1,464 +0,0 @@
-# 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) isType;
-
-  # 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 = isType "notdef";
-  mkNotdef = {_type = "notdef";};
-
-  # General property type, it has a property attribute and a content
-  # attribute.  The property attribute refers 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 properties
-  # 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 = isType "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'.
-  delayPropertiesWithIter = iter: path: attrs:
-    let cleanAttrs = rmProperties attrs; in
-    if isProperty attrs then
-      iter (a: v:
-        lib.addErrorContext "while moving properties on the attribute `${a}':" (
-          triggerPropertiesGlobalDelay a (
-            triggerPropertiesDelay a (
-              copyProperties attrs v
-      )))) path cleanAttrs
-    else
-      attrs;
-
-  delayProperties = # implicit attrs argument.
-    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:
-    let
-      callOnDelay = p@{property, ...}:
-        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:
-        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) (
-        triggerPropertiesGlobalEval (
-          evalLocalProperties valList
-        )
-      )
-    else
-      valList;
-
-  evalLocalProperties = valList:
-    filter (x: !isNotdef x) (
-      map triggerPropertiesEval valList
-    );
-
-  # Call onEval function
-  triggerPropertiesEval = val:
-    foldProperty (p@{property, ...}:
-      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: 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;
-
-  /* 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 = isType "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
-  # "always" set is reached.  When an always set is reached the condition
-  # is ignore.
-
-  # Create a "If" property which only contains a condition.
-  isIf = isType "if";
-  mkIf = condition: content: mkProperty {
-    property = {
-      _type = "if";
-      onGlobalDelay = onIfGlobalDelay;
-      onEval = onIfEval;
-      inherit condition;
-    };
-    inherit content;
-  };
-
-  mkAssert = assertion: message: content:
-    mkIf
-      (if assertion then true else throw "\nFailed assertion: ${message}")
-      content;
-
-  # Evaluate the "If" statements when either "ThenElse" or "Always"
-  # statement is encountered.  Otherwise it removes multiple If statements and
-  # replaces them by one "If" statement 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)
-            # then, push the condition 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
-          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
-  # priorities between values.  The default priority is 100. The lowest
-  # priorities are kept.  The template argument must reproduce the same
-  # attribute set hierarchy to override leaves of the hierarchy.
-  isOverride = isType "override";
-  mkOverrideTemplate = priority: template: content: mkProperty {
-    property = {
-      _type = "override";
-      onDelay = onOverrideDelay;
-      onGlobalEval = onOverrideGlobalEval;
-      inherit priority template;
-    };
-    inherit content;
-  };
-
-  # Like mkOverrideTemplate, but without the template argument.
-  mkOverride = priority: content: mkOverrideTemplate priority {} content;
-
-  # Sugar to override the default value of the option by making a new
-  # default value based on the configuration.
-  mkDefaultValue = mkOverride 1000;
-  mkDefault = mkOverride 1000;
-  mkForce = mkOverride 50;
-  mkStrict = mkOverride 0;
-
-  # 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;
-
-  # Keep values having lowest priority numbers only throwing away those having
-  # a higher priority assigned.
-  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;
-
-  /* mkOrder */
-
-  # Order definitions based on there index value.  This property is useful
-  # when the result of the merge function depends on the order on the
-  # initial list.  (e.g. concatStrings) Definitions are ordered based on
-  # their rank.  The lowest ranked definition would be the first to element
-  # of the list used by the merge function.  And the highest ranked
-  # definition would be the last.  Definitions which does not have any rank
-  # value have the default rank of 100.
-  isOrder = isType "order";
-  mkOrder = rank: content: mkProperty {
-    property = {
-      _type = "order";
-      onGlobalEval = onOrderGlobalEval;
-      inherit rank;
-    };
-    inherit content;
-  };
-
-  mkHeader = mkOrder 10;
-  mkFooter = mkOrder 1000;
-
-  # Fetch the rank of each definition (add the default rank is none) and
-  # sort them based on their ranking.
-  onOrderGlobalEval = valList:
-    let
-      defaultRank = 100;
-
-      inherit (builtins) lessThan;
-
-      getRankVal =
-        foldProperty
-          (foldFilter isOrder
-            (p@{property, content, ...}:
-              if content ? rank then
-                content
-              else
-                content // {
-                  inherit (property) rank;
-                }
-            )
-            (p@{property, content, ...}:
-              content // {
-                value = p // { content = content.value; };
-              }
-            )
-          ) (value: { inherit value; });
-
-      addDefaultRank = x:
-        if x ? rank then x
-        else x // { rank = defaultRank; };
-
-      rankValList = map (x: addDefaultRank (getRankVal x)) valList;
-
-      cmp = x: y:
-        builtins.lessThan x.rank y.rank;
-    in
-      map (x: x.value) (sort cmp rankValList);
-
-  /* mkFixStrictness */
-
-  # This is a hack used to restore laziness on some option definitions.
-  # Some option definitions are evaluated when they are not used.  This
-  # error is caused by the strictness of type checking builtins.  Builtins
-  # like 'isAttrs' are too strict because they have to evaluate their
-  # arguments to check if the type is correct.  This evaluation, cause the
-  # strictness of properties.
-  #
-  # Properties can be stacked on top of each other.  The stackability of
-  # properties on top of the option definition is nice for user manipulation
-  # but require to check if the content of the property is not another
-  # property.  Such testing implies to verify if this is an attribute set
-  # and if it possess the type 'property'. (see isProperty & typeOf/isType)
-  #
-  # To avoid strict evaluation of option definitions, 'mkFixStrictness' is
-  # introduced.  This property protects an option definition by replacing
-  # the base of the stack of properties by 'mkNotDef', when this property is
-  # evaluated it returns the original definition.
-  #
-  # This property is useful over any elements which depends on options which
-  # are raising errors when they get evaluated without the proper settings.
-  #
-  # Plain list and attribute set are lazy structures, which means that the
-  # container gets evaluated but not the content.  Thus, using this property
-  # on top of plain list or attribute set is pointless.
-  #
-  # This is a Hack, you should avoid it!
-
-  # This property has a long name because you should avoid it.
-  isFixStrictness = attrs: (typeOf attrs) == "fix-strictness";
-  mkFixStrictness = value:
-    mkProperty {
-      property = {
-        _type = "fix-strictness";
-        onEval = p: value;
-      };
-      content = mkNotdef;
-    };
-
-}