graph.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. //Copyright 2013 GoGraphviz Authors
  2. //
  3. //Licensed under the Apache License, Version 2.0 (the "License");
  4. //you may not use this file except in compliance with the License.
  5. //You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. //Unless required by applicable law or agreed to in writing, software
  10. //distributed under the License is distributed on an "AS IS" BASIS,
  11. //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. //See the License for the specific language governing permissions and
  13. //limitations under the License.
  14. package gographviz
  15. import (
  16. "fmt"
  17. "strings"
  18. )
  19. // Graph is the analysed representation of the Graph parsed from the DOT format.
  20. type Graph struct {
  21. Attrs Attrs
  22. Name string
  23. Directed bool
  24. Strict bool
  25. Nodes *Nodes
  26. Edges *Edges
  27. SubGraphs *SubGraphs
  28. Relations *Relations
  29. }
  30. // NewGraph creates a new empty graph, ready to be populated.
  31. func NewGraph() *Graph {
  32. return &Graph{
  33. Attrs: make(Attrs),
  34. Name: "",
  35. Directed: false,
  36. Strict: false,
  37. Nodes: NewNodes(),
  38. Edges: NewEdges(),
  39. SubGraphs: NewSubGraphs(),
  40. Relations: NewRelations(),
  41. }
  42. }
  43. // SetStrict sets whether a graph is strict.
  44. // If the graph is strict then multiple edges are not allowed between the same pairs of nodes,
  45. // see dot man page.
  46. func (g *Graph) SetStrict(strict bool) error {
  47. g.Strict = strict
  48. return nil
  49. }
  50. // SetDir sets whether the graph is directed (true) or undirected (false).
  51. func (g *Graph) SetDir(dir bool) error {
  52. g.Directed = dir
  53. return nil
  54. }
  55. // SetName sets the graph name.
  56. func (g *Graph) SetName(name string) error {
  57. g.Name = name
  58. return nil
  59. }
  60. // AddPortEdge adds an edge to the graph from node src to node dst.
  61. // srcPort and dstPort are the port the node ports, leave as empty strings if it is not required.
  62. // This does not imply the adding of missing nodes.
  63. func (g *Graph) AddPortEdge(src, srcPort, dst, dstPort string, directed bool, attrs map[string]string) error {
  64. as, err := NewAttrs(attrs)
  65. if err != nil {
  66. return err
  67. }
  68. g.Edges.Add(&Edge{src, srcPort, dst, dstPort, directed, as})
  69. return nil
  70. }
  71. // AddEdge adds an edge to the graph from node src to node dst.
  72. // This does not imply the adding of missing nodes.
  73. // If directed is set to true then SetDir(true) must also be called or there will be a syntax error in the output.
  74. func (g *Graph) AddEdge(src, dst string, directed bool, attrs map[string]string) error {
  75. return g.AddPortEdge(src, "", dst, "", directed, attrs)
  76. }
  77. // AddNode adds a node to a graph/subgraph.
  78. // If not subgraph exists use the name of the main graph.
  79. // This does not imply the adding of a missing subgraph.
  80. func (g *Graph) AddNode(parentGraph string, name string, attrs map[string]string) error {
  81. as, err := NewAttrs(attrs)
  82. if err != nil {
  83. return err
  84. }
  85. g.Nodes.Add(&Node{name, as})
  86. g.Relations.Add(parentGraph, name)
  87. return nil
  88. }
  89. // RemoveNode removes a node from the graph
  90. func (g *Graph) RemoveNode(parentGraph string, name string) error {
  91. err := g.Nodes.Remove(name)
  92. if err != nil {
  93. return err
  94. }
  95. g.Relations.Remove(parentGraph, name)
  96. edges := NewEdges()
  97. for _, e := range g.Edges.Edges {
  98. if e.Dst == name || e.Src == name {
  99. continue
  100. }
  101. edges.Add(e)
  102. }
  103. g.Edges = edges
  104. return nil
  105. }
  106. func (g *Graph) getAttrs(graphName string) (Attrs, error) {
  107. if g.Name == graphName {
  108. return g.Attrs, nil
  109. }
  110. sub, ok := g.SubGraphs.SubGraphs[graphName]
  111. if !ok {
  112. return nil, fmt.Errorf("graph or subgraph %s does not exist", graphName)
  113. }
  114. return sub.Attrs, nil
  115. }
  116. // AddAttr adds an attribute to a graph/subgraph.
  117. func (g *Graph) AddAttr(parentGraph string, field string, value string) error {
  118. a, err := g.getAttrs(parentGraph)
  119. if err != nil {
  120. return err
  121. }
  122. return a.Add(field, value)
  123. }
  124. // AddSubGraph adds a subgraph to a graph/subgraph.
  125. func (g *Graph) AddSubGraph(parentGraph string, name string, attrs map[string]string) error {
  126. g.Relations.Add(parentGraph, name)
  127. g.SubGraphs.Add(name)
  128. for key, value := range attrs {
  129. if err := g.AddAttr(name, key, value); err != nil {
  130. return err
  131. }
  132. }
  133. return nil
  134. }
  135. // RemoveSubGraph removes the subgraph including nodes
  136. func (g *Graph) RemoveSubGraph(parentGraph string, name string) error {
  137. for child := range g.Relations.ParentToChildren[name] {
  138. err := g.RemoveNode(parentGraph, child)
  139. if err != nil {
  140. return err
  141. }
  142. }
  143. g.Relations.Remove(parentGraph, name)
  144. g.SubGraphs.Remove(name)
  145. edges := NewEdges()
  146. for _, e := range g.Edges.Edges {
  147. if e.Dst == name || e.DstPort == name || e.Src == name || e.SrcPort == name {
  148. continue
  149. }
  150. edges.Add(e)
  151. }
  152. g.Edges = edges
  153. return nil
  154. }
  155. // IsNode returns whether a given node name exists as a node in the graph.
  156. func (g *Graph) IsNode(name string) bool {
  157. _, ok := g.Nodes.Lookup[name]
  158. return ok
  159. }
  160. // IsSubGraph returns whether a given subgraph name exists as a subgraph in the graph.
  161. func (g *Graph) IsSubGraph(name string) bool {
  162. _, ok := g.SubGraphs.SubGraphs[name]
  163. return ok
  164. }
  165. func (g *Graph) isClusterSubGraph(name string) bool {
  166. isSubGraph := g.IsSubGraph(name)
  167. isCluster := strings.HasPrefix(name, "cluster")
  168. return isSubGraph && isCluster
  169. }