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  }