at 22.05-pre 11 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 /* note please dont 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, its 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 "warning: ${msg}" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.") 319 else msg: builtins.trace "warning: ${msg}"; 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}