summary refs log tree commit diff
path: root/pkgs
diff options
context:
space:
mode:
authorMarc Weber <marco-oweber@gmx.de>2007-08-18 22:12:00 +0000
committerMarc Weber <marco-oweber@gmx.de>2007-08-18 22:12:00 +0000
commit6af4bd3ca69db85478af692bd21b878bc13b829c (patch)
treeeb16a08e707ddd962e807d22960356a16a66ca30 /pkgs
parentcfab5a8cf9789c373354af36e65566212f3a739d (diff)
downloadnixpkgs-6af4bd3ca69db85478af692bd21b878bc13b829c.tar
nixpkgs-6af4bd3ca69db85478af692bd21b878bc13b829c.tar.gz
nixpkgs-6af4bd3ca69db85478af692bd21b878bc13b829c.tar.bz2
nixpkgs-6af4bd3ca69db85478af692bd21b878bc13b829c.tar.lz
nixpkgs-6af4bd3ca69db85478af692bd21b878bc13b829c.tar.xz
nixpkgs-6af4bd3ca69db85478af692bd21b878bc13b829c.tar.zst
nixpkgs-6af4bd3ca69db85478af692bd21b878bc13b829c.zip
primop functions listToAttrs (+test), __isAttrs, __trace added
new configuration style proposal in lib/default-unstable.nix

