Skip to content

Commit 8b1c974

Browse files
committed
refactor: drop termui-widgets library
Use the library built for tview, so that we don't have to have two UI libraries working in parallel in the same TUI. Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
1 parent 5baa002 commit 8b1c974

File tree

11 files changed

+324
-425
lines changed

11 files changed

+324
-425
lines changed

cmd/talosctl/cmd/talos/processes.go

Lines changed: 6 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,19 @@ import (
1010
"path/filepath"
1111
"sort"
1212
"strings"
13-
"time"
1413

1514
"github.com/dustin/go-humanize"
16-
ui "github.com/gizak/termui/v3"
17-
"github.com/gizak/termui/v3/widgets"
1815
"github.com/ryanuber/columnize"
1916
"github.com/spf13/cobra"
20-
"golang.org/x/term"
2117
"google.golang.org/grpc"
2218
"google.golang.org/grpc/peer"
2319

2420
"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers"
25-
"github.com/siderolabs/talos/pkg/cli"
2621
machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine"
2722
"github.com/siderolabs/talos/pkg/machinery/client"
2823
)
2924

30-
var (
31-
sortMethod string
32-
watchProcesses bool
33-
)
25+
var sortMethod string
3426

3527
// processesCmd represents the processes command.
3628
var processesCmd = &cobra.Command{
@@ -41,104 +33,23 @@ var processesCmd = &cobra.Command{
4133
Args: cobra.NoArgs,
4234
RunE: func(cmd *cobra.Command, args []string) error {
4335
return WithClient(func(ctx context.Context, c *client.Client) error {
44-
var err error
45-
46-
switch {
47-
case watchProcesses:
48-
if err = ui.Init(); err != nil {
49-
return fmt.Errorf("failed to initialize termui: %w", err)
50-
}
51-
52-
defer ui.Close()
53-
54-
processesUI(ctx, c)
55-
default:
56-
var output string
57-
58-
output, err = processesOutput(ctx, c)
59-
if err != nil {
60-
return err
61-
}
62-
// Note this is unlimited output of process lines
63-
// we arent artificially limited by the box we would otherwise draw
64-
fmt.Println(output)
36+
output, err := processesOutput(ctx, c)
37+
if err != nil {
38+
return err
6539
}
6640

41+
fmt.Println(output)
42+
6743
return nil
6844
})
6945
},
7046
}
7147

7248
func init() {
7349
processesCmd.Flags().StringVarP(&sortMethod, "sort", "s", "rss", "Column to sort output by. [rss|cpu]")
74-
processesCmd.Flags().BoolVarP(&watchProcesses, "watch", "w", false, "Stream running processes")
7550
addCommand(processesCmd)
7651
}
7752

78-
func processesUI(ctx context.Context, c *client.Client) {
79-
l := widgets.NewParagraph()
80-
l.Border = false
81-
l.WrapText = false
82-
l.PaddingTop = 0
83-
l.PaddingBottom = 0
84-
85-
var processOutput string
86-
87-
draw := func() {
88-
// Attempt to get terminal dimensions
89-
// Since we're getting this data on each call
90-
// we'll be able to handle terminal window resizing
91-
w, h, err := term.GetSize(0)
92-
cli.Should(err)
93-
// x, y, w, h
94-
l.SetRect(0, 0, w, h)
95-
l.WrapText = false
96-
97-
processOutput, err = processesOutput(ctx, c)
98-
if err != nil {
99-
l.Text = err.Error()
100-
l.WrapText = true
101-
102-
ui.Render(l)
103-
104-
return
105-
}
106-
107-
// Dont refresh if we dont have any output
108-
if processOutput == "" {
109-
return
110-
}
111-
112-
// Truncate our output based on terminal size
113-
l.Text = processOutput
114-
115-
ui.Render(l)
116-
}
117-
118-
draw()
119-
120-
uiEvents := ui.PollEvents()
121-
ticker := time.NewTicker(time.Second).C
122-
123-
for {
124-
select {
125-
case <-ctx.Done():
126-
return
127-
case e := <-uiEvents:
128-
switch e.ID {
129-
case "q", "<C-c>":
130-
return
131-
case "r", "m":
132-
sortMethod = "rss"
133-
case "c":
134-
sortMethod = "cpu"
135-
}
136-
case <-ticker:
137-
draw()
138-
}
139-
}
140-
}
141-
14253
type by func(p1, p2 *machineapi.ProcessInfo) bool
14354

14455
func (b by) sort(procs []*machineapi.ProcessInfo) {

go.mod

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ require (
8383
github.com/g0rbe/go-chattr v1.0.1
8484
github.com/gdamore/tcell/v2 v2.13.8
8585
github.com/gertd/go-pluralize v0.2.1
86-
github.com/gizak/termui/v3 v3.1.0
8786
github.com/godbus/dbus/v5 v5.2.2
8887
github.com/golang/mock v1.7.0-rc.1
8988
github.com/google/cadvisor v0.56.2
@@ -119,6 +118,7 @@ require (
119118
github.com/miekg/dns v1.1.72
120119
github.com/moby/moby/api v1.53.0
121120
github.com/moby/moby/client v0.2.2
121+
github.com/navidys/tvxwidgets v0.13.0
122122
github.com/nberlee/go-netstat v0.1.2
123123
github.com/opencontainers/go-digest v1.0.0
124124
github.com/opencontainers/image-spec v1.1.1
@@ -289,7 +289,6 @@ require (
289289
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
290290
github.com/mailru/easyjson v0.9.0 // indirect
291291
github.com/mattn/go-colorable v0.1.14 // indirect
292-
github.com/mattn/go-runewidth v0.0.16 // indirect
293292
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
294293
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect
295294
github.com/mdlayher/packet v1.1.2 // indirect
@@ -312,7 +311,6 @@ require (
312311
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
313312
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
314313
github.com/neticdk/go-stdlib v1.0.0 // indirect
315-
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d // indirect
316314
github.com/opencontainers/selinux v1.13.1 // indirect
317315
github.com/opentracing/opentracing-go v1.2.0 // indirect
318316
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect

go.sum

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,6 @@ github.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlL
249249
github.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk=
250250
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
251251
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
252-
github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc=
253-
github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY=
254252
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
255253
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
256254
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -455,9 +453,6 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP
455453
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
456454
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
457455
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
458-
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
459-
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
460-
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
461456
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
462457
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
463458
github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875 h1:ql8x//rJsHMjS+qqEag8n3i4azw1QneKh5PieH9UEbY=
@@ -500,7 +495,6 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
500495
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
501496
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
502497
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
503-
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
504498
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
505499
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
506500
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
@@ -538,16 +532,16 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
538532
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
539533
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
540534
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
535+
github.com/navidys/tvxwidgets v0.13.0 h1:ccGODowWhHQH7zh43lwdeML+qpZS0cMHByjS3CPcRJY=
536+
github.com/navidys/tvxwidgets v0.13.0/go.mod h1:C+hTUXTFCOaYQkKlwqqn9K54RT0zrNqfqhI/RWwt+g4=
541537
github.com/nberlee/go-netstat v0.1.2 h1:wgPV1YOUo+kDFypqiKgfxMtnSs1Wb42c7ahI4qyEUJc=
542538
github.com/nberlee/go-netstat v0.1.2/go.mod h1:GvDCRLsUKMRN1wULkt7tpnDmjSIE6YGf5zeVq+mBO64=
543539
github.com/neticdk/go-stdlib v1.0.0 h1:9QCpoMpO5dBJGHJhumZrHzfJyvpVBd2Gc7ODJujfpXY=
544540
github.com/neticdk/go-stdlib v1.0.0/go.mod h1:rch+DEB6VtR972ZPTY6A5OyLmCrp2YlXP0WGjuDDdcw=
545-
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
546-
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
547-
github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
548-
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
549-
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
550-
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
541+
github.com/onsi/ginkgo/v2 v2.27.5 h1:ZeVgZMx2PDMdJm/+w5fE/OyG6ILo1Y3e+QX4zSR0zTE=
542+
github.com/onsi/ginkgo/v2 v2.27.5/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
543+
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
544+
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
551545
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
552546
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
553547
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
@@ -595,7 +589,6 @@ github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4
595589
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
596590
github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c=
597591
github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY=
598-
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
599592
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
600593
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
601594
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=

internal/pkg/dashboard/components/gauges.go

Lines changed: 35 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,56 @@
55
package components
66

77
import (
8-
"fmt"
98
"math"
109

11-
ui "github.com/gizak/termui/v3"
12-
"github.com/gizak/termui/v3/widgets"
10+
"github.com/gdamore/tcell/v2"
11+
"github.com/navidys/tvxwidgets"
12+
"github.com/rivo/tview"
1313

1414
"github.com/siderolabs/talos/internal/pkg/dashboard/apidata"
1515
)
1616

1717
// SystemGauges quickly show CPU/mem load.
1818
type SystemGauges struct {
19-
*TermUIWrapper
19+
tview.Primitive
2020

21-
inner *systemGaugesInner
21+
cpuGauge *tvxwidgets.PercentageModeGauge
22+
memGauge *tvxwidgets.PercentageModeGauge
2223
}
2324

2425
// NewSystemGauges creates SystemGauges.
2526
func NewSystemGauges() *SystemGauges {
26-
inner := systemGaugesInner{
27-
Block: *ui.NewBlock(),
28-
}
27+
root := tview.NewGrid().SetRows(0).SetColumns(0)
28+
root.SetBorderPadding(1, 2, 1, 1)
29+
30+
cpuGauge := tvxwidgets.NewPercentageModeGauge()
31+
cpuGauge.SetBorder(false)
32+
cpuGauge.SetMaxValue(100)
33+
cpuGauge.SetPgBgColor(tview.Styles.ContrastBackgroundColor)
34+
35+
cpuFrame := tview.NewFrame(cpuGauge)
36+
cpuFrame.SetBorders(0, 0, 0, 0, 0, 0).
37+
AddText("[::b]CPU", true, tview.AlignLeft, tcell.ColorDefault)
2938

30-
inner.cpuGauge = widgets.NewGauge()
31-
inner.cpuGauge.Border = false
32-
inner.cpuGauge.Title = "CPU"
39+
root.AddItem(cpuFrame, 0, 0, 1, 1, 0, 0, false)
3340

34-
inner.memGauge = widgets.NewGauge()
35-
inner.memGauge.Title = "MEM"
36-
inner.memGauge.Border = false
41+
memGauge := tvxwidgets.NewPercentageModeGauge()
42+
memGauge.SetBorder(false)
43+
memGauge.SetMaxValue(100)
44+
memGauge.SetPgBgColor(tview.Styles.ContrastBackgroundColor)
3745

38-
wrapper := NewTermUIWrapper(&inner)
46+
memFrame := tview.NewFrame(memGauge)
47+
memFrame.SetBorders(0, 0, 0, 0, 0, 0).
48+
AddText("[::b]MEM", true, tview.AlignLeft, tcell.ColorDefault)
49+
50+
root.AddItem(memFrame, 1, 0, 1, 1, 0, 0, false)
3951

4052
widget := &SystemGauges{
41-
TermUIWrapper: wrapper,
42-
inner: &inner,
43-
}
53+
Primitive: root,
4454

45-
widget.SetBorderPadding(1, 0, 0, 0)
55+
cpuGauge: cpuGauge,
56+
memGauge: memGauge,
57+
}
4658

4759
return widget
4860
}
@@ -52,46 +64,13 @@ func (widget *SystemGauges) OnAPIDataChange(node string, data *apidata.Data) {
5264
nodeData := data.Nodes[node]
5365

5466
if nodeData == nil {
55-
widget.inner.cpuGauge.Label = noData
56-
widget.inner.cpuGauge.Percent = 0
57-
widget.inner.memGauge.Label = noData
58-
widget.inner.memGauge.Percent = 0
67+
widget.cpuGauge.SetValue(0)
68+
widget.memGauge.SetValue(0)
5969
} else {
6070
memUsed := nodeData.MemUsage()
61-
62-
widget.inner.memGauge.Percent = int(math.Round(memUsed * 100.0))
63-
widget.inner.memGauge.Label = fmt.Sprintf("%.1f%%", memUsed*100.0)
71+
widget.memGauge.SetValue(int(math.Round(memUsed * 100.0)))
6472

6573
cpuUsed := nodeData.CPUUsageByName("usage")
66-
67-
widget.inner.cpuGauge.Percent = int(math.Round(cpuUsed * 100.0))
68-
widget.inner.cpuGauge.Label = fmt.Sprintf("%.1f%%", cpuUsed*100.0)
69-
}
70-
}
71-
72-
type systemGaugesInner struct {
73-
ui.Block
74-
75-
cpuGauge *widgets.Gauge
76-
memGauge *widgets.Gauge
77-
}
78-
79-
// Draw implements io.Drawable.
80-
func (widget *systemGaugesInner) Draw(buf *ui.Buffer) {
81-
width := widget.Dx()
82-
height := widget.Dy()
83-
84-
y := 0
85-
itemHeight := 2
86-
87-
for _, item := range []ui.Drawable{widget.cpuGauge, widget.memGauge} {
88-
item.SetRect(widget.Min.X, widget.Min.Y+y, widget.Min.X+width, widget.Min.Y+y+itemHeight+1)
89-
item.Draw(buf)
90-
91-
y += itemHeight
92-
93-
if y > height {
94-
break
95-
}
74+
widget.cpuGauge.SetValue(int(math.Round(cpuUsed * 100.0)))
9675
}
9776
}

0 commit comments

Comments
 (0)