src/relock/relock.bend
ezx@1.9.0.0 · 83 lines · 0 definitions
1# relock: what `ez add` and `ez remove` share to leave the lock in step with
2# the ledger they write (EZ-DOC-6). Each command plans its edit as before;
3# then the plain `ez lock` planner (lock/plan.bend) is run over the World the
4# edit leaves: the ledger the edit writes to ez.toml, the `.bend` files git
5# lists, and the answers to the lock's questions. The two plans become one:
6# the edit's effects, then the lines a person is told about the lock, then the
7# lock's effects, which write ez.lock.toml last. A lock that refuses refuses
8# the whole command, with no effect at all, so neither file changes.
9#
10# A plain lock moves no pin (EZ-DOC-5), so every dependency and tool the edit
11# did not touch keeps the pin it had, and only what the edit changed is read
12# anew.
13import Base
14import ezx@1.9.0.0/src/lock/plan.bend as P
15import ezx@1.9.0.0/src/lock/world.bend as W
16
17# the ledger's path, which is fixed
18def toml() -> String:
19 "ez.toml"
20
21# what ez.toml holds once a plan has run, when it held `was` before
22def ledger.of(wrote: P.Wrote, was: Maybe<&2, String>) -> Maybe<&2, String>:
23 match wrote:
24 case P.Kept{}:
25 was
26 case P.Put{text}:
27 Some{text}
28
29# the ledger an edit leaves, when ez.toml held `was` before it
30def ledger(pl: P.Plan, was: Maybe<&2, String>) -> Maybe<&2, String>:
31 ledger.of(P.put.plan(pl, toml()), was)
32
33# the World a plain `ez lock` reads, run in `here` over a ledger, the `.bend`
34# files git lists, and the answers it was given. It asks the upgrade nothing.
35def world(+here: String, ledger: Maybe<&2, String>, listing: W.Listing, rs: List<&2, W.Reply>) -> W.World:
36 W.World{W.Args{False{}, "", here}, ledger, listing, rs, []}
37
38# how a plan ends
39def outcome(pl: P.Plan) -> P.Outcome:
40 P.Plan{_es, o} = pl
41 o
42
43# whether a plan ends in a refusal
44def refuses(pl: P.Plan) -> Bool:
45 P.Plan{_es, o} = pl
46 match o:
47 case P.Success{}:
48 False{}
49 case P.Refused{_why}:
50 True{}
51
52# the edit and the lock as one plan, once the edit is known to succeed: the
53# edit's effects, the notes, and the lock's effects, or, when the lock
54# refuses, a refusal with no effect, its reason followed by `tail`
55def join.lock(lock: P.Plan, +edit: P.Plan, notes: List<&2, P.Effect>, +tail: String) -> P.Plan:
56 P.Plan{es, outcome} = lock
57 match outcome:
58 case P.Success{}:
59 P.Plan{List.append(&2, P.Effect, P.effects(edit), List.append(&2, P.Effect, notes, es)),
60 P.Success{}}
61 case P.Refused{why}:
62 P.Plan{[], P.Refused{why ++ tail}}
63
64def join.edit(refused: Bool, +edit: P.Plan, lock: P.Plan, notes: List<&2, P.Effect>, +tail: String) -> P.Plan:
65 match refused:
66 case True{}:
67 P.Plan{[], P.Refused{P.why(outcome(edit))}}
68 case False{}:
69 join.lock(lock, edit, notes, tail)
70
71# an edit followed by the lock over what it leaves. An edit that refuses is
72# the plan, with no effect; one that succeeds is joined to the lock.
73def join(+edit: P.Plan, lock: P.Plan, notes: List<&2, P.Effect>, +tail: String) -> P.Plan:
74 join.edit(refuses(edit), edit, lock, notes, tail)
75
76# what the lock still asks, as one list: the packages, then the names. A
77# plain lock asks the upgrade nothing.
78def asks(st: P.Step) -> List<&2, W.Ask>:
79 match st:
80 case P.Asking{as, _ups, ns}:
81 List.append(&2, W.Ask, as, ns)
82 case P.Run{_pl}:
83 []