depgraph: alphabetize/style
This commit is contained in:
parent
c0a7e5b98b
commit
f4e9dda0ea
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/digraph"
|
"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 {
|
type Graph struct {
|
||||||
Name string
|
Name string
|
||||||
Meta interface{}
|
Meta interface{}
|
||||||
|
@ -19,6 +19,91 @@ type Graph struct {
|
||||||
Root *Noun
|
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:
|
// 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.
|
// 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
|
// 2) All nouns in the graph must be reachable from the root
|
||||||
|
@ -68,88 +153,3 @@ CHECK_CYCLES:
|
||||||
}
|
}
|
||||||
return nil
|
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
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGraph_Validate_NoRoot(t *testing.T) {
|
func TestGraph_Validate(t *testing.T) {
|
||||||
nodes := ParseNouns(`a -> b
|
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)
|
list := NounMapToList(nodes)
|
||||||
|
|
||||||
g := &Graph{Name: "Test", Nouns: list}
|
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
|
nodes := ParseNouns(`a -> b
|
||||||
c -> d`)
|
b -> a`)
|
||||||
list := NounMapToList(nodes)
|
list := NounMapToList(nodes)
|
||||||
|
|
||||||
g := &Graph{Name: "Test", Nouns: list}
|
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 VersionMeta int
|
||||||
type VersionConstraint struct {
|
type VersionConstraint struct {
|
||||||
Min int
|
Min int
|
||||||
|
|
Loading…
Reference in New Issue