domain/architecture/system/deployment/ops.bend

near-v-framework@0.4.0.0 · 108 lines · 17 definitions

1import Base
2import near-v-framework@0.4.0.0/domain/architecture/system/deployment/type.bend as D
3
4# ---- what a deploy breaks: compared with what was deployed before (its address and stores) ----
5def address(d: D.Deployment) -> String:
6  match d:
7    case D.Deployment{a, _, _, _}:
8      a
9
10def stores(d: D.Deployment) -> List<&2, String>:
11  match d:
12    case D.Deployment{_, ss, _, _}:
13      ss
14
15def accepted(d: D.Deployment) -> List<&2, D.Break>:
16  match d:
17    case D.Deployment{_, _, acc, _}:
18      acc
19
20def keep_break(present: Bool, +o: String, rest: List<&2, D.Break>) -> List<&2, D.Break>:
21  match present:
22    case True{}:
23      rest
24    case False{}:
25      D.StoreRemoved{o} <> rest
26
27def removed(olds: List<&2, String>, +news: List<&2, String>) -> List<&2, D.Break>:
28  match olds:
29    case []:
30      []
31    case +o <> rest:
32      keep_break(List.contains(~String, ~String.eq, news, o), o, removed(rest, news))
33
34# The address changing, then each store the new deployment drops. A first deploy (no address before) breaks nothing.
35def breaks(+before: String, olds: List<&2, String>, +d: D.Deployment) -> List<&2, D.Break>:
36  List.append(&2, D.Break,
37    Bool.pick(List<&2, D.Break>, String.is_empty(before) || String.eq(before, address(d)), [], [D.AddressChanged{}]),
38    removed(olds, stores(d)))
39
40def break_eq(a: D.Break, b: D.Break) -> Bool:
41  match a b:
42    case D.AddressChanged{} D.AddressChanged{}:
43      True{}
44    case D.StoreRemoved{x} D.StoreRemoved{y}:
45      String.eq(x, y)
46    case _ _:
47      False{}
48
49def breaks_eq(a: List<&2, D.Break>, b: List<&2, D.Break>) -> Bool:
50  match a:
51    case []:
52      List.is_empty(&2, D.Break, b)
53    case x <> xs:
54      match b:
55        case []:
56          False{}
57        case y <> ys:
58          break_eq(x, y) && breaks_eq(xs, ys)
59
60def show_break(b: D.Break) -> String:
61  match b:
62    case D.AddressChanged{}:
63      "the address changes"
64    case D.StoreRemoved{n}:
65      "store " ++ n ++ " is removed"
66
67def shown(bs: List<&2, D.Break>) -> List<&2, String>:
68  match bs:
69    case []:
70      []
71    case b <> rest:
72      show_break(b) <> shown(rest)
73
74def show_breaks(bs: List<&2, D.Break>) -> String:
75  String.join(shown(bs), ", ")
76
77def store_lines(ss: List<&2, String>) -> String:
78  match ss:
79    case []:
80      ""
81    case s <> rest:
82      "store " ++ s ++ "\n" ++ store_lines(rest)
83
84# What a deploy records as deployed: the address, then one store per line.
85def record(+d: D.Deployment) -> String:
86  "address " ++ address(d) ++ "\n" ++ store_lines(stores(d))
87
88def keep_rest(c: Bool, +prefix: String, l: String, rest: List<&2, String>) -> List<&2, String>:
89  match c:
90    case True{}:
91      String.drop(l, String.length(prefix)) <> rest
92    case False{}:
93      rest
94
95# The lines that start with a prefix, without it.
96def after(+prefix: String, ls: List<&2, String>) -> List<&2, String>:
97  match ls:
98    case []:
99      []
100    case +l <> rest:
101      keep_rest(String.starts_with(l, prefix), prefix, l, after(prefix, rest))
102
103# The address and stores in a record ("" and [] when nothing was deployed).
104def recorded_address(+text: String) -> String:
105  Maybe.default(&2, String, List.head(&2, String, after("address ", String.lines(text))), "")
106
107def recorded_stores(+text: String) -> List<&2, String>:
108  after("store ", String.lines(text))