daemon/shadowcli.bend

cswap-bend-cli@0.1.0.0 · 116 lines · 20 definitions

1import Base
2import cswap-bend-cli@0.1.0.0/fs.bend as Fs
3import cswap-bend-cli@0.1.0.0/act.bend as Act
4import cswap-bend-cli@0.1.0.0/store/base.bend as SBase
5import cswap-bend-cli@0.1.0.0/swlive.bend as L
6import cswap-bend-cli@0.1.0.0/daemon/config.bend as Cfg
7import cswap-bend-cli@0.1.0.0/daemon/shadow.bend as Sh
8
9# The `--shadow` / `--shadow-log PATH` flags of `cswap auto`, taken out before
10# the ordinary flags are parsed, and the shadow run they select.
11
12# shadow?, the log path, the remaining arguments.
13
14type Split is Data:
15  Split{shadow: Bool, log: Maybe<&2, String>, rest: List<&2, String>}
16
17def ActM(-A: Type) -> Type:
18  Act.of(A)
19
20def ActM.pure(-A: Type, x: A) -> Act.of(A):
21  Act.pure(A, x)
22
23def ActM.bind(-A: Type, -B: Type, m: Act.of(A), f: A -> Act.of(B)) -> Act.of(B):
24  Act.bind(A, B, m, f)
25
26def sp_shadow(+s: Split) -> Bool:
27  match s:
28    case Split{sh, l, r}:
29      sh
30
31def sp_log(+s: Split) -> Maybe<&2, String>:
32  match s:
33    case Split{sh, l, r}:
34      l
35
36def sp_rest(+s: Split) -> List<&2, String>:
37  match s:
38    case Split{sh, l, r}:
39      r
40
41def keep(+a: String, +s: Split) -> Split:
42  match s:
43    case Split{sh, l, r}:
44      Split{sh, l, a <> r}
45
46def mark(+s: Split) -> Split:
47  match s:
48    case Split{sh, l, r}:
49      Split{True{}, l, r}
50
51def set_log(+v: String, +s: Split) -> Split:
52  match s:
53    case Split{sh, l, r}:
54      Split{sh, Some{v}, r}
55
56def pick(+pend: Bool, +is_sh: Bool, +is_log: Bool, +a: String, +r: Split) -> Split:
57  match pend is_sh is_log:
58    case True{} _ _:
59      set_log(a, r)
60    case False{} True{} _:
61      mark(r)
62    case False{} False{} True{}:
63      r
64    case False{} False{} False{}:
65      keep(a, r)
66
67def next_pend(+pend: Bool, +is_log: Bool) -> Bool:
68  match pend:
69    case True{}:
70      False{}
71    case False{}:
72      is_log
73
74# `pend`: the previous argument was --shadow-log, so this one is its value.
75def split(+xs: List<&2, String>, +pend: Bool) -> Split:
76  match xs:
77    case Nil{}:
78      Split{False{}, None{}, []}
79    case Con{a, t}:
80      pick(pend, String.eq(a, "--shadow"), String.eq(a, "--shadow-log"), a, split(t, next_pend(pend, String.eq(a, "--shadow-log"))))
81
82def settings_text(r: Fs.Res(String)) -> String:
83  match r:
84    case Fail{e}:
85      ""
86    case Done{t}:
87      t
88
89def read_settings(+ctx: SBase.Ctx) -> Act.of(String):
90  Act.lift(String, IO.bind(Fs.Res(String), String, Fs.read_file(SBase.root_of(ctx) ++ "/settings.json"), r => IO.pure(String, settings_text(r))))
91
92def flag_once(+f: Cfg.Flags) -> Bool:
93  match f:
94    case Cfg.Flags{o, j, d, th, iv, cd, st, md, ia}:
95      o
96
97def started(+ctx: SBase.Ctx, +opts: L.Opts, +log: String, +f: Cfg.Flags, +text: String) -> Act.of(U32):
98  Sh.run(Sh.Sh{ctx, Cfg.merge(Cfg.from_text(text), f), opts, log}, flag_once(f))
99
100def with_flags(+ctx: SBase.Ctx, +opts: L.Opts, +log: String, r: Result<&2, &2, String, Cfg.Flags>) -> Act.of(U32):
101  match r:
102    case Fail{msg}:
103      Act.fail(U32, 2, "cswap auto: error: " ++ msg)
104    case Done{f}:
105      Act.bind(String, U32, read_settings(ctx), t => started(ctx, opts, log, f, t))
106
107def with_log(+ctx: SBase.Ctx, +opts: L.Opts, +m: Maybe<&2, String>, +rest: List<&2, String>) -> Act.of(U32):
108  match m:
109    case None{}:
110      Act.fail(U32, 2, "cswap auto: error: --shadow needs --shadow-log PATH")
111    case Some{log}:
112      with_flags(ctx, opts, log, Cfg.parse_flags(rest))
113
114# Run `auto --shadow ...` (ARGS is what follows the verb).
115def run(+ctx: SBase.Ctx, +opts: L.Opts, +sp: Split) -> Act.of(U32):
116  with_log(ctx, opts, sp_log(sp), sp_rest(sp))