| 1 | package legatus |
| 2 | |
| 3 | import ( |
| 4 | "io" |
| 5 | "log/slog" |
| 6 | ) |
| 7 | |
| 8 | // ErrorPolicy governs cross-host behavior. Within a single host's flow a failed |
| 9 | // step always stops that flow (IV7); ErrorPolicy decides what happens to the |
| 10 | // other hosts. |
| 11 | type ErrorPolicy int |
| 12 | |
| 13 | const ( |
| 14 | // ContinueOnError runs every host and collects all failures (default). |
| 15 | ContinueOnError ErrorPolicy = iota |
| 16 | // FailFast cancels remaining hosts after the first host failure (best-effort). |
| 17 | FailFast |
| 18 | ) |
| 19 | |
| 20 | // Option configures a Runner. |
| 21 | type Option func(*Runner) |
| 22 | |
| 23 | // WithConcurrency caps how many hosts run at once. Values < 1 are ignored. |
| 24 | func WithConcurrency(n int) Option { |
| 25 | return func(r *Runner) { |
| 26 | if n > 0 { |
| 27 | r.concurrency = n |
| 28 | } |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | // WithErrorPolicy sets the cross-host error policy. |
| 33 | func WithErrorPolicy(p ErrorPolicy) Option { return func(r *Runner) { r.policy = p } } |
| 34 | |
| 35 | // WithReporter sets the progress reporter. |
| 36 | func WithReporter(rep Reporter) Option { |
| 37 | return func(r *Runner) { |
| 38 | if rep != nil { |
| 39 | r.reporter = rep |
| 40 | } |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | // WithPrompter sets the prompter handed to each FlowCtx. |
| 45 | func WithPrompter(p Prompter) Option { |
| 46 | return func(r *Runner) { |
| 47 | if p != nil { |
| 48 | r.prompter = p |
| 49 | } |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | // WithLogger sets the base structured logger. |
| 54 | func WithLogger(l *slog.Logger) Option { |
| 55 | return func(r *Runner) { |
| 56 | if l != nil { |
| 57 | r.logger = l |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | // WithDryRun toggles dry-run: steps are Checked, never Applied. |
| 63 | func WithDryRun(d bool) Option { return func(r *Runner) { r.dryRun = d } } |
| 64 | |
| 65 | // WithDialer sets the dialer used to open per-host connections. |
| 66 | func WithDialer(d Dialer) Option { return func(r *Runner) { r.dialer = d } } |
| 67 | |
| 68 | // WithOutput sets the human-facing output sink threaded into each flow's |
| 69 | // FlowCtx.Out(). Steps that stream (e.g. steps.Command{Stream}) write here. |
| 70 | func WithOutput(w io.Writer) Option { |
| 71 | return func(r *Runner) { |
| 72 | if w != nil { |
| 73 | r.out = w |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | |