depgraph: alphabetize/style
This commit is contained in:
parent
c0a7e5b98b
commit
f4e9dda0ea
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/hashicorp/terraform/digraph"
|
||||
)
|
||||
|
||||
// Graph is used to represent the entire dependency graph
|
||||
// Graph is used to represent a dependency graph.
|
||||
type Graph struct {
|
||||
Name string
|
||||
Meta interface{}
|
||||
|
@ -19,6 +19,91 @@ type Graph struct {
|
|||
Root *Noun
|
||||
}
|
||||
|
||||
// ValidateError implements the Error interface but provides
|
||||
// additional information on a validation error.
|
||||
type ValidateError struct {
|
||||
// If set, then the graph is missing a single root, on which
|
||||
// there are no depdendencies
|
||||
MissingRoot bool
|
||||
|
||||
// Unreachable are nodes that could not be reached from
|
||||
// the root noun.
|
||||
Unreachable []*Noun
|
||||
|
||||
// Cycles are groups of strongly connected nodes, which
|
||||
// form a cycle. This is disallowed.
|
||||
Cycles [][]*Noun
|
||||
}
|
||||
|
||||
func (v *ValidateError) Error() string {
|
||||
return "The depedency graph is not valid"
|
||||
}
|
||||
|
||||
// ConstraintError is used to return detailed violation
|
||||
// information from CheckConstraints
|
||||
type ConstraintError struct {
|
||||
Violations []*Violation
|
||||
}
|
||||
|
||||
func (c *ConstraintError) Error() string {
|
||||
return fmt.Sprintf("%d constraint violations", len(c.Violations))
|
||||
}
|
||||
|
||||
// Violation is used to pass along information about
|
||||
// a constraint violation
|
||||
type Violation struct {
|
||||
Source *Noun
|
||||
Target *Noun
|
||||
Dependency *Dependency
|
||||
Constraint Constraint
|
||||
Err error
|
||||
}
|
||||
|
||||
func (v *Violation) Error() string {
|
||||
return fmt.Sprintf("Constraint %v between %v and %v violated: %v",
|
||||
v.Constraint, v.Source, v.Target, v.Err)
|
||||
}
|
||||
|
||||
// CheckConstraints walks the graph and ensures that all
|
||||
// user imposed constraints are satisfied.
|
||||
func (g *Graph) CheckConstraints() error {
|
||||
// Ensure we have a root
|
||||
if g.Root == nil {
|
||||
return fmt.Errorf("Graph must be validated before checking constraint violations")
|
||||
}
|
||||
|
||||
// Create a constraint error
|
||||
cErr := &ConstraintError{}
|
||||
|
||||
// Walk from the root
|
||||
digraph.DepthFirstWalk(g.Root, func(n digraph.Node) bool {
|
||||
noun := n.(*Noun)
|
||||
for _, dep := range noun.Deps {
|
||||
target := dep.Target
|
||||
for _, constraint := range dep.Constraints {
|
||||
ok, err := constraint.Satisfied(noun, target)
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
violation := &Violation{
|
||||
Source: noun,
|
||||
Target: target,
|
||||
Dependency: dep,
|
||||
Constraint: constraint,
|
||||
Err: err,
|
||||
}
|
||||
cErr.Violations = append(cErr.Violations, violation)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if cErr.Violations != nil {
|
||||
return cErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate is used to ensure that a few properties of the graph are not violated:
|
||||
// 1) There must be a single "root", or source on which nothing depends.
|
||||
// 2) All nouns in the graph must be reachable from the root
|
||||
|
@ -68,88 +153,3 @@ CHECK_CYCLES:
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateError implements the Error interface but provides
|
||||
// additional information on a validation error
|
||||
type ValidateError struct {
|
||||
// If set, then the graph is missing a single root, on which
|
||||
// there are no depdendencies
|
||||
MissingRoot bool
|
||||
|
||||
// Unreachable are nodes that could not be reached from
|
||||
// the root noun.
|
||||
Unreachable []*Noun
|
||||
|
||||
// Cycles are groups of strongly connected nodes, which
|
||||
// form a cycle. This is disallowed.
|
||||
Cycles [][]*Noun
|
||||
}
|
||||
|
||||
func (v *ValidateError) Error() string {
|
||||
return "The depedency graph is not valid"
|
||||
}
|
||||
|
||||
// CheckConstraints walks the graph and ensures that all
|
||||
// user imposed constraints are satisfied.
|
||||
func (g *Graph) CheckConstraints() error {
|
||||
// Ensure we have a root
|
||||
if g.Root == nil {
|
||||
return fmt.Errorf("Graph must be validated before checking constraint violations")
|
||||
}
|
||||
|
||||
// Create a constraint error
|
||||
cErr := &ConstraintError{}
|
||||
|
||||
// Walk from the root
|
||||
digraph.DepthFirstWalk(g.Root, func(n digraph.Node) bool {
|
||||
noun := n.(*Noun)
|
||||
for _, dep := range noun.Deps {
|
||||
target := dep.Target
|
||||
for _, constraint := range dep.Constraints {
|
||||
ok, err := constraint.Satisfied(noun, target)
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
violation := &Violation{
|
||||
Source: noun,
|
||||
Target: target,
|
||||
Dependency: dep,
|
||||
Constraint: constraint,
|
||||
Err: err,
|
||||
}
|
||||
cErr.Violations = append(cErr.Violations, violation)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if cErr.Violations != nil {
|
||||
return cErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConstraintError is used to return detailed violation
|
||||
// information from CheckConstraints
|
||||
type ConstraintError struct {
|
||||
Violations []*Violation
|
||||
}
|
||||
|
||||
func (c *ConstraintError) Error() string {
|
||||
return fmt.Sprintf("%d constraint violations", len(c.Violations))
|
||||
}
|
||||
|
||||
// Violation is used to pass along information about
|
||||
// a constraint violation
|
||||
type Violation struct {
|
||||
Source *Noun
|
||||
Target *Noun
|
||||
Dependency *Dependency
|
||||
Constraint Constraint
|
||||
Err error
|
||||
}
|
||||
|
||||
func (v *Violation) Error() string {
|
||||
return fmt.Sprintf("Constraint %v between %v and %v violated: %v",
|
||||
v.Constraint, v.Source, v.Target, v.Err)
|
||||
}
|
||||
|
|
|
@ -53,9 +53,55 @@ func NounMapToList(m map[string]*Noun) []*Noun {
|
|||
return list
|
||||
}
|
||||
|
||||
func TestGraph_Validate_NoRoot(t *testing.T) {
|
||||
func TestGraph_Validate(t *testing.T) {
|
||||
nodes := ParseNouns(`a -> b
|
||||
b -> a`)
|
||||
a -> c
|
||||
b -> d
|
||||
b -> e
|
||||
c -> d
|
||||
c -> e`)
|
||||
list := NounMapToList(nodes)
|
||||
|
||||
g := &Graph{Name: "Test", Nouns: list}
|
||||
if err := g.Validate(); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGraph_Validate_Cycle(t *testing.T) {
|
||||
nodes := ParseNouns(`a -> b
|
||||
a -> c
|
||||
b -> d
|
||||
d -> b`)
|
||||
list := NounMapToList(nodes)
|
||||
|
||||
g := &Graph{Name: "Test", Nouns: list}
|
||||
err := g.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("expected err")
|
||||
}
|
||||
|
||||
vErr, ok := err.(*ValidateError)
|
||||
if !ok {
|
||||
t.Fatalf("expected validate error")
|
||||
}
|
||||
|
||||
if len(vErr.Cycles) != 1 {
|
||||
t.Fatalf("expected cycles")
|
||||
}
|
||||
|
||||
cycle := vErr.Cycles[0]
|
||||
if cycle[0].Name != "d" {
|
||||
t.Fatalf("bad: %v", cycle)
|
||||
}
|
||||
if cycle[1].Name != "b" {
|
||||
t.Fatalf("bad: %v", cycle)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGraph_Validate_MultiRoot(t *testing.T) {
|
||||
nodes := ParseNouns(`a -> b
|
||||
c -> d`)
|
||||
list := NounMapToList(nodes)
|
||||
|
||||
g := &Graph{Name: "Test", Nouns: list}
|
||||
|
@ -74,9 +120,9 @@ b -> a`)
|
|||
}
|
||||
}
|
||||
|
||||
func TestGraph_Validate_MultiRoot(t *testing.T) {
|
||||
func TestGraph_Validate_NoRoot(t *testing.T) {
|
||||
nodes := ParseNouns(`a -> b
|
||||
c -> d`)
|
||||
b -> a`)
|
||||
list := NounMapToList(nodes)
|
||||
|
||||
g := &Graph{Name: "Test", Nouns: list}
|
||||
|
@ -122,53 +168,6 @@ x -> x`)
|
|||
}
|
||||
}
|
||||
|
||||
func TestGraph_Validate_Cycle(t *testing.T) {
|
||||
nodes := ParseNouns(`a -> b
|
||||
a -> c
|
||||
b -> d
|
||||
d -> b`)
|
||||
list := NounMapToList(nodes)
|
||||
|
||||
g := &Graph{Name: "Test", Nouns: list}
|
||||
err := g.Validate()
|
||||
if err == nil {
|
||||
t.Fatalf("expected err")
|
||||
}
|
||||
|
||||
vErr, ok := err.(*ValidateError)
|
||||
if !ok {
|
||||
t.Fatalf("expected validate error")
|
||||
}
|
||||
|
||||
if len(vErr.Cycles) != 1 {
|
||||
t.Fatalf("expected cycles")
|
||||
}
|
||||
|
||||
cycle := vErr.Cycles[0]
|
||||
if cycle[0].Name != "d" {
|
||||
t.Fatalf("bad: %v", cycle)
|
||||
}
|
||||
if cycle[1].Name != "b" {
|
||||
t.Fatalf("bad: %v", cycle)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGraph_Validate(t *testing.T) {
|
||||
nodes := ParseNouns(`a -> b
|
||||
a -> c
|
||||
b -> d
|
||||
b -> e
|
||||
c -> d
|
||||
c -> e`)
|
||||
list := NounMapToList(nodes)
|
||||
|
||||
g := &Graph{Name: "Test", Nouns: list}
|
||||
err := g.Validate()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type VersionMeta int
|
||||
type VersionConstraint struct {
|
||||
Min int
|
||||
|
|
Loading…
Reference in New Issue