at 23.11-beta 16 kB view raw
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 "warning: ${msg}" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.") 350 else msg: builtins.trace "warning: ${msg}"; 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}