github.com/ibm-cloud/terraform@v0.6.4-0.20170726051544-8872b87621df/dag/graph.go (about)

     1  package dag
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"sort"
     9  )
    10  
    11  // Graph is used to represent a dependency graph.
    12  type Graph struct {
    13  	vertices  *Set
    14  	edges     *Set
    15  	downEdges map[interface{}]*Set
    16  	upEdges   map[interface{}]*Set
    17  
    18  	// JSON encoder for recording debug information
    19  	debug *encoder
    20  }
    21  
    22  // Subgrapher allows a Vertex to be a Graph itself, by returning a Grapher.
    23  type Subgrapher interface {
    24  	Subgraph() Grapher
    25  }
    26  
    27  // A Grapher is any type that returns a Grapher, mainly used to identify
    28  // dag.Graph and dag.AcyclicGraph.  In the case of Graph and AcyclicGraph, they
    29  // return themselves.
    30  type Grapher interface {
    31  	DirectedGraph() Grapher
    32  }
    33  
    34  // Vertex of the graph.
    35  type Vertex interface{}
    36  
    37  // NamedVertex is an optional interface that can be implemented by Vertex
    38  // to give it a human-friendly name that is used for outputting the graph.
    39  type NamedVertex interface {
    40  	Vertex
    41  	Name() string
    42  }
    43  
    44  func (g *Graph) DirectedGraph() Grapher {
    45  	return g
    46  }
    47  
    48  // Vertices returns the list of all the vertices in the graph.
    49  func (g *Graph) Vertices() []Vertex {
    50  	list := g.vertices.List()
    51  	result := make([]Vertex, len(list))
    52  	for i, v := range list {
    53  		result[i] = v.(Vertex)
    54  	}
    55  
    56  	return result
    57  }
    58  
    59  // Edges returns the list of all the edges in the graph.
    60  func (g *Graph) Edges() []Edge {
    61  	list := g.edges.List()
    62  	result := make([]Edge, len(list))
    63  	for i, v := range list {
    64  		result[i] = v.(Edge)
    65  	}
    66  
    67  	return result
    68  }
    69  
    70  // EdgesFrom returns the list of edges from the given source.
    71  func (g *Graph) EdgesFrom(v Vertex) []Edge {
    72  	var result []Edge
    73  	from := hashcode(v)
    74  	for _, e := range g.Edges() {
    75  		if hashcode(e.Source()) == from {
    76  			result = append(result, e)
    77  		}
    78  	}
    79  
    80  	return result
    81  }
    82  
    83  // EdgesTo returns the list of edges to the given target.
    84  func (g *Graph) EdgesTo(v Vertex) []Edge {
    85  	var result []Edge
    86  	search := hashcode(v)
    87  	for _, e := range g.Edges() {
    88  		if hashcode(e.Target()) == search {
    89  			result = append(result, e)
    90  		}
    91  	}
    92  
    93  	return result
    94  }
    95  
    96  // HasVertex checks if the given Vertex is present in the graph.
    97  func (g *Graph) HasVertex(v Vertex) bool {
    98  	return g.vertices.Include(v)
    99  }
   100  
   101  // HasEdge checks if the given Edge is present in the graph.
   102  func (g *Graph) HasEdge(e Edge) bool {
   103  	return g.edges.Include(e)
   104  }
   105  
   106  // Add adds a vertex to the graph. This is safe to call multiple time with
   107  // the same Vertex.
   108  func (g *Graph) Add(v Vertex) Vertex {
   109  	g.init()
   110  	g.vertices.Add(v)
   111  	g.debug.Add(v)
   112  	return v
   113  }
   114  
   115  // Remove removes a vertex from the graph. This will also remove any
   116  // edges with this vertex as a source or target.
   117  func (g *Graph) Remove(v Vertex) Vertex {
   118  	// Delete the vertex itself
   119  	g.vertices.Delete(v)
   120  	g.debug.Remove(v)
   121  
   122  	// Delete the edges to non-existent things
   123  	for _, target := range g.DownEdges(v).List() {
   124  		g.RemoveEdge(BasicEdge(v, target))
   125  	}
   126  	for _, source := range g.UpEdges(v).List() {
   127  		g.RemoveEdge(BasicEdge(source, v))
   128  	}
   129  
   130  	return nil
   131  }
   132  
   133  // Replace replaces the original Vertex with replacement. If the original
   134  // does not exist within the graph, then false is returned. Otherwise, true
   135  // is returned.
   136  func (g *Graph) Replace(original, replacement Vertex) bool {
   137  	// If we don't have the original, we can't do anything
   138  	if !g.vertices.Include(original) {
   139  		return false
   140  	}
   141  
   142  	defer g.debug.BeginOperation("Replace", "").End("")
   143  
   144  	// If they're the same, then don't do anything
   145  	if original == replacement {
   146  		return true
   147  	}
   148  
   149  	// Add our new vertex, then copy all the edges
   150  	g.Add(replacement)
   151  	for _, target := range g.DownEdges(original).List() {
   152  		g.Connect(BasicEdge(replacement, target))
   153  	}
   154  	for _, source := range g.UpEdges(original).List() {
   155  		g.Connect(BasicEdge(source, replacement))
   156  	}
   157  
   158  	// Remove our old vertex, which will also remove all the edges
   159  	g.Remove(original)
   160  
   161  	return true
   162  }
   163  
   164  // RemoveEdge removes an edge from the graph.
   165  func (g *Graph) RemoveEdge(edge Edge) {
   166  	g.init()
   167  	g.debug.RemoveEdge(edge)
   168  
   169  	// Delete the edge from the set
   170  	g.edges.Delete(edge)
   171  
   172  	// Delete the up/down edges
   173  	if s, ok := g.downEdges[hashcode(edge.Source())]; ok {
   174  		s.Delete(edge.Target())
   175  	}
   176  	if s, ok := g.upEdges[hashcode(edge.Target())]; ok {
   177  		s.Delete(edge.Source())
   178  	}
   179  }
   180  
   181  // DownEdges returns the outward edges from the source Vertex v.
   182  func (g *Graph) DownEdges(v Vertex) *Set {
   183  	g.init()
   184  	return g.downEdges[hashcode(v)]
   185  }
   186  
   187  // UpEdges returns the inward edges to the destination Vertex v.
   188  func (g *Graph) UpEdges(v Vertex) *Set {
   189  	g.init()
   190  	return g.upEdges[hashcode(v)]
   191  }
   192  
   193  // Connect adds an edge with the given source and target. This is safe to
   194  // call multiple times with the same value. Note that the same value is
   195  // verified through pointer equality of the vertices, not through the
   196  // value of the edge itself.
   197  func (g *Graph) Connect(edge Edge) {
   198  	g.init()
   199  	g.debug.Connect(edge)
   200  
   201  	source := edge.Source()
   202  	target := edge.Target()
   203  	sourceCode := hashcode(source)
   204  	targetCode := hashcode(target)
   205  
   206  	// Do we have this already? If so, don't add it again.
   207  	if s, ok := g.downEdges[sourceCode]; ok && s.Include(target) {
   208  		return
   209  	}
   210  
   211  	// Add the edge to the set
   212  	g.edges.Add(edge)
   213  
   214  	// Add the down edge
   215  	s, ok := g.downEdges[sourceCode]
   216  	if !ok {
   217  		s = new(Set)
   218  		g.downEdges[sourceCode] = s
   219  	}
   220  	s.Add(target)
   221  
   222  	// Add the up edge
   223  	s, ok = g.upEdges[targetCode]
   224  	if !ok {
   225  		s = new(Set)
   226  		g.upEdges[targetCode] = s
   227  	}
   228  	s.Add(source)
   229  }
   230  
   231  // String outputs some human-friendly output for the graph structure.
   232  func (g *Graph) StringWithNodeTypes() string {
   233  	var buf bytes.Buffer
   234  
   235  	// Build the list of node names and a mapping so that we can more
   236  	// easily alphabetize the output to remain deterministic.
   237  	vertices := g.Vertices()
   238  	names := make([]string, 0, len(vertices))
   239  	mapping := make(map[string]Vertex, len(vertices))
   240  	for _, v := range vertices {
   241  		name := VertexName(v)
   242  		names = append(names, name)
   243  		mapping[name] = v
   244  	}
   245  	sort.Strings(names)
   246  
   247  	// Write each node in order...
   248  	for _, name := range names {
   249  		v := mapping[name]
   250  		targets := g.downEdges[hashcode(v)]
   251  
   252  		buf.WriteString(fmt.Sprintf("%s - %T\n", name, v))
   253  
   254  		// Alphabetize dependencies
   255  		deps := make([]string, 0, targets.Len())
   256  		targetNodes := make(map[string]Vertex)
   257  		for _, target := range targets.List() {
   258  			dep := VertexName(target)
   259  			deps = append(deps, dep)
   260  			targetNodes[dep] = target
   261  		}
   262  		sort.Strings(deps)
   263  
   264  		// Write dependencies
   265  		for _, d := range deps {
   266  			buf.WriteString(fmt.Sprintf("  %s - %T\n", d, targetNodes[d]))
   267  		}
   268  	}
   269  
   270  	return buf.String()
   271  }
   272  
   273  // String outputs some human-friendly output for the graph structure.
   274  func (g *Graph) String() string {
   275  	var buf bytes.Buffer
   276  
   277  	// Build the list of node names and a mapping so that we can more
   278  	// easily alphabetize the output to remain deterministic.
   279  	vertices := g.Vertices()
   280  	names := make([]string, 0, len(vertices))
   281  	mapping := make(map[string]Vertex, len(vertices))
   282  	for _, v := range vertices {
   283  		name := VertexName(v)
   284  		names = append(names, name)
   285  		mapping[name] = v
   286  	}
   287  	sort.Strings(names)
   288  
   289  	// Write each node in order...
   290  	for _, name := range names {
   291  		v := mapping[name]
   292  		targets := g.downEdges[hashcode(v)]
   293  
   294  		buf.WriteString(fmt.Sprintf("%s\n", name))
   295  
   296  		// Alphabetize dependencies
   297  		deps := make([]string, 0, targets.Len())
   298  		for _, target := range targets.List() {
   299  			deps = append(deps, VertexName(target))
   300  		}
   301  		sort.Strings(deps)
   302  
   303  		// Write dependencies
   304  		for _, d := range deps {
   305  			buf.WriteString(fmt.Sprintf("  %s\n", d))
   306  		}
   307  	}
   308  
   309  	return buf.String()
   310  }
   311  
   312  func (g *Graph) init() {
   313  	if g.vertices == nil {
   314  		g.vertices = new(Set)
   315  	}
   316  	if g.edges == nil {
   317  		g.edges = new(Set)
   318  	}
   319  	if g.downEdges == nil {
   320  		g.downEdges = make(map[interface{}]*Set)
   321  	}
   322  	if g.upEdges == nil {
   323  		g.upEdges = make(map[interface{}]*Set)
   324  	}
   325  }
   326  
   327  // Dot returns a dot-formatted representation of the Graph.
   328  func (g *Graph) Dot(opts *DotOpts) []byte {
   329  	return newMarshalGraph("", g).Dot(opts)
   330  }
   331  
   332  // MarshalJSON returns a JSON representation of the entire Graph.
   333  func (g *Graph) MarshalJSON() ([]byte, error) {
   334  	dg := newMarshalGraph("root", g)
   335  	return json.MarshalIndent(dg, "", "  ")
   336  }
   337  
   338  // SetDebugWriter sets the io.Writer where the Graph will record debug
   339  // information. After this is set, the graph will immediately encode itself to
   340  // the stream, and continue to record all subsequent operations.
   341  func (g *Graph) SetDebugWriter(w io.Writer) {
   342  	g.debug = &encoder{w: w}
   343  	g.debug.Encode(newMarshalGraph("root", g))
   344  }
   345  
   346  // DebugVertexInfo encodes arbitrary information about a vertex in the graph
   347  // debug logs.
   348  func (g *Graph) DebugVertexInfo(v Vertex, info string) {
   349  	va := newVertexInfo(typeVertexInfo, v, info)
   350  	g.debug.Encode(va)
   351  }
   352  
   353  // DebugEdgeInfo encodes arbitrary information about an edge in the graph debug
   354  // logs.
   355  func (g *Graph) DebugEdgeInfo(e Edge, info string) {
   356  	ea := newEdgeInfo(typeEdgeInfo, e, info)
   357  	g.debug.Encode(ea)
   358  }
   359  
   360  // DebugVisitInfo records a visit to a Vertex during a walk operation.
   361  func (g *Graph) DebugVisitInfo(v Vertex, info string) {
   362  	vi := newVertexInfo(typeVisitInfo, v, info)
   363  	g.debug.Encode(vi)
   364  }
   365  
   366  // DebugOperation marks the start of a set of graph transformations in
   367  // the debug log, and returns a DebugOperationEnd func, which marks the end of
   368  // the operation in the log. Additional information can be added to the log via
   369  // the info parameter.
   370  //
   371  // The returned func's End method allows this method to be called from a single
   372  // defer statement:
   373  //     defer g.DebugOperationBegin("OpName", "operating").End("")
   374  //
   375  // The returned function must be called to properly close the logical operation
   376  // in the logs.
   377  func (g *Graph) DebugOperation(operation string, info string) DebugOperationEnd {
   378  	return g.debug.BeginOperation(operation, info)
   379  }
   380  
   381  // VertexName returns the name of a vertex.
   382  func VertexName(raw Vertex) string {
   383  	switch v := raw.(type) {
   384  	case NamedVertex:
   385  		return v.Name()
   386  	case fmt.Stringer:
   387  		return fmt.Sprintf("%s", v)
   388  	default:
   389  		return fmt.Sprintf("%v", v)
   390  	}
   391  }