2
0

dep_resolver.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. package preview
  2. import (
  3. "fmt"
  4. "github.com/porter-dev/switchboard/pkg/types"
  5. )
  6. type dependencyResolver struct {
  7. resources []*types.Resource
  8. graph map[string][]string
  9. resolved map[string]bool
  10. unresolved map[string]bool
  11. }
  12. func newDependencyResolver(resources []*types.Resource) *dependencyResolver {
  13. return &dependencyResolver{
  14. resources: resources,
  15. graph: make(map[string][]string),
  16. resolved: make(map[string]bool),
  17. unresolved: make(map[string]bool),
  18. }
  19. }
  20. func (r *dependencyResolver) Resolve() error {
  21. if len(r.resources) > 0 {
  22. // construct dependency graph
  23. for _, resource := range r.resources {
  24. // check for duplicate resource
  25. if _, ok := r.graph[resource.Name]; ok {
  26. return fmt.Errorf("duplicate resource detected: '%s'", resource.Name)
  27. }
  28. r.graph[resource.Name] = append(r.graph[resource.Name], resource.DependsOn...)
  29. }
  30. err := r.depResolve(r.resources[0].Name)
  31. if err != nil {
  32. return err
  33. }
  34. }
  35. return nil
  36. }
  37. func (r *dependencyResolver) depResolve(name string) error {
  38. r.unresolved[name] = true
  39. for _, dep := range r.graph[name] {
  40. if _, ok := r.graph[dep]; !ok {
  41. return fmt.Errorf("no such resource as: '%s'", dep)
  42. }
  43. if _, ok := r.resolved[dep]; !ok {
  44. if _, ok = r.unresolved[dep]; ok {
  45. return fmt.Errorf("circular depedency detected: '%s' -> '%s'", name, dep)
  46. }
  47. err := r.depResolve(dep)
  48. if err != nil {
  49. return err
  50. }
  51. }
  52. }
  53. r.resolved[name] = true
  54. delete(r.unresolved, name)
  55. return nil
  56. }