src/ws/up.bend
ezx@1.11.0.0 · 416 lines · 45 definitions
1
2
3
4
5
6
7
8
9
10import Base
11import ezx@1.11.0.0/src/ledger/manifest.bend as M
12import ezx@1.11.0.0/src/ledger/render.bend as Rend
13import ezx@1.11.0.0/src/toml/toml.bend as T
14import ezx@1.11.0.0/src/lock/world.bend as LW
15import ezx@1.11.0.0/src/lock/plan.bend as LP
16import ezx@1.11.0.0/src/pkg/pkg.bend as K
17import ezx@1.11.0.0/src/ws/workspace.bend as W
18import ezx@1.11.0.0/src/ws/joint.bend as J
19import ezx@1.11.0.0/src/ws/moved.bend as Mv
20
21
22
23
24
25type Back is Data:
26 Alone{}
27 Back{text: String, spec: W.Spec, found: List<&2, J.Found>, lock: String}
28
29
30
31
32
33
34def source.back(own: M.Source, joint: M.Source) -> M.Source:
35 match own:
36 case M.Hub{nv}:
37 M.Hub{nv}
38 case M.Git{url, _rev, _tag, _root, _nar, vend}:
39 match joint:
40 case M.Hub{_jn}:
41 M.Git{url, _rev, _tag, _root, _nar, vend}
42 case M.Git{_ju, jr, jt, jo, jn, _jv}:
43 M.Git{url, jr, jt, jo, jn, vend}
44 case M.Member{_jp, _jm}:
45 M.Git{url, _rev, _tag, _root, _nar, vend}
46 case M.Member{path, named}:
47 M.Member{path, named}
48
49
50
51
52def dep.back.src(own: M.Source, +nn: String, +hh: String, +ee: String, joint: M.Dep) -> M.Dep:
53 match own:
54 case M.Member{path, nv}:
55 M.Dep{nn, hh, ee, M.Member{path, nv}}
56 case M.Hub{nv}:
57 M.Dep{_jn, jh, je, js} = joint
58 M.Dep{nn, jh, je, source.back(M.Hub{nv}, js)}
59 case M.Git{url, rev, tag, root, nar, vend}:
60 M.Dep{_jn, jh, je, js} = joint
61 M.Dep{nn, jh, je, source.back(M.Git{url, rev, tag, root, nar, vend}, js)}
62
63
64def dep.back.at(own: M.Dep, joint: M.Dep) -> M.Dep:
65 M.Dep{nn, hh, ee, os} = own
66 dep.back.src(os, nn, hh, ee, joint)
67
68
69def dep.back(+own: M.Dep, +js: List<&2, M.Dep>) -> M.Dep:
70 dep.back.at(own, M.find(js, M.dep.name(own)))
71
72
73def deps.back(ds: List<&2, M.Dep>, +js: List<&2, M.Dep>) -> List<&2, M.Dep>:
74 match ds:
75 case []:
76 []
77 case +hd <> tl:
78 dep.back(hd, js) <> deps.back(tl, js)
79
80
81def tool.back.at(own: M.Tool, joint: M.Tool) -> M.Tool:
82 M.Tool{nn, ee, bb, os} = own
83 M.Tool{_jn, _je, _jb, js} = joint
84 M.Tool{nn, ee, bb, source.back(os, js)}
85
86
87def tool.back(+own: M.Tool, +ts: List<&2, M.Tool>) -> M.Tool:
88 tool.back.at(own, M.tool.find(ts, M.tool.name(own)))
89
90
91def tools.back(ts: List<&2, M.Tool>, +js: List<&2, M.Tool>) -> List<&2, M.Tool>:
92 match ts:
93 case []:
94 []
95 case +hd <> tl:
96 tool.back(hd, js) <> tools.back(tl, js)
97
98
99def ledger.back(mm: M.Manifest, joint: M.Manifest) -> M.Manifest:
100 M.Manifest{nn, ee, bb, hh, pa, pv, ds, ts} = mm
101 M.Manifest{_jn, _je, _jb, _jh, _jpa, _jpv, +jd, +jt} = joint
102 M.Manifest{nn, ee, bb, hh, pa, pv, deps.back(ds, jd), tools.back(ts, jt)}
103
104
105
106
107
108def array.items(ts: List<&2, String>) -> String:
109 match ts:
110 case []:
111 ""
112 case +hd <> []:
113 T.quote(hd)
114 case +hd <> tl:
115 T.quote(hd) ++ ", " ++ array.items(tl)
116
117
118def entries.text(es: List<&2, W.Entry>) -> List<&2, String>:
119 match es:
120 case []:
121 []
122 case hd <> tl:
123 W.entry.text(hd) <> entries.text(tl)
124
125
126def paths.text(ps: List<&2, List<&2, String>>) -> List<&2, String>:
127 match ps:
128 case []:
129 []
130 case hd <> tl:
131 W.segs.text(hd) <> paths.text(tl)
132
133
134def spec.text(spec: W.Spec) -> String:
135 W.Spec{es, ex} = spec
136 "[workspace]\nmembers = [" ++ array.items(entries.text(es)) ++ "]\nexclude = [" ++
137 array.items(paths.text(ex)) ++ "]\n"
138
139
140
141def root.text(+mm: M.Manifest, +spec: W.Spec, +root: W.Root) -> String:
142 +body = Rend.text(mm)
143 T.normal(Bool.pick(String, W.root.member(root), body, String.drop(body, 10n)) ++ spec.text(spec))
144
145
146
147
148
149
150def write.if(+mm: M.Manifest, +joint: M.Manifest, +at: String, +text: String) -> List<&2, LP.Effect>:
151 Bool.pick(List<&2, LP.Effect>, String.eq(Rend.show(mm), Rend.show(ledger.back(mm, joint))),
152 [], [LP.Write{at, text}])
153
154
155def member.write(rd: M.Read, +ds: List<&2, String>, +joint: M.Manifest) -> List<&2, LP.Effect>:
156 match rd:
157 case M.Bad{_why}:
158 []
159 case M.Good{+mm}:
160 write.if(mm, joint, W.segs.text(ds) ++ "/ez.toml", Rend.show(ledger.back(mm, joint)))
161
162
163def found.pick(hit: Bool, +text: String, +ds: List<&2, String>, +joint: M.Manifest) -> List<&2, LP.Effect>:
164 match hit:
165 case True{}:
166 member.write(M.parse(text), ds, joint)
167 case False{}:
168 []
169
170
171def found.write(
172 lg: Maybe<&2, W.Ledger>,
173 +text: String,
174 +dirs: List<&2, List<&2, String>>,
175 +joint: M.Manifest
176) -> List<&2, LP.Effect>:
177 match lg:
178 case None{}:
179 []
180 case Some{ll}:
181 +ds = W.ledger.dir(ll)
182 found.pick(W.has(dirs, ds), text, ds, joint)
183
184
185def members.write(
186 fs: List<&2, J.Found>,
187 +dirs: List<&2, List<&2, String>>,
188 +joint: M.Manifest
189) -> List<&2, LP.Effect>:
190 match fs:
191 case []:
192 []
193 case J.Found{+pp, +tt} <> tl:
194 List.append(&2, LP.Effect, found.write(W.ledger.of(pp, tt), tt, dirs, joint),
195 members.write(tl, dirs, joint))
196
197
198def root.write(rd: M.Read, +spec: W.Spec, +root: W.Root, +joint: M.Manifest) -> List<&2, LP.Effect>:
199 match rd:
200 case M.Bad{_why}:
201 []
202 case M.Good{+mm}:
203 write.if(mm, joint, "ez.toml", root.text(ledger.back(mm, joint), spec, root))
204
205
206
207def writes.members(
208 ms: W.Members,
209 +text: String,
210 +spec: W.Spec,
211 +fs: List<&2, J.Found>,
212 +joint: M.Manifest
213) -> List<&2, LP.Effect>:
214 match ms:
215 case W.Refused{_why}:
216 []
217 case W.Members{_root, +dirs}:
218 List.append(&2, LP.Effect, root.write(M.parse(text), spec, W.root.of(text), joint),
219 members.write(fs, dirs, joint))
220
221
222def writes.joint(joint: M.Read, +text: String, +spec: W.Spec, +fs: List<&2, J.Found>) -> List<&2, LP.Effect>:
223 match joint:
224 case M.Bad{_why}:
225 []
226 case M.Good{+jm}:
227 writes.members(W.members(spec, W.root.of(text), J.ledgers(fs)), text, spec, fs, jm)
228
229
230def writes(back: Back, joint: M.Read) -> List<&2, LP.Effect>:
231 match back:
232 case Alone{}:
233 []
234 case Back{+text, +spec, +fs, _lock}:
235 writes.joint(joint, text, spec, fs)
236
237
238def effect.write(
239 hit: Bool,
240 at: String,
241 text: String,
242 ws: List<&2, LP.Effect>,
243 rest: List<&2, LP.Effect>
244) -> List<&2, LP.Effect>:
245 match hit:
246 case True{}:
247 List.append(&2, LP.Effect, ws, rest)
248 case False{}:
249 LP.Write{at, text} <> rest
250
251
252def effect.back(effect: LP.Effect, +ws: List<&2, LP.Effect>, rest: List<&2, LP.Effect>) -> List<&2, LP.Effect>:
253 match effect:
254 case LP.Write{+at, text}:
255 effect.write(String.eq(at, "ez.toml"), at, text, ws, rest)
256 case LP.Lay{pl, hash, files}:
257 LP.Lay{pl, hash, files} <> rest
258 case LP.Drop{hash}:
259 LP.Drop{hash} <> rest
260 case LP.Say{text}:
261 LP.Say{text} <> rest
262 case LP.Name{nv, hash}:
263 LP.Name{nv, hash} <> rest
264
265
266def effects.back(es: List<&2, LP.Effect>, +ws: List<&2, LP.Effect>) -> List<&2, LP.Effect>:
267 match es:
268 case []:
269 []
270 case hd <> tl:
271 rest = effects.back(tl, ws)
272 effect.back(hd, ws, rest)
273
274
275def plan.back(pl: LP.Plan, +ws: List<&2, LP.Effect>) -> LP.Plan:
276 LP.Plan{es, outcome} = pl
277 LP.Plan{effects.back(es, ws), outcome}
278
279
280
281
282
283type Up is Data:
284 Up{world: LW.World, edits: List<&2, LP.Effect>}
285
286
287def files.of(world: LW.World) -> List<&2, K.Source>:
288 LW.World{_args, _ledger, listing, _replies, _ups} = world
289 J.files(listing)
290
291
292
293
294def up.moves(+ms: List<&2, Mv.Shift>, +text: String, +fs: List<&2, J.Found>, +world: LW.World) -> Up:
295 +files = files.of(world)
296 +moved = Mv.rewrite(Mv.swaps(ms), files)
297 Up{Mv.world.moved(J.joint(text, fs, moved), moved, world), Mv.edits(Mv.swaps(ms), files)}
298
299
300
301def up.of(+text: String, +fs: List<&2, J.Found>, +lock: String, +world: LW.World) -> Up:
302 up.moves(Mv.cascade(Mv.ctx(text, fs, files.of(world), lock, LW.args.only(world))), text, fs, world)
303
304
305def up.world(got: Up) -> LW.World:
306 Up{w2, _eds} = got
307 w2
308
309
310
311def world.at(up: Bool, +text: String, +fs: List<&2, J.Found>, +lock: String, +world: LW.World) -> LW.World:
312 match up:
313 case True{}:
314 up.world(up.of(text, fs, lock, world))
315 case False{}:
316 world
317
318
319def plans.on(back: Back, +world: LW.World) -> LW.World:
320 match back:
321 case Alone{}:
322 world
323 case Back{+text, _spec, +fs, +lock}:
324 world.at(LW.args.upgrade(world), text, fs, lock, world)
325
326
327
328
329
330def stale.at(up: Bool, +lock: String, +world: LW.World) -> String:
331 match up:
332 case True{}:
333 ""
334 case False{}:
335 Mv.stale.world(lock, world)
336
337
338def stale(back: Back, +world: LW.World) -> String:
339 match back:
340 case Alone{}:
341 ""
342 case Back{_text, _spec, _fs, +lock}:
343 stale.at(LW.args.upgrade(world), lock, world)
344
345
346def refused(+why: String) -> LP.Plan:
347 LP.Plan{[], LP.Refused{why}}
348
349
350def edits.put(refuses: Bool, eds: List<&2, LP.Effect>, pl: LP.Plan) -> LP.Plan:
351 match refuses:
352 case True{}:
353 pl
354 case False{}:
355 LP.Plan{es, outcome} = pl
356 LP.Plan{List.append(&2, LP.Effect, eds, es), outcome}
357
358
359
360
361def plan.up(got: Up, +back: Back) -> LP.Plan:
362 Up{+w2, eds} = got
363 edits.put(LP.refuses(w2), eds, plan.back(LP.plan(w2), writes(back, LP.ledger.next(w2))))
364
365
366def plan.plain(fine: Bool, +why: String, +world: LW.World) -> LP.Plan:
367 match fine:
368 case True{}:
369 LP.plan(world)
370 case False{}:
371 refused(why)
372
373
374def plan.at(up: Bool, +back: Back, +world: LW.World) -> LP.Plan:
375 match up:
376 case True{}:
377 match back:
378 case Alone{}:
379 LP.plan(world)
380 case Back{+text, +spec, +fs, +lock}:
381 plan.up(up.of(text, fs, lock, world), Back{text, spec, fs, lock})
382 case False{}:
383 match back:
384 case Alone{}:
385 LP.plan(world)
386 case Back{_text, _spec, _fs, +lock}:
387 +why = Mv.stale.world(lock, world)
388 plan.plain(String.is_empty(why), why, world)
389
390
391
392
393
394
395
396def plan(back: Back, +world: LW.World) -> LP.Plan:
397 match back:
398 case Alone{}:
399 LP.plan(world)
400 case Back{+text, +spec, +fs, +lock}:
401 plan.at(LW.args.upgrade(world), Back{text, spec, fs, lock}, world)
402
403
404def step.plain(fine: Bool, +why: String, +world: LW.World) -> LP.Step:
405 match fine:
406 case True{}:
407 LP.step(world)
408 case False{}:
409 LP.Run{refused(why)}
410
411
412
413def step(+back: Back, +world: LW.World) -> LP.Step:
414 +why = stale(back, world)
415 step.plain(String.is_empty(why), why, plans.on(back, world))
416