src/ws/joint.bend
ezx@1.11.0.0 · 930 lines · 99 definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import Base
22import ezx@1.11.0.0/src/ledger/manifest.bend as M
23import ezx@1.11.0.0/src/ledger/render.bend as Rend
24import ezx@1.11.0.0/src/pkg/path.bend as P
25import ezx@1.11.0.0/src/pkg/pkg.bend as K
26import ezx@1.11.0.0/src/lock/lock.bend as L
27import ezx@1.11.0.0/src/lock/world.bend as LW
28import ezx@1.11.0.0/src/pub/plan.bend as PP
29import ezx@1.11.0.0/src/ws/workspace.bend as W
30
31
32
33type Found is Data:
34 Found{path: String, text: String}
35
36
37type Member is Data:
38 Member{dir: List<&2, String>, m: M.Manifest}
39
40
41
42
43type Joint is Data:
44 Lone{}
45 Clash{why: String}
46 Joint{m: M.Manifest}
47
48
49
50
51
52
53def source.at(+dir: String, src: M.Source) -> M.Source:
54 match src:
55 case M.Hub{nv}:
56 M.Hub{nv}
57 case M.Git{url, rev, tag, root, nar, vend}:
58 M.Git{P.anchor(dir, url), rev, tag, root, nar, vend}
59 case M.Member{path, named}:
60 M.Member{path, named}
61
62
63def dep.at(+dir: String, dependency: M.Dep) -> M.Dep:
64 M.Dep{nn, hh, ee, ss} = dependency
65 M.Dep{nn, hh, ee, source.at(dir, ss)}
66
67
68def deps.at(+dir: String, ds: List<&2, M.Dep>) -> List<&2, M.Dep>:
69 match ds:
70 case []:
71 []
72 case hd <> tl:
73 dep.at(dir, hd) <> deps.at(dir, tl)
74
75
76def tool.at(+dir: String, pin: M.Tool) -> M.Tool:
77 M.Tool{nn, ee, bb, ss} = pin
78 M.Tool{nn, ee, bb, source.at(dir, ss)}
79
80
81def tools.at(+dir: String, ts: List<&2, M.Tool>) -> List<&2, M.Tool>:
82 match ts:
83 case []:
84 []
85 case hd <> tl:
86 tool.at(dir, hd) <> tools.at(dir, tl)
87
88
89def members.deps(ms: List<&2, Member>) -> List<&2, M.Dep>:
90 match ms:
91 case []:
92 []
93 case Member{ds, mm} <> tl:
94 M.Manifest{_n, _e, _b, _h, _pa, _pv, xs, _ts} = mm
95 List.append(&2, M.Dep, deps.at(W.segs.text(ds), xs), members.deps(tl))
96
97
98def members.tools(ms: List<&2, Member>) -> List<&2, M.Tool>:
99 match ms:
100 case []:
101 []
102 case Member{ds, mm} <> tl:
103 M.Manifest{_n, _e, _b, _h, _pa, _pv, _xs, ts} = mm
104 List.append(&2, M.Tool, tools.at(W.segs.text(ds), ts), members.tools(tl))
105
106
107def all.deps(root: M.Manifest, ms: List<&2, Member>) -> List<&2, M.Dep>:
108 M.Manifest{_n, _e, _b, _h, _pa, _pv, ds, _ts} = root
109 List.append(&2, M.Dep, ds, members.deps(ms))
110
111
112def all.tools(root: M.Manifest, ms: List<&2, Member>) -> List<&2, M.Tool>:
113 M.Manifest{_n, _e, _b, _h, _pa, _pv, _ds, ts} = root
114 List.append(&2, M.Tool, ts, members.tools(ms))
115
116
117
118
119
120def firsts(ds: List<&2, M.Dep>) -> List<&2, M.Dep>:
121 match ds:
122 case []:
123 []
124 case +hd <> tl:
125 hd <> Rend.without(firsts(tl), M.dep.name(hd))
126
127
128def tools.without.put(hit: Bool, pin: M.Tool, rest: List<&2, M.Tool>) -> List<&2, M.Tool>:
129 match hit:
130 case True{}:
131 rest
132 case False{}:
133 pin <> rest
134
135
136def tools.without(ts: List<&2, M.Tool>, +name: String) -> List<&2, M.Tool>:
137 match ts:
138 case []:
139 []
140 case +hd <> tl:
141 tools.without.put(String.eq(M.tool.name(hd), name), hd, tools.without(tl, name))
142
143
144def tools.firsts(ts: List<&2, M.Tool>) -> List<&2, M.Tool>:
145 match ts:
146 case []:
147 []
148 case +hd <> tl:
149 hd <> tools.without(tools.firsts(tl), M.tool.name(hd))
150
151
152def bit.eq(aa: Bool, bb: Bool) -> Bool:
153 match aa:
154 case True{}:
155 bb
156 case False{}:
157 Bool.not(bb)
158
159
160def source.eq(aa: M.Source, bb: M.Source) -> Bool:
161 match aa:
162 case M.Hub{an}:
163 match bb:
164 case M.Hub{bn}:
165 String.eq(an, bn)
166 case M.Git{_u, _r, _t, _o, _n, _v}:
167 False{}
168 case M.Member{_p, _m}:
169 False{}
170 case M.Git{au, ar, at, ao, an, av}:
171 match bb:
172 case M.Hub{_bn}:
173 False{}
174 case M.Git{bu, br, bt, bo, bn, bv}:
175 Bool.and(Bool.and(Bool.and(String.eq(au, bu), String.eq(ar, br)),
176 Bool.and(String.eq(at, bt), String.eq(ao, bo))),
177 Bool.and(String.eq(an, bn), bit.eq(av, bv)))
178 case M.Member{_p, _m}:
179 False{}
180 case M.Member{ap, am}:
181 match bb:
182 case M.Hub{_bn}:
183 False{}
184 case M.Git{_u, _r, _t, _o, _n, _v}:
185 False{}
186 case M.Member{bp, bm}:
187 Bool.and(String.eq(ap, bp), String.eq(am, bm))
188
189
190def dep.eq(aa: M.Dep, bb: M.Dep) -> Bool:
191 M.Dep{an, ah, ae, asrc} = aa
192 M.Dep{bn, bh, be, bsrc} = bb
193 Bool.and(Bool.and(String.eq(an, bn), String.eq(ah, bh)),
194 Bool.and(String.eq(ae, be), source.eq(asrc, bsrc)))
195
196
197def tool.eq(aa: M.Tool, bb: M.Tool) -> Bool:
198 M.Tool{an, ae, ab, asrc} = aa
199 M.Tool{bn, be, bb2, bsrc} = bb
200 Bool.and(Bool.and(String.eq(an, bn), String.eq(ae, be)),
201 Bool.and(String.eq(ab, bb2), source.eq(asrc, bsrc)))
202
203
204
205def agree.go(ds: List<&2, M.Dep>, +all: List<&2, M.Dep>) -> Bool:
206 match ds:
207 case []:
208 True{}
209 case +hd <> tl:
210 rest = agree.go(tl, all)
211 Bool.and(dep.eq(hd, M.find(all, M.dep.name(hd))), rest)
212
213
214def agree(+ds: List<&2, M.Dep>) -> Bool:
215 agree.go(ds, ds)
216
217
218
219def clash.go(ds: List<&2, M.Dep>, +all: List<&2, M.Dep>) -> String:
220 match ds:
221 case []:
222 ""
223 case +hd <> tl:
224 rest = clash.go(tl, all)
225 Bool.pick(String, dep.eq(hd, M.find(all, M.dep.name(hd))), rest, M.dep.name(hd))
226
227
228def tools.agree.go(ts: List<&2, M.Tool>, +all: List<&2, M.Tool>) -> Bool:
229 match ts:
230 case []:
231 True{}
232 case +hd <> tl:
233 rest = tools.agree.go(tl, all)
234 Bool.and(tool.eq(hd, M.tool.find(all, M.tool.name(hd))), rest)
235
236
237def tools.agree(+ts: List<&2, M.Tool>) -> Bool:
238 tools.agree.go(ts, ts)
239
240
241
242def tools.clash.go(ts: List<&2, M.Tool>, +all: List<&2, M.Tool>) -> String:
243 match ts:
244 case []:
245 ""
246 case +hd <> tl:
247 rest = tools.clash.go(tl, all)
248 Bool.pick(String, tool.eq(hd, M.tool.find(all, M.tool.name(hd))), rest, M.tool.name(hd))
249
250
251
252
253
254def pin.at(hit: Bool, src: M.Source, rest: M.Source) -> M.Source:
255 match hit:
256 case True{}:
257 src
258 case False{}:
259 rest
260
261
262
263def pin.of(ds: List<&2, M.Dep>, +url: String) -> M.Source:
264 match ds:
265 case []:
266 M.Hub{""}
267 case M.Dep{_n, _h, _e, +src} <> tl:
268 rest = pin.of(tl, url)
269 pin.at(String.eq(M.source.url(src), url), src, rest)
270
271
272def pin.same(aa: M.Source, bb: M.Source) -> Bool:
273 match aa:
274 case M.Hub{_an}:
275 True{}
276 case M.Git{_au, ar, at, _ao, _an, _av}:
277 match bb:
278 case M.Hub{_bn}:
279 True{}
280 case M.Git{_bu, br, bt, _bo, _bn, _bv}:
281 Bool.and(String.eq(ar, br), String.eq(at, bt))
282 case M.Member{_bp, _bm}:
283 True{}
284 case M.Member{_ap, _am}:
285 True{}
286
287
288def pins.go(ds: List<&2, M.Dep>, +all: List<&2, M.Dep>) -> Bool:
289 match ds:
290 case []:
291 True{}
292 case M.Dep{_n, _h, _e, +src} <> tl:
293 rest = pins.go(tl, all)
294 Bool.and(pin.same(src, pin.of(all, M.source.url(src))), rest)
295
296
297def pins(+ds: List<&2, M.Dep>) -> Bool:
298 pins.go(ds, ds)
299
300
301def pins.clash.go(ds: List<&2, M.Dep>, +all: List<&2, M.Dep>) -> String:
302 match ds:
303 case []:
304 ""
305 case M.Dep{_n, _h, _e, +src} <> tl:
306 rest = pins.clash.go(tl, all)
307 Bool.pick(String, pin.same(src, pin.of(all, M.source.url(src))), rest, M.source.url(src))
308
309
310
311
312
313
314def hub.one(+hub: String, mm: M.Manifest) -> Bool:
315 M.Manifest{_n, _e, _b, +hh, _pa, _pv, _ds, _ts} = mm
316 Bool.or(String.is_empty(hh), String.eq(hh, hub))
317
318
319def hubs(+hub: String, ms: List<&2, Member>) -> Bool:
320 match ms:
321 case []:
322 True{}
323 case Member{_ds, mm} <> tl:
324 rest = hubs(hub, tl)
325 Bool.and(hub.one(hub, mm), rest)
326
327
328def hubs.other(+hub: String, ms: List<&2, Member>) -> String:
329 match ms:
330 case []:
331 ""
332 case Member{+ds, mm} <> tl:
333 rest = hubs.other(hub, tl)
334 Bool.pick(String, hub.one(hub, mm), rest, W.segs.text(ds))
335
336
337
338
339
340def root.hub(root: M.Manifest) -> String:
341 M.Manifest{_n, _e, _b, hh, _pa, _pv, _ds, _ts} = root
342 hh
343
344
345
346
347def ok(+root: M.Manifest, +ms: List<&2, Member>) -> Bool:
348 Bool.and(hubs(root.hub(root), ms),
349 Bool.and(Bool.and(agree(all.deps(root, ms)), pins(all.deps(root, ms))),
350 tools.agree(all.tools(root, ms))))
351
352
353def why(+root: M.Manifest, +ms: List<&2, Member>) -> String:
354 +other = hubs.other(root.hub(root), ms)
355 +dep = clash.go(all.deps(root, ms), all.deps(root, ms))
356 +pin = pins.clash.go(all.deps(root, ms), all.deps(root, ms))
357 +tool = tools.clash.go(all.tools(root, ms), all.tools(root, ms))
358 Bool.pick(String, String.is_empty(other),
359 Bool.pick(String, String.is_empty(dep),
360 Bool.pick(String, String.is_empty(pin),
361 "ez: workspace members pin the tool " ++ tool ++ " differently",
362 "ez: workspace members pin " ++ pin ++ " at different commits; " ++
363 "move it for all of them with ez lock --upgrade --package"),
364 "ez: workspace members depend on " ++ dep ++ " differently"),
365 "ez: workspace member " ++ other ++ " names another hub than the root's")
366
367
368
369def joined(root: M.Manifest, +ms: List<&2, Member>) -> M.Manifest:
370 M.Manifest{nn, ee, bb, hh, pa, pv, ds, ts} = root
371 M.Manifest{nn, ee, bb, hh, pa, pv,
372 firsts(List.append(&2, M.Dep, ds, members.deps(ms))),
373 tools.firsts(List.append(&2, M.Tool, ts, members.tools(ms)))}
374
375
376def combine.go(fine: Bool, +root: M.Manifest, +ms: List<&2, Member>) -> Joint:
377 match fine:
378 case True{}:
379 Joint{joined(root, ms)}
380 case False{}:
381 Clash{why(root, ms)}
382
383
384def combine(+root: M.Manifest, +ms: List<&2, Member>) -> Joint:
385 combine.go(ok(root, ms), root, ms)
386
387
388type Read is Data:
389 Unread{why: String}
390 Read{ms: List<&2, Member>}
391
392
393
394
395
396
397type Res is Data:
398 Got{dep: M.Dep}
399 Bad{why: String}
400
401
402def entry.at(+dir: List<&2, String>, +entry: String) -> String:
403 P.join(W.segs.text(dir), entry)
404
405
406def ledger.at(+dir: List<&2, String>) -> String:
407 P.join(W.segs.text(dir), "ez.toml")
408
409
410def member.name(mb: Member) -> String:
411 Member{_dir, mm} = mb
412 M.Manifest{nn, _e, _b, _h, _pa, _pv, _ds, _ts} = mm
413 nn
414
415
416def named.at(hit: Bool, hd: Member, rest: Maybe<&2, Member>) -> Maybe<&2, Member>:
417 match hit:
418 case True{}:
419 Some{hd}
420 case False{}:
421 rest
422
423
424def named(ms: List<&2, Member>, +name: String) -> Maybe<&2, Member>:
425 match ms:
426 case []:
427 None{}
428 case +hd <> tl:
429 rest = named(tl, name)
430 named.at(String.eq(member.name(hd), name), hd, rest)
431
432
433
434
435def walked(got: K.Walked, +name: String, +entry: String, +nv: String) -> Res:
436 match got:
437 case K.Walked{hash, root, _fs, _sums}:
438 Got{M.Dep{name, hash, entry, M.Member{root, nv}}}
439 case K.Asks{at}:
440 Bad{"ez: workspace member " ++ name ++ " imports " ++ at ++ ", which git does not track"}
441 case K.Refused{why}:
442 Bad{why}
443
444
445
446
447
448def by.name(named: PP.Named, got: K.Walked, +name: String, +entry: String) -> Res:
449 match named:
450 case PP.ByHash{}:
451 walked(got, name, entry, "")
452 case PP.ByName{nv}:
453 walked(got, name, entry, nv)
454 case PP.Unnamed{why}:
455 Bad{why ++ "; workspace member " ++ name ++ " is imported by the name ez publish would give it"}
456
457
458def member.dep(mm: M.Manifest, +dir: List<&2, String>, +name: String, +files: List<&2, K.Source>) -> Res:
459 M.Manifest{_n, ee, _b, _h, pa, pv, _ds, _ts} = mm
460 +entry = entry.at(dir, ee)
461 by.name(PP.naming(pa, pv), K.of(entry, files), name, entry)
462
463
464
465def target.at(
466 own: Bool,
467 +name: String,
468 mm: M.Manifest,
469 +dir: List<&2, String>,
470 +files: List<&2, K.Source>,
471 +self: List<&2, String>
472) -> Res:
473 match own:
474 case True{}:
475 Bad{"ez: " ++ ledger.at(self) ++ " names " ++ name ++ " as a workspace member, and that member is itself"}
476 case False{}:
477 member.dep(mm, dir, name, files)
478
479
480def target(
481 found: Maybe<&2, Member>,
482 +self: List<&2, String>,
483 +name: String,
484 +files: List<&2, K.Source>
485) -> Res:
486 match found:
487 case None{}:
488 Bad{"ez: " ++ ledger.at(self) ++ " names " ++ name ++ " as a workspace member, and no member's " ++
489 "[package] is named " ++ name}
490 case Some{mb}:
491 Member{+dir, mm} = mb
492 target.at(W.segs.eq(dir, self), name, mm, dir, files, self)
493
494
495def bare(+hash: String, +entry: String, +path: String, +nv: String) -> Bool:
496 Bool.and(Bool.and(String.is_empty(hash), String.is_empty(entry)),
497 Bool.and(String.is_empty(path), String.is_empty(nv)))
498
499
500def section(
501 plain: Bool,
502 found: Maybe<&2, Member>,
503 +self: List<&2, String>,
504 +name: String,
505 +files: List<&2, K.Source>
506) -> Res:
507 match plain:
508 case True{}:
509 target(found, self, name, files)
510 case False{}:
511 Bad{"ez: " ++ ledger.at(self) ++ " gives the workspace member " ++ name ++
512 " a hash, an entry or a source; its section is `workspace = true` alone"}
513
514
515
516def dep.res.src(
517 src: M.Source,
518 +name: String,
519 +hash: String,
520 +entry: String,
521 +ms: List<&2, Member>,
522 +self: List<&2, String>,
523 +files: List<&2, K.Source>
524) -> Res:
525 match src:
526 case M.Hub{nv}:
527 Got{M.Dep{name, hash, entry, M.Hub{nv}}}
528 case M.Git{url, rev, tag, root, nar, vend}:
529 Got{M.Dep{name, hash, entry, M.Git{url, rev, tag, root, nar, vend}}}
530 case M.Member{+path, +nv}:
531 section(bare(hash, entry, path, nv), named(ms, name), self, name, files)
532
533
534def dep.res(
535 dependency: M.Dep,
536 +ms: List<&2, Member>,
537 +self: List<&2, String>,
538 +files: List<&2, K.Source>
539) -> Res:
540 M.Dep{nn, hh, ee, src} = dependency
541 dep.res.src(src, nn, hh, ee, ms, self, files)
542
543
544type Deps is Data:
545 Deps{ds: List<&2, M.Dep>}
546 Unmet{why: String}
547
548
549def deps.cons(got: Res, rest: Deps) -> Deps:
550 match got:
551 case Bad{why}:
552 Unmet{why}
553 case Got{dd}:
554 match rest:
555 case Unmet{why}:
556 Unmet{why}
557 case Deps{ds}:
558 Deps{dd <> ds}
559
560
561
562def deps.res(
563 ds: List<&2, M.Dep>,
564 +ms: List<&2, Member>,
565 +self: List<&2, String>,
566 +files: List<&2, K.Source>
567) -> Deps:
568 match ds:
569 case []:
570 Deps{[]}
571 case hd <> tl:
572 rest = deps.res(tl, ms, self, files)
573 deps.cons(dep.res(hd, ms, self, files), rest)
574
575
576def with.deps(mm: M.Manifest, ds: List<&2, M.Dep>) -> M.Manifest:
577 M.Manifest{nn, ee, bb, hh, pa, pv, _ds, ts} = mm
578 M.Manifest{nn, ee, bb, hh, pa, pv, ds, ts}
579
580
581def res.put(got: Deps, +dir: List<&2, String>, mm: M.Manifest, rest: Read) -> Read:
582 match got:
583 case Unmet{why}:
584 Unread{why}
585 case Deps{ds}:
586 match rest:
587 case Unread{why}:
588 Unread{why}
589 case Read{xs}:
590 Read{Member{dir, with.deps(mm, ds)} <> xs}
591
592
593def deps.of(mm: M.Manifest) -> List<&2, M.Dep>:
594 M.Manifest{_n, _e, _b, _h, _pa, _pv, ds, _ts} = mm
595 ds
596
597
598def res.one(mb: Member, +ms: List<&2, Member>, +files: List<&2, K.Source>, rest: Read) -> Read:
599 Member{+dir, +mm} = mb
600 res.put(deps.res(deps.of(mm), ms, dir, files), dir, mm, rest)
601
602
603def res.all(xs: List<&2, Member>, +ms: List<&2, Member>, +files: List<&2, K.Source>) -> Read:
604 match xs:
605 case []:
606 Read{[]}
607 case hd <> tl:
608 rest = res.all(tl, ms, files)
609 res.one(hd, ms, files, rest)
610
611
612def member.naming(mb: Member) -> PP.Named:
613 Member{_dir, mm} = mb
614 M.Manifest{_n, _e, _b, _h, pa, pv, _ds, _ts} = mm
615 PP.naming(pa, pv)
616
617
618
619def named.one(named: PP.Named, mb: Member, +files: List<&2, K.Source>, rest: Deps) -> Deps:
620 match named:
621 case PP.ByHash{}:
622 rest
623 case PP.Unnamed{_why}:
624 rest
625 case PP.ByName{_nv}:
626 Member{+dir, +mm} = mb
627 deps.cons(member.dep(mm, dir, member.name(Member{dir, mm}), files), rest)
628
629
630
631
632
633
634def names.deps(xs: List<&2, Member>, +files: List<&2, K.Source>) -> Deps:
635 match xs:
636 case []:
637 Deps{[]}
638 case +hd <> tl:
639 rest = names.deps(tl, files)
640 named.one(member.naming(hd), hd, files, rest)
641
642
643
644def res.joint(xs: List<&2, Member>, +ns: List<&2, M.Dep>) -> Joint:
645 match xs:
646 case []:
647 Clash{"ez: the workspace root has no ledger"}
648 case Member{_dir, +root} <> ms:
649 combine(with.deps(root, List.append(&2, M.Dep, deps.of(root), ns)), ms)
650
651
652def res.named(xs: List<&2, Member>, got: Deps) -> Joint:
653 match got:
654 case Unmet{why}:
655 Clash{why}
656 case Deps{ns}:
657 res.joint(xs, ns)
658
659
660def res.read(rd: Read, got: Deps) -> Joint:
661 match rd:
662 case Unread{why}:
663 Clash{why}
664 case Read{xs}:
665 res.named(xs, got)
666
667
668def with.root(root: M.Manifest, ms: List<&2, Member>) -> List<&2, Member>:
669 Member{[], root} <> ms
670
671
672
673
674
675def resolve(+root: M.Manifest, ms: List<&2, Member>, +files: List<&2, K.Source>) -> Joint:
676 +all = with.root(root, ms)
677 res.read(res.all(all, all, files), names.deps(all, files))
678
679
680
681
682
683def text.at(fs: List<&2, K.Source>, +at: String) -> String:
684 match fs:
685 case []:
686 ""
687 case K.Source{+fa, ft} <> tl:
688 rest = text.at(tl, at)
689 Bool.pick(String, String.eq(fa, at), ft, rest)
690
691
692def texts(sums: List<&2, K.Item>, +fs: List<&2, K.Source>) -> List<&2, String>:
693 match sums:
694 case []:
695 []
696 case K.Item{at, _sum} <> tl:
697 text.at(fs, at) <> texts(tl, fs)
698
699
700
701def seed.walked(got: K.Walked, +hash: String, +path: String, +entry: String) -> List<&2, LW.Reply>:
702 match got:
703 case K.Walked{_h, _root, fs, +sums}:
704 [LW.Reply{LW.Pkg{hash, L.Member{path, entry}, ""},
705 LW.Got{LW.Clone{""}, K.manifest_of(sums), texts(sums, fs)}}]
706 case K.Asks{_at}:
707 []
708 case K.Refused{_why}:
709 []
710
711
712
713def seed.src(src: M.Source, +hash: String, +entry: String, +files: List<&2, K.Source>) -> List<&2, LW.Reply>:
714 match src:
715 case M.Hub{_nv}:
716 []
717 case M.Git{_url, _rev, _tag, _root, _nar, _vend}:
718 []
719 case M.Member{path, _nv}:
720 seed.walked(K.of(entry, files), hash, path, entry)
721
722
723def seed(dependency: M.Dep, +files: List<&2, K.Source>) -> List<&2, LW.Reply>:
724 M.Dep{_n, hh, ee, src} = dependency
725 seed.src(src, hh, ee, files)
726
727
728def seeds.of(ds: List<&2, M.Dep>, +files: List<&2, K.Source>) -> List<&2, LW.Reply>:
729 match ds:
730 case []:
731 []
732 case hd <> tl:
733 List.append(&2, LW.Reply, seed(hd, files), seeds.of(tl, files))
734
735
736
737def seeds(jj: Joint, +files: List<&2, K.Source>) -> List<&2, LW.Reply>:
738 match jj:
739 case Lone{}:
740 []
741 case Clash{_why}:
742 []
743 case Joint{mm}:
744 seeds.of(deps.of(mm), files)
745
746
747def files.of(ls: List<&2, LW.Source>) -> List<&2, K.Source>:
748 match ls:
749 case []:
750 []
751 case LW.Source{at, text} <> tl:
752 K.Source{at, text} <> files.of(tl)
753
754
755def files(listing: LW.Listing) -> List<&2, K.Source>:
756 match listing:
757 case LW.Listed{ls}:
758 files.of(ls)
759 case LW.Unlisted{_why}:
760 []
761
762
763
764
765
766def ledgers.put(lg: Maybe<&2, W.Ledger>, rest: List<&2, W.Ledger>) -> List<&2, W.Ledger>:
767 match lg:
768 case None{}:
769 rest
770 case Some{ll}:
771 ll <> rest
772
773
774def ledgers(fs: List<&2, Found>) -> List<&2, W.Ledger>:
775 match fs:
776 case []:
777 []
778 case Found{+pp, +tt} <> tl:
779 ledgers.put(W.ledger.of(pp, tt), ledgers(tl))
780
781
782def read.cons(+dir: List<&2, String>, rd: M.Read, rest: Read) -> Read:
783 match rd:
784 case M.Bad{why}:
785 Unread{"ez: workspace member " ++ W.segs.text(dir) ++ " has an ez.toml that does not parse: " ++ why}
786 case M.Good{mm}:
787 match rest:
788 case Unread{why}:
789 Unread{why}
790 case Read{ms}:
791 Read{Member{dir, mm} <> ms}
792
793
794def read.pick(hit: Bool, +dir: List<&2, String>, +text: String, rest: Read) -> Read:
795 match hit:
796 case True{}:
797 read.cons(dir, M.parse(text), rest)
798 case False{}:
799 rest
800
801
802def read.one(lg: Maybe<&2, W.Ledger>, +dirs: List<&2, List<&2, String>>, +text: String, rest: Read) -> Read:
803 match lg:
804 case None{}:
805 rest
806 case Some{ll}:
807 +dir = W.ledger.dir(ll)
808 read.pick(W.has(dirs, dir), dir, text, rest)
809
810
811def read.all(fs: List<&2, Found>, +dirs: List<&2, List<&2, String>>) -> Read:
812 match fs:
813 case []:
814 Read{[]}
815 case Found{+pp, +tt} <> tl:
816 rest = read.all(tl, dirs)
817 read.one(W.ledger.of(pp, tt), dirs, tt, rest)
818
819
820
821def joint.read(rd: Read, +root: M.Manifest, +files: List<&2, K.Source>) -> Joint:
822 match rd:
823 case Unread{why}:
824 Clash{why}
825 case Read{ms}:
826 resolve(root, ms, files)
827
828
829def joint.root(
830 rd: M.Read,
831 +fs: List<&2, Found>,
832 +dirs: List<&2, List<&2, String>>,
833 +files: List<&2, K.Source>
834) -> Joint:
835 match rd:
836 case M.Bad{why}:
837 Clash{why}
838 case M.Good{root}:
839 joint.read(read.all(fs, dirs), root, files)
840
841
842def joint.members(
843 ms: W.Members,
844 +text: String,
845 +fs: List<&2, Found>,
846 +files: List<&2, K.Source>
847) -> Joint:
848 match ms:
849 case W.Refused{why}:
850 Clash{why}
851 case W.Members{_root, dirs}:
852 joint.root(M.parse(text), fs, dirs, files)
853
854
855def joint.spec(rd: W.Read, +text: String, +fs: List<&2, Found>, +files: List<&2, K.Source>) -> Joint:
856 match rd:
857 case W.Lone{}:
858 Lone{}
859 case W.Bad{why}:
860 Clash{why}
861 case W.Root{+spec}:
862 joint.members(W.members(spec, W.root.of(text), ledgers(fs)), text, fs, files)
863
864
865
866
867
868
869def resolved.read(rd: Read, +root: M.Manifest, +files: List<&2, K.Source>) -> Read:
870 match rd:
871 case Unread{why}:
872 Unread{why}
873 case Read{ms}:
874 +all = with.root(root, ms)
875 res.all(all, all, files)
876
877
878def resolved.root(
879 rd: M.Read,
880 +fs: List<&2, Found>,
881 +dirs: List<&2, List<&2, String>>,
882 +files: List<&2, K.Source>
883) -> Read:
884 match rd:
885 case M.Bad{why}:
886 Unread{why}
887 case M.Good{+root}:
888 resolved.read(read.all(fs, dirs), root, files)
889
890
891def resolved.members(ms: W.Members, +text: String, +fs: List<&2, Found>, +files: List<&2, K.Source>) -> Read:
892 match ms:
893 case W.Refused{why}:
894 Unread{why}
895 case W.Members{_root, dirs}:
896 resolved.root(M.parse(text), fs, dirs, files)
897
898
899def resolved.spec(rd: W.Read, +text: String, +fs: List<&2, Found>, +files: List<&2, K.Source>) -> Read:
900 match rd:
901 case W.Lone{}:
902 Read{[]}
903 case W.Bad{why}:
904 Unread{why}
905 case W.Root{+spec}:
906 resolved.members(W.members(spec, W.root.of(text), ledgers(fs)), text, fs, files)
907
908
909
910
911def resolved(+text: String, +fs: List<&2, Found>, +files: List<&2, K.Source>) -> Read:
912 resolved.spec(W.spec.of(text), text, fs, files)
913
914
915
916
917
918
919def joint(+text: String, +fs: List<&2, Found>, +files: List<&2, K.Source>) -> Joint:
920 joint.spec(W.spec.of(text), text, fs, files)
921
922
923def joint.text(+jj: Joint, +own: Maybe<&2, String>) -> Maybe<&2, String>:
924 match jj:
925 case Lone{}:
926 own
927 case Clash{_why}:
928 own
929 case Joint{mm}:
930 Some{Rend.show(mm)}