{ lib }: let inherit (lib) all concatStringsSep findFirst flip getAttr head isFunction length recursiveUpdate splitVersion tail take versionAtLeast versionOlder zipListsWith ; in recursiveUpdate lib (rec { versions = let truncate = n: v: concatStringsSep "." (take n (splitVersion v)); opTruncate = op: v0: v: let n = length (splitVersion v0); in op (truncate n v) (truncate n v0); in rec { /* Get string of the first n parts of a version string. Example: - truncate 2 "1.2.3-stuff" => "1.2" - truncate 4 "1.2.3-stuff" => "1.2.3.stuff" */ inherit truncate; /* Get string of the first three parts (major, minor and patch) of a version string. Example: majorMinorPatch "1.2.3-stuff" => "1.2.3" */ majorMinorPatch = truncate 3; /* Version comparison predicates, - isGe v0 v <-> v is greater or equal than v0 [*] - isLe v0 v <-> v is lesser or equal than v0 [*] - isGt v0 v <-> v is strictly greater than v0 [*] - isLt v0 v <-> v is strictly lesser than v0 [*] - isEq v0 v <-> v is equal to v0 [*] - range low high v <-> v is between low and high [**] [*] truncating v to the same number of digits as v0 [**] truncating v to low for the lower bound and high for the upper bound Examples: - isGe "8.10" "8.10.1" => true - isLe "8.10" "8.10.1" => true - isGt "8.10" "8.10.1" => false - isGt "8.10.0" "8.10.1" => true - isEq "8.10" "8.10.1" => true - range "8.10" "8.11" "8.11.1" => true - range "8.10" "8.11+" "8.11.0" => false - range "8.10" "8.11+" "8.11+beta1" => false */ isGe = opTruncate versionAtLeast; isGt = opTruncate (flip versionOlder); isLe = opTruncate (flip versionAtLeast); isLt = opTruncate versionOlder; isEq = opTruncate pred.equal; range = low: high: pred.inter (versions.isGe low) (versions.isLe high); }; /* Returns a list of list, splitting it using a predicate. This is analoguous to builtins.split sep list, with a predicate as a separator and a list instead of a string. Type: splitList :: (a -> bool) -> [a] -> [[a]] Example: splitList (x: x == "x") [ "y" "x" "z" "t" ] => [ [ "y" ] "x" [ "z" "t" ] ] */ splitList = pred: l: # put in file lists let loop = ( vv: v: l: if l == [ ] then vv ++ [ v ] else let hd = head l; tl = tail l; in if pred hd then loop ( vv ++ [ v hd ] ) [ ] tl else loop vv (v ++ [ hd ]) tl ); in loop [ ] [ ] l; pred = { # Predicate intersection, union, and complement inter = p: q: x: p x && q x; union = p: q: x: p x || q x; compl = p: x: !p x; true = p: true; false = p: false; # predicate "being equal to y" equal = y: x: x == y; }; /* Emulate a "switch - case" construct, instead of relying on `if then else if ...` */ /* Usage: ```nix switch-if [ if-clause-1 .. if-clause-k ] default-out ``` where a if-clause has the form `{ cond = b; out = r; }` the first branch such as `b` is true */ switch-if = c: d: (findFirst (getAttr "cond") { } c).out or d; /* Usage: ```nix switch x [ simple-clause-1 .. simple-clause-k ] default-out ``` where a simple-clause has the form `{ case = p; out = r; }` the first branch such as `p x` is true or ```nix switch [ x1 .. xn ] [ complex-clause-1 .. complex-clause-k ] default-out ``` where a complex-clause is either a simple-clause or has the form { cases = [ p1 .. pn ]; out = r; } in which case the first branch such as all `pi x` are true if the variables p are not functions, they are converted to a equal p if out is missing the default-out is taken */ switch = var: clauses: default: with pred; let compare = f: if isFunction f then f else equal f; combine = cl: var: if cl ? case then compare cl.case var else all (equal true) (zipListsWith compare cl.cases var); in switch-if (map (cl: { cond = combine cl var; inherit (cl) out; }) clauses) default; /* Override arguments to mkCoqDerivation for a Coq library. This function allows you to easily override arguments to mkCoqDerivation, even when they are not exposed by the Coq library directly. Type: overrideCoqDerivation :: AttrSet -> CoqLibraryDerivation -> CoqLibraryDerivation Example: ```nix coqPackages.lib.overrideCoqDerivation { defaultVersion = "9999"; release."9999".sha256 = "1lq8x86vd3vqqh2yq6hvyagpnhfq5wmk5pg2z0xq7b7dbbbhyfkw"; } coqPackages.QuickChick; ``` This example overrides the `defaultVersion` and `release` arguments that are passed to `mkCoqDerivation` in the QuickChick derivation. Note that there is a difference between using `.override` on a Coq library vs this `overrideCoqDerivation` function. `.override` allows you to modify arguments to the derivation itself, for instance by passing different versions of dependencies: ```nix coqPackages.QuickChick.override { ssreflect = my-cool-ssreflect; } ``` whereas `overrideCoqDerivation` allows you to override arguments to the call to `mkCoqDerivation` in the Coq library. Note that all Coq libraries in Nixpkgs have a `version` argument for easily using a different version. So if all you want to do is use a different version, and the derivation for the Coq library already has support for the version you want, you likely only need to update the `version` argument on the library derivation. This is done with `.override`: ```nix coqPackages.QuickChick.override { version = "1.4.0"; } ``` */ overrideCoqDerivation = f: drv: (drv.override (args: { mkCoqDerivation = drv_: (args.mkCoqDerivation drv_).override f; })); })