src/add/world.bend source
src/add/world.bend on the hub · documented module
# add/world: what `ez add` reads. The arguments it was given; the directory# it runs in (`here`), which every git question anchors a relative path to;# HOME, which a `~/` target is expanded against; the ledger's text, None when# there is no ez.toml; `.gitignore`'s text, "" when there is none; and the# answers to the questions the planner (add/plan.bend) asked. The questions# and answers are the upgrade's (lock/up.bend), which the lock's interpreter# answers: `Tags`, `Head` and `Refs` for what a ref names, and `Clone` for the# checkout at the rev, with its NAR hash and every file's text. A hub# package added by its `<name>@<version>` (add/hub.bend) asks the lock's own# questions instead (lock/world.bend), which the lock's interpreter answers# too: `Name` for the hash the hub says the name names, and `Pkg` for the# package's manifest and files, served by the hub. Those answers are `hubs`.## Everything here is a projection: what a World says, read one way. The# planner is written over these, so each law about the plan is a law about# them.import Baseimport ../lock/up.bend as Upimport ../lock/world.bend as Wimport ../ledger/manifest.bend as Mimport ../pkg/path.bend as Pimport ../ez/target.bend as Tgtimport ../ez/named.bend as Named# what `ez add <target> [ref] [entry.bend] [--rename NAME]` was given, each# "" when it was nottype Args is Data: Args{target: String, ref: String, entry: String, rename: String}# everything `ez add` readstype World is Data: World{args: Args, here: String, home: String, ledger: Maybe<&2, String>, ignore: String, replies: List<&2, Up.Reply>, hubs: List<&2, W.Reply>}# the ledger's path, which is fixeddef toml() -> String: "ez.toml"# the ignore file's path, which is fixeddef ignore.file() -> String: ".gitignore"# the argumentsdef args(world: World) -> Args: World{a, _here, _home, _ledger, _ignore, _replies, _hubs} = world adef args.target(given: Args) -> String: Args{t, _ref, _entry, _rename} = given tdef args.ref(given: Args) -> String: Args{_t, r, _entry, _rename} = given rdef args.entry(given: Args) -> String: Args{_t, _ref, e, _rename} = given edef args.rename(given: Args) -> String: Args{_t, _ref, _entry, r} = given r# the target asked fordef target(world: World) -> String: args.target(args(world))# the ref asked for, "" for nonedef ref(world: World) -> String: args.ref(args(world))def entry.arg(world: World) -> String: args.entry(args(world))# the `--rename` asked for, "" for nonedef rename(world: World) -> String: args.rename(args(world))# the directory ez runs in, which is the project rootdef here(world: World) -> String: World{_args, h, _home, _ledger, _ignore, _replies, _hubs} = world h# HOME, which a `~/` target is expanded againstdef home(world: World) -> String: World{_args, _here, h, _ledger, _ignore, _replies, _hubs} = world h# the ledger's text, None when there is no ez.tomldef ledger(world: World) -> Maybe<&2, String>: World{_args, _here, _home, l, _ignore, _replies, _hubs} = world l# `.gitignore`'s text, "" when there is nonedef ignore(world: World) -> String: World{_args, _here, _home, _ledger, i, _replies, _hubs} = world i# every question answered so fardef replies(world: World) -> List<&2, Up.Reply>: World{_args, _here, _home, _ledger, _ignore, rs, _hubs} = world rs# every hub question answered so fardef hubs(world: World) -> List<&2, W.Reply>: World{_args, _here, _home, _ledger, _ignore, _replies, hs} = world hs# the ledger as read: what the file says, or, with no file, a read that did# not parse and says why. A missing ledger is not an empty one to write back.def read.of(got: Maybe<&2, String>) -> M.Read: match got: case None{}: M.Bad{"no " ++ toml() ++ " here; ez add works on a project's " ++ "ledger, and ez init makes one"} case Some{text}: M.parse(text)# the ledger, readdef read(world: World) -> M.Read: read.of(ledger(world))# the model of a ledger that read; an empty one otherwise, which nothing# writes, since a ledger that did not read is refuseddef manifest.of(led: M.Read) -> M.Manifest: match led: case M.Bad{_why}: M.Manifest{"", "", "", "", "", "", [], []} case M.Good{m}: m# the dependencies of a ledger that was readdef deps.of(manifest: M.Manifest) -> List<&2, M.Dep>: M.Manifest{_n, _e, _b, _h, _pa, _pv, ds, _ts} = manifest ds# the ledger's dependencies, none when it did not readdef deps(world: World) -> List<&2, M.Dep>: deps.of(manifest.of(read(world)))# where the target namesdef place(world: World) -> Tgt.Place: Tgt.classify(target(world))# the source a place records: a URL as it is, a path as it was given with a# leading `~/` expanded against HOME, and nothing for a target that names# nothingdef url.of(place: Tgt.Place, +home: String) -> String: match place: case Tgt.Bad{_why}: "" case Tgt.Local{path}: Tgt.expand(home, path) case Tgt.Remote{url, _slug}: url# the source the ledger records (EZ-LED-8)def url(+world: World) -> String: url.of(place(world), home(world))# the source as git is to read it: a relative path taken from where ez runs,# which is the project root. Every question the planner asks carries this.def from(+world: World) -> String: P.anchor(here(world), url(world))# the name the source gives itself: a repository's, or the directory's the# path resolves todef fresh(+world: World) -> String: Named.called(place(world), from(world))# what the target names: a hub package by its `<name>@<version>`, or a placedef aim(world: World) -> Tgt.Aim: Tgt.aim(target(world))# whether the target is a hub package's `<name>@<version>`def named(world: World) -> Bool: Tgt.aim.named(aim(world))# the hub the ledger names, which a name and its package are asked ofdef hub(world: World) -> String: M.hub_of(read(world))