src/pub/world.bend

ezx@1.4.0.0 · 106 lines · 0 definitions

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 <entry>
12# --publish`, with the `<name>@<version>` 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.
17import Base
18import ezx@1.4.0.0/src/tool/world.bend as TW
19
20# a question the planner asks
21type 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 <entry> --publish [<named>]`
25  Lock{}                    # ez.lock.toml's text
26  Hub{url: String}          # `GET <url>`, 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
30type Answer is Data:
31  Told{answer: TW.Answer}
32  Ran{ok: Bool, text: String}
33
34# one question, answered
35type Reply is Data:
36  Reply{ask: Ask, answer: Answer}
37
38# everything `ez publish` reads
39type World is Data:
40  World{here: String, ledger: Maybe<&2, String>, replies: List<&2, Reply>}
41
42# the ledger's path, which is fixed
43def toml() -> String:
44  "ez.toml"
45
46# the lock's path, which is fixed
47def lockfile() -> String:
48  "ez.lock.toml"
49
50# the directory the project is in
51def 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
56def ledger(world: World) -> Maybe<&2, String>:
57  World{_here, l, _replies} = world
58  l
59
60# every question answered so far
61def 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.
69def 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
83type 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.
89def 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
97def 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
105def heard(+world: World, ask: Ask) -> Heard:
106  look(replies(world), key(ask))