diff --git a/internal/config/config.go b/internal/config/config.go index 5f6a854..efb90ad 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -91,14 +91,13 @@ func Parse(path string) (Config, error) { if err != nil { return Config{}, fmt.Errorf("build dag: %w", err) } - graph.Resolve() - cfg := graph.cfg + cfg := graph.Resolve() if err = cfg.validate(); err != nil { return Config{}, fmt.Errorf("validate config: %w", err) } - return *cfg, nil + return cfg, nil } // Decode decodes from a slice of bytes to a [Config] structure. diff --git a/internal/config/configgraph.go b/internal/config/configgraph.go index 1d086fb..e2c6666 100644 --- a/internal/config/configgraph.go +++ b/internal/config/configgraph.go @@ -7,9 +7,6 @@ import ( "fmt" "io" "log/slog" - "os" - - hdag "github.com/heimdalr/dag" "github.com/adevinta/lava/internal/config/dag" "github.com/adevinta/lava/internal/urlutil" @@ -19,7 +16,6 @@ import ( type ConfigGraph struct { dag *dag.DAG configs map[string]Config - cfg *Config } // NewConfigGraph creates a new [ConfigGraph] that represents the whole configuration. @@ -88,25 +84,25 @@ func (cg *ConfigGraph) Config(url string) (Config, error) { return Config{}, fmt.Errorf("could not find config for %s", url) } -// Visit executes the merge when a vertex is visited. -func (cg *ConfigGraph) Visit(v hdag.Vertexer) { - _, cfg := v.Vertex() - config, err := cg.Config(cfg.(string)) - if err != nil { - os.Exit(1) - } - if cg.cfg == nil { - cg.cfg = &config - } else { - mergedConfig, err := merge(config, *cg.cfg) +// Resolve walks the dag and merge the configuration. +func (cg *ConfigGraph) Resolve() Config { + var cfg *Config + cg.dag.DFSWalk(func(vertexID string, vertex interface{}) { + vexCfg, err := cg.Config(vertex.(string)) if err != nil { - os.Exit(1) + panic(err) } - cg.cfg = &mergedConfig - } -} -// Resolve walks the dag and merge the configuration. -func (cg *ConfigGraph) Resolve() { - cg.dag.Dag.DFSWalk(cg) + if cfg == nil { + cfg = &vexCfg + return + } + + vexCfg, err = merge(vexCfg, *cfg) + if err != nil { + panic(err) + } + cfg = &vexCfg + }) + return *cfg } diff --git a/internal/config/configgraph_test.go b/internal/config/configgraph_test.go index d13e4b6..6f04507 100644 --- a/internal/config/configgraph_test.go +++ b/internal/config/configgraph_test.go @@ -27,7 +27,7 @@ func TestNewConfigGraph(t *testing.T) { "testdata/include/no_includes.yaml": { LavaVersion: ptr("v1.0.0"), ChecktypeURLs: []string{ - "commonchecktypes.json", + "checktypes_no_includes.json", }, Targets: []Target{ { @@ -61,7 +61,7 @@ func TestNewConfigGraph(t *testing.T) { "testdata/include/no_includes.yaml": { LavaVersion: ptr("v1.0.0"), ChecktypeURLs: []string{ - "commonchecktypes.json", + "checktypes_no_includes.json", }, Targets: []Target{ { @@ -103,7 +103,7 @@ func TestNewConfigGraph(t *testing.T) { "testdata/include/no_includes.yaml": { LavaVersion: ptr("v1.0.0"), ChecktypeURLs: []string{ - "commonchecktypes.json", + "checktypes_no_includes.json", }, Targets: []Target{ { @@ -172,7 +172,7 @@ func TestNewConfigGraph(t *testing.T) { "testdata/include/no_includes.yaml": { LavaVersion: ptr("v1.0.0"), ChecktypeURLs: []string{ - "commonchecktypes.json", + "checktypes_no_includes.json", }, Targets: []Target{ { @@ -216,7 +216,7 @@ func TestConfigGraph_Resolve(t *testing.T) { want: Config{ LavaVersion: ptr("v1.0.0"), ChecktypeURLs: []string{ - "commonchecktypes.json", + "checktypes_no_includes.json", }, Targets: []Target{ { @@ -234,7 +234,7 @@ func TestConfigGraph_Resolve(t *testing.T) { Includes: []string{"testdata/include/no_includes.yaml"}, LavaVersion: ptr("v1.0.0"), ChecktypeURLs: []string{ - "commonchecktypes.json", + "checktypes_no_includes.json", "checktypes.json", }, Targets: []Target{ @@ -260,7 +260,7 @@ func TestConfigGraph_Resolve(t *testing.T) { }, LavaVersion: ptr("v1.0.0"), ChecktypeURLs: []string{ - "commonchecktypes.json", + "checktypes_no_includes.json", "checktypes.json", }, Targets: []Target{ @@ -289,7 +289,7 @@ func TestConfigGraph_Resolve(t *testing.T) { LavaVersion: ptr("v1.0.0"), ChecktypeURLs: []string{ "checktypes.json", - "commonchecktypes.json", + "checktypes_no_includes.json", "checktypes.json", "checktypes.json", }, @@ -324,12 +324,11 @@ func TestConfigGraph_Resolve(t *testing.T) { if err != nil { t.Errorf("build dag: %v", err) } - graph.Resolve() - got := graph.cfg + got := graph.Resolve() if (err != nil) != tt.wantErr { - t.Errorf("unexpected error: want: %v, got: %v", tt.wantErr, err) + t.Errorf("unexpected error: %v", err) } - if diff := cmp.Diff(tt.want, *got); diff != "" { + if diff := cmp.Diff(tt.want, got); diff != "" { t.Errorf("configs mismatch (-want +got):\n%v", diff) } }) diff --git a/internal/config/dag/dag.go b/internal/config/dag/dag.go index 48b11e6..b90e5bd 100644 --- a/internal/config/dag/dag.go +++ b/internal/config/dag/dag.go @@ -29,14 +29,14 @@ var ( // DAG represents a Direct Acyclic Graph object. type DAG struct { - Dag *hdag.DAG + dag *hdag.DAG vertices map[string]string } // New returns a Directed Acyclic Graph object. func New() *DAG { return &DAG{ - Dag: hdag.NewDAG(), + dag: hdag.NewDAG(), vertices: make(map[string]string), } } @@ -44,7 +44,7 @@ func New() *DAG { // AddVertex adds the vertex x to the DAG. AddVertex returns an error if s is // nil or s is already part of the graph. func (d *DAG) AddVertex(s string) (string, error) { - id, err := d.Dag.AddVertex(s) + id, err := d.dag.AddVertex(s) if err != nil { if errors.As(err, &hdag.VertexDuplicateError{}) { return id, fmt.Errorf("%w: %s", ErrDuplicatedVertex, s) @@ -66,7 +66,7 @@ func (d *DAG) AddEdge(from, to string) error { if toID == "" { return fmt.Errorf("%w: %s", ErrUnknownVertex, to) } - err := d.Dag.AddEdge(fromID, toID) + err := d.dag.AddEdge(fromID, toID) if err != nil { if errors.As(err, &hdag.EdgeDuplicateError{}) { return fmt.Errorf("%w: from %s to %s", ErrDuplicatedEdge, from, to) @@ -94,3 +94,13 @@ func (d *DAG) getVertexID(s string) string { } return "" } + +type WalkFunc func(vertexID string, vertex interface{}) + +func (fn WalkFunc) Visit(v hdag.Vertexer) { + fn(v.Vertex()) +} + +func (d *DAG) DFSWalk(fn WalkFunc) { + d.dag.DFSWalk(fn) +} diff --git a/internal/config/testdata/include/common.yaml b/internal/config/testdata/include/common.yaml index 9374887..b4dd278 100644 --- a/internal/config/testdata/include/common.yaml +++ b/internal/config/testdata/include/common.yaml @@ -8,4 +8,4 @@ targets: - identifier: example.com type: DomainName report: - severity: critical \ No newline at end of file + severity: critical diff --git a/internal/config/testdata/include/common_a.yaml b/internal/config/testdata/include/common_a.yaml index 38d1f1f..30cefd2 100644 --- a/internal/config/testdata/include/common_a.yaml +++ b/internal/config/testdata/include/common_a.yaml @@ -7,4 +7,4 @@ targets: - identifier: example.com type: DomainName report: - severity: medium \ No newline at end of file + severity: medium diff --git a/internal/config/testdata/include/no_includes.yaml b/internal/config/testdata/include/no_includes.yaml index 2c36635..ec00775 100644 --- a/internal/config/testdata/include/no_includes.yaml +++ b/internal/config/testdata/include/no_includes.yaml @@ -1,6 +1,6 @@ lava: v1.0.0 checktypes: - - commonchecktypes.json + - checktypes_no_includes.json targets: - identifier: example.com type: DomainName