1 # pub/world: what `ez publish` reads. The directory the project is in 2 # (`here`), which git is asked about; the ledger's text, None when there is no 3 # ez.toml; and the answers to the questions the planner (pub/plan.bend) 4 # asked. There is no field for BEND_LIB, the hub or the clock, because the 5 # planner reads none of them. 6 # 7 # A question is one of the tool commands' own (tool/world.bend): `Locate` for 8 # what git says of the project, `git status --porcelain 9 # --untracked-files=normal` among it, and `Read` for a file the package walk 10 # asks for. Two are publish's: `Tracked`, every file git tracks under the 11 # project with its `git ls-files -v` tag, and `Upload`, `bend 12 # --publish`, with the `@` the ledger names the package by 13 # after it when it names one, run and what it printed. The upload carries the 14 # line said just before it runs: the description the hub will show. The upload is the one 15 # question whose answering is not a read: it sends the package, so the planner 16 # asks it last, once every check that can be made before it has passed. 17 import Base 18 import ../tool/world.bend as TW 19 20 # a question the planner asks 21 type Ask is Data: 22 Tool{ask: TW.Ask} # a file's text, or what git says of a path 23 Tracked{} # `git ls-files -v` in the project 24 Upload{entry: String, named: String, says: String} # `bend --publish []` 25 Lock{} # ez.lock.toml's text 26 Hub{url: String} # `GET `, a url under the ledger's hub 27 28 # the answer to one: the tool commands' answer, or whether a program exited 0 29 # and what it printed 30 type Answer is Data: 31 Told{answer: TW.Answer} 32 Ran{ok: Bool, text: String} 33 34 # one question, answered 35 type Reply is Data: 36 Reply{ask: Ask, answer: Answer} 37 38 # everything `ez publish` reads 39 type World is Data: 40 World{here: String, ledger: Maybe<&2, String>, replies: List<&2, Reply>} 41 42 # the ledger's path, which is fixed 43 def toml() -> String: 44 "ez.toml" 45 46 # the lock's path, which is fixed 47 def lockfile() -> String: 48 "ez.lock.toml" 49 50 # the directory the project is in 51 def here(world: World) -> String: 52 World{h, _ledger, _replies} = world 53 h 54 55 # the ledger's text, None when there is no ez.toml 56 def ledger(world: World) -> Maybe<&2, String>: 57 World{_here, l, _replies} = world 58 l 59 60 # every question answered so far 61 def replies(world: World) -> List<&2, Reply>: 62 World{_here, _ledger, rs} = world 63 rs 64 65 # the key a question is looked up by. A command uploads once, so the upload's 66 # key does not name the entry: the planner looks its answer up without 67 # knowing which entry the ledger names, and a law about that answer holds 68 # whatever the ledger says. 69 def key(ask: Ask) -> String: 70 match ask: 71 case Tool{q}: 72 TW.key(q) 73 case Tracked{}: 74 "tracked" 75 case Upload{_entry, _named, _says}: 76 "upload" 77 case Lock{}: 78 "lock" 79 case Hub{url}: 80 "hub " ++ url 81 82 # an answer looked up, or none yet 83 type Heard is Data: 84 Heard{answer: Answer} 85 Open{} 86 87 # this answer when it is the question's, otherwise the rest's. The rest 88 # arrives as a thunk, so the first hit ends the scan. 89 def look.step(hit: Bool, answer: Answer, rest: Unit -> Heard) -> Heard: 90 match hit: 91 case True{}: 92 Heard{answer} 93 case False{}: 94 rest(Unit{}) 95 96 # the first answer given to a question 97 def look(rs: List<&2, Reply>, +want: String) -> Heard: 98 match rs: 99 case []: 100 Open{} 101 case Reply{ask, answer} <> t: 102 look.step(String.eq(key(ask), want), answer, _u => look(t, want)) 103 104 # the answer to a question, or none yet 105 def heard(+world: World, ask: Ask) -> Heard: 106 look(replies(world), key(ask))