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
65 # note please don’t add a function like `compose = flip pipe`.
66 # This would confuse users, because the order of the functions
67 # in the list is not clear. With pipe, it’s obvious that it
68 # goes first-to-last. With `compose`, not so much.
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 /* The latest release that is supported, at the time of release branch-off,
170 if applicable.
171
172 Ideally, out-of-tree modules should be able to evaluate cleanly with all
173 supported Nixpkgs versions (master, release and old release until EOL).
174 So if possible, deprecation warnings should take effect only when all
175 out-of-tree expressions/libs/modules can upgrade to the new way without
176 losing support for supported Nixpkgs versions.
177
178 This release number allows deprecation warnings to be implemented such that
179 they take effect as soon as the oldest release reaches end of life. */
180 oldestSupportedRelease =
181 # Update on master only. Do not backport.
182 2305;
183
184 /* Whether a feature is supported in all supported releases (at the time of
185 release branch-off, if applicable). See `oldestSupportedRelease`. */
186 isInOldestRelease =
187 /* Release number of feature introduction as an integer, e.g. 2111 for 21.11.
188 Set it to the upcoming release, matching the nixpkgs/.version file.
189 */
190 release:
191 release <= lib.trivial.oldestSupportedRelease;
192
193 /* Returns the current nixpkgs release code name.
194
195 On each release the first letter is bumped and a new animal is chosen
196 starting with that new letter.
197 */
198 codeName = "Tapir";
199
200 /* Returns the current nixpkgs version suffix as string. */
201 versionSuffix =
202 let suffixFile = ../.version-suffix;
203 in if pathExists suffixFile
204 then lib.strings.fileContents suffixFile
205 else "pre-git";
206
207 /* Attempts to return the the current revision of nixpkgs and
208 returns the supplied default value otherwise.
209
210 Type: revisionWithDefault :: string -> string
211 */
212 revisionWithDefault =
213 # Default value to return if revision can not be determined
214 default:
215 let
216 revisionFile = "${toString ./..}/.git-revision";
217 gitRepo = "${toString ./..}/.git";
218 in if lib.pathIsGitRepo gitRepo
219 then lib.commitIdFromGitRepo gitRepo
220 else if lib.pathExists revisionFile then lib.fileContents revisionFile
221 else default;
222
223 nixpkgsVersion = builtins.trace "`lib.nixpkgsVersion` is deprecated, use `lib.version` instead!" version;
224
225 /* Determine whether the function is being called from inside a Nix
226 shell.
227
228 Type: inNixShell :: bool
229 */
230 inNixShell = builtins.getEnv "IN_NIX_SHELL" != "";
231
232 /* Determine whether the function is being called from inside pure-eval mode
233 by seeing whether `builtins` contains `currentSystem`. If not, we must be in
234 pure-eval mode.
235
236 Type: inPureEvalMode :: bool
237 */
238 inPureEvalMode = ! builtins ? currentSystem;
239
240 ## Integer operations
241
242 /* Return minimum of two numbers. */
243 min = x: y: if x < y then x else y;
244
245 /* Return maximum of two numbers. */
246 max = x: y: if x > y then x else y;
247
248 /* Integer modulus
249
250 Example:
251 mod 11 10
252 => 1
253 mod 1 10
254 => 1
255 */
256 mod = base: int: base - (int * (builtins.div base int));
257
258
259 ## Comparisons
260
261 /* C-style comparisons
262
263 a < b, compare a b => -1
264 a == b, compare a b => 0
265 a > b, compare a b => 1
266 */
267 compare = a: b:
268 if a < b
269 then -1
270 else if a > b
271 then 1
272 else 0;
273
274 /* Split type into two subtypes by predicate `p`, take all elements
275 of the first subtype to be less than all the elements of the
276 second subtype, compare elements of a single subtype with `yes`
277 and `no` respectively.
278
279 Type: (a -> bool) -> (a -> a -> int) -> (a -> a -> int) -> (a -> a -> int)
280
281 Example:
282 let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in
283
284 cmp "a" "z" => -1
285 cmp "fooa" "fooz" => -1
286
287 cmp "f" "a" => 1
288 cmp "fooa" "a" => -1
289 # while
290 compare "fooa" "a" => 1
291 */
292 splitByAndCompare =
293 # Predicate
294 p:
295 # Comparison function if predicate holds for both values
296 yes:
297 # Comparison function if predicate holds for neither value
298 no:
299 # First value to compare
300 a:
301 # Second value to compare
302 b:
303 if p a
304 then if p b then yes a b else -1
305 else if p b then 1 else no a b;
306
307
308 /* Reads a JSON file.
309
310 Type: importJSON :: path -> any
311 */
312 importJSON = path:
313 builtins.fromJSON (builtins.readFile path);
314
315 /* Reads a TOML file.
316
317 Type: importTOML :: path -> any
318 */
319 importTOML = path:
320 builtins.fromTOML (builtins.readFile path);
321
322 ## Warnings
323
324 # See https://github.com/NixOS/nix/issues/749. Eventually we'd like these
325 # to expand to Nix builtins that carry metadata so that Nix can filter out
326 # the INFO messages without parsing the message string.
327 #
328 # Usage:
329 # {
330 # foo = lib.warn "foo is deprecated" oldFoo;
331 # bar = lib.warnIf (bar == "") "Empty bar is deprecated" bar;
332 # }
333 #
334 # TODO: figure out a clever way to integrate location information from
335 # something like __unsafeGetAttrPos.
336
337 /*
338 Print a warning before returning the second argument. This function behaves
339 like `builtins.trace`, but requires a string message and formats it as a
340 warning, including the `warning: ` prefix.
341
342 To get a call stack trace and abort evaluation, set the environment variable
343 `NIX_ABORT_ON_WARN=true` and set the Nix options `--option pure-eval false --show-trace`
344
345 Type: string -> a -> a
346 */
347 warn =
348 if lib.elem (builtins.getEnv "NIX_ABORT_ON_WARN") ["1" "true" "yes"]
349 then msg: builtins.trace "[1;31mwarning: ${msg}[0m" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.")
350 else msg: builtins.trace "[1;31mwarning: ${msg}[0m";
351
352 /*
353 Like warn, but only warn when the first argument is `true`.
354
355 Type: bool -> string -> a -> a
356 */
357 warnIf = cond: msg: if cond then warn msg else x: x;
358
359 /*
360 Like warnIf, but negated (warn if the first argument is `false`).
361
362 Type: bool -> string -> a -> a
363 */
364 warnIfNot = cond: msg: if cond then x: x else warn msg;
365
366 /*
367 Like the `assert b; e` expression, but with a custom error message and
368 without the semicolon.
369
370 If true, return the identity function, `r: r`.
371
372 If false, throw the error message.
373
374 Calls can be juxtaposed using function application, as `(r: r) a = a`, so
375 `(r: r) (r: r) a = a`, and so forth.
376
377 Type: bool -> string -> a -> a
378
379 Example:
380
381 throwIfNot (lib.isList overlays) "The overlays argument to nixpkgs must be a list."
382 lib.foldr (x: throwIfNot (lib.isFunction x) "All overlays passed to nixpkgs must be functions.") (r: r) overlays
383 pkgs
384
385 */
386 throwIfNot = cond: msg: if cond then x: x else throw msg;
387
388 /*
389 Like throwIfNot, but negated (throw if the first argument is `true`).
390
391 Type: bool -> string -> a -> a
392 */
393 throwIf = cond: msg: if cond then throw msg else x: x;
394
395 /* Check if the elements in a list are valid values from a enum, returning the identity function, or throwing an error message otherwise.
396
397 Example:
398 let colorVariants = ["bright" "dark" "black"]
399 in checkListOfEnum "color variants" [ "standard" "light" "dark" ] colorVariants;
400 =>
401 error: color variants: bright, black unexpected; valid ones: standard, light, dark
402
403 Type: String -> List ComparableVal -> List ComparableVal -> a -> a
404 */
405 checkListOfEnum = msg: valid: given:
406 let
407 unexpected = lib.subtractLists valid given;
408 in
409 lib.throwIfNot (unexpected == [])
410 "${msg}: ${builtins.concatStringsSep ", " (builtins.map builtins.toString unexpected)} unexpected; valid ones: ${builtins.concatStringsSep ", " (builtins.map builtins.toString valid)}";
411
412 info = msg: builtins.trace "INFO: ${msg}";
413
414 showWarnings = warnings: res: lib.foldr (w: x: warn w x) res warnings;
415
416 ## Function annotations
417
418 /* Add metadata about expected function arguments to a function.
419 The metadata should match the format given by
420 builtins.functionArgs, i.e. a set from expected argument to a bool
421 representing whether that argument has a default or not.
422 setFunctionArgs : (a → b) → Map String Bool → (a → b)
423
424 This function is necessary because you can't dynamically create a
425 function of the { a, b ? foo, ... }: format, but some facilities
426 like callPackage expect to be able to query expected arguments.
427 */
428 setFunctionArgs = f: args:
429 { # TODO: Should we add call-time "type" checking like built in?
430 __functor = self: f;
431 __functionArgs = args;
432 };
433
434 /* Extract the expected function arguments from a function.
435 This works both with nix-native { a, b ? foo, ... }: style
436 functions and functions with args set with 'setFunctionArgs'. It
437 has the same return type and semantics as builtins.functionArgs.
438 setFunctionArgs : (a → b) → Map String Bool.
439 */
440 functionArgs = f:
441 if f ? __functor
442 then f.__functionArgs or (lib.functionArgs (f.__functor f))
443 else builtins.functionArgs f;
444
445 /* Check whether something is a function or something
446 annotated with function args.
447 */
448 isFunction = f: builtins.isFunction f ||
449 (f ? __functor && isFunction (f.__functor f));
450
451 /*
452 `mirrorFunctionArgs f g` creates a new function `g'` with the same behavior as `g` (`g' x == g x`)
453 but its function arguments mirroring `f` (`lib.functionArgs g' == lib.functionArgs f`).
454
455 Type:
456 mirrorFunctionArgs :: (a -> b) -> (a -> c) -> (a -> c)
457
458 Example:
459 addab = {a, b}: a + b
460 addab { a = 2; b = 4; }
461 => 6
462 lib.functionArgs addab
463 => { a = false; b = false; }
464 addab1 = attrs: addab attrs + 1
465 addab1 { a = 2; b = 4; }
466 => 7
467 lib.functionArgs addab1
468 => { }
469 addab1' = lib.mirrorFunctionArgs addab addab1
470 addab1' { a = 2; b = 4; }
471 => 7
472 lib.functionArgs addab1'
473 => { a = false; b = false; }
474 */
475 mirrorFunctionArgs =
476 # Function to provide the argument metadata
477 f:
478 let
479 fArgs = functionArgs f;
480 in
481 # Function to set the argument metadata to
482 g:
483 setFunctionArgs g fArgs;
484
485 /*
486 Turns any non-callable values into constant functions.
487 Returns callable values as is.
488
489 Example:
490
491 nix-repl> lib.toFunction 1 2
492 1
493
494 nix-repl> lib.toFunction (x: x + 1) 2
495 3
496 */
497 toFunction =
498 # Any value
499 v:
500 if isFunction v
501 then v
502 else k: v;
503
504 /* Convert the given positive integer to a string of its hexadecimal
505 representation. For example:
506
507 toHexString 0 => "0"
508
509 toHexString 16 => "10"
510
511 toHexString 250 => "FA"
512 */
513 toHexString = i:
514 let
515 toHexDigit = d:
516 if d < 10
517 then toString d
518 else
519 {
520 "10" = "A";
521 "11" = "B";
522 "12" = "C";
523 "13" = "D";
524 "14" = "E";
525 "15" = "F";
526 }.${toString d};
527 in
528 lib.concatMapStrings toHexDigit (toBaseDigits 16 i);
529
530 /* `toBaseDigits base i` converts the positive integer i to a list of its
531 digits in the given base. For example:
532
533 toBaseDigits 10 123 => [ 1 2 3 ]
534
535 toBaseDigits 2 6 => [ 1 1 0 ]
536
537 toBaseDigits 16 250 => [ 15 10 ]
538 */
539 toBaseDigits = base: i:
540 let
541 go = i:
542 if i < base
543 then [i]
544 else
545 let
546 r = i - ((i / base) * base);
547 q = (i - r) / base;
548 in
549 [r] ++ go q;
550 in
551 assert (isInt base);
552 assert (isInt i);
553 assert (base >= 2);
554 assert (i >= 0);
555 lib.reverseList (go i);
556}