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. 12 import Base 13 import ./plan.bend as RP 14 import ../lock/plan.bend as P 15 import ../lock/world.bend as W 16 import ../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 20 type World is Data: 21 World{remove: RP.World, here: String, listing: W.Listing, locks: List<&2, W.Reply>} 22 23 # the remove's World 24 def remove(world: World) -> RP.World: 25 World{r, _here, _listing, _locks} = world 26 r 27 28 # the ledger's text the remove read 29 def 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 34 def 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 39 def 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 43 def 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 48 def 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 53 def 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 57 type 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 62 def 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 70 def 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 78 def next(+world: World) -> Next: 79 next.made(R.refuses(RP.plan(remove(world))), world)