diff options
Diffstat (limited to 'internal/resource/repository.go')
| -rw-r--r-- | internal/resource/repository.go | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/internal/resource/repository.go b/internal/resource/repository.go index 8cb88b3..69617d4 100644 --- a/internal/resource/repository.go +++ b/internal/resource/repository.go @@ -11,11 +11,11 @@ var ( once sync.Once ) -func getRepository() repository { +func getRepository() *repository { once.Do(func() { repo = newRepository() }) - return repo + return &repo } func resetRepository() { @@ -24,17 +24,16 @@ func resetRepository() { type repository struct { registered map[string]Resource - mu *sync.Mutex + mu sync.Mutex } func newRepository() repository { return repository{ registered: make(map[string]Resource), - mu: new(sync.Mutex), } } -func (r repository) register(res Resource) error { +func (r *repository) register(res Resource) error { r.mu.Lock() defer r.mu.Unlock() @@ -47,3 +46,57 @@ func (r repository) register(res Resource) error { return nil } + +func (r *repository) apply() error { + r.mu.Lock() + defer r.mu.Unlock() + + visited := make(map[string]bool) + visiting := make(map[string]bool) + var order []Resource + + var visit func(id string) error + visit = func(id string) error { + if visiting[id] { + return fmt.Errorf("circular dependency detected involving %s", id) + } + if visited[id] { + return nil + } + + res, ok := r.registered[id] + if !ok { + return fmt.Errorf("resource %s is depended upon but not registered", id) + } + + visiting[id] = true + for depID := range res.dependsOn { + if err := visit(depID); err != nil { + return err + } + } + delete(visiting, id) + visited[id] = true + order = append(order, res) + return nil + } + + for id := range r.registered { + if err := visit(id); err != nil { + return err + } + } + + for _, res := range order { + log.Printf("Applying resource %v", res) + if err := res.Apply.Apply(); err != nil { + return fmt.Errorf("failed to apply %v: %w", res, err) + } + } + + return nil +} + +func Apply() error { + return getRepository().apply() +} |
