src/fetch/world.bend source
src/fetch/world.bend on the hub · documented module
# fetch/world: what `ez fetch` reads. The directory the project is in# (`here`), which a relative path in the lock is anchored to; whether there is# an ez.toml, since fetch fills BEND_LIB for a project and nothing else; the# lock's text, None when there is no ez.lock.toml; and the answers to the# questions the planner (fetch/plan.bend) asked. There is no field for# BEND_LIB's path, the environment or the clock, because the planner reads# none of them.## A question is about one package of the lock, by its hash: the tree already# under BEND_LIB (`Laid`), or the package fetched from where the lock says it# comes from. A git package is the upgrade's own `Clone` question# (lock/up.bend), a shallow checkout at the pinned rev with every file's# text; a hub package is the lock's own question (lock/world.bend), the# hub's manifest and every file it names. `Laid` and a hub package are# answered the way the lock answers its questions, with a manifest and the# texts of the files it names, and a clone the way the upgrade answers# `Clone`.## A name the lock records is asked about too: the file bend reads its hash# from, `$BEND_LIB/names/<nv>` (`Named`), as it is, or that there is none.import Baseimport ../toml/toml.bend as Timport ../lock/lock.bend as Limport ../lock/world.bend as Wimport ../lock/up.bend as Up# a question about one package of the lock, or one name it recordstype Ask is Data: Laid{hash: String} # the tree under BEND_LIB/<hash>, as its manifest names it Git{hash: String, ask: Up.Ask} # a checkout at the pinned rev (`Up.Clone`) Hub{ask: W.Ask} # the hub's manifest and every file it names (`W.Pkg`) Named{nv: String} # the file BEND_LIB/names/<nv>, as it is# the answer to one question: a manifest and the texts of the files it# names, what a clone answered, or a names file's text, None when there is# nonetype Answer is Data: Read{answer: W.Answer} # Laid, Hub Said{answer: Up.Answer} # Git Held{got: Maybe<&2, String>} # Named# one question, answeredtype Reply is Data: Reply{ask: Ask, answer: Answer}# everything `ez fetch` readstype World is Data: World{here: String, ledger: Bool, lock: Maybe<&2, String>, replies: List<&2, Reply>}# the ledger's path, which is fixeddef toml() -> String: "ez.toml"# the lock's path, which is fixeddef lockfile() -> String: "ez.lock.toml"# the directory the project is in, which every relative path in the lock is# read againstdef here(world: World) -> String: World{h, _ledger, _lock, _replies} = world h# whether there is an ez.tomldef ledger(world: World) -> Bool: World{_here, l, _lock, _replies} = world l# the lock's text, None when there is no ez.lock.tomldef lock(world: World) -> Maybe<&2, String>: World{_here, _ledger, l, _replies} = world l# every question answered so fardef replies(world: World) -> List<&2, Reply>: World{_here, _ledger, _lock, rs} = world rs# a lock's text, as tables; none when there is no lockdef sects.of(got: Maybe<&2, String>) -> List<&2, T.Sect>: match got: case None{}: [] case Some{text}: T.sects(T.parse(text))# the lock, as tablesdef sects(world: World) -> List<&2, T.Sect>: sects.of(lock(world))# a hub question as a keydef hub.key(ask: W.Ask) -> String: match ask: case W.Pkg{hash, _src, hub}: "hub\n" ++ hash ++ "\n" ++ hub case W.Name{nv, hub}: "hubname\n" ++ nv ++ "\n" ++ hub case W.Lock{}: "hublock"# a question as a key. A lock's value never holds a newline, so the fields# are kept apart by one.def key(ask: Ask) -> String: match ask: case Laid{hash}: "laid\n" ++ hash case Git{hash, q}: "git\n" ++ hash ++ "\n" ++ Up.key(q) case Hub{q}: hub.key(q) case Named{nv}: "named\n" ++ nv# an answer looked up, or none yettype Heard is Data: Heard{answer: Answer} Open{}# this answer when it is the question's, otherwise the rest's. The rest# arrives as a thunk, so the first hit ends the scan.def look.step(hit: Bool, answer: Answer, rest: Unit -> Heard) -> Heard: match hit: case True{}: Heard{answer} case False{}: rest(Unit{})# the first answer given to a questiondef look(rs: List<&2, Reply>, +want: String) -> Heard: match rs: case []: Open{} case Reply{ask, answer} <> t: look.step(String.eq(key(ask), want), answer, _u => look(t, want))# the answer to a question, or none yetdef heard(rs: List<&2, Reply>, ask: Ask) -> Heard: look(rs, key(ask))