src/add/world.bend
ezx@1.6.0.0 · 181 lines · 0 definitions
1# add/world: what `ez add` reads. The arguments it was given; the directory
2# it runs in (`here`), which every git question anchors a relative path to;
3# HOME, which a `~/` target is expanded against; the ledger's text, None when
4# there is no ez.toml; `.gitignore`'s text, "" when there is none; and the
5# answers to the questions the planner (add/plan.bend) asked. The questions
6# and answers are the upgrade's (lock/up.bend), which the lock's interpreter
7# answers: `Tags`, `Head` and `Refs` for what a ref names, and `Clone` for the
8# checkout at the rev, with its NAR hash and every file's text. A hub
9# package added by its `<name>@<version>` (add/hub.bend) asks the lock's own
10# questions instead (lock/world.bend), which the lock's interpreter answers
11# too: `Name` for the hash the hub says the name names, and `Pkg` for the
12# package's manifest and files, served by the hub. Those answers are `hubs`.
13#
14# Everything here is a projection: what a World says, read one way. The
15# planner is written over these, so each law about the plan is a law about
16# them.
17import Base
18import ezx@1.6.0.0/src/lock/up.bend as Up
19import ezx@1.6.0.0/src/lock/world.bend as W
20import ezx@1.6.0.0/src/ledger/manifest.bend as M
21import ezx@1.6.0.0/src/pkg/path.bend as P
22import ezx@1.6.0.0/src/ez/target.bend as Tgt
23import ezx@1.6.0.0/src/ez/named.bend as Named
24
25# what `ez add <target> [ref] [entry.bend] [--rename NAME]` was given, each
26# "" when it was not
27type Args is Data:
28 Args{target: String, ref: String, entry: String, rename: String}
29
30# everything `ez add` reads
31type World is Data:
32 World{args: Args, here: String, home: String, ledger: Maybe<&2, String>,
33 ignore: String, replies: List<&2, Up.Reply>, hubs: List<&2, W.Reply>}
34
35# the ledger's path, which is fixed
36def toml() -> String:
37 "ez.toml"
38
39# the ignore file's path, which is fixed
40def ignore.file() -> String:
41 ".gitignore"
42
43# the arguments
44def args(world: World) -> Args:
45 World{a, _here, _home, _ledger, _ignore, _replies, _hubs} = world
46 a
47
48def args.target(given: Args) -> String:
49 Args{t, _ref, _entry, _rename} = given
50 t
51
52def args.ref(given: Args) -> String:
53 Args{_t, r, _entry, _rename} = given
54 r
55
56def args.entry(given: Args) -> String:
57 Args{_t, _ref, e, _rename} = given
58 e
59
60def args.rename(given: Args) -> String:
61 Args{_t, _ref, _entry, r} = given
62 r
63
64# the target asked for
65def target(world: World) -> String:
66 args.target(args(world))
67
68# the ref asked for, "" for none
69def ref(world: World) -> String:
70 args.ref(args(world))
71
72def entry.arg(world: World) -> String:
73 args.entry(args(world))
74
75# the `--rename` asked for, "" for none
76def rename(world: World) -> String:
77 args.rename(args(world))
78
79# the directory ez runs in, which is the project root
80def here(world: World) -> String:
81 World{_args, h, _home, _ledger, _ignore, _replies, _hubs} = world
82 h
83
84# HOME, which a `~/` target is expanded against
85def home(world: World) -> String:
86 World{_args, _here, h, _ledger, _ignore, _replies, _hubs} = world
87 h
88
89# the ledger's text, None when there is no ez.toml
90def ledger(world: World) -> Maybe<&2, String>:
91 World{_args, _here, _home, l, _ignore, _replies, _hubs} = world
92 l
93
94# `.gitignore`'s text, "" when there is none
95def ignore(world: World) -> String:
96 World{_args, _here, _home, _ledger, i, _replies, _hubs} = world
97 i
98
99# every question answered so far
100def replies(world: World) -> List<&2, Up.Reply>:
101 World{_args, _here, _home, _ledger, _ignore, rs, _hubs} = world
102 rs
103
104# every hub question answered so far
105def hubs(world: World) -> List<&2, W.Reply>:
106 World{_args, _here, _home, _ledger, _ignore, _replies, hs} = world
107 hs
108
109# the ledger as read: what the file says, or, with no file, a read that did
110# not parse and says why. A missing ledger is not an empty one to write back.
111def read.of(got: Maybe<&2, String>) -> M.Read:
112 match got:
113 case None{}:
114 M.Bad{"no " ++ toml() ++ " here; ez add works on a project's " ++
115 "ledger, and ez init makes one"}
116 case Some{text}:
117 M.parse(text)
118
119# the ledger, read
120def read(world: World) -> M.Read:
121 read.of(ledger(world))
122
123# the model of a ledger that read; an empty one otherwise, which nothing
124# writes, since a ledger that did not read is refused
125def manifest.of(led: M.Read) -> M.Manifest:
126 match led:
127 case M.Bad{_why}:
128 M.Manifest{"", "", "", "", "", "", [], []}
129 case M.Good{m}:
130 m
131
132# the dependencies of a ledger that was read
133def deps.of(manifest: M.Manifest) -> List<&2, M.Dep>:
134 M.Manifest{_n, _e, _b, _h, _pa, _pv, ds, _ts} = manifest
135 ds
136
137# the ledger's dependencies, none when it did not read
138def deps(world: World) -> List<&2, M.Dep>:
139 deps.of(manifest.of(read(world)))
140
141# where the target names
142def place(world: World) -> Tgt.Place:
143 Tgt.classify(target(world))
144
145# the source a place records: a URL as it is, a path as it was given with a
146# leading `~/` expanded against HOME, and nothing for a target that names
147# nothing
148def url.of(place: Tgt.Place, +home: String) -> String:
149 match place:
150 case Tgt.Bad{_why}:
151 ""
152 case Tgt.Local{path}:
153 Tgt.expand(home, path)
154 case Tgt.Remote{url, _slug}:
155 url
156
157# the source the ledger records (EZ-LED-8)
158def url(+world: World) -> String:
159 url.of(place(world), home(world))
160
161# the source as git is to read it: a relative path taken from where ez runs,
162# which is the project root. Every question the planner asks carries this.
163def from(+world: World) -> String:
164 P.anchor(here(world), url(world))
165
166# the name the source gives itself: a repository's, or the directory's the
167# path resolves to
168def fresh(+world: World) -> String:
169 Named.called(place(world), from(world))
170
171# what the target names: a hub package by its `<name>@<version>`, or a place
172def aim(world: World) -> Tgt.Aim:
173 Tgt.aim(target(world))
174
175# whether the target is a hub package's `<name>@<version>`
176def named(world: World) -> Bool:
177 Tgt.aim.named(aim(world))
178
179# the hub the ledger names, which a name and its package are asked of
180def hub(world: World) -> String:
181 M.hub_of(read(world))