spec.go

v0.6.1
Doc Versions Source
1
// Package flowspec turns a legatus Flow into a single declarative table instead
2
// of imperative builder code. A Spec is a list of Rows; each Row carries the
3
// conditionality that consumers otherwise hand-roll as control flow:
4
//
5
//   - Gate  — a static feature gate (the `if cfg.X.Enabled` around a block).
6
//   - Over  — a fan-out list (the `for _, e := range cfg.Exits` loop).
7
//   - When  — a per-host apply-time gate (steps.When), evaluated against the host.
8
//   - Make  — the step factory for one item.
9
//
10
// Spec implements legatus.FlowSource, so a Spec is handed to Runner.Run exactly
11
// where a static Flow would be. Resolve lowers the table to a Flow once, before
12
// any host fan-out, which is why Gate/Over are host-independent and only When
13
// sees the host.
14
package flowspec
15
16
import (
17
	"go.bigb.es/auxilia/legatus"
18
	"go.bigb.es/auxilia/legatus/steps"
19
)
20
21
// Row is one entry in a Spec. Every column is optional except Make:
22
//
23
//   - Gate nil  — the row is always included; false drops it (Over/Make unrun).
24
//   - Over nil  — a single pass with item == ""; otherwise one pass per element.
25
//   - When nil  — the emitted steps are unconditional; otherwise each is wrapped
26
//     in steps.When{Cond: When}.
27
type Row struct {
28
	Gate func() bool
29
	Over func() []string
30
	When func(*legatus.FlowCtx) bool
31
	Make func(item string) ([]legatus.Step, error)
32
}
33
34
// Spec is a named, ordered table of Rows that resolves to a legatus.Flow.
35
type Spec struct {
36
	Name string
37
	Rows []Row
38
}
39
40
// Resolve lowers the table to a Flow, walking rows in declaration order: a row
41
// whose Gate is false contributes nothing; otherwise Make runs once per Over item
42
// (or once with ""), and each produced step is wrapped in steps.When when the row
43
// has a When gate. The first Make error aborts, returning Flow{Name} (no steps)
44
// plus the error so the Runner can name the failed flow.
45
func (s Spec) Resolve() (legatus.Flow, error) {
46
	var out []legatus.Step
47
	for _, row := range s.Rows {
48
		if row.Gate != nil && !row.Gate() {
49
			continue
50
		}
51
		items := []string{""}
52
		if row.Over != nil {
53
			items = row.Over()
54
		}
55
		for _, item := range items {
56
			made, err := row.Make(item)
57
			if err != nil {
58
				return legatus.Flow{Name: s.Name}, err
59
			}
60
			for _, st := range made {
61
				if row.When != nil {
62
					st = steps.When{Cond: row.When, Step: st}
63
				}
64
				out = append(out, st)
65
			}
66
		}
67
	}
68
	return legatus.Flow{Name: s.Name, Steps: out}, nil
69
}
70

Source Files