Merge pull request #49383 from tazjin/docs/lib-docstrings

Update library function "docstrings" for nixdoc generation
This commit is contained in:
Graham Christensen 2018-10-29 11:00:02 +00:00 committed by GitHub
commit 0c5d9e5c52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 539 additions and 215 deletions

View File

@ -23,27 +23,54 @@ rec {
# -- TRACING -- # -- TRACING --
/* Trace msg, but only if pred is true. /* Conditionally trace the supplied message, based on a predicate.
Type: traceIf :: bool -> string -> a -> a
Example: Example:
traceIf true "hello" 3 traceIf true "hello" 3
trace: hello trace: hello
=> 3 => 3
*/ */
traceIf = pred: msg: x: if pred then trace msg x else x; traceIf =
# Predicate to check
pred:
# Message that should be traced
msg:
# Value to return
x: if pred then trace msg x else x;
/* Trace the value and also return it. /* Trace the supplied value after applying a function to it, and
return the original value.
Type: traceValFn :: (a -> b) -> a -> a
Example: Example:
traceValFn (v: "mystring ${v}") "foo" traceValFn (v: "mystring ${v}") "foo"
trace: mystring foo trace: mystring foo
=> "foo" => "foo"
*/ */
traceValFn = f: x: trace (f x) x; traceValFn =
# Function to apply
f:
# Value to trace and return
x: trace (f x) x;
/* Trace the supplied value and return it.
Type: traceVal :: a -> a
Example:
traceVal 42
# trace: 42
=> 42
*/
traceVal = traceValFn id; traceVal = traceValFn id;
/* `builtins.trace`, but the value is `builtins.deepSeq`ed first. /* `builtins.trace`, but the value is `builtins.deepSeq`ed first.
Type: traceSeq :: a -> b -> b
Example: Example:
trace { a.b.c = 3; } null trace { a.b.c = 3; } null
trace: { a = <CODE>; } trace: { a = <CODE>; }
@ -52,7 +79,11 @@ rec {
trace: { a = { b = { c = 3; }; }; } trace: { a = { b = { c = 3; }; }; }
=> null => null
*/ */
traceSeq = x: y: trace (builtins.deepSeq x x) y; traceSeq =
# The value to trace
x:
# The value to return
y: trace (builtins.deepSeq x x) y;
/* Like `traceSeq`, but only evaluate down to depth n. /* Like `traceSeq`, but only evaluate down to depth n.
This is very useful because lots of `traceSeq` usages This is very useful because lots of `traceSeq` usages
@ -76,27 +107,49 @@ rec {
in trace (generators.toPretty { allowPrettyValues = true; } in trace (generators.toPretty { allowPrettyValues = true; }
(modify depth snip x)) y; (modify depth snip x)) y;
/* A combination of `traceVal` and `traceSeq` */ /* A combination of `traceVal` and `traceSeq` that applies a
traceValSeqFn = f: v: traceValFn f (builtins.deepSeq v v); provided function to the value to be traced after `deepSeq`ing
it.
*/
traceValSeqFn =
# Function to apply
f:
# Value to trace
v: traceValFn f (builtins.deepSeq v v);
/* A combination of `traceVal` and `traceSeq`. */
traceValSeq = traceValSeqFn id; traceValSeq = traceValSeqFn id;
/* A combination of `traceVal` and `traceSeqN` that applies a
provided function to the value to be traced. */
traceValSeqNFn =
# Function to apply
f:
depth:
# Value to trace
v: traceSeqN depth (f v) v;
/* A combination of `traceVal` and `traceSeqN`. */ /* A combination of `traceVal` and `traceSeqN`. */
traceValSeqNFn = f: depth: v: traceSeqN depth (f v) v;
traceValSeqN = traceValSeqNFn id; traceValSeqN = traceValSeqNFn id;
# -- TESTING -- # -- TESTING --
/* Evaluate a set of tests. A test is an attribute set {expr, /* Evaluate a set of tests. A test is an attribute set `{expr,
expected}, denoting an expression and its expected result. The expected}`, denoting an expression and its expected result. The
result is a list of failed tests, each represented as {name, result is a list of failed tests, each represented as `{name,
expected, actual}, denoting the attribute name of the failing expected, actual}`, denoting the attribute name of the failing
test and its expected and actual results. Used for regression test and its expected and actual results.
testing of the functions in lib; see tests.nix for an example.
Only tests having names starting with "test" are run. Used for regression testing of the functions in lib; see
Add attr { tests = ["testName"]; } to run these test only tests.nix for an example. Only tests having names starting with
"test" are run.
Add attr { tests = ["testName"]; } to run these tests only.
*/ */
runTests = tests: lib.concatLists (lib.attrValues (lib.mapAttrs (name: test: runTests =
# Tests to run
tests: lib.concatLists (lib.attrValues (lib.mapAttrs (name: test:
let testsToRun = if tests ? tests then tests.tests else []; let testsToRun = if tests ? tests then tests.tests else [];
in if (substring 0 4 name == "test" || elem name testsToRun) in if (substring 0 4 name == "test" || elem name testsToRun)
&& ((testsToRun == []) || elem name tests.tests) && ((testsToRun == []) || elem name tests.tests)
@ -105,8 +158,11 @@ rec {
then [ { inherit name; expected = test.expected; result = test.expr; } ] then [ { inherit name; expected = test.expected; result = test.expr; } ]
else [] ) tests)); else [] ) tests));
# create a test assuming that list elements are true /* Create a test assuming that list elements are `true`.
# usage: { testX = allTrue [ true ]; }
Example:
{ testX = allTrue [ true ]; }
*/
testAllTrue = expr: { inherit expr; expected = map (x: true) expr; }; testAllTrue = expr: { inherit expr; expected = map (x: true) expr; };

View File

@ -1,4 +1,5 @@
# General list operations. # General list operations.
{ lib }: { lib }:
with lib.trivial; with lib.trivial;
let let
@ -8,21 +9,23 @@ rec {
inherit (builtins) head tail length isList elemAt concatLists filter elem genList; inherit (builtins) head tail length isList elemAt concatLists filter elem genList;
/* Create a list consisting of a single element. `singleton x' is /* Create a list consisting of a single element. `singleton x` is
sometimes more convenient with respect to indentation than `[x]' sometimes more convenient with respect to indentation than `[x]`
when x spans multiple lines. when x spans multiple lines.
Type: singleton :: a -> [a]
Example: Example:
singleton "foo" singleton "foo"
=> [ "foo" ] => [ "foo" ]
*/ */
singleton = x: [x]; singleton = x: [x];
/* right fold a binary function `op' between successive elements of /* right fold a binary function `op` between successive elements of
`list' with `nul' as the starting value, i.e., `list` with `nul' as the starting value, i.e.,
`foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))'. `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`.
Type:
foldr :: (a -> b -> b) -> b -> [a] -> b Type: foldr :: (a -> b -> b) -> b -> [a] -> b
Example: Example:
concat = foldr (a: b: a + b) "z" concat = foldr (a: b: a + b) "z"
@ -42,16 +45,15 @@ rec {
else op (elemAt list n) (fold' (n + 1)); else op (elemAt list n) (fold' (n + 1));
in fold' 0; in fold' 0;
/* `fold' is an alias of `foldr' for historic reasons */ /* `fold` is an alias of `foldr` for historic reasons */
# FIXME(Profpatsch): deprecate? # FIXME(Profpatsch): deprecate?
fold = foldr; fold = foldr;
/* left fold, like `foldr', but from the left: /* left fold, like `foldr`, but from the left:
`foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`. `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`.
Type: Type: foldl :: (b -> a -> b) -> b -> [a] -> b
foldl :: (b -> a -> b) -> b -> [a] -> b
Example: Example:
lconcat = foldl (a: b: a + b) "z" lconcat = foldl (a: b: a + b) "z"
@ -70,16 +72,20 @@ rec {
else op (foldl' (n - 1)) (elemAt list n); else op (foldl' (n - 1)) (elemAt list n);
in foldl' (length list - 1); in foldl' (length list - 1);
/* Strict version of `foldl'. /* Strict version of `foldl`.
The difference is that evaluation is forced upon access. Usually used The difference is that evaluation is forced upon access. Usually used
with small whole results (in contract with lazily-generated list or large with small whole results (in contract with lazily-generated list or large
lists where only a part is consumed.) lists where only a part is consumed.)
Type: foldl' :: (b -> a -> b) -> b -> [a] -> b
*/ */
foldl' = builtins.foldl' or foldl; foldl' = builtins.foldl' or foldl;
/* Map with index starting from 0 /* Map with index starting from 0
Type: imap0 :: (int -> a -> b) -> [a] -> [b]
Example: Example:
imap0 (i: v: "${v}-${toString i}") ["a" "b"] imap0 (i: v: "${v}-${toString i}") ["a" "b"]
=> [ "a-0" "b-1" ] => [ "a-0" "b-1" ]
@ -88,6 +94,8 @@ rec {
/* Map with index starting from 1 /* Map with index starting from 1
Type: imap1 :: (int -> a -> b) -> [a] -> [b]
Example: Example:
imap1 (i: v: "${v}-${toString i}") ["a" "b"] imap1 (i: v: "${v}-${toString i}") ["a" "b"]
=> [ "a-1" "b-2" ] => [ "a-1" "b-2" ]
@ -96,6 +104,8 @@ rec {
/* Map and concatenate the result. /* Map and concatenate the result.
Type: concatMap :: (a -> [b]) -> [a] -> [b]
Example: Example:
concatMap (x: [x] ++ ["z"]) ["a" "b"] concatMap (x: [x] ++ ["z"]) ["a" "b"]
=> [ "a" "z" "b" "z" ] => [ "a" "z" "b" "z" ]
@ -118,15 +128,21 @@ rec {
/* Remove elements equal to 'e' from a list. Useful for buildInputs. /* Remove elements equal to 'e' from a list. Useful for buildInputs.
Type: remove :: a -> [a] -> [a]
Example: Example:
remove 3 [ 1 3 4 3 ] remove 3 [ 1 3 4 3 ]
=> [ 1 4 ] => [ 1 4 ]
*/ */
remove = e: filter (x: x != e); remove =
# Element to remove from the list
e: filter (x: x != e);
/* Find the sole element in the list matching the specified /* Find the sole element in the list matching the specified
predicate, returns `default' if no such element exists, or predicate, returns `default` if no such element exists, or
`multiple' if there are multiple matching elements. `multiple` if there are multiple matching elements.
Type: findSingle :: (a -> bool) -> a -> a -> [a] -> a
Example: Example:
findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ] findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
@ -136,14 +152,24 @@ rec {
findSingle (x: x == 3) "none" "multiple" [ 1 9 ] findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
=> "none" => "none"
*/ */
findSingle = pred: default: multiple: list: findSingle =
# Predicate
pred:
# Default value to return if element was not found.
default:
# Default value to return if more than one element was found
multiple:
# Input list
list:
let found = filter pred list; len = length found; let found = filter pred list; len = length found;
in if len == 0 then default in if len == 0 then default
else if len != 1 then multiple else if len != 1 then multiple
else head found; else head found;
/* Find the first element in the list matching the specified /* Find the first element in the list matching the specified
predicate or returns `default' if no such element exists. predicate or return `default` if no such element exists.
Type: findFirst :: (a -> bool) -> a -> [a] -> a
Example: Example:
findFirst (x: x > 3) 7 [ 1 6 4 ] findFirst (x: x > 3) 7 [ 1 6 4 ]
@ -151,12 +177,20 @@ rec {
findFirst (x: x > 9) 7 [ 1 6 4 ] findFirst (x: x > 9) 7 [ 1 6 4 ]
=> 7 => 7
*/ */
findFirst = pred: default: list: findFirst =
# Predicate
pred:
# Default value to return
default:
# Input list
list:
let found = filter pred list; let found = filter pred list;
in if found == [] then default else head found; in if found == [] then default else head found;
/* Return true iff function `pred' returns true for at least element /* Return true if function `pred` returns true for at least one
of `list'. element of `list`.
Type: any :: (a -> bool) -> [a] -> bool
Example: Example:
any isString [ 1 "a" { } ] any isString [ 1 "a" { } ]
@ -166,8 +200,10 @@ rec {
*/ */
any = builtins.any or (pred: foldr (x: y: if pred x then true else y) false); any = builtins.any or (pred: foldr (x: y: if pred x then true else y) false);
/* Return true iff function `pred' returns true for all elements of /* Return true if function `pred` returns true for all elements of
`list'. `list`.
Type: all :: (a -> bool) -> [a] -> bool
Example: Example:
all (x: x < 3) [ 1 2 ] all (x: x < 3) [ 1 2 ]
@ -177,19 +213,25 @@ rec {
*/ */
all = builtins.all or (pred: foldr (x: y: if pred x then y else false) true); all = builtins.all or (pred: foldr (x: y: if pred x then y else false) true);
/* Count how many times function `pred' returns true for the elements /* Count how many elements of `list` match the supplied predicate
of `list'. function.
Type: count :: (a -> bool) -> [a] -> int
Example: Example:
count (x: x == 3) [ 3 2 3 4 6 ] count (x: x == 3) [ 3 2 3 4 6 ]
=> 2 => 2
*/ */
count = pred: foldl' (c: x: if pred x then c + 1 else c) 0; count =
# Predicate
pred: foldl' (c: x: if pred x then c + 1 else c) 0;
/* Return a singleton list or an empty list, depending on a boolean /* Return a singleton list or an empty list, depending on a boolean
value. Useful when building lists with optional elements value. Useful when building lists with optional elements
(e.g. `++ optional (system == "i686-linux") flashplayer'). (e.g. `++ optional (system == "i686-linux") flashplayer').
Type: optional :: bool -> a -> [a]
Example: Example:
optional true "foo" optional true "foo"
=> [ "foo" ] => [ "foo" ]
@ -200,13 +242,19 @@ rec {
/* Return a list or an empty list, depending on a boolean value. /* Return a list or an empty list, depending on a boolean value.
Type: optionals :: bool -> [a] -> [a]
Example: Example:
optionals true [ 2 3 ] optionals true [ 2 3 ]
=> [ 2 3 ] => [ 2 3 ]
optionals false [ 2 3 ] optionals false [ 2 3 ]
=> [ ] => [ ]
*/ */
optionals = cond: elems: if cond then elems else []; optionals =
# Condition
cond:
# List to return if condition is true
elems: if cond then elems else [];
/* If argument is a list, return it; else, wrap it in a singleton /* If argument is a list, return it; else, wrap it in a singleton
@ -223,20 +271,28 @@ rec {
/* Return a list of integers from `first' up to and including `last'. /* Return a list of integers from `first' up to and including `last'.
Type: range :: int -> int -> [int]
Example: Example:
range 2 4 range 2 4
=> [ 2 3 4 ] => [ 2 3 4 ]
range 3 2 range 3 2
=> [ ] => [ ]
*/ */
range = first: last: range =
# First integer in the range
first:
# Last integer in the range
last:
if first > last then if first > last then
[] []
else else
genList (n: first + n) (last - first + 1); genList (n: first + n) (last - first + 1);
/* Splits the elements of a list in two lists, `right' and /* Splits the elements of a list in two lists, `right` and
`wrong', depending on the evaluation of a predicate. `wrong`, depending on the evaluation of a predicate.
Type: (a -> bool) -> [a] -> { right :: [a], wrong :: [a] }
Example: Example:
partition (x: x > 2) [ 5 1 2 3 4 ] partition (x: x > 2) [ 5 1 2 3 4 ]
@ -252,7 +308,7 @@ rec {
/* Splits the elements of a list into many lists, using the return value of a predicate. /* Splits the elements of a list into many lists, using the return value of a predicate.
Predicate should return a string which becomes keys of attrset `groupBy' returns. Predicate should return a string which becomes keys of attrset `groupBy' returns.
`groupBy'' allows to customise the combining function and initial value `groupBy'` allows to customise the combining function and initial value
Example: Example:
groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ] groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
@ -268,10 +324,6 @@ rec {
xfce = [ { name = "xfce"; script = "xfce4-session &"; } ]; xfce = [ { name = "xfce"; script = "xfce4-session &"; } ];
} }
groupBy' allows to customise the combining function and initial value
Example:
groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ] groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
=> { true = 12; false = 3; } => { true = 12; false = 3; }
*/ */
@ -289,17 +341,27 @@ rec {
the merging stops at the shortest. How both lists are merged is defined the merging stops at the shortest. How both lists are merged is defined
by the first argument. by the first argument.
Type: zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c]
Example: Example:
zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"] zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
=> ["he" "lo"] => ["he" "lo"]
*/ */
zipListsWith = f: fst: snd: zipListsWith =
# Function to zip elements of both lists
f:
# First list
fst:
# Second list
snd:
genList genList
(n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd)); (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd));
/* Merges two lists of the same size together. If the sizes aren't the same /* Merges two lists of the same size together. If the sizes aren't the same
the merging stops at the shortest. the merging stops at the shortest.
Type: zipLists :: [a] -> [b] -> [{ fst :: a, snd :: b}]
Example: Example:
zipLists [ 1 2 ] [ "a" "b" ] zipLists [ 1 2 ] [ "a" "b" ]
=> [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ] => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
@ -308,6 +370,8 @@ rec {
/* Reverse the order of the elements of a list. /* Reverse the order of the elements of a list.
Type: reverseList :: [a] -> [a]
Example: Example:
reverseList [ "b" "o" "j" ] reverseList [ "b" "o" "j" ]
@ -321,8 +385,7 @@ rec {
`before a b == true` means that `b` depends on `a` (there's an `before a b == true` means that `b` depends on `a` (there's an
edge from `b` to `a`). edge from `b` to `a`).
Examples: Example:
listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ] listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ]
== { minimal = "/"; # minimal element == { minimal = "/"; # minimal element
visited = [ "/home/user" ]; # seen elements (in reverse order) visited = [ "/home/user" ]; # seen elements (in reverse order)
@ -336,7 +399,6 @@ rec {
rest = [ "/home" "other" ]; # everything else rest = [ "/home" "other" ]; # everything else
*/ */
listDfs = stopOnCycles: before: list: listDfs = stopOnCycles: before: list:
let let
dfs' = us: visited: rest: dfs' = us: visited: rest:
@ -361,7 +423,7 @@ rec {
`before a b == true` means that `b` should be after `a` `before a b == true` means that `b` should be after `a`
in the result. in the result.
Examples: Example:
toposort hasPrefix [ "/home/user" "other" "/" "/home" ] toposort hasPrefix [ "/home/user" "other" "/" "/home" ]
== { result = [ "/" "/home" "/home/user" "other" ]; } == { result = [ "/" "/home" "/home/user" "other" ]; }
@ -376,7 +438,6 @@ rec {
toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; } toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; }
*/ */
toposort = before: list: toposort = before: list:
let let
dfsthis = listDfs true before list; dfsthis = listDfs true before list;
@ -467,26 +528,38 @@ rec {
/* Return the first (at most) N elements of a list. /* Return the first (at most) N elements of a list.
Type: take :: int -> [a] -> [a]
Example: Example:
take 2 [ "a" "b" "c" "d" ] take 2 [ "a" "b" "c" "d" ]
=> [ "a" "b" ] => [ "a" "b" ]
take 2 [ ] take 2 [ ]
=> [ ] => [ ]
*/ */
take = count: sublist 0 count; take =
# Number of elements to take
count: sublist 0 count;
/* Remove the first (at most) N elements of a list. /* Remove the first (at most) N elements of a list.
Type: drop :: int -> [a] -> [a]
Example: Example:
drop 2 [ "a" "b" "c" "d" ] drop 2 [ "a" "b" "c" "d" ]
=> [ "c" "d" ] => [ "c" "d" ]
drop 2 [ ] drop 2 [ ]
=> [ ] => [ ]
*/ */
drop = count: list: sublist count (length list) list; drop =
# Number of elements to drop
count:
# Input list
list: sublist count (length list) list;
/* Return a list consisting of at most count elements of list, /* Return a list consisting of at most `count` elements of `list`,
starting at index start. starting at index `start`.
Type: sublist :: int -> int -> [a] -> [a]
Example: Example:
sublist 1 3 [ "a" "b" "c" "d" "e" ] sublist 1 3 [ "a" "b" "c" "d" "e" ]
@ -494,7 +567,13 @@ rec {
sublist 1 3 [ ] sublist 1 3 [ ]
=> [ ] => [ ]
*/ */
sublist = start: count: list: sublist =
# Index at which to start the sublist
start:
# Number of elements to take
count:
# Input list
list:
let len = length list; in let len = length list; in
genList genList
(n: elemAt list (n + start)) (n: elemAt list (n + start))
@ -504,6 +583,10 @@ rec {
/* Return the last element of a list. /* Return the last element of a list.
This function throws an error if the list is empty.
Type: last :: [a] -> a
Example: Example:
last [ 1 2 3 ] last [ 1 2 3 ]
=> 3 => 3
@ -512,7 +595,11 @@ rec {
assert lib.assertMsg (list != []) "lists.last: list must not be empty!"; assert lib.assertMsg (list != []) "lists.last: list must not be empty!";
elemAt list (length list - 1); elemAt list (length list - 1);
/* Return all elements but the last /* Return all elements but the last.
This function throws an error if the list is empty.
Type: init :: [a] -> [a]
Example: Example:
init [ 1 2 3 ] init [ 1 2 3 ]
@ -523,7 +610,7 @@ rec {
take (length list - 1) list; take (length list - 1) list;
/* return the image of the cross product of some lists by a function /* Return the image of the cross product of some lists by a function.
Example: Example:
crossLists (x:y: "${toString x}${toString y}") [[1 2] [3 4]] crossLists (x:y: "${toString x}${toString y}") [[1 2] [3 4]]
@ -534,8 +621,9 @@ rec {
/* Remove duplicate elements from the list. O(n^2) complexity. /* Remove duplicate elements from the list. O(n^2) complexity.
Example: Type: unique :: [a] -> [a]
Example:
unique [ 3 2 3 4 ] unique [ 3 2 3 4 ]
=> [ 3 2 4 ] => [ 3 2 4 ]
*/ */

View File

@ -8,61 +8,72 @@ with lib.strings;
rec { rec {
# Returns true when the given argument is an option /* Returns true when the given argument is an option
#
# Examples: Type: isOption :: a -> bool
# isOption 1 // => false
# isOption (mkOption {}) // => true Example:
isOption 1 // => false
isOption (mkOption {}) // => true
*/
isOption = lib.isType "option"; isOption = lib.isType "option";
# Creates an Option attribute set. mkOption accepts an attribute set with the following keys: /* Creates an Option attribute set. mkOption accepts an attribute set with the following keys:
#
# default: Default value used when no definition is given in the configuration. All keys default to `null` when not given.
# defaultText: Textual representation of the default, for in the manual.
# example: Example value used in the manual. Example:
# description: String describing the option. mkOption { } // => { _type = "option"; }
# type: Option type, providing type-checking and value merging. mkOption { defaultText = "foo"; } // => { _type = "option"; defaultText = "foo"; }
# apply: Function that converts the option value to something else. */
# internal: Whether the option is for NixOS developers only.
# visible: Whether the option shows up in the manual.
# readOnly: Whether the option can be set only once
# options: Obsolete, used by types.optionSet.
#
# All keys default to `null` when not given.
#
# Examples:
# mkOption { } // => { _type = "option"; }
# mkOption { defaultText = "foo"; } // => { _type = "option"; defaultText = "foo"; }
mkOption = mkOption =
{ default ? null # Default value used when no definition is given in the configuration. {
, defaultText ? null # Textual representation of the default, for in the manual. # Default value used when no definition is given in the configuration.
, example ? null # Example value used in the manual. default ? null,
, description ? null # String describing the option. # Textual representation of the default, for the manual.
, relatedPackages ? null # Related packages used in the manual (see `genRelatedPackages` in ../nixos/doc/manual/default.nix). defaultText ? null,
, type ? null # Option type, providing type-checking and value merging. # Example value used in the manual.
, apply ? null # Function that converts the option value to something else. example ? null,
, internal ? null # Whether the option is for NixOS developers only. # String describing the option.
, visible ? null # Whether the option shows up in the manual. description ? null,
, readOnly ? null # Whether the option can be set only once # Related packages used in the manual (see `genRelatedPackages` in ../nixos/doc/manual/default.nix).
, options ? null # Obsolete, used by types.optionSet. relatedPackages ? null,
# Option type, providing type-checking and value merging.
type ? null,
# Function that converts the option value to something else.
apply ? null,
# Whether the option is for NixOS developers only.
internal ? null,
# Whether the option shows up in the manual.
visible ? null,
# Whether the option can be set only once
readOnly ? null,
# Obsolete, used by types.optionSet.
options ? null
} @ attrs: } @ attrs:
attrs // { _type = "option"; }; attrs // { _type = "option"; };
# Creates a Option attribute set for a boolean value option i.e an option to be toggled on or off: /* Creates an Option attribute set for a boolean value option i.e an
# option to be toggled on or off:
# Examples:
# mkEnableOption "foo" // => { _type = "option"; default = false; description = "Whether to enable foo."; example = true; type = { ... }; } Example:
mkEnableOption = name: mkOption { mkEnableOption "foo"
=> { _type = "option"; default = false; description = "Whether to enable foo."; example = true; type = { ... }; }
*/
mkEnableOption =
# Name for the created option
name: mkOption {
default = false; default = false;
example = true; example = true;
description = "Whether to enable ${name}."; description = "Whether to enable ${name}.";
type = lib.types.bool; type = lib.types.bool;
}; };
# This option accept anything, but it does not produce any result. This /* This option accepts anything, but it does not produce any result.
# is useful for sharing a module across different module sets without
# having to implement similar features as long as the value of the options This is useful for sharing a module across different module sets
# are not expected. without having to implement similar features as long as the
values of the options are not accessed. */
mkSinkUndeclaredOptions = attrs: mkOption ({ mkSinkUndeclaredOptions = attrs: mkOption ({
internal = true; internal = true;
visible = false; visible = false;
@ -102,18 +113,24 @@ rec {
else else
val) (head defs).value defs; val) (head defs).value defs;
# Extracts values of all "value" keys of the given list /* Extracts values of all "value" keys of the given list.
#
# Examples: Type: getValues :: [ { value :: a } ] -> [a]
# getValues [ { value = 1; } { value = 2; } ] // => [ 1 2 ]
# getValues [ ] // => [ ] Example:
getValues [ { value = 1; } { value = 2; } ] // => [ 1 2 ]
getValues [ ] // => [ ]
*/
getValues = map (x: x.value); getValues = map (x: x.value);
# Extracts values of all "file" keys of the given list /* Extracts values of all "file" keys of the given list
#
# Examples: Type: getFiles :: [ { file :: a } ] -> [a]
# getFiles [ { file = "file1"; } { file = "file2"; } ] // => [ "file1" "file2" ]
# getFiles [ ] // => [ ] Example:
getFiles [ { file = "file1"; } { file = "file2"; } ] // => [ "file1" "file2" ]
getFiles [ ] // => [ ]
*/
getFiles = map (x: x.file); getFiles = map (x: x.file);
# Generate documentation template from the list of option declaration like # Generate documentation template from the list of option declaration like
@ -146,10 +163,13 @@ rec {
/* This function recursively removes all derivation attributes from /* This function recursively removes all derivation attributes from
`x' except for the `name' attribute. This is to make the `x` except for the `name` attribute.
generation of `options.xml' much more efficient: the XML
representation of derivations is very large (on the order of This is to make the generation of `options.xml` much more
megabytes) and is not actually used by the manual generator. */ efficient: the XML representation of derivations is very large
(on the order of megabytes) and is not actually used by the
manual generator.
*/
scrubOptionValue = x: scrubOptionValue = x:
if isDerivation x then if isDerivation x then
{ type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; } { type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; }
@ -158,20 +178,21 @@ rec {
else x; else x;
/* For use in the example option attribute. It causes the given /* For use in the `example` option attribute. It causes the given
text to be included verbatim in documentation. This is necessary text to be included verbatim in documentation. This is necessary
for example values that are not simple values, e.g., for example values that are not simple values, e.g., functions.
functions. */ */
literalExample = text: { _type = "literalExample"; inherit text; }; literalExample = text: { _type = "literalExample"; inherit text; };
# Helper functions.
/* Helper functions. */ /* Convert an option, described as a list of the option parts in to a
safe, human readable version.
# Convert an option, described as a list of the option parts in to a Example:
# safe, human readable version. ie: (showOption ["foo" "bar" "baz"]) == "foo.bar.baz"
# (showOption ["foo" "bar.baz" "tux"]) == "foo.\"bar.baz\".tux"
# (showOption ["foo" "bar" "baz"]) == "foo.bar.baz" */
# (showOption ["foo" "bar.baz" "tux"]) == "foo.\"bar.baz\".tux"
showOption = parts: let showOption = parts: let
escapeOptionPart = part: escapeOptionPart = part:
let let

View File

@ -12,6 +12,8 @@ rec {
/* Concatenate a list of strings. /* Concatenate a list of strings.
Type: concatStrings :: [string] -> string
Example: Example:
concatStrings ["foo" "bar"] concatStrings ["foo" "bar"]
=> "foobar" => "foobar"
@ -20,15 +22,19 @@ rec {
/* Map a function over a list and concatenate the resulting strings. /* Map a function over a list and concatenate the resulting strings.
Type: concatMapStrings :: (a -> string) -> [a] -> string
Example: Example:
concatMapStrings (x: "a" + x) ["foo" "bar"] concatMapStrings (x: "a" + x) ["foo" "bar"]
=> "afooabar" => "afooabar"
*/ */
concatMapStrings = f: list: concatStrings (map f list); concatMapStrings = f: list: concatStrings (map f list);
/* Like `concatMapStrings' except that the f functions also gets the /* Like `concatMapStrings` except that the f functions also gets the
position as a parameter. position as a parameter.
Type: concatImapStrings :: (int -> a -> string) -> [a] -> string
Example: Example:
concatImapStrings (pos: x: "${toString pos}-${x}") ["foo" "bar"] concatImapStrings (pos: x: "${toString pos}-${x}") ["foo" "bar"]
=> "1-foo2-bar" => "1-foo2-bar"
@ -37,17 +43,25 @@ rec {
/* Place an element between each element of a list /* Place an element between each element of a list
Type: intersperse :: a -> [a] -> [a]
Example: Example:
intersperse "/" ["usr" "local" "bin"] intersperse "/" ["usr" "local" "bin"]
=> ["usr" "/" "local" "/" "bin"]. => ["usr" "/" "local" "/" "bin"].
*/ */
intersperse = separator: list: intersperse =
# Separator to add between elements
separator:
# Input list
list:
if list == [] || length list == 1 if list == [] || length list == 1
then list then list
else tail (lib.concatMap (x: [separator x]) list); else tail (lib.concatMap (x: [separator x]) list);
/* Concatenate a list of strings with a separator between each element /* Concatenate a list of strings with a separator between each element
Type: concatStringsSep :: string -> [string] -> string
Example: Example:
concatStringsSep "/" ["usr" "local" "bin"] concatStringsSep "/" ["usr" "local" "bin"]
=> "usr/local/bin" => "usr/local/bin"
@ -55,43 +69,77 @@ rec {
concatStringsSep = builtins.concatStringsSep or (separator: list: concatStringsSep = builtins.concatStringsSep or (separator: list:
concatStrings (intersperse separator list)); concatStrings (intersperse separator list));
/* First maps over the list and then concatenates it. /* Maps a function over a list of strings and then concatenates the
result with the specified separator interspersed between
elements.
Type: concatMapStringsSep :: string -> (string -> string) -> [string] -> string
Example: Example:
concatMapStringsSep "-" (x: toUpper x) ["foo" "bar" "baz"] concatMapStringsSep "-" (x: toUpper x) ["foo" "bar" "baz"]
=> "FOO-BAR-BAZ" => "FOO-BAR-BAZ"
*/ */
concatMapStringsSep = sep: f: list: concatStringsSep sep (map f list); concatMapStringsSep =
# Separator to add between elements
sep:
# Function to map over the list
f:
# List of input strings
list: concatStringsSep sep (map f list);
/* First imaps over the list and then concatenates it. /* Same as `concatMapStringsSep`, but the mapping function
additionally receives the position of its argument.
Type: concatMapStringsSep :: string -> (int -> string -> string) -> [string] -> string
Example: Example:
concatImapStringsSep "-" (pos: x: toString (x / pos)) [ 6 6 6 ] concatImapStringsSep "-" (pos: x: toString (x / pos)) [ 6 6 6 ]
=> "6-3-2" => "6-3-2"
*/ */
concatImapStringsSep = sep: f: list: concatStringsSep sep (lib.imap1 f list); concatImapStringsSep =
# Separator to add between elements
sep:
# Function that receives elements and their positions
f:
# List of input strings
list: concatStringsSep sep (lib.imap1 f list);
/* Construct a Unix-style search path consisting of each `subDir" /* Construct a Unix-style, colon-separated search path consisting of
directory of the given list of packages. the given `subDir` appended to each of the given paths.
Type: makeSearchPath :: string -> [string] -> string
Example: Example:
makeSearchPath "bin" ["/root" "/usr" "/usr/local"] makeSearchPath "bin" ["/root" "/usr" "/usr/local"]
=> "/root/bin:/usr/bin:/usr/local/bin" => "/root/bin:/usr/bin:/usr/local/bin"
makeSearchPath "bin" ["/"] makeSearchPath "bin" [""]
=> "//bin" => "/bin"
*/ */
makeSearchPath = subDir: packages: makeSearchPath =
concatStringsSep ":" (map (path: path + "/" + subDir) (builtins.filter (x: x != null) packages)); # Directory name to append
subDir:
# List of base paths
paths:
concatStringsSep ":" (map (path: path + "/" + subDir) (builtins.filter (x: x != null) paths));
/* Construct a Unix-style search path, using given package output. /* Construct a Unix-style search path by appending the given
If no output is found, fallback to `.out` and then to the default. `subDir` to the specified `output` of each of the packages. If no
output by the given name is found, fallback to `.out` and then to
the default.
Type: string -> string -> [package] -> string
Example: Example:
makeSearchPathOutput "dev" "bin" [ pkgs.openssl pkgs.zlib ] makeSearchPathOutput "dev" "bin" [ pkgs.openssl pkgs.zlib ]
=> "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev/bin:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/bin" => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev/bin:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/bin"
*/ */
makeSearchPathOutput = output: subDir: pkgs: makeSearchPath subDir (map (lib.getOutput output) pkgs); makeSearchPathOutput =
# Package output to use
output:
# Directory name to append
subDir:
# List of packages
pkgs: makeSearchPath subDir (map (lib.getOutput output) pkgs);
/* Construct a library search path (such as RPATH) containing the /* Construct a library search path (such as RPATH) containing the
libraries for a set of packages libraries for a set of packages
@ -117,13 +165,12 @@ rec {
/* Construct a perl search path (such as $PERL5LIB) /* Construct a perl search path (such as $PERL5LIB)
FIXME(zimbatm): this should be moved in perl-specific code
Example: Example:
pkgs = import <nixpkgs> { } pkgs = import <nixpkgs> { }
makePerlPath [ pkgs.perlPackages.libnet ] makePerlPath [ pkgs.perlPackages.libnet ]
=> "/nix/store/n0m1fk9c960d8wlrs62sncnadygqqc6y-perl-Net-SMTP-1.25/lib/perl5/site_perl" => "/nix/store/n0m1fk9c960d8wlrs62sncnadygqqc6y-perl-Net-SMTP-1.25/lib/perl5/site_perl"
*/ */
# FIXME(zimbatm): this should be moved in perl-specific code
makePerlPath = makeSearchPathOutput "lib" "lib/perl5/site_perl"; makePerlPath = makeSearchPathOutput "lib" "lib/perl5/site_perl";
/* Construct a perl search path recursively including all dependencies (such as $PERL5LIB) /* Construct a perl search path recursively including all dependencies (such as $PERL5LIB)
@ -138,34 +185,51 @@ rec {
/* Depending on the boolean `cond', return either the given string /* Depending on the boolean `cond', return either the given string
or the empty string. Useful to concatenate against a bigger string. or the empty string. Useful to concatenate against a bigger string.
Type: optionalString :: bool -> string -> string
Example: Example:
optionalString true "some-string" optionalString true "some-string"
=> "some-string" => "some-string"
optionalString false "some-string" optionalString false "some-string"
=> "" => ""
*/ */
optionalString = cond: string: if cond then string else ""; optionalString =
# Condition
cond:
# String to return if condition is true
string: if cond then string else "";
/* Determine whether a string has given prefix. /* Determine whether a string has given prefix.
Type: hasPrefix :: string -> string -> bool
Example: Example:
hasPrefix "foo" "foobar" hasPrefix "foo" "foobar"
=> true => true
hasPrefix "foo" "barfoo" hasPrefix "foo" "barfoo"
=> false => false
*/ */
hasPrefix = pref: str: hasPrefix =
substring 0 (stringLength pref) str == pref; # Prefix to check for
pref:
# Input string
str: substring 0 (stringLength pref) str == pref;
/* Determine whether a string has given suffix. /* Determine whether a string has given suffix.
Type: hasSuffix :: string -> string -> bool
Example: Example:
hasSuffix "foo" "foobar" hasSuffix "foo" "foobar"
=> false => false
hasSuffix "foo" "barfoo" hasSuffix "foo" "barfoo"
=> true => true
*/ */
hasSuffix = suffix: content: hasSuffix =
# Suffix to check for
suffix:
# Input string
content:
let let
lenContent = stringLength content; lenContent = stringLength content;
lenSuffix = stringLength suffix; lenSuffix = stringLength suffix;
@ -180,6 +244,8 @@ rec {
Also note that Nix treats strings as a list of bytes and thus doesn't Also note that Nix treats strings as a list of bytes and thus doesn't
handle unicode. handle unicode.
Type: stringtoCharacters :: string -> [string]
Example: Example:
stringToCharacters "" stringToCharacters ""
=> [ ] => [ ]
@ -194,18 +260,25 @@ rec {
/* Manipulate a string character by character and replace them by /* Manipulate a string character by character and replace them by
strings before concatenating the results. strings before concatenating the results.
Type: stringAsChars :: (string -> string) -> string -> string
Example: Example:
stringAsChars (x: if x == "a" then "i" else x) "nax" stringAsChars (x: if x == "a" then "i" else x) "nax"
=> "nix" => "nix"
*/ */
stringAsChars = f: s: stringAsChars =
concatStrings ( # Function to map over each individual character
f:
# Input string
s: concatStrings (
map f (stringToCharacters s) map f (stringToCharacters s)
); );
/* Escape occurrence of the elements of list in string by /* Escape occurrence of the elements of `list` in `string` by
prefixing it with a backslash. prefixing it with a backslash.
Type: escape :: [string] -> string -> string
Example: Example:
escape ["(" ")"] "(foo)" escape ["(" ")"] "(foo)"
=> "\\(foo\\)" => "\\(foo\\)"
@ -214,6 +287,8 @@ rec {
/* Quote string to be used safely within the Bourne shell. /* Quote string to be used safely within the Bourne shell.
Type: escapeShellArg :: string -> string
Example: Example:
escapeShellArg "esc'ape\nme" escapeShellArg "esc'ape\nme"
=> "'esc'\\''ape\nme'" => "'esc'\\''ape\nme'"
@ -222,6 +297,8 @@ rec {
/* Quote all arguments to be safely passed to the Bourne shell. /* Quote all arguments to be safely passed to the Bourne shell.
Type: escapeShellArgs :: [string] -> string
Example: Example:
escapeShellArgs ["one" "two three" "four'five"] escapeShellArgs ["one" "two three" "four'five"]
=> "'one' 'two three' 'four'\\''five'" => "'one' 'two three' 'four'\\''five'"
@ -230,13 +307,15 @@ rec {
/* Turn a string into a Nix expression representing that string /* Turn a string into a Nix expression representing that string
Type: string -> string
Example: Example:
escapeNixString "hello\${}\n" escapeNixString "hello\${}\n"
=> "\"hello\\\${}\\n\"" => "\"hello\\\${}\\n\""
*/ */
escapeNixString = s: escape ["$"] (builtins.toJSON s); escapeNixString = s: escape ["$"] (builtins.toJSON s);
/* Obsolete - use replaceStrings instead. */ # Obsolete - use replaceStrings instead.
replaceChars = builtins.replaceStrings or ( replaceChars = builtins.replaceStrings or (
del: new: s: del: new: s:
let let
@ -256,6 +335,8 @@ rec {
/* Converts an ASCII string to lower-case. /* Converts an ASCII string to lower-case.
Type: toLower :: string -> string
Example: Example:
toLower "HOME" toLower "HOME"
=> "home" => "home"
@ -264,6 +345,8 @@ rec {
/* Converts an ASCII string to upper-case. /* Converts an ASCII string to upper-case.
Type: toUpper :: string -> string
Example: Example:
toUpper "home" toUpper "home"
=> "HOME" => "HOME"
@ -273,7 +356,7 @@ rec {
/* Appends string context from another string. This is an implementation /* Appends string context from another string. This is an implementation
detail of Nix. detail of Nix.
Strings in Nix carry an invisible `context' which is a list of strings Strings in Nix carry an invisible `context` which is a list of strings
representing store paths. If the string is later used in a derivation representing store paths. If the string is later used in a derivation
attribute, the derivation will properly populate the inputDrvs and attribute, the derivation will properly populate the inputDrvs and
inputSrcs. inputSrcs.
@ -319,8 +402,9 @@ rec {
in in
recurse 0 0; recurse 0 0;
/* Return the suffix of the second argument if the first argument matches /* Return a string without the specified prefix, if the prefix matches.
its prefix.
Type: string -> string -> string
Example: Example:
removePrefix "foo." "foo.bar.baz" removePrefix "foo." "foo.bar.baz"
@ -328,18 +412,23 @@ rec {
removePrefix "xxx" "foo.bar.baz" removePrefix "xxx" "foo.bar.baz"
=> "foo.bar.baz" => "foo.bar.baz"
*/ */
removePrefix = pre: s: removePrefix =
# Prefix to remove if it matches
prefix:
# Input string
str:
let let
preLen = stringLength pre; preLen = stringLength prefix;
sLen = stringLength s; sLen = stringLength str;
in in
if hasPrefix pre s then if hasPrefix prefix str then
substring preLen (sLen - preLen) s substring preLen (sLen - preLen) str
else else
s; str;
/* Return the prefix of the second argument if the first argument matches /* Return a string without the specified suffix, if the suffix matches.
its suffix.
Type: string -> string -> string
Example: Example:
removeSuffix "front" "homefront" removeSuffix "front" "homefront"
@ -347,17 +436,21 @@ rec {
removeSuffix "xxx" "homefront" removeSuffix "xxx" "homefront"
=> "homefront" => "homefront"
*/ */
removeSuffix = suf: s: removeSuffix =
# Suffix to remove if it matches
suffix:
# Input string
str:
let let
sufLen = stringLength suf; sufLen = stringLength suffix;
sLen = stringLength s; sLen = stringLength str;
in in
if sufLen <= sLen && suf == substring (sLen - sufLen) sufLen s then if sufLen <= sLen && suffix == substring (sLen - sufLen) sufLen str then
substring 0 (sLen - sufLen) s substring 0 (sLen - sufLen) str
else else
s; str;
/* Return true iff string v1 denotes a version older than v2. /* Return true if string v1 denotes a version older than v2.
Example: Example:
versionOlder "1.1" "1.2" versionOlder "1.1" "1.2"
@ -367,7 +460,7 @@ rec {
*/ */
versionOlder = v1: v2: builtins.compareVersions v2 v1 == 1; versionOlder = v1: v2: builtins.compareVersions v2 v1 == 1;
/* Return true iff string v1 denotes a version equal to or newer than v2. /* Return true if string v1 denotes a version equal to or newer than v2.
Example: Example:
versionAtLeast "1.1" "1.0" versionAtLeast "1.1" "1.0"
@ -459,6 +552,11 @@ rec {
/* Create a fixed width string with additional prefix to match /* Create a fixed width string with additional prefix to match
required width. required width.
This function will fail if the input string is longer than the
requested length.
Type: fixedWidthString :: int -> string -> string
Example: Example:
fixedWidthString 5 "0" (toString 15) fixedWidthString 5 "0" (toString 15)
=> "00015" => "00015"
@ -509,8 +607,9 @@ rec {
else else
false; false;
/* Convert string to int /* Parse a string string as an int.
Obviously, it is a bit hacky to use fromJSON that way.
Type: string -> int
Example: Example:
toInt "1337" toInt "1337"
@ -520,17 +619,18 @@ rec {
toInt "3.14" toInt "3.14"
=> error: floating point JSON numbers are not supported => error: floating point JSON numbers are not supported
*/ */
# Obviously, it is a bit hacky to use fromJSON this way.
toInt = str: toInt = str:
let may_be_int = builtins.fromJSON str; in let may_be_int = builtins.fromJSON str; in
if builtins.isInt may_be_int if builtins.isInt may_be_int
then may_be_int then may_be_int
else throw "Could not convert ${str} to int."; else throw "Could not convert ${str} to int.";
/* Read a list of paths from `file', relative to the `rootPath'. Lines /* Read a list of paths from `file`, relative to the `rootPath`.
beginning with `#' are treated as comments and ignored. Whitespace Lines beginning with `#` are treated as comments and ignored.
is significant. Whitespace is significant.
NOTE: this function is not performant and should be avoided NOTE: This function is not performant and should be avoided.
Example: Example:
readPathsFromFile /prefix readPathsFromFile /prefix
@ -552,6 +652,8 @@ rec {
/* Read the contents of a file removing the trailing \n /* Read the contents of a file removing the trailing \n
Type: fileContents :: path -> string
Example: Example:
$ echo "1.0" > ./version $ echo "1.0" > ./version

View File

@ -9,23 +9,37 @@ rec {
Type: id :: a -> a Type: id :: a -> a
*/ */
id = x: x; id =
# The value to return
x: x;
/* The constant function /* The constant function
Ignores the second argument.
Or: Construct a function that always returns a static value. Ignores the second argument. If called with only one argument,
constructs a function that always returns a static value.
Type: const :: a -> b -> a Type: const :: a -> b -> a
Example: Example:
let f = const 5; in f 10 let f = const 5; in f 10
=> 5 => 5
*/ */
const = x: y: x; const =
# Value to return
x:
# Value to ignore
y: x;
## Named versions corresponding to some builtin operators. ## Named versions corresponding to some builtin operators.
/* Concatenate two lists */ /* Concatenate two lists
Type: concat :: [a] -> [a] -> [a]
Example:
concat [ 1 2 ] [ 3 4 ]
=> [ 1 2 3 4 ]
*/
concat = x: y: x ++ y; concat = x: y: x ++ y;
/* boolean or */ /* boolean or */
@ -53,27 +67,40 @@ rec {
bitNot = builtins.sub (-1); bitNot = builtins.sub (-1);
/* Convert a boolean to a string. /* Convert a boolean to a string.
Note that toString on a bool returns "1" and "".
This function uses the strings "true" and "false" to represent
boolean values. Calling `toString` on a bool instead returns "1"
and "" (sic!).
Type: boolToString :: bool -> string
*/ */
boolToString = b: if b then "true" else "false"; boolToString = b: if b then "true" else "false";
/* Merge two attribute sets shallowly, right side trumps left /* Merge two attribute sets shallowly, right side trumps left
mergeAttrs :: attrs -> attrs -> attrs
Example: Example:
mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; } mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; }
=> { a = 1; b = 3; c = 4; } => { a = 1; b = 3; c = 4; }
*/ */
mergeAttrs = x: y: x // y; mergeAttrs =
# Left attribute set
x:
# Right attribute set (higher precedence for equal keys)
y: x // y;
/* Flip the order of the arguments of a binary function. /* Flip the order of the arguments of a binary function.
Type: flip :: (a -> b -> c) -> (b -> a -> c)
Example: Example:
flip concat [1] [2] flip concat [1] [2]
=> [ 2 1 ] => [ 2 1 ]
*/ */
flip = f: a: b: f b a; flip = f: a: b: f b a;
/* Apply function if argument is non-null. /* Apply function if the supplied argument is non-null.
Example: Example:
mapNullable (x: x+1) null mapNullable (x: x+1) null
@ -81,7 +108,11 @@ rec {
mapNullable (x: x+1) 22 mapNullable (x: x+1) 22
=> 23 => 23
*/ */
mapNullable = f: a: if isNull a then a else f a; mapNullable =
# Function to call
f:
# Argument to check for null before passing it to `f`
a: if isNull a then a else f a;
# Pull in some builtins not included elsewhere. # Pull in some builtins not included elsewhere.
inherit (builtins) inherit (builtins)
@ -92,21 +123,27 @@ rec {
## nixpks version strings ## nixpks version strings
# The current full nixpkgs version number. /* Returns the current full nixpkgs version number. */
version = release + versionSuffix; version = release + versionSuffix;
# The current nixpkgs version number as string. /* Returns the current nixpkgs release number as string. */
release = lib.strings.fileContents ../.version; release = lib.strings.fileContents ../.version;
# The current nixpkgs version suffix as string. /* Returns the current nixpkgs version suffix as string. */
versionSuffix = versionSuffix =
let suffixFile = ../.version-suffix; let suffixFile = ../.version-suffix;
in if pathExists suffixFile in if pathExists suffixFile
then lib.strings.fileContents suffixFile then lib.strings.fileContents suffixFile
else "pre-git"; else "pre-git";
# Attempt to get the revision nixpkgs is from /* Attempts to return the the current revision of nixpkgs and
revisionWithDefault = default: returns the supplied default value otherwise.
Type: revisionWithDefault :: string -> string
*/
revisionWithDefault =
# Default value to return if revision can not be determined
default:
let let
revisionFile = "${toString ./..}/.git-revision"; revisionFile = "${toString ./..}/.git-revision";
gitRepo = "${toString ./..}/.git"; gitRepo = "${toString ./..}/.git";
@ -117,14 +154,20 @@ rec {
nixpkgsVersion = builtins.trace "`lib.nixpkgsVersion` is deprecated, use `lib.version` instead!" version; nixpkgsVersion = builtins.trace "`lib.nixpkgsVersion` is deprecated, use `lib.version` instead!" version;
# Whether we're being called by nix-shell. /* Determine whether the function is being called from inside a Nix
shell.
Type: inNixShell :: bool
*/
inNixShell = builtins.getEnv "IN_NIX_SHELL" != ""; inNixShell = builtins.getEnv "IN_NIX_SHELL" != "";
## Integer operations ## Integer operations
# Return minimum/maximum of two numbers. /* Return minimum of two numbers. */
min = x: y: if x < y then x else y; min = x: y: if x < y then x else y;
/* Return maximum of two numbers. */
max = x: y: if x > y then x else y; max = x: y: if x > y then x else y;
/* Integer modulus /* Integer modulus
@ -158,8 +201,9 @@ rec {
second subtype, compare elements of a single subtype with `yes` second subtype, compare elements of a single subtype with `yes`
and `no` respectively. and `no` respectively.
Example: Type: (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int)
Example:
let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in
cmp "a" "z" => -1 cmp "a" "z" => -1
@ -170,31 +214,44 @@ rec {
# while # while
compare "fooa" "a" => 1 compare "fooa" "a" => 1
*/ */
splitByAndCompare = p: yes: no: a: b: splitByAndCompare =
# Predicate
p:
# Comparison function if predicate holds for both values
yes:
# Comparison function if predicate holds for neither value
no:
# First value to compare
a:
# Second value to compare
b:
if p a if p a
then if p b then yes a b else -1 then if p b then yes a b else -1
else if p b then 1 else no a b; else if p b then 1 else no a b;
/* Reads a JSON file. */ /* Reads a JSON file.
Type :: path -> any
*/
importJSON = path: importJSON = path:
builtins.fromJSON (builtins.readFile path); builtins.fromJSON (builtins.readFile path);
## Warnings ## Warnings
/* See https://github.com/NixOS/nix/issues/749. Eventually we'd like these # See https://github.com/NixOS/nix/issues/749. Eventually we'd like these
to expand to Nix builtins that carry metadata so that Nix can filter out # to expand to Nix builtins that carry metadata so that Nix can filter out
the INFO messages without parsing the message string. # the INFO messages without parsing the message string.
#
# Usage:
# {
# foo = lib.warn "foo is deprecated" oldFoo;
# }
#
# TODO: figure out a clever way to integrate location information from
# something like __unsafeGetAttrPos.
Usage:
{
foo = lib.warn "foo is deprecated" oldFoo;
}
TODO: figure out a clever way to integrate location information from
something like __unsafeGetAttrPos.
*/
warn = msg: builtins.trace "WARNING: ${msg}"; warn = msg: builtins.trace "WARNING: ${msg}";
info = msg: builtins.trace "INFO: ${msg}"; info = msg: builtins.trace "INFO: ${msg}";