diff --git a/cmd/clusterctl/cmd/describe_cluster.go b/cmd/clusterctl/cmd/describe_cluster.go index 626339d6bdc7..ebe1a1c71edf 100644 --- a/cmd/clusterctl/cmd/describe_cluster.go +++ b/cmd/clusterctl/cmd/describe_cluster.go @@ -158,9 +158,13 @@ func runDescribeCluster(cmd *cobra.Command, name string) error { switch dc.v1beta2 { case true: - cmdtree.PrintObjectTree(tree, os.Stdout) + if err := cmdtree.PrintObjectTree(tree, os.Stdout); err != nil { + return errors.Wrap(err, "failed to print object tree") + } default: - cmdtree.PrintObjectTreeV1Beta1(tree) + if err := cmdtree.PrintObjectTreeV1Beta1(tree); err != nil { + return errors.Wrap(err, "failed to print object tree v1beta1") + } } return nil diff --git a/go.mod b/go.mod index 17a52aa1cd8c..8b97dcb410d6 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/google/cel-go v0.26.0 github.com/google/go-cmp v0.7.0 github.com/google/go-github/v53 v53.2.0 - github.com/olekukonko/tablewriter v0.0.5 + github.com/olekukonko/tablewriter v1.0.9 github.com/onsi/ginkgo/v2 v2.25.3 github.com/onsi/gomega v1.38.2 github.com/pkg/errors v0.9.1 @@ -99,9 +99,9 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/spdystream v0.5.0 // indirect @@ -109,13 +109,16 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect + github.com/olekukonko/errors v1.1.0 // indirect + github.com/olekukonko/ll v0.1.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rivo/uniseg v0.4.2 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect diff --git a/go.sum b/go.sum index 729332dba2f6..0b9dc673080f 100644 --- a/go.sum +++ b/go.sum @@ -223,14 +223,12 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -247,8 +245,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= +github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= +github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.1.1 h1:9Dfeed5/Mgaxb9lHRAftLK9pVfYETvHn+If6lywVhJc= +github.com/olekukonko/ll v0.1.1/go.mod h1:2dJo+hYZcJMLMbKwHEWvxCUbAOLc/CXWS9noET22Mdo= +github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8= +github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw= github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= @@ -275,8 +279,8 @@ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkq github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= -github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= @@ -466,7 +470,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= diff --git a/hack/tools/go.mod b/hack/tools/go.mod index 6c0d536218ea..3df796491390 100644 --- a/hack/tools/go.mod +++ b/hack/tools/go.mod @@ -120,9 +120,9 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -135,7 +135,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rivo/uniseg v0.4.4 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/saschagrunert/go-modiff v1.3.5 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect diff --git a/hack/tools/go.sum b/hack/tools/go.sum index 63494cf58f07..e65249195768 100644 --- a/hack/tools/go.sum +++ b/hack/tools/go.sum @@ -231,13 +231,12 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -294,8 +293,8 @@ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkq github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= @@ -443,7 +442,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/util/tree/tree.go b/internal/util/tree/tree.go index 4891ecf11b55..a13771b57329 100644 --- a/internal/util/tree/tree.go +++ b/internal/util/tree/tree.go @@ -28,6 +28,8 @@ import ( "github.com/fatih/color" "github.com/gobuffalo/flect" "github.com/olekukonko/tablewriter" + "github.com/olekukonko/tablewriter/tw" + "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -61,69 +63,98 @@ var ( cyan = color.New(color.FgCyan) ) +// CreateObjectTree creates a new tablewriter.Table for the object tree. +// Returns a new tablewriter.Table for the object tree. +func CreateObjectTree(w io.Writer) *tablewriter.Table { + cfg := tablewriter.Config{ + Row: tw.CellConfig{ + Formatting: tw.CellFormatting{AutoWrap: tw.WrapNone}, + Alignment: tw.CellAlignment{Global: tw.AlignLeft}, + Padding: tw.CellPadding{Global: tw.Padding{Left: "", Right: " "}}, + }, + Header: tw.CellConfig{ + Alignment: tw.CellAlignment{Global: tw.AlignLeft}, + }, + Behavior: tw.Behavior{TrimSpace: tw.Off}, + } + + // Creates the output table + tbl := tablewriter.NewTable(w, tablewriter.WithConfig(cfg), tablewriter.WithRendition(tw.Rendition{ + Settings: tw.Settings{ + Separators: tw.SeparatorsNone, Lines: tw.LinesNone, + }, + Borders: tw.BorderNone, + })) + + return tbl +} + +// CreateObjectTreeV1Beta1 creates a new tablewriter.Table for the object tree. +// Returns a new tablewriter.Table for the object tree. +func CreateObjectTreeV1Beta1(w io.Writer) *tablewriter.Table { + cfg := tablewriter.Config{ + Row: tw.CellConfig{ + Formatting: tw.CellFormatting{AutoWrap: tw.WrapNone}, + Alignment: tw.CellAlignment{Global: tw.AlignLeft}, + Padding: tw.CellPadding{Global: tw.Padding{Left: "", Right: " "}}, + }, + Header: tw.CellConfig{ + Alignment: tw.CellAlignment{Global: tw.AlignLeft}, + }, + Behavior: tw.Behavior{TrimSpace: tw.Off}, + } + // Creates the output table + tbl := tablewriter.NewTable(w, tablewriter.WithConfig(cfg), tablewriter.WithRendition(tw.Rendition{ + Settings: tw.Settings{ + Separators: tw.SeparatorsNone, Lines: tw.LinesNone, + }, + Borders: tw.BorderNone, + })) + + return tbl +} + // PrintObjectTree prints the cluster status to stdout. // Note: this function is exposed only for usage in clusterctl and Cluster API E2E tests. -func PrintObjectTree(tree *tree.ObjectTree, w io.Writer) { - // Creates the output table - tbl := tablewriter.NewWriter(w) - tbl.SetHeader([]string{"NAME", "REPLICAS", "AVAILABLE", "READY", "UP TO DATE", "STATUS", "REASON", "SINCE", "MESSAGE"}) +func PrintObjectTree(tree *tree.ObjectTree, w io.Writer) error { + tbl := CreateObjectTree(w) - formatTableTree(tbl) - // Add row for the root object, the cluster, and recursively for all the nodes representing the cluster status. - addObjectRow("", tbl, tree, tree.GetRoot()) + tbl.Header([]string{"NAME", "REPLICAS", "AVAILABLE", "READY", "UP TO DATE", "STATUS", "REASON", "SINCE", "MESSAGE"}) + + if err := addObjectRow("", tbl, tree, tree.GetRoot()); err != nil { + return errors.Wrap(err, "failed to add object rows") + } // Prints the output table - tbl.Render() + if err := tbl.Render(); err != nil { + return errors.Wrap(err, "failed to render table") + } + + return nil } // PrintObjectTreeV1Beta1 prints the cluster status to stdout. // Note: this function is exposed only for usage in clusterctl and Cluster API E2E tests. -func PrintObjectTreeV1Beta1(tree *tree.ObjectTree) { - // Creates the output table - tbl := tablewriter.NewWriter(os.Stdout) - tbl.SetHeader([]string{"NAME", "READY", "SEVERITY", "REASON", "SINCE", "MESSAGE"}) +func PrintObjectTreeV1Beta1(tree *tree.ObjectTree) error { + tbl := CreateObjectTreeV1Beta1(os.Stdin) + tbl.Header([]string{"NAME", "READY", "SEVERITY", "REASON", "SINCE", "MESSAGE"}) - formatTableTreeV1Beta1(tbl) // Add row for the root object, the cluster, and recursively for all the nodes representing the cluster status. - addObjectRowV1Beta1("", tbl, tree, tree.GetRoot()) + if err := addObjectRowV1Beta1("", tbl, tree, tree.GetRoot()); err != nil { + return errors.Wrap(err, "failed to add object rows") + } // Prints the output table - tbl.Render() -} - -// formats the table with required attributes. -func formatTableTree(tbl *tablewriter.Table) { - tbl.SetAutoWrapText(false) - tbl.SetHeaderAlignment(tablewriter.ALIGN_LEFT) - tbl.SetAlignment(tablewriter.ALIGN_LEFT) - - tbl.SetCenterSeparator("") - tbl.SetRowSeparator("") - - tbl.SetHeaderLine(false) - tbl.SetTablePadding(" ") - tbl.SetNoWhiteSpace(true) -} - -// formats the table with required attributes. -func formatTableTreeV1Beta1(tbl *tablewriter.Table) { - tbl.SetAutoWrapText(false) - tbl.SetHeaderAlignment(tablewriter.ALIGN_LEFT) - tbl.SetAlignment(tablewriter.ALIGN_LEFT) - - tbl.SetCenterSeparator("") - tbl.SetColumnSeparator("") - tbl.SetRowSeparator("") + if err := tbl.Render(); err != nil { + return errors.Wrap(err, "failed to render table") + } - tbl.SetHeaderLine(false) - tbl.SetBorder(false) - tbl.SetTablePadding(" ") - tbl.SetNoWhiteSpace(true) + return nil } // addObjectRow add a row for a given object, and recursively for all the object's children. // NOTE: each row name gets a prefix, that generates a tree view like representation. -func addObjectRow(prefix string, tbl *tablewriter.Table, objectTree *tree.ObjectTree, obj ctrlclient.Object) { +func addObjectRow(prefix string, tbl *tablewriter.Table, objectTree *tree.ObjectTree, obj ctrlclient.Object) error { // Get a row descriptor for a given object. // With v1beta2, the return value of this func adapt to the object represented in the line. rowDescriptor := newRowDescriptor(obj) @@ -161,7 +192,7 @@ func addObjectRow(prefix string, tbl *tablewriter.Table, objectTree *tree.Object if len(msg) >= 1 { msg0 = msg[0] } - tbl.Append([]string{ + if err := tbl.Append([]string{ fmt.Sprintf("%s%s", gray.Sprint(prefix), name), rowDescriptor.replicas, rowDescriptor.availableCounters, @@ -170,11 +201,13 @@ func addObjectRow(prefix string, tbl *tablewriter.Table, objectTree *tree.Object rowDescriptor.status, rowDescriptor.reason, rowDescriptor.age, - msg0}) + msg0}); err != nil { + return errors.Wrap(err, "failed to append main row") + } multilinePrefix := getRootMultiLineObjectPrefix(obj, objectTree) for _, m := range msg[1:] { - tbl.Append([]string{ + if err := tbl.Append([]string{ gray.Sprint(multilinePrefix), "", "", @@ -183,12 +216,16 @@ func addObjectRow(prefix string, tbl *tablewriter.Table, objectTree *tree.Object "", "", "", - m}) + m}); err != nil { + return errors.Wrap(err, "failed to append multiline row") + } } // If it is required to show all the conditions for the object, add a row for each object's conditions. if tree.IsShowConditionsObject(obj) { - addOtherConditions(prefix, tbl, objectTree, obj) + if err := addOtherConditions(prefix, tbl, objectTree, obj); err != nil { + return errors.Wrap(err, "failed to add other conditions") + } } // Add a row for each object's children, taking care of updating the tree view prefix. @@ -196,8 +233,12 @@ func addObjectRow(prefix string, tbl *tablewriter.Table, objectTree *tree.Object childrenObj = orderChildrenObjects(childrenObj) for i, child := range childrenObj { - addObjectRow(getChildPrefix(prefix, i, len(childrenObj)), tbl, objectTree, child) + if err := addObjectRow(getChildPrefix(prefix, i, len(childrenObj)), tbl, objectTree, child); err != nil { + return errors.Wrap(err, "failed to add child object row") + } } + + return nil } func orderChildrenObjects(childrenObj []ctrlclient.Object) []ctrlclient.Object { @@ -217,7 +258,7 @@ func orderChildrenObjects(childrenObj []ctrlclient.Object) []ctrlclient.Object { // addObjectRowV1Beta1 add a row for a given object, and recursively for all the object's children. // NOTE: each row name gets a prefix, that generates a tree view like representation. -func addObjectRowV1Beta1(prefix string, tbl *tablewriter.Table, objectTree *tree.ObjectTree, obj ctrlclient.Object) { +func addObjectRowV1Beta1(prefix string, tbl *tablewriter.Table, objectTree *tree.ObjectTree, obj ctrlclient.Object) error { // Gets the descriptor for the object's ready condition, if any. readyDescriptor := v1beta1ConditionDescriptor{readyColor: gray} if ready := tree.GetV1Beta1ReadyCondition(obj); ready != nil { @@ -241,17 +282,21 @@ func addObjectRowV1Beta1(prefix string, tbl *tablewriter.Table, objectTree *tree // Add the row representing the object that includes // - The row name with the tree view prefix. // - The object's ready condition. - tbl.Append([]string{ + if err := tbl.Append([]string{ fmt.Sprintf("%s%s", gray.Sprint(prefix), name), readyDescriptor.readyColor.Sprint(readyDescriptor.status), readyDescriptor.readyColor.Sprint(readyDescriptor.severity), readyDescriptor.readyColor.Sprint(readyDescriptor.reason), readyDescriptor.age, - readyDescriptor.message}) + readyDescriptor.message}); err != nil { + return errors.Wrap(err, "failed to append main row") + } // If it is required to show all the conditions for the object, add a row for each object's conditions. if tree.IsShowConditionsObject(obj) { - addOtherConditionsV1Beta1(prefix, tbl, objectTree, obj) + if err := addOtherConditionsV1Beta1(prefix, tbl, objectTree, obj); err != nil { + return errors.Wrap(err, "failed to add other conditions") + } } // Add a row for each object's children, taking care of updating the tree view prefix. @@ -270,12 +315,16 @@ func addObjectRowV1Beta1(prefix string, tbl *tablewriter.Table, objectTree *tree sort.Slice(childrenObj, printBefore) for i, child := range childrenObj { - addObjectRowV1Beta1(getChildPrefix(prefix, i, len(childrenObj)), tbl, objectTree, child) + if err := addObjectRowV1Beta1(getChildPrefix(prefix, i, len(childrenObj)), tbl, objectTree, child); err != nil { + return errors.Wrap(err, "failed to add child object row") + } } + + return nil } // addOtherConditions adds a row for each object condition. -func addOtherConditions(prefix string, tbl *tablewriter.Table, objectTree *tree.ObjectTree, obj ctrlclient.Object) { +func addOtherConditions(prefix string, tbl *tablewriter.Table, objectTree *tree.ObjectTree, obj ctrlclient.Object) error { // Add a row for each other condition, taking care of updating the tree view prefix. // In this case the tree prefix get a filler, to indent conditions from objects, and eventually a // and additional pipe if the object has children that should be presented after the conditions. @@ -312,7 +361,7 @@ func addOtherConditions(prefix string, tbl *tablewriter.Table, objectTree *tree. if len(msg) >= 1 { msg0 = msg[0] } - tbl.Append([]string{ + if err := tbl.Append([]string{ fmt.Sprintf("%s%s", gray.Sprint(childPrefix), cyan.Sprint(condition.Type)), "", "", @@ -321,10 +370,12 @@ func addOtherConditions(prefix string, tbl *tablewriter.Table, objectTree *tree. c.Sprint(status), reason, age, - msg0}) + msg0}); err != nil { + return errors.Wrap(err, "failed to append condition row") + } for _, m := range msg[1:] { - tbl.Append([]string{ + if err := tbl.Append([]string{ gray.Sprint(getMultilineConditionPrefix(childPrefix)), "", "", @@ -333,14 +384,18 @@ func addOtherConditions(prefix string, tbl *tablewriter.Table, objectTree *tree. "", "", "", - m}) + m}); err != nil { + return errors.Wrap(err, "failed to append multiline condition row") + } } } + + return nil } // addOtherConditionsV1Beta1 adds a row for each object condition except the ready condition, // which is already represented on the object's main row. -func addOtherConditionsV1Beta1(prefix string, tbl *tablewriter.Table, objectTree *tree.ObjectTree, obj ctrlclient.Object) { +func addOtherConditionsV1Beta1(prefix string, tbl *tablewriter.Table, objectTree *tree.ObjectTree, obj ctrlclient.Object) error { // Add a row for each other condition, taking care of updating the tree view prefix. // In this case the tree prefix get a filler, to indent conditions from objects, and eventually a // and additional pipe if the object has children that should be presented after the conditions. @@ -355,14 +410,18 @@ func addOtherConditionsV1Beta1(prefix string, tbl *tablewriter.Table, objectTree otherCondition := otherConditions[i] otherDescriptor := newV1Beta1ConditionDescriptor(otherCondition) otherConditionPrefix := getChildPrefix(prefix+childrenPipe+filler, i, len(otherConditions)) - tbl.Append([]string{ + if err := tbl.Append([]string{ fmt.Sprintf("%s%s", gray.Sprint(otherConditionPrefix), cyan.Sprint(otherCondition.Type)), otherDescriptor.readyColor.Sprint(otherDescriptor.status), otherDescriptor.readyColor.Sprint(otherDescriptor.severity), otherDescriptor.readyColor.Sprint(otherDescriptor.reason), otherDescriptor.age, - otherDescriptor.message}) + otherDescriptor.message}); err != nil { + return errors.Wrap(err, "failed to append other condition row") + } } + + return nil } // getChildPrefix return the tree view prefix for a row representing a child object. diff --git a/internal/util/tree/tree_test.go b/internal/util/tree/tree_test.go index b0ad6070fef4..eeb0cd814f54 100644 --- a/internal/util/tree/tree_test.go +++ b/internal/util/tree/tree_test.go @@ -19,11 +19,11 @@ package tree import ( "bytes" "fmt" + "os" "strings" "testing" "github.com/fatih/color" - "github.com/olekukonko/tablewriter" . "github.com/onsi/gomega" gtype "github.com/onsi/gomega/types" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -279,16 +279,15 @@ func Test_V1Beta1TreePrefix(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) var output bytes.Buffer - - // Creates the output table - tbl := tablewriter.NewWriter(&output) - - formatTableTreeV1Beta1(tbl) + tbl := CreateObjectTreeV1Beta1(&output) // Add row for the root object, the cluster, and recursively for all the nodes representing the cluster status. - addObjectRowV1Beta1("", tbl, tt.objectTree, tt.objectTree.GetRoot()) - tbl.Render() - + err := addObjectRowV1Beta1("", tbl, tt.objectTree, tt.objectTree.GetRoot()) + g.Expect(err).ToNot(HaveOccurred(), "Failed to add object rows") + if err := tbl.Render(); err != nil { + fmt.Printf("Error rendering table: %v", err) + os.Exit(1) + } // Compare the output with the expected prefix. // We only check whether the output starts with the expected prefix, // meaning expectPrefix does not contain the full expected output. @@ -511,15 +510,16 @@ func Test_TreePrefix(t *testing.T) { g := NewWithT(t) var output bytes.Buffer - // Creates the output table - tbl := tablewriter.NewWriter(&output) - - formatTableTree(tbl) + tbl := CreateObjectTree(&output) // Add row for the root object, the cluster, and recursively for all the nodes representing the cluster status. - addObjectRow("", tbl, tt.objectTree, tt.objectTree.GetRoot()) - tbl.Render() + err := addObjectRow("", tbl, tt.objectTree, tt.objectTree.GetRoot()) + g.Expect(err).ToNot(HaveOccurred(), "Failed to add object rows") + if err := tbl.Render(); err != nil { + fmt.Printf("Error rendering table: %v", err) + os.Exit(1) + } // Remove empty lines from the output. We need this because v1beta2 adds lines at the beginning and end. outputString := strings.TrimSpace(output.String()) diff --git a/test/framework/cluster_helpers.go b/test/framework/cluster_helpers.go index 6983696aace1..535da0dcd342 100644 --- a/test/framework/cluster_helpers.go +++ b/test/framework/cluster_helpers.go @@ -381,9 +381,9 @@ func DescribeCluster(ctx context.Context, input DescribeClusterInput) { defer f.Close() w := bufio.NewWriter(f) - cmdtree.PrintObjectTree(tree, w) + Expect(cmdtree.PrintObjectTree(tree, w)).To(Succeed(), "Failed to print object tree to file") if CurrentSpecReport().Failed() { - cmdtree.PrintObjectTree(tree, GinkgoWriter) + Expect(cmdtree.PrintObjectTree(tree, GinkgoWriter)).To(Succeed(), "Failed to print object tree to GinkgoWriter") } Expect(w.Flush()).To(Succeed(), "Failed to save clusterctl describe output") } diff --git a/test/go.mod b/test/go.mod index 72109ee3e970..5707c95d1727 100644 --- a/test/go.mod +++ b/test/go.mod @@ -97,9 +97,9 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect @@ -110,7 +110,10 @@ require ( github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect + github.com/olekukonko/errors v1.1.0 // indirect + github.com/olekukonko/ll v0.1.1 // indirect + github.com/olekukonko/tablewriter v1.0.9 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -118,7 +121,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/rivo/uniseg v0.4.2 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect diff --git a/test/go.sum b/test/go.sum index de9ff79cf12b..2bd9cff90f9d 100644 --- a/test/go.sum +++ b/test/go.sum @@ -188,14 +188,12 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -222,8 +220,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= +github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= +github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.1.1 h1:9Dfeed5/Mgaxb9lHRAftLK9pVfYETvHn+If6lywVhJc= +github.com/olekukonko/ll v0.1.1/go.mod h1:2dJo+hYZcJMLMbKwHEWvxCUbAOLc/CXWS9noET22Mdo= +github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8= +github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw= github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= @@ -253,8 +257,8 @@ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkq github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= -github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -401,7 +405,6 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=