src/ledger/ignore.bend
ezx@1.11.0.0 · 396 lines · 46 definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30import Base
31import ezx@1.11.0.0/src/ledger/manifest.bend as M
32
33
34type Rule is Data:
35 Other{}
36 Dir{}
37 Star{}
38 Lib{}
39 Pkgs{}
40 Allow{hash: String}
41
42
43type Line is Data:
44 Line{kind: Rule, text: String}
45
46
47def allow(+hash: String) -> String:
48 "!.ez/lib/" ++ hash
49
50
51
52def lead(+pat: String) -> String:
53 Bool.pick(String, String.starts_with(pat, "/"), String.drop(pat, 1n), pat)
54
55
56
57def trail(+pat: String) -> String:
58 Bool.pick(String, String.ends_with(pat, "/"),
59 String.take(pat, Nat.sub(String.length(pat), 1n)), pat)
60
61
62def bare(+pat: String) -> String:
63 trail(lead(pat))
64
65
66def loose.under(under: Bool, +rest: String) -> Rule:
67 match under:
68 case True{}:
69 Bool.pick(Rule, String.is_empty(rest), Other{}, Allow{rest})
70 case False{}:
71 Other{}
72
73
74def loose.neg(+pat: String) -> Rule:
75 Bool.pick(Rule, String.eq(pat, ".ez/lib"), Lib{},
76 loose.under(String.starts_with(pat, ".ez/lib/"), String.drop(pat, 8n)))
77
78
79
80def loose.pos(+pat: String) -> Rule:
81 Bool.pick(Rule, String.eq(pat, ".ez"), Dir{},
82 Bool.pick(Rule, String.eq(pat, ".ez/*"), Star{},
83 Bool.pick(Rule, String.eq(pat, ".ez/lib/*"), Pkgs{}, Other{})))
84
85
86def loose.go(neg: Bool, +pat: String) -> Rule:
87 match neg:
88 case True{}:
89 loose.neg(bare(String.drop(pat, 1n)))
90 case False{}:
91 loose.pos(bare(pat))
92
93
94def loose(+line: String) -> Rule:
95 +pat = String.trim(line)
96 loose.go(String.starts_with(pat, "!"), pat)
97
98
99def canon(empty: Bool, +rest: String) -> Rule:
100 match empty:
101 case True{}:
102 Lib{}
103 case False{}:
104 Allow{rest}
105
106
107def kind.go(exact: Bool, +line: String) -> Rule:
108 match exact:
109 case True{}:
110 canon(String.is_empty(String.drop(line, 9n)), String.drop(line, 9n))
111 case False{}:
112 loose(line)
113
114
115def kind(+line: String) -> Rule:
116 kind.go(String.starts_with(line, "!.ez/lib/"), line)
117
118
119def tag(ls: List<&2, String>) -> List<&2, Line>:
120 match ls:
121 case []:
122 []
123 case +h <> t:
124 Line{kind(h), h} <> tag(t)
125
126
127def hashes.put(what: Rule, rest: List<&2, String>) -> List<&2, String>:
128 match what:
129 case Allow{h}:
130 h <> rest
131 case Other{}:
132 rest
133 case Dir{}:
134 rest
135 case Star{}:
136 rest
137 case Lib{}:
138 rest
139 case Pkgs{}:
140 rest
141
142
143
144def hashes(ls: List<&2, String>) -> List<&2, String>:
145 match ls:
146 case []:
147 []
148 case +h <> t:
149 hashes.put(kind(h), hashes(t))
150
151
152def others.put(what: Rule, +line: String, rest: List<&2, String>) -> List<&2, String>:
153 match what:
154 case Other{}:
155 line <> rest
156 case Allow{_h}:
157 rest
158 case Dir{}:
159 rest
160 case Star{}:
161 rest
162 case Lib{}:
163 rest
164 case Pkgs{}:
165 rest
166
167
168def others(ls: List<&2, String>) -> List<&2, String>:
169 match ls:
170 case []:
171 []
172 case +h <> t:
173 others.put(kind(h), h, others(t))
174
175
176def vendors.put(vend: Bool, +hash: String, rest: List<&2, String>) -> List<&2, String>:
177 match vend:
178 case True{}:
179 hash <> rest
180 case False{}:
181 rest
182
183
184
185def vendors(ds: List<&2, M.Dep>) -> List<&2, String>:
186 match ds:
187 case []:
188 []
189 case +h <> t:
190 vendors.put(M.source.vendor(M.source.dep(h)), M.dep.hash(h), vendors(t))
191
192
193def named(hs: List<&2, String>, +hash: String) -> Bool:
194 match hs:
195 case []:
196 False{}
197 case h <> t:
198 +rest = named(t, hash)
199 Bool.or(String.eq(h, hash), rest)
200
201
202def once.put(skip: Bool, +hash: String, rest: List<&2, String>) -> List<&2, String>:
203 match skip:
204 case True{}:
205 rest
206 case False{}:
207 hash <> rest
208
209
210def once.seen(skip: Bool, +hash: String, +seen: List<&2, String>) -> List<&2, String>:
211 match skip:
212 case True{}:
213 seen
214 case False{}:
215 hash <> seen
216
217
218
219
220def once.go(hs: List<&2, String>, +seen: List<&2, String>) -> List<&2, String>:
221 match hs:
222 case []:
223 []
224 case +h <> t:
225 +skip = Bool.or(String.is_empty(h), named(seen, h))
226 once.put(skip, h, once.go(t, once.seen(skip, h, seen)))
227
228
229
230
231def vended(ds: List<&2, M.Dep>) -> List<&2, String>:
232 once.go(vendors(ds), [])
233
234
235def allow.each(hs: List<&2, String>) -> List<&2, String>:
236 match hs:
237 case []:
238 []
239 case +h <> t:
240 allow(h) <> allow.each(t)
241
242
243def allows(ds: List<&2, M.Dep>) -> List<&2, String>:
244 allow.each(vended(ds))
245
246
247def same(left: Rule, right: Rule) -> Bool:
248 match left right:
249 case Dir{} Dir{}:
250 True{}
251 case Star{} Star{}:
252 True{}
253 case Lib{} Lib{}:
254 True{}
255 case Pkgs{} Pkgs{}:
256 True{}
257 case _ _:
258 False{}
259
260
261def has.step(hit: Bool, rest: Unit -> Bool) -> Bool:
262 match hit:
263 case True{}:
264 True{}
265 case False{}:
266 rest(Unit{})
267
268
269def has(ls: List<&2, Line>, +want: Rule) -> Bool:
270 match ls:
271 case []:
272 False{}
273 case Line{+what, _text} <> t:
274 has.step(same(what, want), _u => has(t, want))
275
276
277def rule.put(there: Bool, +line: String, rest: List<&2, String>) -> List<&2, String>:
278 match there:
279 case True{}:
280 rest
281 case False{}:
282 line <> rest
283
284
285def rules.go(star: Bool, lib: Bool, pkgs: Bool) -> List<&2, String>:
286 rule.put(star, ".ez/*", rule.put(lib, "!.ez/lib", rule.put(pkgs, ".ez/lib/*", [])))
287
288
289def rules(+ls: List<&2, Line>) -> List<&2, String>:
290 rules.go(has(ls, Star{}), has(ls, Lib{}), has(ls, Pkgs{}))
291
292
293
294
295def need(skip: Bool, +rs: List<&2, String>) -> List<&2, String>:
296 match skip:
297 case True{}:
298 []
299 case False{}:
300 rs
301
302
303def block(+ds: List<&2, M.Dep>, +ls: List<&2, Line>) -> List<&2, String>:
304 List.append(&2, String,
305 need(Bool.or(has(ls, Dir{}), List.is_empty(&2, String, vended(ds))), rules(ls)),
306 allows(ds))
307
308
309def placed(done: Bool, +blk: List<&2, String>) -> List<&2, String>:
310 Bool.pick(List<&2, String>, done, [], blk)
311
312
313
314
315
316def walk(ls: List<&2, Line>, +fix: List<&2, String>, +blk: List<&2, String>, done: Bool) -> List<&2, String>:
317 match ls:
318 case []:
319 placed(done, blk)
320 case Line{k, +line} <> t:
321 match k:
322 case Other{}:
323 line <> walk(t, fix, blk, done)
324 case Dir{}:
325 List.append(&2, String, fix, walk(t, fix, blk, done))
326 case Star{}:
327 line <> walk(t, fix, blk, done)
328 case Lib{}:
329 line <> walk(t, fix, blk, done)
330 case Pkgs{}:
331 line <> walk(t, fix, blk, done)
332 case Allow{_h}:
333 List.append(&2, String, placed(done, blk), walk(t, fix, blk, True{}))
334
335
336def lines.go(+ds: List<&2, M.Dep>, +ls: List<&2, Line>) -> List<&2, String>:
337 walk(ls, rules(ls), block(ds, ls), False{})
338
339
340
341def lines(ds: List<&2, M.Dep>, ls: List<&2, String>) -> List<&2, String>:
342 lines.go(ds, tag(ls))
343
344
345
346
347
348
349
350
351
352def unend.go(rest: List<&2, String>, +last: String) -> List<&2, String>:
353 match rest:
354 case []:
355 Bool.pick(List<&2, String>, String.is_empty(last), [], [last])
356 case +h2 <> t2:
357 last <> unend.go(t2, h2)
358
359
360def unend(ps: List<&2, String>) -> List<&2, String>:
361 match ps:
362 case []:
363 []
364 case +h <> t:
365 unend.go(t, h)
366
367
368
369def file.lines(text: String) -> List<&2, String>:
370 unend(String.lines(text))
371
372
373
374def file.text(ls: List<&2, String>) -> String:
375 match ls:
376 case []:
377 ""
378 case h <> t:
379 String.append(h, SCon{'\n', file.text(t)})
380
381
382
383def text.out(same: Bool, +text: String, +out: String) -> String:
384 match same:
385 case True{}:
386 text
387 case False{}:
388 out
389
390
391
392
393def sync(ds: List<&2, M.Dep>, +text: String) -> String:
394 +was = file.lines(text)
395 +out = file.text(lines(ds, was))
396 text.out(String.eq(out, file.text(was)), text, out)