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 /*
307 Print a warning before returning the second argument. This function behaves
308 like `builtins.trace`, but requires a string message and formats it as a
309 warning, including the `warning: ` prefix.
310
311 To get a call stack trace and abort evaluation, set the environment variable
312 `NIX_ABORT_ON_WARN=true` and set the Nix options `--option pure-eval false --show-trace`
313
314 Type: string -> a -> a
315 */
316 warn =
317 if lib.elem (builtins.getEnv "NIX_ABORT_ON_WARN") ["1" "true" "yes"]
318 then msg: builtins.trace "[1;31mwarning: ${msg}[0m" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.")
319 else msg: builtins.trace "[1;31mwarning: ${msg}[0m";
320
321 /*
322 Like warn, but only warn when the first argument is `true`.
323
324 Type: bool -> string -> a -> a
325 */
326 warnIf = cond: msg: if cond then warn msg else id;
327
328 info = msg: builtins.trace "INFO: ${msg}";
329
330 showWarnings = warnings: res: lib.foldr (w: x: warn w x) res warnings;
331
332 ## Function annotations
333
334 /* Add metadata about expected function arguments to a function.
335 The metadata should match the format given by
336 builtins.functionArgs, i.e. a set from expected argument to a bool
337 representing whether that argument has a default or not.
338 setFunctionArgs : (a → b) → Map String Bool → (a → b)
339
340 This function is necessary because you can't dynamically create a
341 function of the { a, b ? foo, ... }: format, but some facilities
342 like callPackage expect to be able to query expected arguments.
343 */
344 setFunctionArgs = f: args:
345 { # TODO: Should we add call-time "type" checking like built in?
346 __functor = self: f;
347 __functionArgs = args;
348 };
349
350 /* Extract the expected function arguments from a function.
351 This works both with nix-native { a, b ? foo, ... }: style
352 functions and functions with args set with 'setFunctionArgs'. It
353 has the same return type and semantics as builtins.functionArgs.
354 setFunctionArgs : (a → b) → Map String Bool.
355 */
356 functionArgs = f:
357 if f ? __functor
358 then f.__functionArgs or (lib.functionArgs (f.__functor f))
359 else builtins.functionArgs f;
360
361 /* Check whether something is a function or something
362 annotated with function args.
363 */
364 isFunction = f: builtins.isFunction f ||
365 (f ? __functor && isFunction (f.__functor f));
366
367 /* Convert the given positive integer to a string of its hexadecimal
368 representation. For example:
369
370 toHexString 0 => "0"
371
372 toHexString 16 => "10"
373
374 toHexString 250 => "FA"
375 */
376 toHexString = i:
377 let
378 toHexDigit = d:
379 if d < 10
380 then toString d
381 else
382 {
383 "10" = "A";
384 "11" = "B";
385 "12" = "C";
386 "13" = "D";
387 "14" = "E";
388 "15" = "F";
389 }.${toString d};
390 in
391 lib.concatMapStrings toHexDigit (toBaseDigits 16 i);
392
393 /* `toBaseDigits base i` converts the positive integer i to a list of its
394 digits in the given base. For example:
395
396 toBaseDigits 10 123 => [ 1 2 3 ]
397
398 toBaseDigits 2 6 => [ 1 1 0 ]
399
400 toBaseDigits 16 250 => [ 15 10 ]
401 */
402 toBaseDigits = base: i:
403 let
404 go = i:
405 if i < base
406 then [i]
407 else
408 let
409 r = i - ((i / base) * base);
410 q = (i - r) / base;
411 in
412 [r] ++ go q;
413 in
414 assert (base >= 2);
415 assert (i >= 0);
416 lib.reverseList (go i);
417}