src/remove/plan.bend
ezx@1.11.0.0 · 194 lines · 24 definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import Base
19import ezx@1.11.0.0/src/lock/plan.bend as P
20import ezx@1.11.0.0/src/ledger/manifest.bend as M
21import ezx@1.11.0.0/src/ledger/render.bend as Rend
22import ezx@1.11.0.0/src/ledger/ignore.bend as I
23
24
25
26type World is Data:
27 World{name: String, ledger: Maybe<&2, String>, ignore: String}
28
29
30def toml() -> String:
31 "ez.toml"
32
33
34def ignore.file() -> String:
35 ".gitignore"
36
37
38
39def read.of(got: Maybe<&2, String>) -> M.Read:
40 match got:
41 case None{}:
42 M.Bad{"no " ++ toml() ++ " here; ez remove works on a project's " ++
43 "ledger, and ez init makes one"}
44 case Some{text}:
45 M.parse(text)
46
47
48def deps.of(manifest: M.Manifest) -> List<&2, M.Dep>:
49 M.Manifest{_n, _e, _b, _h, _pa, _pv, ds, _ts} = manifest
50 ds
51
52
53def any.step(hit: Bool, rest: Unit -> Bool) -> Bool:
54 match hit:
55 case True{}:
56 True{}
57 case False{}:
58 rest(Unit{})
59
60
61def named(ds: List<&2, M.Dep>, +name: String) -> Bool:
62 match ds:
63 case []:
64 False{}
65 case +h <> t:
66 any.step(String.eq(M.dep.name(h), name), _u => named(t, name))
67
68
69def holds(ds: List<&2, M.Dep>, +hash: String) -> Bool:
70 match ds:
71 case []:
72 False{}
73 case +h <> t:
74 any.step(String.eq(M.dep.hash(h), hash), _u => holds(t, hash))
75
76
77def char.ok(+ch: Char) -> Bool:
78 Bool.not(Bool.or(Char.is_eq(ch, '/'), Char.is_eq(ch, '\\')))
79
80
81def chars.ok(text: String) -> Bool:
82 match text:
83 case SNil{}:
84 True{}
85 case SCon{+h, t}:
86 +rest = chars.ok(t)
87 Bool.and(char.ok(h), rest)
88
89
90
91
92def safe(+hash: String) -> Bool:
93 Bool.and(String.starts_with(hash, "0x"), chars.ok(hash))
94
95
96
97def gone.hash(keep: Bool, +hash: String, rest: List<&2, String>) -> List<&2, String>:
98 match keep:
99 case True{}:
100 rest
101 case False{}:
102 hash <> rest
103
104
105def gone.put(hit: Bool, +hash: String, +left: List<&2, M.Dep>, rest: List<&2, String>) -> List<&2, String>:
106 match hit:
107 case True{}:
108 gone.hash(Bool.or(holds(left, hash), Bool.not(safe(hash))), hash, rest)
109 case False{}:
110 rest
111
112
113
114def gone(ds: List<&2, M.Dep>, +name: String, +left: List<&2, M.Dep>) -> List<&2, String>:
115 match ds:
116 case []:
117 []
118 case +h <> t:
119 gone.put(Bool.and(String.eq(M.dep.name(h), name),
120 M.source.vendor(M.source.dep(h))), M.dep.hash(h), left, gone(t, name, left))
121
122
123def ignore.put(same: Bool, +next: String, rest: List<&2, P.Effect>) -> List<&2, P.Effect>:
124 match same:
125 case True{}:
126 rest
127 case False{}:
128 P.Write{ignore.file(), next} <> rest
129
130
131
132
133def edits(+led: M.Manifest, +name: String, +ignore: String) -> List<&2, P.Effect>:
134 +left = deps.of(Rend.remove(led, name))
135 +next = I.sync(left, ignore)
136 P.Write{toml(), Rend.show(Rend.remove(led, name))} <>
137 ignore.put(String.eq(next, ignore), next,
138 P.drops.of(gone(deps.of(led), name, left), []))
139
140
141def absent(+name: String) -> String:
142 "ez: " ++ toml() ++ " has no dependency named " ++ name
143
144
145
146
147def refusal(named: Bool, +name: String) -> String:
148 Bool.pick(String, named, Rend.unrenderable(), absent(name))
149
150
151
152def plan.has(has: Bool, +led: M.Manifest, +name: String, +ignore: String) -> P.Plan:
153 match has:
154 case True{}:
155 P.Plan{edits(led, name, ignore), P.Success{}}
156 case False{}:
157 P.Plan{[], P.Refused{refusal(named(deps.of(led), name), name)}}
158
159
160
161
162def plan.read(led: M.Read, +name: String, +ignore: String) -> P.Plan:
163 match led:
164 case M.Bad{why}:
165 P.Plan{[], P.Refused{"ez: " ++ M.show(M.Bad{why})}}
166 case M.Good{+m}:
167 plan.has(Bool.and(named(deps.of(m), name), Rend.renderable(Rend.remove(m, name))),
168 m, name, ignore)
169
170
171def plan(world: World) -> P.Plan:
172 World{+n, l, +ig} = world
173 plan.read(read.of(l), n, ig)
174
175
176def refuses.plan(pl: P.Plan) -> Bool:
177 P.Plan{_es, outcome} = pl
178 match outcome:
179 case P.Success{}:
180 False{}
181 case P.Refused{_why}:
182 True{}
183
184
185def refuses(world: World) -> Bool:
186 refuses.plan(plan(world))
187
188
189def after(wrote: P.Wrote, +was: String) -> String:
190 match wrote:
191 case P.Kept{}:
192 was
193 case P.Put{text}:
194 text