nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{ lib }:
2
3let
4 inherit (lib)
5 all
6 concatStringsSep
7 findFirst
8 flip
9 getAttr
10 head
11 isFunction
12 length
13 recursiveUpdate
14 splitVersion
15 tail
16 take
17 versionAtLeast
18 versionOlder
19 zipListsWith
20 ;
21in
22rec {
23
24 versions =
25 let
26 truncate = n: v: concatStringsSep "." (take n (splitVersion v));
27 opTruncate =
28 op: v0: v:
29 let
30 n = length (splitVersion v0);
31 in
32 op (truncate n v) (truncate n v0);
33 in
34 rec {
35
36 /*
37 Get string of the first n parts of a version string.
38
39 Example:
40 - truncate 2 "1.2.3-stuff"
41 => "1.2"
42
43 - truncate 4 "1.2.3-stuff"
44 => "1.2.3.stuff"
45 */
46
47 inherit truncate;
48
49 /*
50 Get string of the first three parts (major, minor and patch)
51 of a version string.
52
53 Example:
54 majorMinorPatch "1.2.3-stuff"
55 => "1.2.3"
56 */
57 majorMinorPatch = truncate 3;
58
59 /*
60 Version comparison predicates,
61 - isGe v0 v <-> v is greater or equal than v0 [*]
62 - isLe v0 v <-> v is lesser or equal than v0 [*]
63 - isGt v0 v <-> v is strictly greater than v0 [*]
64 - isLt v0 v <-> v is strictly lesser than v0 [*]
65 - isEq v0 v <-> v is equal to v0 [*]
66 - range low high v <-> v is between low and high [**]
67
68 [*] truncating v to the same number of digits as v0
69 [**] truncating v to low for the lower bound and high for the upper bound
70
71 Examples:
72 - isGe "8.10" "8.10.1"
73 => true
74 - isLe "8.10" "8.10.1"
75 => true
76 - isGt "8.10" "8.10.1"
77 => false
78 - isGt "8.10.0" "8.10.1"
79 => true
80 - isEq "8.10" "8.10.1"
81 => true
82 - range "8.10" "8.11" "8.11.1"
83 => true
84 - range "8.10" "8.11+" "8.11.0"
85 => false
86 - range "8.10" "8.11+" "8.11+beta1"
87 => false
88 */
89 isGe = opTruncate versionAtLeast;
90 isGt = opTruncate (flip versionOlder);
91 isLe = opTruncate (flip versionAtLeast);
92 isLt = opTruncate versionOlder;
93 isEq = opTruncate pred.equal;
94 range = low: high: pred.inter (versions.isGe low) (versions.isLe high);
95 };
96
97 /*
98 Returns a list of list, splitting it using a predicate.
99 This is analogous to builtins.split sep list,
100 with a predicate as a separator and a list instead of a string.
101
102 Type: splitList :: (a -> bool) -> [a] -> [[a]]
103
104 Example:
105 splitList (x: x == "x") [ "y" "x" "z" "t" ]
106 => [ [ "y" ] "x" [ "z" "t" ] ]
107 */
108 splitList =
109 pred: l: # put in file lists
110 let
111 loop = (
112 vv: v: l:
113 if l == [ ] then
114 vv ++ [ v ]
115 else
116 let
117 hd = head l;
118 tl = tail l;
119 in
120 if pred hd then
121 loop (
122 vv
123 ++ [
124 v
125 hd
126 ]
127 ) [ ] tl
128 else
129 loop vv (v ++ [ hd ]) tl
130 );
131 in
132 loop [ ] [ ] l;
133
134 pred = {
135 # Predicate intersection, union, and complement
136 inter =
137 p: q: x:
138 p x && q x;
139 union =
140 p: q: x:
141 p x || q x;
142 compl = p: x: !p x;
143 true = p: true;
144 false = p: false;
145
146 # predicate "being equal to y"
147 equal = y: x: x == y;
148 };
149
150 /*
151 Emulate a "switch - case" construct,
152 instead of relying on `if then else if ...`
153 */
154 /*
155 Usage:
156 ```nix
157 switch-if [
158 if-clause-1
159 ..
160 if-clause-k
161 ] default-out
162 ```
163 where a if-clause has the form `{ cond = b; out = r; }`
164 the first branch such as `b` is true
165 */
166
167 switch-if = c: d: (findFirst (getAttr "cond") { } c).out or d;
168
169 /*
170 Usage:
171 ```nix
172 switch x [
173 simple-clause-1
174 ..
175 simple-clause-k
176 ] default-out
177 ```
178 where a simple-clause has the form `{ case = p; out = r; }`
179 the first branch such as `p x` is true
180 or
181 ```nix
182 switch [ x1 .. xn ] [
183 complex-clause-1
184 ..
185 complex-clause-k
186 ] default-out
187 ```
188 where a complex-clause is either a simple-clause
189 or has the form { cases = [ p1 .. pn ]; out = r; }
190 in which case the first branch such as all `pi x` are true
191
192 if the variables p are not functions,
193 they are converted to a equal p
194 if out is missing the default-out is taken
195 */
196
197 switch =
198 var: clauses: default:
199 with pred;
200 let
201 compare = f: if isFunction f then f else equal f;
202 combine =
203 cl: var:
204 if cl ? case then compare cl.case var else all (equal true) (zipListsWith compare cl.cases var);
205 in
206 switch-if (map (cl: {
207 cond = combine cl var;
208 inherit (cl) out;
209 }) clauses) default;
210}