Prechádzať zdrojové kódy

add dependency resolver and circular dep checker

Mohammed Nafees 3 rokov pred
rodič
commit
fa9e2153f6

+ 68 - 0
internal/integrations/preview/dep_resolver.go

@@ -0,0 +1,68 @@
+package preview
+
+import (
+	"fmt"
+
+	"github.com/porter-dev/switchboard/pkg/types"
+)
+
+type dependencyResolver struct {
+	resources  []*types.Resource
+	graph      map[string][]string
+	resolved   map[string]bool
+	unresolved map[string]bool
+}
+
+func newDependencyResolver(resources []*types.Resource) *dependencyResolver {
+	return &dependencyResolver{
+		resources:  resources,
+		graph:      make(map[string][]string),
+		resolved:   make(map[string]bool),
+		unresolved: make(map[string]bool),
+	}
+}
+
+func (r *dependencyResolver) Resolve() error {
+	// construct dependency graph
+	for _, resource := range r.resources {
+		// check for duplicate resource
+		if _, ok := r.graph[resource.Name]; ok {
+			return fmt.Errorf("duplicate resource detected: '%s'", resource.Name)
+		}
+
+		r.graph[resource.Name] = append(r.graph[resource.Name], resource.DependsOn...)
+	}
+
+	err := r.depResolve(r.resources[0].Name)
+
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (r *dependencyResolver) depResolve(name string) error {
+	r.unresolved[name] = true
+
+	for _, dep := range r.graph[name] {
+		if _, ok := r.graph[dep]; !ok {
+			return fmt.Errorf("no such resource as: '%s'", dep)
+		}
+
+		if _, ok := r.resolved[dep]; !ok {
+			if _, ok = r.unresolved[dep]; ok {
+				return fmt.Errorf("circular depedency detected: '%s' -> '%s'", name, dep)
+			}
+			err := r.depResolve(dep)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	r.resolved[name] = true
+	delete(r.unresolved, name)
+
+	return nil
+}

+ 10 - 0
internal/integrations/preview/validate.go

@@ -20,6 +20,7 @@ type driverBasedResourceValidator func(*types.Resource) error
 var driverValidators = make(map[string]driverBasedResourceValidator)
 
 func init() {
+	driverValidators[""] = deployDriverValidator
 	driverValidators["deploy"] = deployDriverValidator
 	driverValidators["build-image"] = buildImageDriverValidator
 	driverValidators["push-image"] = pushImageDriverValidator
@@ -39,6 +40,15 @@ func Validate(contents string) []error {
 		return errors
 	}
 
+	depResolver := newDependencyResolver(resGroup.Resources)
+
+	err = depResolver.Resolve()
+
+	if err != nil {
+		errors = append(errors, fmt.Errorf("error resolving dependencies: %w", err))
+		return errors
+	}
+
 	for _, res := range resGroup.Resources {
 		if validator, ok := driverValidators[res.Driver]; ok {
 			if err := validator(res); err != nil {