1 import Base 2 import ../fs.bend as Fs 3 import ../act.bend as Act 4 import ../store/base.bend as SBase 5 import ../swlive.bend as L 6 import ./config.bend as Cfg 7 import ./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 14 type Split is Data: 15 Split{shadow: Bool, log: Maybe<&2, String>, rest: List<&2, String>} 16 17 def ActM(-A: Type) -> Type: 18 Act.of(A) 19 20 def ActM.pure(-A: Type, x: A) -> Act.of(A): 21 Act.pure(A, x) 22 23 def 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 26 def sp_shadow(+s: Split) -> Bool: 27 match s: 28 case Split{sh, l, r}: 29 sh 30 31 def sp_log(+s: Split) -> Maybe<&2, String>: 32 match s: 33 case Split{sh, l, r}: 34 l 35 36 def sp_rest(+s: Split) -> List<&2, String>: 37 match s: 38 case Split{sh, l, r}: 39 r 40 41 def keep(+a: String, +s: Split) -> Split: 42 match s: 43 case Split{sh, l, r}: 44 Split{sh, l, a <> r} 45 46 def mark(+s: Split) -> Split: 47 match s: 48 case Split{sh, l, r}: 49 Split{True{}, l, r} 50 51 def set_log(+v: String, +s: Split) -> Split: 52 match s: 53 case Split{sh, l, r}: 54 Split{sh, Some{v}, r} 55 56 def 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 67 def 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. 75 def 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 82 def settings_text(r: Fs.Res(String)) -> String: 83 match r: 84 case Fail{e}: 85 "" 86 case Done{t}: 87 t 88 89 def 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 92 def 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 97 def 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 100 def 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 107 def 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). 115 def run(+ctx: SBase.Ctx, +opts: L.Opts, +sp: Split) -> Act.of(U32): 116 with_log(ctx, opts, sp_log(sp), sp_rest(sp))