pgraph: Replace edge struct with interface

This further cleans up the pgraph lib to be more generic.
This commit is contained in:
James Shubin
2017-05-28 19:51:56 -04:00
parent a87288d519
commit 4150ae7307
12 changed files with 247 additions and 173 deletions

View File

@@ -492,8 +492,13 @@ func (obj *Main) Run() error {
resources.VtoR(v).Exit() // sync
return nil
}
edgeCmpFn := func(e1, e2 pgraph.Edge) (bool, error) {
edge1 := e1.(*resources.Edge) // panic if wrong
edge2 := e2.(*resources.Edge) // panic if wrong
return edge1.Name == edge2.Name && edge1.Notify == edge2.Notify, nil // simple cmp
}
// on success, this updates the receiver graph...
if err := oldGraph.GraphSync(newGraph, vertexCmpFn, vertexAddFn, vertexRemoveFn); err != nil {
if err := oldGraph.GraphSync(newGraph, vertexCmpFn, vertexAddFn, vertexRemoveFn, edgeCmpFn); err != nil {
log.Printf("Main: Error running graph sync: %v", err)
// unpause!
if !first {

View File

@@ -29,7 +29,7 @@ import (
// This updates the Graph on success only.
// FIXME: should we do this with copies of the vertex resources?
// FIXME: add test cases
func (obj *Graph) GraphSync(newGraph *Graph, vertexCmpFn func(Vertex, Vertex) (bool, error), vertexAddFn func(Vertex) error, vertexRemoveFn func(Vertex) error) error {
func (obj *Graph) GraphSync(newGraph *Graph, vertexCmpFn func(Vertex, Vertex) (bool, error), vertexAddFn func(Vertex) error, vertexRemoveFn func(Vertex) error, edgeCmpFn func(Edge, Edge) (bool, error)) error {
oldGraph := obj.Copy() // work on a copy of the old graph
if oldGraph == nil {
@@ -43,7 +43,7 @@ func (obj *Graph) GraphSync(newGraph *Graph, vertexCmpFn func(Vertex, Vertex) (b
var lookup = make(map[Vertex]Vertex)
var vertexKeep []Vertex // list of vertices which are the same in new graph
var edgeKeep []*Edge // list of vertices which are the same in new graph
var edgeKeep []Edge // list of vertices which are the same in new graph
for v := range newGraph.Adjacency() { // loop through the vertices (resources)
var vertex Vertex
@@ -100,9 +100,14 @@ func (obj *Graph) GraphSync(newGraph *Graph, vertexCmpFn func(Vertex, Vertex) (b
}
edge, exists := oldGraph.Adjacency()[vertex1][vertex2]
if !exists || edge.Name != e.Name { // TODO: edgeCmp
edge = e // use or overwrite edge
if !exists {
edge = e // use edge
} else if b, err := edgeCmpFn(edge, e); err != nil {
return errwrap.Wrapf(err, "edgeCmpFn failed")
} else if !b {
edge = e // overwrite edge
}
oldGraph.Adjacency()[vertex1][vertex2] = edge // store it (AddEdge)
edgeKeep = append(edgeKeep, edge) // mark as saved
}

View File

@@ -50,11 +50,11 @@ func (g *Graph) Graphviz() (out string) {
for j := range g.Adjacency()[i] {
k := g.Adjacency()[i][j]
// use str for clearer output ordering
if k.Notify {
str += fmt.Sprintf("\t\"%s\" -> \"%s\" [label=\"%s\",style=bold];\n", i, j, k.Name)
} else {
str += fmt.Sprintf("\t\"%s\" -> \"%s\" [label=\"%s\"];\n", i, j, k.Name)
}
//if fmtBoldFn(k) { // TODO: add this sort of formatting
// str += fmt.Sprintf("\t\"%s\" -> \"%s\" [label=\"%s\",style=bold];\n", i, j, k)
//} else {
str += fmt.Sprintf("\t\"%s\" -> \"%s\" [label=\"%s\"];\n", i, j, k)
//}
}
}
out += str

View File

@@ -34,7 +34,7 @@ import (
type Graph struct {
Name string
adjacency map[Vertex]map[Vertex]*Edge // Vertex -> Vertex (edge)
adjacency map[Vertex]map[Vertex]Edge // Vertex -> Vertex (edge)
kv map[string]interface{} // some values associated with the graph
}
@@ -44,12 +44,10 @@ type Vertex interface {
fmt.Stringer // String() string
}
// Edge is the primary edge struct in this library.
type Edge struct {
Name string
Notify bool // should we send a refresh notification along this edge?
refresh bool // is there a notify pending for the dest vertex ?
// Edge is the primary edge struct in this library. It can be anything that
// implements Stringer. The string output must be stable and unique in a graph.
type Edge interface {
fmt.Stringer // String() string
}
// Init initializes the graph which populates all the internal structures.
@@ -58,7 +56,7 @@ func (g *Graph) Init() error {
return fmt.Errorf("can't initialize graph with empty name")
}
//g.adjacency = make(map[Vertex]map[Vertex]*Edge) // not required
//g.adjacency = make(map[Vertex]map[Vertex]Edge) // not required
//g.kv = make(map[string]interface{}) // not required
return nil
}
@@ -81,21 +79,11 @@ func NewVertex(x Vertex) Vertex {
return x
}
// NewEdge returns a new graph edge struct.
func NewEdge(name string) *Edge {
return &Edge{
Name: name,
}
}
// Refresh returns the pending refresh status of this edge.
func (obj *Edge) Refresh() bool {
return obj.refresh
}
// SetRefresh sets the pending refresh status of this edge.
func (obj *Edge) SetRefresh(b bool) {
obj.refresh = b
// NewEdge returns whatever was passed in. This is for compatibility with the
// usage of the old NewEdge method. This is considered deprecated.
// FIXME: remove me
func NewEdge(x Edge) Edge {
return x
}
// Value returns a value stored alongside the graph in a particular key.
@@ -119,7 +107,7 @@ func (g *Graph) Copy() *Graph {
}
newGraph := &Graph{
Name: g.Name,
adjacency: make(map[Vertex]map[Vertex]*Edge, len(g.adjacency)),
adjacency: make(map[Vertex]map[Vertex]Edge, len(g.adjacency)),
kv: g.kv,
}
for k, v := range g.adjacency {
@@ -141,11 +129,11 @@ func (g *Graph) SetName(name string) {
// AddVertex uses variadic input to add all listed vertices to the graph.
func (g *Graph) AddVertex(xv ...Vertex) {
if g.adjacency == nil { // initialize on first use
g.adjacency = make(map[Vertex]map[Vertex]*Edge)
g.adjacency = make(map[Vertex]map[Vertex]Edge)
}
for _, v := range xv {
if _, exists := g.adjacency[v]; !exists {
g.adjacency[v] = make(map[Vertex]*Edge)
g.adjacency[v] = make(map[Vertex]Edge)
}
}
}
@@ -159,7 +147,7 @@ func (g *Graph) DeleteVertex(v Vertex) {
}
// AddEdge adds a directed edge to the graph from v1 to v2.
func (g *Graph) AddEdge(v1, v2 Vertex, e *Edge) {
func (g *Graph) AddEdge(v1, v2 Vertex, e Edge) {
// NOTE: this doesn't allow more than one edge between two vertexes...
g.AddVertex(v1, v2) // supports adding N vertices now
// TODO: check if an edge exists to avoid overwriting it!
@@ -169,7 +157,7 @@ func (g *Graph) AddEdge(v1, v2 Vertex, e *Edge) {
// DeleteEdge deletes a particular edge from the graph.
// FIXME: add test cases
func (g *Graph) DeleteEdge(e *Edge) {
func (g *Graph) DeleteEdge(e Edge) {
for v1 := range g.adjacency {
for v2, edge := range g.adjacency[v1] {
if e == edge {
@@ -218,7 +206,7 @@ func (g *Graph) NumEdges() int {
// Adjacency returns the adjacency map representing this graph. This is useful
// for users who which to operate on the raw data structure more efficiently.
// This works because maps are reference types so we can edit this at will.
func (g *Graph) Adjacency() map[Vertex]map[Vertex]*Edge {
func (g *Graph) Adjacency() map[Vertex]map[Vertex]Edge {
return g.adjacency
}
@@ -303,8 +291,8 @@ func (g *Graph) GraphVertices(v Vertex) []Vertex {
}
// IncomingGraphEdges returns all of the edges that point to vertex v (??? -> v).
func (g *Graph) IncomingGraphEdges(v Vertex) []*Edge {
var edges []*Edge
func (g *Graph) IncomingGraphEdges(v Vertex) []Edge {
var edges []Edge
for v1 := range g.adjacency { // reverse paths
for v2, e := range g.adjacency[v1] {
if v2 == v {
@@ -316,8 +304,8 @@ func (g *Graph) IncomingGraphEdges(v Vertex) []*Edge {
}
// OutgoingGraphEdges returns all of the edges that point from vertex v (v -> ???).
func (g *Graph) OutgoingGraphEdges(v Vertex) []*Edge {
var edges []*Edge
func (g *Graph) OutgoingGraphEdges(v Vertex) []Edge {
var edges []Edge
for _, e := range g.adjacency[v] { // forward paths
edges = append(edges, e)
}
@@ -326,8 +314,8 @@ func (g *Graph) OutgoingGraphEdges(v Vertex) []*Edge {
// GraphEdges returns an array (slice) of all edges that connect to vertex v.
// This is the union of IncomingGraphEdges and OutgoingGraphEdges.
func (g *Graph) GraphEdges(v Vertex) []*Edge {
var edges []*Edge
func (g *Graph) GraphEdges(v Vertex) []Edge {
var edges []Edge
edges = append(edges, g.IncomingGraphEdges(v)...)
edges = append(edges, g.OutgoingGraphEdges(v)...)
return edges
@@ -535,7 +523,7 @@ func VertexContains(needle Vertex, haystack []Vertex) bool {
}
// EdgeContains is an "in array" function to test for an edge in a slice of edges.
func EdgeContains(needle *Edge, haystack []*Edge) bool {
func EdgeContains(needle Edge, haystack []Edge) bool {
for _, v := range haystack {
if needle == v {
return true

View File

@@ -27,7 +27,7 @@ type vertex struct {
name string
}
// String is a required method of the Vertex interface we must fulfill.
// String is a required method of the Vertex interface that we must fulfill.
func (v *vertex) String() string {
return v.name
}
@@ -38,6 +38,22 @@ func NV(s string) Vertex {
return NewVertex(obj)
}
// edge is a test struct to test the library.
type edge struct {
name string
}
// String is a required method of the Edge interface that we must fulfill.
func (e *edge) String() string {
return e.name
}
// NE is a helper function to make testing easier. It creates a new noop edge.
func NE(s string) Edge {
obj := &edge{s}
return NewEdge(obj)
}
func TestPgraphT1(t *testing.T) {
G := &Graph{}
@@ -52,7 +68,7 @@ func TestPgraphT1(t *testing.T) {
v1 := NV("v1")
v2 := NV("v2")
e1 := NewEdge("e1")
e1 := NE("e1")
G.AddEdge(v1, v2, e1)
if i := G.NumVertices(); i != 2 {
@@ -73,12 +89,12 @@ func TestPgraphT2(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
//e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
//e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v1, e3)
@@ -100,12 +116,12 @@ func TestPgraphT3(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
//e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
//e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v1, e3)
@@ -138,9 +154,9 @@ func TestPgraphT4(t *testing.T) {
v1 := NV("v1")
v2 := NV("v2")
v3 := NV("v3")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v1, e3)
@@ -163,12 +179,12 @@ func TestPgraphT5(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
//e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
//e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v1, e3)
@@ -196,12 +212,12 @@ func TestPgraphT6(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
//e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
//e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v1, e3)
@@ -226,9 +242,9 @@ func TestPgraphT7(t *testing.T) {
v1 := NV("v1")
v2 := NV("v2")
v3 := NV("v3")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v1, e3)
@@ -300,12 +316,12 @@ func TestPgraphT9(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v1, v3, e2)
G.AddEdge(v2, v4, e3)
@@ -376,12 +392,12 @@ func TestPgraphT10(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v4, e3)
@@ -433,11 +449,11 @@ func TestPgraphReachability0(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v1, v4, e3)
@@ -467,12 +483,12 @@ func TestPgraphReachability1(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
//e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
//e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v4, e3)
@@ -501,12 +517,12 @@ func TestPgraphReachability2(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v1, v3, e2)
G.AddEdge(v2, v4, e3)
@@ -538,12 +554,12 @@ func TestPgraphReachability3(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v4, e3)
@@ -573,12 +589,12 @@ func TestPgraphReachability4(t *testing.T) {
v4 := NV("v4")
v5 := NV("v5")
v6 := NV("v6")
e1 := NewEdge("e1")
e2 := NewEdge("e2")
e3 := NewEdge("e3")
e4 := NewEdge("e4")
e5 := NewEdge("e5")
e6 := NewEdge("e6")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
e5 := NE("e5")
e6 := NE("e6")
G.AddEdge(v1, v2, e1)
G.AddEdge(v2, v3, e2)
G.AddEdge(v3, v4, e3)

View File

@@ -140,6 +140,7 @@ func (obj *BaseRes) RefreshPending() bool {
var refresh bool
for _, edge := range obj.Graph.IncomingGraphEdges(obj.Vertex) {
// if we asked for a notify *and* if one is pending!
edge := edge.(*Edge) // panic if wrong
if edge.Notify && edge.Refresh() {
refresh = true
break
@@ -151,6 +152,7 @@ func (obj *BaseRes) RefreshPending() bool {
// SetUpstreamRefresh sets the refresh value to any upstream vertices.
func (obj *BaseRes) SetUpstreamRefresh(b bool) {
for _, edge := range obj.Graph.IncomingGraphEdges(obj.Vertex) {
edge := edge.(*Edge) // panic if wrong
if edge.Notify {
edge.SetRefresh(b)
}
@@ -160,6 +162,7 @@ func (obj *BaseRes) SetUpstreamRefresh(b bool) {
// SetDownstreamRefresh sets the refresh value to any downstream vertices.
func (obj *BaseRes) SetDownstreamRefresh(b bool) {
for _, edge := range obj.Graph.OutgoingGraphEdges(obj.Vertex) {
edge := edge.(*Edge) // panic if wrong
// if we asked for a notify *and* if one is pending!
if edge.Notify {
edge.SetRefresh(b)

View File

@@ -61,11 +61,13 @@ func addEdgesByMatchingUIDS(g *pgraph.Graph, v pgraph.Vertex, uids []ResUID) []b
if uid.IsReversed() {
txt := fmt.Sprintf("AutoEdge: %s -> %s", VtoR(vv).String(), VtoR(v).String())
log.Printf("Compile: Adding %s", txt)
g.AddEdge(vv, v, pgraph.NewEdge(txt))
edge := &Edge{Name: txt}
g.AddEdge(vv, v, edge)
} else { // edges go the "normal" way, eg: pkg resource
txt := fmt.Sprintf("AutoEdge: %s -> %s", VtoR(v).String(), VtoR(vv).String())
log.Printf("Compile: Adding %s", txt)
g.AddEdge(v, vv, pgraph.NewEdge(txt))
edge := &Edge{Name: txt}
g.AddEdge(v, vv, edge)
}
found = true
break

View File

@@ -35,7 +35,7 @@ type AutoGrouper interface {
vertexNext() (pgraph.Vertex, pgraph.Vertex, error) // mostly algorithmic
vertexCmp(pgraph.Vertex, pgraph.Vertex) error // can we merge these ?
vertexMerge(pgraph.Vertex, pgraph.Vertex) (pgraph.Vertex, error) // vertex merge fn to use
edgeMerge(*pgraph.Edge, *pgraph.Edge) *pgraph.Edge // edge merge fn to use
edgeMerge(pgraph.Edge, pgraph.Edge) pgraph.Edge // edge merge fn to use
vertexTest(bool) (bool, error) // call until false
}
@@ -145,7 +145,7 @@ func (ag *baseGrouper) vertexMerge(v1, v2 pgraph.Vertex) (v pgraph.Vertex, err e
return // success or fail, and no need to merge the actual vertices!
}
func (ag *baseGrouper) edgeMerge(e1, e2 *pgraph.Edge) *pgraph.Edge {
func (ag *baseGrouper) edgeMerge(e1, e2 pgraph.Edge) pgraph.Edge {
return e1 // noop
}
@@ -204,7 +204,7 @@ func (ag *NonReachabilityGrouper) vertexNext() (v1, v2 pgraph.Vertex, err error)
// and then by deleting v2 from the graph. Since more than one edge between two
// vertices is not allowed, duplicate edges are merged as well. an edge merge
// function can be provided if you'd like to control how you merge the edges!
func VertexMerge(g *pgraph.Graph, v1, v2 pgraph.Vertex, vertexMergeFn func(pgraph.Vertex, pgraph.Vertex) (pgraph.Vertex, error), edgeMergeFn func(*pgraph.Edge, *pgraph.Edge) *pgraph.Edge) error {
func VertexMerge(g *pgraph.Graph, v1, v2 pgraph.Vertex, vertexMergeFn func(pgraph.Vertex, pgraph.Vertex) (pgraph.Vertex, error), edgeMergeFn func(pgraph.Edge, pgraph.Edge) pgraph.Edge) error {
// methodology
// 1) edges between v1 and v2 are removed
//Loop:

View File

@@ -29,6 +29,12 @@ import (
"github.com/purpleidea/mgmt/util"
)
// NE is a helper function to make testing easier. It creates a new noop edge.
func NE(s string) pgraph.Edge {
obj := &Edge{Name: s}
return obj
}
type testGrouper struct {
// TODO: this algorithm may not be correct in all cases. replace if needed!
NonReachabilityGrouper // "inherit" what we want, and reimplement the rest
@@ -54,14 +60,16 @@ func (ag *testGrouper) vertexMerge(v1, v2 pgraph.Vertex) (v pgraph.Vertex, err e
return // success or fail, and no need to merge the actual vertices!
}
func (ag *testGrouper) edgeMerge(e1, e2 *pgraph.Edge) *pgraph.Edge {
func (ag *testGrouper) edgeMerge(e1, e2 pgraph.Edge) pgraph.Edge {
edge1 := e1.(*Edge) // panic if wrong
edge2 := e2.(*Edge) // panic if wrong
// HACK: update the name so it makes a union of both names
n1 := strings.Split(e1.Name, ",") // load
n2 := strings.Split(e2.Name, ",") // load
n1 := strings.Split(edge1.Name, ",") // load
n2 := strings.Split(edge2.Name, ",") // load
names := append(n1, n2...)
names = util.StrRemoveDuplicatesInList(names) // remove duplicates
sort.Strings(names)
return pgraph.NewEdge(strings.Join(names, ","))
return &Edge{Name: strings.Join(names, ",")}
}
// helper function
@@ -161,7 +169,8 @@ Loop:
for vv1, ee1 := range g1.Adjacency()[v1] {
vv2 := m[vv1]
ee2 := g2.Adjacency()[v2][vv2]
ee1 := ee1.(*Edge)
ee2 := g2.Adjacency()[v2][vv2].(*Edge)
// these are edges from v1 -> vv1 via ee1 (graph 1)
// to cmp to edges from v2 -> vv2 via ee2 (graph 2)
@@ -240,7 +249,8 @@ func fullPrint(g *pgraph.Graph) (str string) {
}
for v1 := range g.Adjacency() {
for v2, e := range g.Adjacency()[v1] {
str += fmt.Sprintf("* e: %v -> %v # %v\n", VtoR(v1).GetName(), VtoR(v2).GetName(), e.Name)
edge := e.(*Edge)
str += fmt.Sprintf("* e: %v -> %v # %v\n", VtoR(v1).GetName(), VtoR(v2).GetName(), edge.Name)
}
}
return
@@ -460,8 +470,8 @@ func TestPgraphGrouping12(t *testing.T) {
a1 := pgraph.NewVertex(NewNoopResTest("a1"))
a2 := pgraph.NewVertex(NewNoopResTest("a2"))
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e1 := NE("e1")
e2 := NE("e2")
g1.AddEdge(a1, b1, e1)
g1.AddEdge(a2, b1, e2)
}
@@ -469,7 +479,7 @@ func TestPgraphGrouping12(t *testing.T) {
{
a := pgraph.NewVertex(NewNoopResTest("a1,a2"))
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
e := pgraph.NewEdge("e1,e2")
e := NE("e1,e2")
g2.AddEdge(a, b1, e)
}
runGraphCmp(t, g1, g2)
@@ -485,8 +495,8 @@ func TestPgraphGrouping13(t *testing.T) {
a1 := pgraph.NewVertex(NewNoopResTest("a1"))
a2 := pgraph.NewVertex(NewNoopResTest("a2"))
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e1 := NE("e1")
e2 := NE("e2")
g1.AddEdge(b1, a1, e1)
g1.AddEdge(b1, a2, e2)
}
@@ -494,7 +504,7 @@ func TestPgraphGrouping13(t *testing.T) {
{
a := pgraph.NewVertex(NewNoopResTest("a1,a2"))
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
e := pgraph.NewEdge("e1,e2")
e := NE("e1,e2")
g2.AddEdge(b1, a, e)
}
runGraphCmp(t, g1, g2)
@@ -511,9 +521,9 @@ func TestPgraphGrouping14(t *testing.T) {
a2 := pgraph.NewVertex(NewNoopResTest("a2"))
a3 := pgraph.NewVertex(NewNoopResTest("a3"))
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e3 := pgraph.NewEdge("e3")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
g1.AddEdge(a1, b1, e1)
g1.AddEdge(a2, b1, e2)
g1.AddEdge(a3, b1, e3)
@@ -522,7 +532,7 @@ func TestPgraphGrouping14(t *testing.T) {
{
a := pgraph.NewVertex(NewNoopResTest("a1,a2,a3"))
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
e := pgraph.NewEdge("e1,e2,e3")
e := NE("e1,e2,e3")
g2.AddEdge(a, b1, e)
}
runGraphCmp(t, g1, g2)
@@ -541,10 +551,10 @@ func TestPgraphGrouping15(t *testing.T) {
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
b2 := pgraph.NewVertex(NewNoopResTest("b2"))
c1 := pgraph.NewVertex(NewNoopResTest("c1"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e3 := pgraph.NewEdge("e3")
e4 := pgraph.NewEdge("e4")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
g1.AddEdge(a1, b1, e1)
g1.AddEdge(a1, b2, e2)
g1.AddEdge(b1, c1, e3)
@@ -555,8 +565,8 @@ func TestPgraphGrouping15(t *testing.T) {
a1 := pgraph.NewVertex(NewNoopResTest("a1"))
b := pgraph.NewVertex(NewNoopResTest("b1,b2"))
c1 := pgraph.NewVertex(NewNoopResTest("c1"))
e1 := pgraph.NewEdge("e1,e2")
e2 := pgraph.NewEdge("e3,e4")
e1 := NE("e1,e2")
e2 := NE("e3,e4")
g2.AddEdge(a1, b, e1)
g2.AddEdge(b, c1, e2)
}
@@ -578,9 +588,9 @@ func TestPgraphGrouping16(t *testing.T) {
a2 := pgraph.NewVertex(NewNoopResTest("a2"))
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
c1 := pgraph.NewVertex(NewNoopResTest("c1"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e3 := pgraph.NewEdge("e3")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
g1.AddEdge(a1, b1, e1)
g1.AddEdge(b1, c1, e2)
g1.AddEdge(a2, c1, e3)
@@ -590,8 +600,8 @@ func TestPgraphGrouping16(t *testing.T) {
a := pgraph.NewVertex(NewNoopResTest("a1,a2"))
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
c1 := pgraph.NewVertex(NewNoopResTest("c1"))
e1 := pgraph.NewEdge("e1,e3")
e2 := pgraph.NewEdge("e2,e3") // e3 gets "merged through" to BOTH edges!
e1 := NE("e1,e3")
e2 := NE("e2,e3") // e3 gets "merged through" to BOTH edges!
g2.AddEdge(a, b1, e1)
g2.AddEdge(b1, c1, e2)
}
@@ -611,9 +621,9 @@ func TestPgraphGrouping17(t *testing.T) {
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
b2 := pgraph.NewVertex(NewNoopResTest("b2"))
c1 := pgraph.NewVertex(NewNoopResTest("c1"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e3 := pgraph.NewEdge("e3")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
g1.AddEdge(a1, b1, e1)
g1.AddEdge(b1, c1, e2)
g1.AddEdge(b2, c1, e3)
@@ -623,8 +633,8 @@ func TestPgraphGrouping17(t *testing.T) {
a1 := pgraph.NewVertex(NewNoopResTest("a1"))
b := pgraph.NewVertex(NewNoopResTest("b1,b2"))
c1 := pgraph.NewVertex(NewNoopResTest("c1"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2,e3")
e1 := NE("e1")
e2 := NE("e2,e3")
g2.AddEdge(a1, b, e1)
g2.AddEdge(b, c1, e2)
}
@@ -646,10 +656,10 @@ func TestPgraphGrouping18(t *testing.T) {
b1 := pgraph.NewVertex(NewNoopResTest("b1"))
b2 := pgraph.NewVertex(NewNoopResTest("b2"))
c1 := pgraph.NewVertex(NewNoopResTest("c1"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e3 := pgraph.NewEdge("e3")
e4 := pgraph.NewEdge("e4")
e1 := NE("e1")
e2 := NE("e2")
e3 := NE("e3")
e4 := NE("e4")
g1.AddEdge(a1, b1, e1)
g1.AddEdge(b1, c1, e2)
g1.AddEdge(a2, c1, e3)
@@ -660,8 +670,8 @@ func TestPgraphGrouping18(t *testing.T) {
a := pgraph.NewVertex(NewNoopResTest("a1,a2"))
b := pgraph.NewVertex(NewNoopResTest("b1,b2"))
c1 := pgraph.NewVertex(NewNoopResTest("c1"))
e1 := pgraph.NewEdge("e1,e3")
e2 := pgraph.NewEdge("e2,e3,e4") // e3 gets "merged through" to BOTH edges!
e1 := NE("e1,e3")
e2 := NE("e2,e3,e4") // e3 gets "merged through" to BOTH edges!
g2.AddEdge(a, b, e1)
g2.AddEdge(b, c1, e2)
}
@@ -677,14 +687,14 @@ func TestPgraphGroupingConnected0(t *testing.T) {
{
a1 := pgraph.NewVertex(NewNoopResTest("a1"))
a2 := pgraph.NewVertex(NewNoopResTest("a2"))
e1 := pgraph.NewEdge("e1")
e1 := NE("e1")
g1.AddEdge(a1, a2, e1)
}
g2, _ := pgraph.NewGraph("g2") // expected result ?
{
a1 := pgraph.NewVertex(NewNoopResTest("a1"))
a2 := pgraph.NewVertex(NewNoopResTest("a2"))
e1 := pgraph.NewEdge("e1")
e1 := NE("e1")
g2.AddEdge(a1, a2, e1)
}
runGraphCmp(t, g1, g2)
@@ -702,8 +712,8 @@ func TestPgraphGroupingConnected1(t *testing.T) {
a1 := pgraph.NewVertex(NewNoopResTest("a1"))
b := pgraph.NewVertex(NewNoopResTest("b"))
a2 := pgraph.NewVertex(NewNoopResTest("a2"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e1 := NE("e1")
e2 := NE("e2")
g1.AddEdge(a1, b, e1)
g1.AddEdge(b, a2, e2)
}
@@ -712,8 +722,8 @@ func TestPgraphGroupingConnected1(t *testing.T) {
a1 := pgraph.NewVertex(NewNoopResTest("a1"))
b := pgraph.NewVertex(NewNoopResTest("b"))
a2 := pgraph.NewVertex(NewNoopResTest("a2"))
e1 := pgraph.NewEdge("e1")
e2 := pgraph.NewEdge("e2")
e1 := NE("e1")
e2 := NE("e2")
g2.AddEdge(a1, b, e1)
g2.AddEdge(b, a2, e2)
}

41
resources/edge.go Normal file
View File

@@ -0,0 +1,41 @@
// Mgmt
// Copyright (C) 2013-2017+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package resources
// Edge is a struct that represents a graph's edge.
type Edge struct {
Name string
Notify bool // should we send a refresh notification along this edge?
refresh bool // is there a notify pending for the dest vertex ?
}
// String is a required method of the Edge interface that we must fulfill.
func (obj *Edge) String() string {
return obj.Name
}
// Refresh returns the pending refresh status of this edge.
func (obj *Edge) Refresh() bool {
return obj.refresh
}
// SetRefresh sets the pending refresh status of this edge.
func (obj *Edge) SetRefresh(b bool) {
obj.refresh = b
}

View File

@@ -247,8 +247,10 @@ func (c *GraphConfig) NewGraphFromConfig(hostname string, world resources.World,
}
from := lookup[strings.ToLower(e.From.Kind)][e.From.Name]
to := lookup[strings.ToLower(e.To.Kind)][e.To.Name]
edge := pgraph.NewEdge(e.Name)
edge.Notify = e.Notify
edge := &resources.Edge{
Name: e.Name,
Notify: e.Notify,
}
graph.AddEdge(from, to, edge)
}

View File

@@ -293,8 +293,10 @@ func (c *GraphConfig) NewGraphFromConfig(hostname string, world resources.World,
}
from := lookup[strings.ToLower(e.From.Kind)][e.From.Name]
to := lookup[strings.ToLower(e.To.Kind)][e.To.Name]
edge := pgraph.NewEdge(e.Name)
edge.Notify = e.Notify
edge := &resources.Edge{
Name: e.Name,
Notify: e.Notify,
}
graph.AddEdge(from, to, edge)
}