svn path=/nixpkgs/trunk/; revision=9163
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/lib/default-unstable.nix295
1 files changed, 295 insertions, 0 deletions
diff --git a/pkgs/lib/default-unstable.nix b/pkgs/lib/default-unstable.nix
new file mode 100644
index 00000000000..ac87edd17e0
--- /dev/null
+++ b/pkgs/lib/default-unstable.nix
@@ -0,0 +1,295 @@
+# Utility functions.
+
+let
+
+  inherit (builtins)
+    head tail isList stringLength substring lessThan sub listToAttrs;
+
+in
+
+rec {
+
+  # "Fold" a binary function `op' between successive elements of
+  # `list' with `nul' as the starting value, i.e., `fold op nul [x_1
+  # x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))'.  (This is
+  # Haskell's foldr).
+  fold = op: nul: list:
+    if list == []
+    then nul
+    else op (head list) (fold op nul (tail list));
+
+    
+  # Concatenate a list of lists.
+  concatLists =
+    fold (x: y: x ++ y) [];
+
+
+  # Concatenate a list of strings.
+  concatStrings =
+    fold (x: y: x + y) "";
+
+
+  # Place an element between each element of a list, e.g.,
+  # `intersperse "," ["a" "b" "c"]' returns ["a" "," "b" "," "c"].
+  intersperse = separator: list:
+    if list == [] || tail list == []
+    then list
+    else [(head list) separator]
+         ++ (intersperse separator (tail list));
+
+
+  concatStringsSep = separator: list:
+    concatStrings (intersperse separator list);
+
+
+  # Flatten the argument into a single list; that is, nested lists are
+  # spliced into the top-level lists.  E.g., `flatten [1 [2 [3] 4] 5]
+  # == [1 2 3 4 5]' and `flatten 1 == [1]'.
+  flatten = x:
+    if isList x
+    then fold (x: y: (flatten x) ++ y) [] x
+    else [x];
+
+
+  # Return an attribute from nested attribute sets.  For instance ["x"
+  # "y"] applied to some set e returns e.x.y, if it exists.  The
+  # default value is returned otherwise.
+  # comment: I'd rename this to getAttrRec or something like that .. (has the same name as builtin.getAttr) - Marc Weber
+  getAttr = attrPath: default: e:
+    let {
+      attr = head attrPath;
+      body =
+        if attrPath == [] then e
+        else if builtins ? hasAttr && builtins.hasAttr attr e
+        then getAttr (tail attrPath) default (builtins.getAttr attr e)
+        else default;
+    };
+
+
+  # Filter a list using a predicate; that is, return a list containing
+  # every element from `list' for which `pred' returns true.
+  filter = pred: list:
+    fold (x: y: if pred x then [x] ++ y else y) [] list;
+
+
+  # Return true if `list' has an element `x':
+  elem = x: list: fold (a: bs: x == a || bs) false list;
+
+
+  # Find the sole element in the list matching the specified
+  # predicate, or returns the default value.
+  findSingle = pred: default: list:
+    let found = filter pred list;
+    in if found == [] then default
+       else if tail found != [] then
+         abort "Multiple elements match predicate in findSingle."
+       else head found;
+
+
+  # Return true if each element of a list is equal, false otherwise.
+  eqLists = xs: ys:
+    if xs == [] && ys == [] then true
+    else if xs == [] || ys == [] then false
+    else head xs == head ys && eqLists (tail xs) (tail ys);
+
+
+  # Determine whether a filename ends in the given suffix.
+  hasSuffix = ext: fileName:
+    let lenFileName = stringLength fileName;
+        lenExt = stringLength ext;
+    in !(lessThan lenFileName lenExt) &&
+       substring (sub lenFileName lenExt) lenFileName fileName == ext;
+
+       
+  # Bring in a path as a source, filtering out all Subversion and CVS
+  # directories, as well as backup files (*~).
+  cleanSource =
+    let filter = name: type: let baseName = baseNameOf (toString name); in ! (
+      # Filter out Subversion and CVS directories.
+      (type == "directory" && (name == ".svn" || name == "CVS")) ||
+      # Filter out backup files.
+      (hasSuffix "~" name)
+    );
+    in src: builtins.filterSource filter src;
+
+
+  # Return a singleton list or an empty list, depending on a boolean
+  # value.  Useful when building lists with optional elements
+  # (e.g. `++ optional (system == "i686-linux") flashplayer').
+  optional = cond: elem: if cond then [elem] else [];
+
+    
+  # Return a list of integers from `first' up to and including `last'.
+  range = first: last:
+    if builtins.lessThan last first
+    then []
+    else [first] ++ range (builtins.add first 1) last;
+
+  # Return true only if there is an attribute and it is true.
+  checkFlag = attrSet: name:
+	if (name == "true") then true else
+	if (name == "false") then false else
+	if (isInList (getAttr ["flags"] [] attrSet) name) then true else
+	getAttr [name] false attrSet ;
+
+  logicalOR = x: y: x || y;
+  logicalAND = x: y: x && y;
+
+  # Input : attrSet, [ [name default] ... ], name
+  # Output : its value or default.
+  getValue = attrSet: argList: name:
+  ( getAttr [name] (if checkFlag attrSet name then true else
+	if argList == [] then null else
+	let x = builtins.head argList; in
+		if (head x) == name then 
+			(head (tail x))
+		else (getValue attrSet 
+			(tail argList) name)) attrSet );
+
+  # Input : attrSet, [[name default] ...], [ [flagname reqs..] ... ]
+  # Output : are reqs satisfied? It's asserted.
+  checkReqs = attrSet : argList : condList :
+  (
+    fold logicalAND true 
+      (map (x: let name = (head x) ; in
+	
+	((checkFlag attrSet name) -> 
+	(fold logicalAND true
+	(map (y: let val=(getValue attrSet argList y); in
+		(val!=null) && (val!=false)) 
+	(tail x))))) condList)) ;
+	
+   
+  isInList = list: x:
+	if (list == []) then false else
+	if (x == (head list)) then true else
+	isInList (tail list) x;
+  
+  uniqList = {inputList, outputList ? []}:
+	if (inputList == []) then outputList else
+	let x=head inputList; 
+	newOutputList = outputList ++
+	 (if (isInList outputList x) then [] else [x]);
+	in uniqList {outputList=newOutputList; 
+		inputList = (tail inputList);};
+
+  condConcat = name: list: checker:
+	if list == [] then name else
+	if checker (head list) then 
+		condConcat 
+			(name + (head (tail list))) 
+			(tail (tail list)) 
+			checker
+	else condConcat
+		name (tail (tail list)) checker;
+
+
+  # to be used with listToAttrs (_a_ttribute _v_alue)
+  av = attr : value : { inherit attr value; };
+
+  id = x : x;
+  # true if all/ at least one element(s) satisfy f
+  all = f : l : fold logicalAND true (map f l);
+  any = f : l : fold logicalOR false (map f l);
+
+  # iterates over a list of attributes collecting the attribute attr if it exists
+  catAttrs = attr : l : fold ( s : l : if (__hasAttr attr s) then [(__getAttr attr s)] ++ l else l) [] l;
+
+  flattenSet = set : map ( attr : __getAttr attr set) (__attrNames set);
+
+# Marc 2nd proposal: (not everything has been tested in detail yet..)
+# One example showing how to use mandatory dependencies [1], default flags [2], ..
+# 
+# note that you should be able to use either ["value1"] or just "value" .. (if I haven't forgotten a flatten)
+# linuxthreads
+
+    #args: with args.lib; with args;
+    #let
+    #  flagDescr = {
+    #    defaults = { implies   = [ "addOns" "addOns2"]; }; [> [2] defaults and mandatory should be the first listed ? Would you like it different?
+    #    mandatory ={ cfgOption = [ "--with-headers=${args.kernelHeaders}/include" [> [1]
+    #                                "--with-tls" "--without-__thread" "--disable-sanity-checks" ];
+    #                 assert = [ args.glibc.nptl ];
+    #               };
+    #    addOns            = { cfgOption = "--enable-add-ons"; };
+    #    addOns2           = { cfgOption = "--enable-add-ons2"; implies = "addOns"; };
+    #    alternativeAddOn  = { cfgOption = "--enable-add-ons-alt"; blocks = ["addOns", "addOns2"]; };
+    #    justAOption =  { };
+    #  };
+    #  co = chosenOptions flagDescr args args.flags;
+
+    #in args.stdenv.mkDerivation {
+
+    #  # passing the flags in case a library using this want's to check them .. 
+    #  inherit (co) flags buildInputs configureFlags;
+    #  inherit (co.flags) justAOption;
+
+    #  extraSrc = (if co.flags.justAOption then null else src = .. );
+
+    #  src = fetchurl {
+    #    url = http://ftp.gnu.org/gnu/glibc/glibc-2.5.tar.bz2;
+    #    md5 = "1fb29764a6a650a4d5b409dda227ac9f";
+    #  };
+    #}
+
+
+
+  # resolves chosen flags based on flagDescr passed dependencies in args
+  # flagDescr : { name = { cfgOption = "..."; buildInputs = "..."; blocks = "..."; implies = "..."; 
+  #                        assert = "bool";
+  #                        any other options you need which you can get by catAttrs  };
+  #              ...
+  # args = { inherit lib stdenv;
+  #        , inherit < all deps >;
+  #        }
+  # flags = list of chosen options..
+  #
+  # returns: chosen ( like flagDescr but only containing the attributes elected by flags or by implies
+  #          chosenFlat ( chosen flattened to list)
+  #          buildInputs
+  #          configureFlags (both to be passed to mkDerivation)
+  #          flags = { flagName = true/ false for each attribute in flagDescr
+  #                     ... }
+           
+  chosenOptions = flagDescr : args : flags : 
+    let   
+        # helper function
+        collectFlags = state : flags :
+              fold ( flag : s : 
+                     if (__hasAttr flag s.result) then s # this state has already been visited
+                     else if (__hasAttr flag s.blockedFlagsBy) # flag blocked by priviously visited flags?
+                          then throw "flag ${flag} is blocked by ${__getAttr flag s.blockedFlagsBy}"
+                          else if (! __hasAttr flag flagDescr) then throw "unkown flag `${flag}' specified"
+                               else let fDesc = (__getAttr flag flagDescr);
+                                        implied = flatten ( getAttr ["implies"] [] fDesc );
+                                        blocked = flatten ( getAttr ["blocks"] [] fDesc ); 
+                                        s2 = assert (fold ( b : t : 
+                                                 if ( __hasAttr b s.result ) 
+                                                   then  throw "flag ${b} is blocked by ${flag}"
+                                                   else t) true (flatten blocked));
+                                             (collectFlags s implied);
+                                        # add the whole flag to the result set
+                                        in s2 // { result = s2.result //
+                                                      listToAttrs [ { attr = flag; value = (__getAttr flag flagDescr); } ]; }
+              ) state flags;
+        # chosen contains flagDescr but only having those attributes elected by flags (or by implies attributes of elected attributes)
+        chosen = (collectFlags { blockedFlagsBy = {}; result = {}; } flags).result;
+        chosenFlat = flattenSet chosen;
+          
+    in assert ( all (id) (catAttrs "assert" chosenFlat));
+      {
+      # compared to flags flagsSet does also contain the implied flags.. This makes it easy to write assertions. ( assert args.
+      inherit chosen chosenFlat;
+
+      buildInputs = map ( attr: if (! __hasAttr attr args) then throw "argument ${attr} is missing!" else (__getAttr attr args) )
+                    (flatten  (catAttrs "buildInputs" chosenFlat));
+
+      #buildInputNames = catAttrs "name" buildInputs;
+
+      configureFlags = concatStrings (intersperse " " ( catAttrs "cfgOption" chosenFlat)) 
+          + (if (__hasAttr "profilingLibraries" chosen) then "" else " --disable-profiling");
+
+      flags = map ( flag: av flag (__hasAttr flag chosen) ) (__attrNames flagDescr);
+      };
+
+}