src/ledger/render.bend
ezx@1.11.0.0 · 245 lines · 30 definitions
1
2
3
4import Base
5import ezx@1.11.0.0/src/ledger/manifest.bend as M
6import ezx@1.11.0.0/src/toml/toml.bend as T
7
8
9
10def line(key: String, +val: String) -> String:
11 Bool.pick(String, String.is_empty(val), "", key ++ " = \"" ++ val ++ "\"\n")
12
13
14
15def line.bare(key: String, +val: String) -> String:
16 Bool.pick(String, String.is_empty(val), "", key ++ " = " ++ val ++ "\n")
17
18
19
20
21
22def vendor.word(vend: Bool) -> String:
23 match vend:
24 case True{}:
25 "true"
26 case False{}:
27 ""
28
29
30def source(src: M.Source) -> String:
31 match src:
32 case M.Hub{named}:
33 line("hub", named)
34 case M.Git{url, rev, tag, root, nar, vend}:
35 line("git", url) ++ line("rev", rev) ++ line("tag", tag) ++
36 line("root", root) ++ line("narHash", nar) ++ line.bare("vendor", vendor.word(vend))
37 case M.Member{path, named}:
38 line.bare("workspace", "true") ++ line("path", path) ++ line("hub", named)
39
40
41def dep(dependency: M.Dep) -> String:
42 M.Dep{n, h, e, s} = dependency
43 "\n[deps." ++ n ++ "]\n" ++ line("hash", h) ++ source(s) ++ line("entry", e)
44
45
46def deps(ds: List<&2, M.Dep>) -> String:
47 match ds:
48 case []:
49 ""
50 case h <> t:
51 dep(h) ++ deps(t)
52
53
54def tool(pin: M.Tool) -> String:
55 M.Tool{n, e, b, s} = pin
56 "\n[tools." ++ n ++ "]\n" ++ source(s) ++ line("entry", e) ++ line("bin", b)
57
58
59def tools(ts: List<&2, M.Tool>) -> String:
60 match ts:
61 case []:
62 ""
63 case h <> t:
64 tool(h) ++ tools(t)
65
66
67def text(manifest: M.Manifest) -> String:
68 M.Manifest{n, e, b, h, pa, pv, ds, ts} = manifest
69 "[package]\n" ++ line("name", n) ++ line("entry", e) ++ line("bin", b) ++
70 line("hub", h) ++ line("publish-as", pa) ++ line("version", pv) ++
71 deps(ds) ++ tools(ts)
72
73
74def show(manifest: M.Manifest) -> String:
75 T.normal(text(manifest))
76
77
78
79def render(ledger: M.Read) -> String:
80 match ledger:
81 case M.Bad{_why}:
82 ""
83 case M.Good{m}:
84 show(m)
85
86
87def without.put(hit: Bool, dependency: M.Dep, rest: List<&2, M.Dep>) -> List<&2, M.Dep>:
88 match hit:
89 case True{}:
90 rest
91 case False{}:
92 dependency <> rest
93
94
95def without(ds: List<&2, M.Dep>, +name: String) -> List<&2, M.Dep>:
96 match ds:
97 case []:
98 []
99 case +h <> t:
100 without.put(String.eq(M.dep.name(h), name), h, without(t, name))
101
102
103
104def add(manifest: M.Manifest, +dependency: M.Dep) -> M.Manifest:
105 M.Manifest{n, e, b, h, pa, pv, ds, ts} = manifest
106 M.Manifest{n, e, b, h, pa, pv, List.append(&2, M.Dep, without(ds, M.dep.name(dependency)), [dependency]), ts}
107
108
109def remove(manifest: M.Manifest, name: String) -> M.Manifest:
110 M.Manifest{n, e, b, h, pa, pv, ds, ts} = manifest
111 M.Manifest{n, e, b, h, pa, pv, without(ds, name), ts}
112
113
114def vendored(src: M.Source) -> M.Source:
115 match src:
116 case M.Hub{named}:
117 M.Hub{named}
118 case M.Git{url, rev, tag, root, nar, _vend}:
119 M.Git{url, rev, tag, root, nar, True{}}
120 case M.Member{path, named}:
121 M.Member{path, named}
122
123
124def revend(keep: Bool, src: M.Source) -> M.Source:
125 match keep:
126 case True{}:
127 vendored(src)
128 case False{}:
129 src
130
131
132
133
134def readd(ds: List<&2, M.Dep>, dependency: M.Dep) -> M.Dep:
135 M.Dep{+n, h, e, s} = dependency
136 M.Dep{n, h, e, revend(M.source.vendor(M.source.dep(M.find(ds, n))), s)}
137
138
139
140def add.keep(manifest: M.Manifest, dependency: M.Dep) -> M.Manifest:
141 M.Manifest{n, e, b, h, pa, pv, +ds, ts} = manifest
142 add(M.Manifest{n, e, b, h, pa, pv, ds, ts}, readd(ds, dependency))
143
144
145
146
147
148def clear(text: String, +ch: Char) -> Bool:
149 match text:
150 case SNil{}:
151 True{}
152 case SCon{h, t}:
153 rest = clear(t, ch)
154 Bool.and(Bool.not(Char.is_eq(h, ch)), rest)
155
156
157
158
159
160def clean(+text: String) -> Bool:
161 Bool.and(clear(text, '"'), Bool.and(clear(text, '\\'), clear(text, '\n')))
162
163
164
165
166
167
168def source.ok(src: M.Source) -> Bool:
169 match src:
170 case M.Hub{+named}:
171 clean(named)
172 case M.Git{+url, rev, tag, +root, nar, _vend}:
173 Bool.and(Bool.and(Bool.not(String.is_empty(url)), Bool.not(String.is_empty(root))),
174 Bool.and(Bool.and(clean(url), clean(rev)),
175 Bool.and(clean(tag), Bool.and(clean(root), clean(nar)))))
176 case M.Member{+path, +named}:
177 Bool.and(clean(path), clean(named))
178
179
180
181
182def hash.ok(src: M.Source, +hash: String) -> Bool:
183 match src:
184 case M.Hub{_named}:
185 Bool.and(Bool.not(String.is_empty(hash)), clean(hash))
186 case M.Git{_url, _rev, _tag, _root, _nar, _vend}:
187 Bool.and(Bool.not(String.is_empty(hash)), clean(hash))
188 case M.Member{_path, _named}:
189 clean(hash)
190
191
192
193def dep.ok(dependency: M.Dep) -> Bool:
194 M.Dep{+n, +h, +e, +s} = dependency
195 Bool.and(Bool.and(clean(n), hash.ok(s, h)),
196 Bool.and(clean(e), source.ok(s)))
197
198
199def deps.ok(ds: List<&2, M.Dep>) -> Bool:
200 match ds:
201 case []:
202 True{}
203 case h <> t:
204 rest = deps.ok(t)
205 Bool.and(dep.ok(h), rest)
206
207
208
209
210def tool.src.ok(src: M.Source) -> Bool:
211 match src:
212 case M.Hub{named}:
213 String.is_empty(named)
214 case M.Git{url, rev, tag, root, nar, vend}:
215 source.ok(M.Git{url, rev, tag, root, nar, vend})
216 case M.Member{_path, _named}:
217 False{}
218
219
220def tool.ok(pin: M.Tool) -> Bool:
221 M.Tool{+n, +e, +b, s} = pin
222 Bool.and(clean(n), Bool.and(Bool.and(clean(e), clean(b)), tool.src.ok(s)))
223
224
225def tools.ok(ts: List<&2, M.Tool>) -> Bool:
226 match ts:
227 case []:
228 True{}
229 case h <> t:
230 rest = tools.ok(t)
231 Bool.and(tool.ok(h), rest)
232
233
234
235
236
237
238def renderable(manifest: M.Manifest) -> Bool:
239 M.Manifest{+n, +e, +b, +h, +pa, +pv, ds, ts} = manifest
240 Bool.and(Bool.and(Bool.and(clean(n), clean(e)), Bool.and(clean(b), clean(h))),
241 Bool.and(Bool.and(clean(pa), clean(pv)), Bool.and(deps.ok(ds), tools.ok(ts))))
242
243
244def unrenderable() -> String:
245 "ez: ez.toml cannot be written: a name or value holds a quote, a backslash or a newline, a dependency has no hash, or a git source names no repo or no root"