github.com/ves/terraform@v0.8.0-beta2/dag/marshal.go (about)

     1  package dag
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"reflect"
     9  	"sort"
    10  	"strconv"
    11  )
    12  
    13  // the marshal* structs are for serialization of the graph data.
    14  type marshalGraph struct {
    15  	// Type is always "Graph", for identification as a top level object in the
    16  	// JSON stream.
    17  	Type string
    18  
    19  	// Each marshal structure requires a unique ID so that it can be referenced
    20  	// by other structures.
    21  	ID string `json:",omitempty"`
    22  
    23  	// Human readable name for this graph.
    24  	Name string `json:",omitempty"`
    25  
    26  	// Arbitrary attributes that can be added to the output.
    27  	Attrs map[string]string `json:",omitempty"`
    28  
    29  	// List of graph vertices, sorted by ID.
    30  	Vertices []*marshalVertex `json:",omitempty"`
    31  
    32  	// List of edges, sorted by Source ID.
    33  	Edges []*marshalEdge `json:",omitempty"`
    34  
    35  	// Any number of subgraphs. A subgraph itself is considered a vertex, and
    36  	// may be referenced by either end of an edge.
    37  	Subgraphs []*marshalGraph `json:",omitempty"`
    38  
    39  	// Any lists of vertices that are included in cycles.
    40  	Cycles [][]*marshalVertex `json:",omitempty"`
    41  }
    42  
    43  // The add, remove, connect, removeEdge methods mirror the basic Graph
    44  // manipulations to reconstruct a marshalGraph from a debug log.
    45  func (g *marshalGraph) add(v *marshalVertex) {
    46  	g.Vertices = append(g.Vertices, v)
    47  	sort.Sort(vertices(g.Vertices))
    48  }
    49  
    50  func (g *marshalGraph) remove(v *marshalVertex) {
    51  	for i, existing := range g.Vertices {
    52  		if v.ID == existing.ID {
    53  			g.Vertices = append(g.Vertices[:i], g.Vertices[i+1:]...)
    54  			return
    55  		}
    56  	}
    57  }
    58  
    59  func (g *marshalGraph) connect(e *marshalEdge) {
    60  	g.Edges = append(g.Edges, e)
    61  	sort.Sort(edges(g.Edges))
    62  }
    63  
    64  func (g *marshalGraph) removeEdge(e *marshalEdge) {
    65  	for i, existing := range g.Edges {
    66  		if e.Source == existing.Source && e.Target == existing.Target {
    67  			g.Edges = append(g.Edges[:i], g.Edges[i+1:]...)
    68  			return
    69  		}
    70  	}
    71  }
    72  
    73  func (g *marshalGraph) vertexByID(id string) *marshalVertex {
    74  	for _, v := range g.Vertices {
    75  		if id == v.ID {
    76  			return v
    77  		}
    78  	}
    79  	return nil
    80  }
    81  
    82  type marshalVertex struct {
    83  	// Unique ID, used to reference this vertex from other structures.
    84  	ID string
    85  
    86  	// Human readable name
    87  	Name string `json:",omitempty"`
    88  
    89  	Attrs map[string]string `json:",omitempty"`
    90  
    91  	// This is to help transition from the old Dot interfaces. We record if the
    92  	// node was a GraphNodeDotter here, so we know if it should be included in the
    93  	// dot output
    94  	graphNodeDotter bool
    95  }
    96  
    97  func newMarshalVertex(v Vertex) *marshalVertex {
    98  	return &marshalVertex{
    99  		ID:              marshalVertexID(v),
   100  		Name:            VertexName(v),
   101  		Attrs:           make(map[string]string),
   102  		graphNodeDotter: isDotter(v),
   103  	}
   104  }
   105  
   106  func isDotter(v Vertex) bool {
   107  	dn, isDotter := v.(GraphNodeDotter)
   108  	dotOpts := &DotOpts{
   109  		Verbose:    true,
   110  		DrawCycles: true,
   111  	}
   112  	if isDotter && dn.DotNode("fake", dotOpts) == nil {
   113  		isDotter = false
   114  	}
   115  	return isDotter
   116  }
   117  
   118  // vertices is a sort.Interface implementation for sorting vertices by ID
   119  type vertices []*marshalVertex
   120  
   121  func (v vertices) Less(i, j int) bool { return v[i].Name < v[j].Name }
   122  func (v vertices) Len() int           { return len(v) }
   123  func (v vertices) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
   124  
   125  type marshalEdge struct {
   126  	// Human readable name
   127  	Name string
   128  
   129  	// Source and Target Vertices by ID
   130  	Source string
   131  	Target string
   132  
   133  	Attrs map[string]string `json:",omitempty"`
   134  }
   135  
   136  func newMarshalEdge(e Edge) *marshalEdge {
   137  	return &marshalEdge{
   138  		Name:   fmt.Sprintf("%s|%s", VertexName(e.Source()), VertexName(e.Target())),
   139  		Source: marshalVertexID(e.Source()),
   140  		Target: marshalVertexID(e.Target()),
   141  		Attrs:  make(map[string]string),
   142  	}
   143  }
   144  
   145  // edges is a sort.Interface implementation for sorting edges by Source ID
   146  type edges []*marshalEdge
   147  
   148  func (e edges) Less(i, j int) bool { return e[i].Name < e[j].Name }
   149  func (e edges) Len() int           { return len(e) }
   150  func (e edges) Swap(i, j int)      { e[i], e[j] = e[j], e[i] }
   151  
   152  // build a marshalGraph structure from a *Graph
   153  func newMarshalGraph(name string, g *Graph) *marshalGraph {
   154  	mg := &marshalGraph{
   155  		Type:  "Graph",
   156  		Name:  name,
   157  		Attrs: make(map[string]string),
   158  	}
   159  
   160  	for _, v := range g.Vertices() {
   161  		id := marshalVertexID(v)
   162  		if sg, ok := marshalSubgrapher(v); ok {
   163  			smg := newMarshalGraph(VertexName(v), sg)
   164  			smg.ID = id
   165  			mg.Subgraphs = append(mg.Subgraphs, smg)
   166  		}
   167  
   168  		mv := newMarshalVertex(v)
   169  		mg.Vertices = append(mg.Vertices, mv)
   170  	}
   171  
   172  	sort.Sort(vertices(mg.Vertices))
   173  
   174  	for _, e := range g.Edges() {
   175  		mg.Edges = append(mg.Edges, newMarshalEdge(e))
   176  	}
   177  
   178  	sort.Sort(edges(mg.Edges))
   179  
   180  	for _, c := range (&AcyclicGraph{*g}).Cycles() {
   181  		var cycle []*marshalVertex
   182  		for _, v := range c {
   183  			mv := newMarshalVertex(v)
   184  			cycle = append(cycle, mv)
   185  		}
   186  		mg.Cycles = append(mg.Cycles, cycle)
   187  	}
   188  
   189  	return mg
   190  }
   191  
   192  // Attempt to return a unique ID for any vertex.
   193  func marshalVertexID(v Vertex) string {
   194  	val := reflect.ValueOf(v)
   195  	switch val.Kind() {
   196  	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
   197  		return strconv.Itoa(int(val.Pointer()))
   198  	case reflect.Interface:
   199  		return strconv.Itoa(int(val.InterfaceData()[1]))
   200  	}
   201  
   202  	if v, ok := v.(Hashable); ok {
   203  		h := v.Hashcode()
   204  		if h, ok := h.(string); ok {
   205  			return h
   206  		}
   207  	}
   208  
   209  	// fallback to a name, which we hope is unique.
   210  	return VertexName(v)
   211  
   212  	// we could try harder by attempting to read the arbitrary value from the
   213  	// interface, but we shouldn't get here from terraform right now.
   214  }
   215  
   216  // check for a Subgrapher, and return the underlying *Graph.
   217  func marshalSubgrapher(v Vertex) (*Graph, bool) {
   218  	sg, ok := v.(Subgrapher)
   219  	if !ok {
   220  		return nil, false
   221  	}
   222  
   223  	switch g := sg.Subgraph().DirectedGraph().(type) {
   224  	case *Graph:
   225  		return g, true
   226  	case *AcyclicGraph:
   227  		return &g.Graph, true
   228  	}
   229  
   230  	return nil, false
   231  }
   232  
   233  // The DebugOperationEnd func type provides a way to call an End function via a
   234  // method call, allowing for the chaining of methods in a defer statement.
   235  type DebugOperationEnd func(string)
   236  
   237  // End calls function e with the info parameter, marking the end of this
   238  // operation in the logs.
   239  func (e DebugOperationEnd) End(info string) { e(info) }
   240  
   241  // encoder provides methods to write debug data to an io.Writer, and is a noop
   242  // when no writer is present
   243  type encoder struct {
   244  	w io.Writer
   245  }
   246  
   247  // Encode is analogous to json.Encoder.Encode
   248  func (e *encoder) Encode(i interface{}) {
   249  	if e == nil || e.w == nil {
   250  		return
   251  	}
   252  
   253  	js, err := json.Marshal(i)
   254  	if err != nil {
   255  		log.Println("[ERROR] dag:", err)
   256  		return
   257  	}
   258  	js = append(js, '\n')
   259  
   260  	_, err = e.w.Write(js)
   261  	if err != nil {
   262  		log.Println("[ERROR] dag:", err)
   263  		return
   264  	}
   265  }
   266  
   267  func (e *encoder) Add(v Vertex) {
   268  	e.Encode(marshalTransform{
   269  		Type:      "Transform",
   270  		AddVertex: newMarshalVertex(v),
   271  	})
   272  }
   273  
   274  // Remove records the removal of Vertex v.
   275  func (e *encoder) Remove(v Vertex) {
   276  	e.Encode(marshalTransform{
   277  		Type:         "Transform",
   278  		RemoveVertex: newMarshalVertex(v),
   279  	})
   280  }
   281  
   282  func (e *encoder) Connect(edge Edge) {
   283  	e.Encode(marshalTransform{
   284  		Type:    "Transform",
   285  		AddEdge: newMarshalEdge(edge),
   286  	})
   287  }
   288  
   289  func (e *encoder) RemoveEdge(edge Edge) {
   290  	e.Encode(marshalTransform{
   291  		Type:       "Transform",
   292  		RemoveEdge: newMarshalEdge(edge),
   293  	})
   294  }
   295  
   296  // BeginOperation marks the start of set of graph transformations, and returns
   297  // an EndDebugOperation func to be called once the opration is complete.
   298  func (e *encoder) BeginOperation(op string, info string) DebugOperationEnd {
   299  	if e == nil {
   300  		return func(string) {}
   301  	}
   302  
   303  	e.Encode(marshalOperation{
   304  		Type:  "Operation",
   305  		Begin: op,
   306  		Info:  info,
   307  	})
   308  
   309  	return func(info string) {
   310  		e.Encode(marshalOperation{
   311  			Type: "Operation",
   312  			End:  op,
   313  			Info: info,
   314  		})
   315  	}
   316  }
   317  
   318  // structure for recording graph transformations
   319  type marshalTransform struct {
   320  	// Type: "Transform"
   321  	Type         string
   322  	AddEdge      *marshalEdge   `json:",omitempty"`
   323  	RemoveEdge   *marshalEdge   `json:",omitempty"`
   324  	AddVertex    *marshalVertex `json:",omitempty"`
   325  	RemoveVertex *marshalVertex `json:",omitempty"`
   326  }
   327  
   328  func (t marshalTransform) Transform(g *marshalGraph) {
   329  	switch {
   330  	case t.AddEdge != nil:
   331  		g.connect(t.AddEdge)
   332  	case t.RemoveEdge != nil:
   333  		g.removeEdge(t.RemoveEdge)
   334  	case t.AddVertex != nil:
   335  		g.add(t.AddVertex)
   336  	case t.RemoveVertex != nil:
   337  		g.remove(t.RemoveVertex)
   338  	}
   339  }
   340  
   341  // this structure allows us to decode any object in the json stream for
   342  // inspection, then re-decode it into a proper struct if needed.
   343  type streamDecode struct {
   344  	Type string
   345  	Map  map[string]interface{}
   346  	JSON []byte
   347  }
   348  
   349  func (s *streamDecode) UnmarshalJSON(d []byte) error {
   350  	s.JSON = d
   351  	err := json.Unmarshal(d, &s.Map)
   352  	if err != nil {
   353  		return err
   354  	}
   355  
   356  	if t, ok := s.Map["Type"]; ok {
   357  		s.Type, _ = t.(string)
   358  	}
   359  	return nil
   360  }
   361  
   362  // structure for recording the beginning and end of any multi-step
   363  // transformations. These are informational, and not required to reproduce the
   364  // graph state.
   365  type marshalOperation struct {
   366  	Type  string
   367  	Begin string `json:",omitempty"`
   368  	End   string `json:",omitempty"`
   369  	Info  string `json:",omitempty"`
   370  }
   371  
   372  // decodeGraph decodes a marshalGraph from an encoded graph stream.
   373  func decodeGraph(r io.Reader) (*marshalGraph, error) {
   374  	dec := json.NewDecoder(r)
   375  
   376  	// a stream should always start with a graph
   377  	g := &marshalGraph{}
   378  
   379  	err := dec.Decode(g)
   380  	if err != nil {
   381  		return nil, err
   382  	}
   383  
   384  	// now replay any operations that occurred on the original graph
   385  	for dec.More() {
   386  		s := &streamDecode{}
   387  		err := dec.Decode(s)
   388  		if err != nil {
   389  			return g, err
   390  		}
   391  
   392  		// the only Type we're concerned with here is Transform to complete the
   393  		// Graph
   394  		if s.Type != "Transform" {
   395  			continue
   396  		}
   397  
   398  		t := &marshalTransform{}
   399  		err = json.Unmarshal(s.JSON, t)
   400  		if err != nil {
   401  			return g, err
   402  		}
   403  		t.Transform(g)
   404  	}
   405  	return g, nil
   406  }
   407  
   408  // *DebugInfo structs allow encoding arbitrary information about the graph in
   409  // the logs.
   410  type vertexDebugInfo struct {
   411  	Type   string
   412  	Vertex *marshalVertex
   413  	Info   string
   414  }
   415  
   416  func newVertexDebugInfo(v Vertex, info string) *vertexDebugInfo {
   417  	return &vertexDebugInfo{
   418  		Type:   "VertexDebugInfo",
   419  		Vertex: newMarshalVertex(v),
   420  		Info:   info,
   421  	}
   422  }
   423  
   424  type edgeDebugInfo struct {
   425  	Type string
   426  	Edge *marshalEdge
   427  	Info string
   428  }
   429  
   430  func newEdgeDebugInfo(e Edge, info string) *edgeDebugInfo {
   431  	return &edgeDebugInfo{
   432  		Type: "EdgeDebugInfo",
   433  		Edge: newMarshalEdge(e),
   434  		Info: info,
   435  	}
   436  }