src/fetch/world.bend
ezx@1.9.0.0 · 138 lines · 0 definitions
1# fetch/world: what `ez fetch` reads. The directory the project is in
2# (`here`), which a relative path in the lock is anchored to; whether there is
3# an ez.toml, since fetch fills BEND_LIB for a project and nothing else; the
4# lock's text, None when there is no ez.lock.toml; and the answers to the
5# questions the planner (fetch/plan.bend) asked. There is no field for
6# BEND_LIB's path, the environment or the clock, because the planner reads
7# none of them.
8#
9# A question is about one package of the lock, by its hash: the tree already
10# under BEND_LIB (`Laid`), or the package fetched from where the lock says it
11# comes from. A git package is the upgrade's own `Clone` question
12# (lock/up.bend), a shallow checkout at the pinned rev with every file's
13# text; a hub package is the lock's own question (lock/world.bend), the
14# hub's manifest and every file it names. `Laid` and a hub package are
15# answered the way the lock answers its questions, with a manifest and the
16# texts of the files it names, and a clone the way the upgrade answers
17# `Clone`.
18#
19# A name the lock records is asked about too: the file bend reads its hash
20# from, `$BEND_LIB/names/<nv>` (`Named`), as it is, or that there is none.
21import Base
22import ezx@1.9.0.0/src/toml/toml.bend as T
23import ezx@1.9.0.0/src/lock/lock.bend as L
24import ezx@1.9.0.0/src/lock/world.bend as W
25import ezx@1.9.0.0/src/lock/up.bend as Up
26
27# a question about one package of the lock, or one name it records
28type Ask is Data:
29 Laid{hash: String} # the tree under BEND_LIB/<hash>, as its manifest names it
30 Git{hash: String, ask: Up.Ask} # a checkout at the pinned rev (`Up.Clone`)
31 Hub{ask: W.Ask} # the hub's manifest and every file it names (`W.Pkg`)
32 Named{nv: String} # the file BEND_LIB/names/<nv>, as it is
33
34# the answer to one question: a manifest and the texts of the files it
35# names, what a clone answered, or a names file's text, None when there is
36# none
37type Answer is Data:
38 Read{answer: W.Answer} # Laid, Hub
39 Said{answer: Up.Answer} # Git
40 Held{got: Maybe<&2, String>} # Named
41
42# one question, answered
43type Reply is Data:
44 Reply{ask: Ask, answer: Answer}
45
46# everything `ez fetch` reads
47type World is Data:
48 World{here: String, ledger: Bool, lock: Maybe<&2, String>, replies: List<&2, Reply>}
49
50# the ledger's path, which is fixed
51def toml() -> String:
52 "ez.toml"
53
54# the lock's path, which is fixed
55def lockfile() -> String:
56 "ez.lock.toml"
57
58# the directory the project is in, which every relative path in the lock is
59# read against
60def here(world: World) -> String:
61 World{h, _ledger, _lock, _replies} = world
62 h
63
64# whether there is an ez.toml
65def ledger(world: World) -> Bool:
66 World{_here, l, _lock, _replies} = world
67 l
68
69# the lock's text, None when there is no ez.lock.toml
70def lock(world: World) -> Maybe<&2, String>:
71 World{_here, _ledger, l, _replies} = world
72 l
73
74# every question answered so far
75def replies(world: World) -> List<&2, Reply>:
76 World{_here, _ledger, _lock, rs} = world
77 rs
78
79# a lock's text, as tables; none when there is no lock
80def sects.of(got: Maybe<&2, String>) -> List<&2, T.Sect>:
81 match got:
82 case None{}:
83 []
84 case Some{text}:
85 T.sects(T.parse(text))
86
87# the lock, as tables
88def sects(world: World) -> List<&2, T.Sect>:
89 sects.of(lock(world))
90
91# a hub question as a key
92def hub.key(ask: W.Ask) -> String:
93 match ask:
94 case W.Pkg{hash, _src, hub}:
95 "hub\n" ++ hash ++ "\n" ++ hub
96 case W.Name{nv, hub}:
97 "hubname\n" ++ nv ++ "\n" ++ hub
98 case W.Lock{}:
99 "hublock"
100
101# a question as a key. A lock's value never holds a newline, so the fields
102# are kept apart by one.
103def key(ask: Ask) -> String:
104 match ask:
105 case Laid{hash}:
106 "laid\n" ++ hash
107 case Git{hash, q}:
108 "git\n" ++ hash ++ "\n" ++ Up.key(q)
109 case Hub{q}:
110 hub.key(q)
111 case Named{nv}:
112 "named\n" ++ nv
113
114# an answer looked up, or none yet
115type Heard is Data:
116 Heard{answer: Answer}
117 Open{}
118
119# this answer when it is the question's, otherwise the rest's. The rest
120# arrives as a thunk, so the first hit ends the scan.
121def look.step(hit: Bool, answer: Answer, rest: Unit -> Heard) -> Heard:
122 match hit:
123 case True{}:
124 Heard{answer}
125 case False{}:
126 rest(Unit{})
127
128# the first answer given to a question
129def look(rs: List<&2, Reply>, +want: String) -> Heard:
130 match rs:
131 case []:
132 Open{}
133 case Reply{ask, answer} <> t:
134 look.step(String.eq(key(ask), want), answer, _u => look(t, want))
135
136# the answer to a question, or none yet
137def heard(rs: List<&2, Reply>, ask: Ask) -> Heard:
138 look(rs, key(ask))