github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/dependency/util.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package dependency 5 6 import ( 7 "github.com/juju/errors" 8 ) 9 10 // Install is a convenience function for installing multiple manifolds into an 11 // engine at once. It returns the first error it encounters (and installs no more 12 // manifolds). 13 func Install(engine Engine, manifolds Manifolds) error { 14 for name, manifold := range manifolds { 15 if err := engine.Install(name, manifold); err != nil { 16 return errors.Trace(err) 17 } 18 } 19 return nil 20 } 21 22 // Validate will return an error if the dependency graph defined by the supplied 23 // manifolds contains any cycles. 24 func Validate(manifolds Manifolds) error { 25 inputs := make(map[string][]string) 26 for name, manifold := range manifolds { 27 inputs[name] = manifold.Inputs 28 } 29 return validator{ 30 inputs: inputs, 31 doing: make(map[string]bool), 32 done: make(map[string]bool), 33 }.run() 34 } 35 36 // validator implements a topological sort of the nodes defined in inputs; it 37 // doesn't actually produce sorted nodes, but rather exists to return an error 38 // if it determines that the nodes cannot be sorted (and hence a cycle exists). 39 type validator struct { 40 inputs map[string][]string 41 doing map[string]bool 42 done map[string]bool 43 } 44 45 func (v validator) run() error { 46 for node := range v.inputs { 47 if err := v.visit(node); err != nil { 48 return errors.Trace(err) 49 } 50 } 51 return nil 52 } 53 54 func (v validator) visit(node string) error { 55 if v.doing[node] { 56 return errors.Errorf("cycle detected at %q (considering: %v)", node, v.doing) 57 } 58 if !v.done[node] { 59 v.doing[node] = true 60 for _, input := range v.inputs[node] { 61 if err := v.visit(input); err != nil { 62 // Tracing this error will not help anyone. 63 return err 64 } 65 } 66 v.done[node] = true 67 v.doing[node] = false 68 } 69 return nil 70 }