1 # add/run: the interpreter for `ez add`. It reads the directory it runs in, 2 # HOME, ez.toml, `.gitignore` and the `.bend` files git lists into a World, 3 # then loops: it asks the planner (add/relock.bend) what is still open, 4 # answers each question with the lock's interpreter (`Run.answer.ups`: what 5 # git prints for tags, HEAD or a ref, and a checkout at a rev with its NAR 6 # hash and every file's text; `Run.answer.all`: for a hub package's name, 7 # what the hub says the name names, and the package's manifest and files, 8 # and for the lock that follows the add, each package and name it reads, as 9 # `ez lock` answers them), and adds the answers to the World, until nothing 10 # is left to ask. Then it runs the planner's plan with the lock's effect 11 # runner (`Run.exec.plan`), which exits 1 with the reason when the plan 12 # refuses. It decides nothing; that it reads and executes faithfully is 13 # EZ-TRUST-2. 14 import Base 15 import 0x8e26a6f8c31689519e618374376ee3dd/main.bend as R 16 import ../io/file.bend as F 17 import ../lock/run.bend as Run 18 import ../lock/up.bend as Up 19 import ../lock/world.bend as W 20 import ./world.bend as A 21 import ../ws/run.bend as WsRun 22 import ./relock.bend as AR 23 import ../ws/relock.bend as Rel 24 25 # the World with more answers in it 26 def more(world: AR.World, rs: List<&2, Up.Reply>) -> AR.World: 27 AR.World{A.World{args, here, home, ledger, ignore, replies, hubs}, listing, locks} = world 28 AR.World{A.World{args, here, home, ledger, ignore, List.append(&2, Up.Reply, replies, rs), hubs}, 29 listing, locks} 30 31 # the World with more of the hub's answers in it 32 def more.hub(world: AR.World, rs: List<&2, W.Reply>) -> AR.World: 33 AR.World{A.World{args, here, home, ledger, ignore, replies, hubs}, listing, locks} = world 34 AR.World{A.World{args, here, home, ledger, ignore, replies, List.append(&2, W.Reply, hubs, rs)}, 35 listing, locks} 36 37 # the World with more of the lock's answers in it 38 def more.lock(world: AR.World, rs: List<&2, W.Reply>) -> AR.World: 39 AR.World{a, listing, locks} = world 40 AR.World{a, listing, List.append(&2, W.Reply, locks, rs)} 41 42 # the planner's step: its questions answered and the loop gone round again, 43 # or its plan run 44 def loop.step(st: AR.Next, +lib: String, world: AR.World, go: AR.World -> IO(Unit)) -> IO(Unit): 45 match st: 46 case AR.AskGit{asks}: 47 do IO: 48 rs : List<&2, Up.Reply> <- Run.answer.ups(lib, asks) 49 go(more(world, rs)) 50 case AR.AskHub{asks}: 51 do IO: 52 rs : List<&2, W.Reply> <- Run.answer.all(lib, asks) 53 go(more.hub(world, rs)) 54 case AR.AskLock{asks}: 55 do IO: 56 rs : List<&2, W.Reply> <- Run.answer.all(lib, asks) 57 go(more.lock(world, rs)) 58 case AR.Planned{pl}: 59 Run.exec.plan(lib, pl) 60 61 # the rounds the loop may take. The add asks at most three rounds for a git 62 # target and two for a name; the lock after it asks a round per level of the 63 # import graph, as `ez lock` does (`Run.rounds`). This is only a guard against 64 # a planner that keeps asking, and running out of it dies loudly. 65 def rounds() -> Nat: 66 U32.to_nat(100000) 67 68 # the loop, under fuel. Every round adds an answer, since the planner never 69 # asks what the World answers already, so the fuel is only a guard. 70 def loop(fuel: Nat, +lib: String, +ws: Rel.Ws, +world: AR.World) -> IO(Unit): 71 match fuel: 72 case 0n: 73 IO.die(Unit, 1, "ez: ez add kept asking questions") 74 case 1n+f: 75 loop.step(Rel.add.next(ws, world), lib, world, w => loop(f, lib, ws, w)) 76 77 # `ez add [ref] [entry.bend] [--rename NAME]` 78 def run(+target: String, +ref: String, +entry: String, +rename: String) -> IO(Unit): 79 do IO: 80 lib : String <- Run.bend.lib() 81 +pwd : String <- R.exec(["pwd"]) 82 h : Result<&1, &1, U32 & String, String> <- IO.get_env("HOME") 83 +home : String <- IO.pure(String, Run.env.text(h)) 84 pinned : String <- WsRun.add.ref(home, target, ref) 85 led : Maybe<&2, String> <- F.read(A.toml()) 86 ig : Maybe<&2, String> <- F.read(A.ignore.file()) 87 ls : W.Listing <- Run.read.listing() 88 ws : Rel.Ws <- WsRun.relock.ws() 89 loop(rounds(), lib, ws, AR.World{A.World{A.Args{target, pinned, entry, rename}, 90 String.trim(R.text(pwd)), home, led, F.text_of(ig), [], []}, ls, []})