src/remove/relock.bend

ezx@1.10.0.0 · 79 lines · 0 definitions

1# remove/relock: `ez remove` as it runs, the remove and the lock in one plan
2# (EZ-DOC-6). The remove is planned as before (`RP.plan`, remove/plan.bend);
3# once it is known to succeed, the plain `ez lock` planner is run over the
4# World it leaves (`R.world`, relock/relock.bend): the ledger the remove
5# writes, the `.bend` files git lists, and the lock's answers, which the
6# lock's interpreter gives as `ez lock` gives them.
7#
8# The plan, when both succeed: the remove's effects, then the lock's, the
9# lock last. When either refuses, a refusal with no effect at all. A `.bend`
10# file git lists that still imports the dependency removed makes the lock
11# refuse, since ez.toml no longer names it, and so the remove.
12import Base
13import ezx@1.10.0.0/src/remove/plan.bend as RP
14import ezx@1.10.0.0/src/lock/plan.bend as P
15import ezx@1.10.0.0/src/lock/world.bend as W
16import ezx@1.10.0.0/src/relock/relock.bend as R
17
18# what `ez remove` reads: the remove's World, the directory it runs in, the
19# `.bend` files git lists, and the answers to the lock's questions
20type World is Data:
21  World{remove: RP.World, here: String, listing: W.Listing, locks: List<&2, W.Reply>}
22
23# the remove's World
24def remove(world: World) -> RP.World:
25  World{r, _here, _listing, _locks} = world
26  r
27
28# the ledger's text the remove read
29def ledger.was(rw: RP.World) -> Maybe<&2, String>:
30  RP.World{_n, l, _ig} = rw
31  l
32
33# the World a plain `ez lock` reads once the remove has run
34def lock.world(world: World) -> W.World:
35  World{+r, +here, listing, locks} = world
36  R.world(here, R.ledger(RP.plan(r), ledger.was(r)), listing, locks)
37
38# the plan of that lock
39def lock(world: World) -> P.Plan:
40  P.plan(lock.world(world))
41
42# what is added after the lock's reason when the lock refuses
43def tail() -> String:
44  "\nez: ez remove wrote nothing, since it writes ez.toml and ez.lock.toml together;" ++
45    " a .bend file that still imports what it removes has to stop first"
46
47# `ez remove` over a World: the remove, then the lock over what it leaves
48def plan(world: World) -> P.Plan:
49  World{+r, +here, +listing, +locks} = world
50  R.join(RP.plan(r), lock(World{r, here, listing, locks}), [], tail())
51
52# whether `ez remove` refuses on a World
53def refuses(world: World) -> Bool:
54  R.refuses(plan(world))
55
56# what the interpreter does next: answer the lock's questions, or run the plan
57type Next is Data:
58  AskLock{asks: List<&2, W.Ask>}
59  Planned{plan: P.Plan}
60
61# the lock's step, once the remove succeeds
62def next.lock(st: P.Step, +world: World) -> Next:
63  match st:
64    case P.Asking{as, ups, ns}:
65      AskLock{R.asks(P.Asking{as, ups, ns})}
66    case P.Run{_pl}:
67      Planned{plan(world)}
68
69# the remove refused is the plan; otherwise the lock is next
70def next.made(refused: Bool, +world: World) -> Next:
71  match refused:
72    case True{}:
73      Planned{plan(world)}
74    case False{}:
75      next.lock(P.step(lock.world(world)), world)
76
77# what the interpreter does next on a World
78def next(+world: World) -> Next:
79  next.made(R.refuses(RP.plan(remove(world))), world)