Skip to content

Commit 17bf0b8

Browse files
authored
Merge pull request #83 from snorwin/new-dot-graph-library
fix: replace github.com/goccy/go-graphviz with github.com/emicklei/dot
2 parents 77cc18f + b29b020 commit 17bf0b8

File tree

4 files changed

+23
-78
lines changed

4 files changed

+23
-78
lines changed

cmd/get/get.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ func (o *getOptions) Run(args []string) error {
208208
if err != nil {
209209
return err
210210
}
211-
fmt.Fprintf(o.IOStreams.Out, "%v\n", string(toDotGraph))
211+
fmt.Fprintf(o.IOStreams.Out, "%v\n", toDotGraph)
212212

213213
return nil
214214
}

go.mod

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ module sigs.k8s.io/gwctl
33
go 1.25.3
44

55
require (
6+
github.com/emicklei/dot v1.9.2
67
github.com/evanphx/json-patch v5.9.11+incompatible
7-
github.com/goccy/go-graphviz v0.2.9
88
github.com/google/go-cmp v0.7.0
99
github.com/spf13/cobra v1.10.1
1010
github.com/spf13/pflag v1.0.10
@@ -28,12 +28,9 @@ require (
2828
github.com/blang/semver/v4 v4.0.0 // indirect
2929
github.com/chai2010/gettext-go v1.0.2 // indirect
3030
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
31-
github.com/disintegration/imaging v1.6.2 // indirect
3231
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
3332
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
3433
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
35-
github.com/flopp/go-findfont v0.1.0 // indirect
36-
github.com/fogleman/gg v1.3.0 // indirect
3734
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
3835
github.com/go-errors/errors v1.4.2 // indirect
3936
github.com/go-logr/logr v1.4.3 // indirect
@@ -52,7 +49,6 @@ require (
5249
github.com/go-openapi/swag/typeutils v0.25.3 // indirect
5350
github.com/go-openapi/swag/yamlutils v0.25.3 // indirect
5451
github.com/gogo/protobuf v1.3.2 // indirect
55-
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
5652
github.com/google/btree v1.1.3 // indirect
5753
github.com/google/gnostic-models v0.7.1 // indirect
5854
github.com/google/uuid v1.6.0 // indirect
@@ -76,13 +72,11 @@ require (
7672
github.com/prometheus/procfs v0.19.2 // indirect
7773
github.com/russross/blackfriday/v2 v2.1.0 // indirect
7874
github.com/stretchr/testify v1.11.1 // indirect
79-
github.com/tetratelabs/wazero v1.10.1 // indirect
8075
github.com/x448/float16 v0.8.4 // indirect
8176
github.com/xlab/treeprint v1.2.0 // indirect
8277
go.uber.org/zap v1.27.1 // indirect
8378
go.yaml.in/yaml/v2 v2.4.3 // indirect
8479
go.yaml.in/yaml/v3 v3.0.4 // indirect
85-
golang.org/x/image v0.33.0 // indirect
8680
golang.org/x/net v0.47.0 // indirect
8781
golang.org/x/oauth2 v0.33.0 // indirect
8882
golang.org/x/sync v0.18.0 // indirect

go.sum

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,15 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
1212
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
1313
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
1414
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
15-
github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI=
16-
github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI=
1715
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
1816
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
1917
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
2018
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2119
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2220
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
2321
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
24-
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
25-
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
22+
github.com/emicklei/dot v1.9.2 h1:E/Wjz+BAH+JDhybEpISbo+QyDMNSiu/wqmIW9y922P8=
23+
github.com/emicklei/dot v1.9.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
2624
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
2725
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
2826
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
@@ -31,10 +29,6 @@ github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjT
3129
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
3230
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
3331
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
34-
github.com/flopp/go-findfont v0.1.0 h1:lPn0BymDUtJo+ZkV01VS3661HL6F4qFlkhcJN55u6mU=
35-
github.com/flopp/go-findfont v0.1.0/go.mod h1:wKKxRDjD024Rh7VMwoU90i6ikQRCr+JTHB5n4Ejkqvw=
36-
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
37-
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
3832
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
3933
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
4034
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
@@ -79,12 +73,8 @@ github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6
7973
github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
8074
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
8175
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
82-
github.com/goccy/go-graphviz v0.2.9 h1:4yD2MIMpxNt+sOEARDh5jTE2S/jeAKi92w72B83mWGg=
83-
github.com/goccy/go-graphviz v0.2.9/go.mod h1:hssjl/qbvUXGmloY81BwXt2nqoApKo7DFgDj5dLJGb8=
8476
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
8577
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
86-
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
87-
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
8878
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
8979
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
9080
github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
@@ -130,8 +120,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
130120
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
131121
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
132122
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
133-
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
134-
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
135123
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
136124
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
137125
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
@@ -168,8 +156,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
168156
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
169157
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
170158
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
171-
github.com/tetratelabs/wazero v1.10.1 h1:2DugeJf6VVk58KTPszlNfeeN8AhhpwcZqkJj2wwFuH8=
172-
github.com/tetratelabs/wazero v1.10.1/go.mod h1:DRm5twOQ5Gr1AoEdSi0CLjDQF1J9ZAuyqFIjl1KKfQU=
173159
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
174160
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
175161
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
@@ -191,9 +177,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
191177
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
192178
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0=
193179
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
194-
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
195-
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
196-
golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=
197180
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
198181
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
199182
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=

pkg/topology/gateway/graphviz.go

Lines changed: 19 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,50 +17,26 @@ limitations under the License.
1717
package gateway
1818

1919
import (
20-
"bytes"
21-
"context"
22-
"log"
23-
24-
graphviz "github.com/goccy/go-graphviz"
25-
"github.com/goccy/go-graphviz/cgraph"
26-
20+
"github.com/emicklei/dot"
2721
"sigs.k8s.io/gwctl/pkg/common"
2822
"sigs.k8s.io/gwctl/pkg/topology"
2923
)
3024

3125
// TODO:
3226
// - Show policy nodes. Attempt to group policy nodes along with their target
3327
// nodes in a single subgraph so they get rendered closer together.
34-
func ToDot(gwctlGraph *topology.Graph) ([]byte, error) {
35-
ctx := context.Background()
36-
g, err := graphviz.New(ctx)
37-
if err != nil {
38-
return nil, err
39-
}
40-
cGraph, err := g.Graph()
41-
if err != nil {
42-
return nil, err
43-
}
44-
defer func() {
45-
if err := cGraph.Close(); err != nil {
46-
log.Fatal(err)
47-
}
48-
g.Close()
49-
}()
50-
cGraph.SetRankDir(cgraph.BTRank)
51-
52-
cNodeMap := map[common.GKNN]*cgraph.Node{}
28+
func ToDot(gwctlGraph *topology.Graph) (string, error) {
29+
dotGraph := dot.NewGraph(dot.Directed)
5330

5431
// Create nodes.
32+
dotNodeMap := map[common.GKNN]dot.Node{}
5533
for _, nodeMap := range gwctlGraph.Nodes {
5634
for _, node := range nodeMap {
57-
cNode, err := cGraph.CreateNodeByName(node.GKNN().String())
58-
if err != nil {
59-
return nil, err
60-
}
61-
cNodeMap[node.GKNN()] = cNode
62-
cNode.SetStyle(cgraph.FilledNodeStyle)
63-
cNode.SetFillColor(nodeColor(node))
35+
dotNode := dotGraph.Node(node.GKNN().String()).
36+
Attr("style", "filled").
37+
Attr("color", mapNodeColor(node))
38+
39+
dotNodeMap[node.GKNN()] = dotNode
6440

6541
// Set the Node label
6642
gk := node.GKNN().GroupKind()
@@ -71,17 +47,17 @@ func ToDot(gwctlGraph *topology.Graph) ([]byte, error) {
7147
if node.GKNN().Namespace == "" {
7248
name = node.GKNN().Name
7349
}
74-
cNode.SetLabel(gk.String() + "\n" + name)
50+
dotNode.Label(gk.String() + "\n" + name)
7551
}
7652
}
7753

7854
// Create edges.
79-
for fromNodeGKNN, cFromNode := range cNodeMap {
55+
for fromNodeGKNN, dotFromNode := range dotNodeMap {
8056
fromNode := gwctlGraph.Nodes[fromNodeGKNN.GroupKind()][fromNodeGKNN.NamespacedName()]
8157

8258
for relation, outNodeMap := range fromNode.OutNeighbors {
8359
for toNodeGKNN := range outNodeMap {
84-
cToNode := cNodeMap[toNodeGKNN]
60+
dotToNode := dotNodeMap[toNodeGKNN]
8561

8662
// If this is an edge from an HTTPRoute to a Service, then
8763
// reverse the direction of the edge (to affect the rank), and
@@ -90,36 +66,28 @@ func ToDot(gwctlGraph *topology.Graph) ([]byte, error) {
9066
// correct rank.
9167
reverse := (fromNode.GKNN().GroupKind() == common.HTTPRouteGK && toNodeGKNN.GroupKind() == common.ServiceGK) ||
9268
(fromNode.GKNN().GroupKind() == common.GatewayGK && toNodeGKNN.GroupKind() == common.NamespaceGK)
93-
u, v := cFromNode, cToNode
69+
u, v := dotFromNode, dotToNode
9470
if reverse {
9571
u, v = v, u
9672
}
9773

98-
e, err := cGraph.CreateEdgeByName(relation.Name, u, v)
99-
if err != nil {
100-
return nil, err
101-
}
102-
e.SetLabel(relation.Name)
74+
e := dotGraph.Edge(u, v, relation.Name)
75+
10376
if reverse {
104-
e.SetDir(cgraph.BackDir)
77+
e.Attr("dir", "back")
10578
}
10679
// Create a dotted line for the relation to the namespace.
10780
if toNodeGKNN.Kind == common.NamespaceGK.Kind {
108-
e.SetStyle(cgraph.DottedEdgeStyle)
81+
e.Dotted()
10982
}
11083
}
11184
}
11285
}
11386

114-
var buf bytes.Buffer
115-
if err := g.Render(ctx, cGraph, "dot", &buf); err != nil {
116-
return nil, err
117-
}
118-
119-
return buf.Bytes(), nil
87+
return dotGraph.String(), nil
12088
}
12189

122-
func nodeColor(node *topology.Node) string {
90+
func mapNodeColor(node *topology.Node) string {
12391
switch node.GKNN().GroupKind() {
12492
case common.NamespaceGK:
12593
return "#d08770"

0 commit comments

Comments
 (0)