1{ lib }:
2
3rec {
4
5 ## Simple (higher order) functions
6
7 /* The identity function
8 For when you need a function that does “nothing”.
9
10 Type: id :: a -> a
11 */
12 id =
13 # The value to return
14 x: x;
15
16 /* The constant function
17
18 Ignores the second argument. If called with only one argument,
19 constructs a function that always returns a static value.
20
21 Type: const :: a -> b -> a
22 Example:
23 let f = const 5; in f 10
24 => 5
25 */
26 const =
27 # Value to return
28 x:
29 # Value to ignore
30 y: x;
31
32 /* Pipes a value through a list of functions, left to right.
33
34 Type: pipe :: a -> [<functions>] -> <return type of last function>
35 Example:
36 pipe 2 [
37 (x: x + 2) # 2 + 2 = 4
38 (x: x * 2) # 4 * 2 = 8
39 ]
40 => 8
41
42 # ideal to do text transformations
43 pipe [ "a/b" "a/c" ] [
44
45 # create the cp command
46 (map (file: ''cp "${src}/${file}" $out\n''))
47
48 # concatenate all commands into one string
49 lib.concatStrings
50
51 # make that string into a nix derivation
52 (pkgs.runCommand "copy-to-out" {})
53
54 ]
55 => <drv which copies all files to $out>
56
57 The output type of each function has to be the input type
58 of the next function, and the last function returns the
59 final value.
60 */
61 pipe = val: functions:
62 let reverseApply = x: f: f x;
63 in builtins.foldl' reverseApply val functions;
64 /* note please don’t add a function like `compose = flip pipe`.
65 This would confuse users, because the order of the functions
66 in the list is not clear. With pipe, it’s obvious that it
67 goes first-to-last. With `compose`, not so much.
68 */
69
70 ## Named versions corresponding to some builtin operators.
71
72 /* Concatenate two lists
73
74 Type: concat :: [a] -> [a] -> [a]
75
76 Example:
77 concat [ 1 2 ] [ 3 4 ]
78 => [ 1 2 3 4 ]
79 */
80 concat = x: y: x ++ y;
81
82 /* boolean “or” */
83 or = x: y: x || y;
84
85 /* boolean “and” */
86 and = x: y: x && y;
87
88 /* bitwise “and” */
89 bitAnd = builtins.bitAnd
90 or (import ./zip-int-bits.nix
91 (a: b: if a==1 && b==1 then 1 else 0));
92
93 /* bitwise “or” */
94 bitOr = builtins.bitOr
95 or (import ./zip-int-bits.nix
96 (a: b: if a==1 || b==1 then 1 else 0));
97
98 /* bitwise “xor” */
99 bitXor = builtins.bitXor
100 or (import ./zip-int-bits.nix
101 (a: b: if a!=b then 1 else 0));
102
103 /* bitwise “not” */
104 bitNot = builtins.sub (-1);
105
106 /* Convert a boolean to a string.
107
108 This function uses the strings "true" and "false" to represent
109 boolean values. Calling `toString` on a bool instead returns "1"
110 and "" (sic!).
111
112 Type: boolToString :: bool -> string
113 */
114 boolToString = b: if b then "true" else "false";
115
116 /* Merge two attribute sets shallowly, right side trumps left
117
118 mergeAttrs :: attrs -> attrs -> attrs
119
120 Example:
121 mergeAttrs { a = 1; b = 2; } { b = 3; c = 4; }
122 => { a = 1; b = 3; c = 4; }
123 */
124 mergeAttrs =
125 # Left attribute set
126 x:
127 # Right attribute set (higher precedence for equal keys)
128 y: x // y;
129
130 /* Flip the order of the arguments of a binary function.
131
132 Type: flip :: (a -> b -> c) -> (b -> a -> c)
133
134 Example:
135 flip concat [1] [2]
136 => [ 2 1 ]
137 */
138 flip = f: a: b: f b a;
139
140 /* Apply function if the supplied argument is non-null.
141
142 Example:
143 mapNullable (x: x+1) null
144 => null
145 mapNullable (x: x+1) 22
146 => 23
147 */
148 mapNullable =
149 # Function to call
150 f:
151 # Argument to check for null before passing it to `f`
152 a: if a == null then a else f a;
153
154 # Pull in some builtins not included elsewhere.
155 inherit (builtins)
156 pathExists readFile isBool
157 isInt isFloat add sub lessThan
158 seq deepSeq genericClosure;
159
160
161 ## nixpkgs version strings
162
163 /* Returns the current full nixpkgs version number. */
164 version = release + versionSuffix;
165
166 /* Returns the current nixpkgs release number as string. */
167 release = lib.strings.fileContents ../.version;
168
169 /* Returns the current nixpkgs release code name.
170
171 On each release the first letter is bumped and a new animal is chosen
172 starting with that new letter.
173 */
174 codeName = "Porcupine";
175
176 /* Returns the current nixpkgs version suffix as string. */
177 versionSuffix =
178 let suffixFile = ../.version-suffix;
179 in if pathExists suffixFile
180 then lib.strings.fileContents suffixFile
181 else "pre-git";
182
183 /* Attempts to return the the current revision of nixpkgs and
184 returns the supplied default value otherwise.
185
186 Type: revisionWithDefault :: string -> string
187 */
188 revisionWithDefault =
189 # Default value to return if revision can not be determined
190 default:
191 let
192 revisionFile = "${toString ./..}/.git-revision";
193 gitRepo = "${toString ./..}/.git";
194 in if lib.pathIsGitRepo gitRepo
195 then lib.commitIdFromGitRepo gitRepo
196 else if lib.pathExists revisionFile then lib.fileContents revisionFile
197 else default;
198
199 nixpkgsVersion = builtins.trace "`lib.nixpkgsVersion` is deprecated, use `lib.version` instead!" version;
200
201 /* Determine whether the function is being called from inside a Nix
202 shell.
203
204 Type: inNixShell :: bool
205 */
206 inNixShell = builtins.getEnv "IN_NIX_SHELL" != "";
207
208
209 ## Integer operations
210
211 /* Return minimum of two numbers. */
212 min = x: y: if x < y then x else y;
213
214 /* Return maximum of two numbers. */
215 max = x: y: if x > y then x else y;
216
217 /* Integer modulus
218
219 Example:
220 mod 11 10
221 => 1
222 mod 1 10
223 => 1
224 */
225 mod = base: int: base - (int * (builtins.div base int));
226
227
228 ## Comparisons
229
230 /* C-style comparisons
231
232 a < b, compare a b => -1
233 a == b, compare a b => 0
234 a > b, compare a b => 1
235 */
236 compare = a: b:
237 if a < b
238 then -1
239 else if a > b
240 then 1
241 else 0;
242
243 /* Split type into two subtypes by predicate `p`, take all elements
244 of the first subtype to be less than all the elements of the
245 second subtype, compare elements of a single subtype with `yes`
246 and `no` respectively.
247
248 Type: (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int)
249
250 Example:
251 let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in
252
253 cmp "a" "z" => -1
254 cmp "fooa" "fooz" => -1
255
256 cmp "f" "a" => 1
257 cmp "fooa" "a" => -1
258 # while
259 compare "fooa" "a" => 1
260 */
261 splitByAndCompare =
262 # Predicate
263 p:
264 # Comparison function if predicate holds for both values
265 yes:
266 # Comparison function if predicate holds for neither value
267 no:
268 # First value to compare
269 a:
270 # Second value to compare
271 b:
272 if p a
273 then if p b then yes a b else -1
274 else if p b then 1 else no a b;
275
276
277 /* Reads a JSON file.
278
279 Type :: path -> any
280 */
281 importJSON = path:
282 builtins.fromJSON (builtins.readFile path);
283
284 /* Reads a TOML file.
285
286 Type :: path -> any
287 */
288 importTOML = path:
289 builtins.fromTOML (builtins.readFile path);
290
291 ## Warnings
292
293 # See https://github.com/NixOS/nix/issues/749. Eventually we'd like these
294 # to expand to Nix builtins that carry metadata so that Nix can filter out
295 # the INFO messages without parsing the message string.
296 #
297 # Usage:
298 # {
299 # foo = lib.warn "foo is deprecated" oldFoo;
300 # bar = lib.warnIf (bar == "") "Empty bar is deprecated" bar;
301 # }
302 #
303 # TODO: figure out a clever way to integrate location information from
304 # something like __unsafeGetAttrPos.
305
306 warn = msg: builtins.trace "[1;31mwarning: ${msg}[0m";
307 warnIf = cond: msg: if cond then warn msg else id;
308
309 info = msg: builtins.trace "INFO: ${msg}";
310
311 showWarnings = warnings: res: lib.fold (w: x: warn w x) res warnings;
312
313 ## Function annotations
314
315 /* Add metadata about expected function arguments to a function.
316 The metadata should match the format given by
317 builtins.functionArgs, i.e. a set from expected argument to a bool
318 representing whether that argument has a default or not.
319 setFunctionArgs : (a → b) → Map String Bool → (a → b)
320
321 This function is necessary because you can't dynamically create a
322 function of the { a, b ? foo, ... }: format, but some facilities
323 like callPackage expect to be able to query expected arguments.
324 */
325 setFunctionArgs = f: args:
326 { # TODO: Should we add call-time "type" checking like built in?
327 __functor = self: f;
328 __functionArgs = args;
329 };
330
331 /* Extract the expected function arguments from a function.
332 This works both with nix-native { a, b ? foo, ... }: style
333 functions and functions with args set with 'setFunctionArgs'. It
334 has the same return type and semantics as builtins.functionArgs.
335 setFunctionArgs : (a → b) → Map String Bool.
336 */
337 functionArgs = f: f.__functionArgs or (builtins.functionArgs f);
338
339 /* Check whether something is a function or something
340 annotated with function args.
341 */
342 isFunction = f: builtins.isFunction f ||
343 (f ? __functor && isFunction (f.__functor f));
344
345 /* Convert the given positive integer to a string of its hexadecimal
346 representation. For example:
347
348 toHexString 0 => "0"
349
350 toHexString 16 => "10"
351
352 toHexString 250 => "FA"
353 */
354 toHexString = i:
355 let
356 toHexDigit = d:
357 if d < 10
358 then toString d
359 else
360 {
361 "10" = "A";
362 "11" = "B";
363 "12" = "C";
364 "13" = "D";
365 "14" = "E";
366 "15" = "F";
367 }.${toString d};
368 in
369 lib.concatMapStrings toHexDigit (toBaseDigits 16 i);
370
371 /* `toBaseDigits base i` converts the positive integer i to a list of its
372 digits in the given base. For example:
373
374 toBaseDigits 10 123 => [ 1 2 3 ]
375
376 toBaseDigits 2 6 => [ 1 1 0 ]
377
378 toBaseDigits 16 250 => [ 15 10 ]
379 */
380 toBaseDigits = base: i:
381 let
382 go = i:
383 if i < base
384 then [i]
385 else
386 let
387 r = i - ((i / base) * base);
388 q = (i - r) / base;
389 in
390 [r] ++ go q;
391 in
392 assert (base >= 2);
393 assert (i >= 0);
394 lib.reverseList (go i);
395}