2006-09-25 11:07:59 +01:00
|
|
|
# Utility functions.
|
|
|
|
|
2006-11-27 16:58:08 +00:00
|
|
|
let
|
|
|
|
|
2007-01-29 14:53:23 +00:00
|
|
|
inherit (builtins)
|
|
|
|
head tail isList stringLength substring lessThan sub;
|
2006-11-27 16:58:08 +00:00
|
|
|
|
|
|
|
in
|
|
|
|
|
2006-09-25 11:07:59 +01:00
|
|
|
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
|
2006-11-27 16:58:08 +00:00
|
|
|
else op (head list) (fold op nul (tail list));
|
2006-09-25 11:07:59 +01:00
|
|
|
|
|
|
|
|
2007-03-06 00:01:27 +00:00
|
|
|
# Concatenate a list of lists.
|
|
|
|
concatLists =
|
|
|
|
fold (x: y: x ++ y) [];
|
|
|
|
|
|
|
|
|
2006-09-25 11:07:59 +01:00
|
|
|
# Concatenate a list of strings.
|
|
|
|
concatStrings =
|
|
|
|
fold (x: y: x + y) "";
|
|
|
|
|
|
|
|
|
2006-10-12 11:53:16 +01:00
|
|
|
# Place an element between each element of a list, e.g.,
|
|
|
|
# `intersperse "," ["a" "b" "c"]' returns ["a" "," "b" "," "c"].
|
|
|
|
intersperse = separator: list:
|
2006-11-27 16:58:08 +00:00
|
|
|
if list == [] || tail list == []
|
2006-10-12 11:53:16 +01:00
|
|
|
then list
|
2006-11-27 16:58:08 +00:00
|
|
|
else [(head list) separator]
|
|
|
|
++ (intersperse separator (tail list));
|
2006-10-12 11:53:16 +01:00
|
|
|
|
|
|
|
|
2007-05-27 15:34:01 +01:00
|
|
|
concatStringsSep = separator: list:
|
|
|
|
concatStrings (intersperse separator list);
|
|
|
|
|
|
|
|
|
2006-09-25 11:07:59 +01:00
|
|
|
# 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:
|
2006-11-27 16:58:08 +00:00
|
|
|
if isList x
|
2006-09-25 11:07:59 +01:00
|
|
|
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.
|
|
|
|
getAttr = attrPath: default: e:
|
|
|
|
let {
|
2006-11-27 16:58:08 +00:00
|
|
|
attr = head attrPath;
|
2006-09-25 11:07:59 +01:00
|
|
|
body =
|
|
|
|
if attrPath == [] then e
|
|
|
|
else if builtins ? hasAttr && builtins.hasAttr attr e
|
2006-11-27 16:58:08 +00:00
|
|
|
then getAttr (tail attrPath) default (builtins.getAttr attr e)
|
2006-09-25 11:07:59 +01:00
|
|
|
else default;
|
|
|
|
};
|
2006-11-27 16:58:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
# 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;
|
|
|
|
|
|
|
|
|
2007-01-08 22:49:26 +00:00
|
|
|
# Return true if `list' has an element `x':
|
|
|
|
elem = x: list: fold (a: bs: x == a || bs) false list;
|
|
|
|
|
|
|
|
|
2006-12-21 00:09:40 +00:00
|
|
|
# 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;
|
|
|
|
|
|
|
|
|
2006-11-27 16:58:08 +00:00
|
|
|
# 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);
|
|
|
|
|
2007-01-29 14:53:23 +00:00
|
|
|
|
|
|
|
# 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 (*~).
|
2007-01-15 09:20:18 +00:00
|
|
|
cleanSource =
|
2007-01-29 14:53:23 +00:00
|
|
|
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)
|
|
|
|
);
|
2007-01-15 09:20:18 +00:00
|
|
|
in src: builtins.filterSource filter src;
|
|
|
|
|
2007-05-20 21:24:43 +01:00
|
|
|
|
|
|
|
# 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 [];
|
|
|
|
|
2007-06-09 20:45:55 +01:00
|
|
|
|
|
|
|
# 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;
|
|
|
|
|
2007-08-11 11:34:07 +01:00
|
|
|
# Return true only if there is an attribute and it is true.
|
|
|
|
checkFlag = attrSet: name:
|
|
|
|
if (name == "true") then true else
|
2007-08-11 12:14:36 +01:00
|
|
|
if (name == "false") then false else
|
2007-08-15 21:54:11 +01:00
|
|
|
if (isInList (getAttr ["flags"] [] attrSet) name) then true else
|
2007-08-11 11:34:07 +01:00
|
|
|
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:
|
2007-08-15 21:54:11 +01:00
|
|
|
( getAttr [name] (if checkFlag attrSet name then true else
|
|
|
|
if argList == [] then null else
|
2007-08-11 11:34:07 +01:00
|
|
|
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;
|
2007-08-11 12:14:36 +01:00
|
|
|
|
|
|
|
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);};
|
|
|
|
|
2007-08-15 22:17:11 +01:00
|
|
|
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;
|
|
|
|
|
2006-11-27 16:58:08 +00:00
|
|
|
}
|