From 9426b818d60b986cbd22289b50275b52270dca1d Mon Sep 17 00:00:00 2001 From: Joshua Blanch Date: Mon, 23 Dec 2024 11:08:22 +0000 Subject: [PATCH 1/5] monitor: add monitoring of cpu % of applications and use bubbletea as tui Signed-off-by: Joshua Blanch --- cmd/monitor.go | 220 +++++++++++++++++++++++++++++++++++++++---------- go.mod | 25 ++++-- go.sum | 87 +++++++++---------- 3 files changed, 232 insertions(+), 100 deletions(-) diff --git a/cmd/monitor.go b/cmd/monitor.go index 13e8d2f..4c548f2 100644 --- a/cmd/monitor.go +++ b/cmd/monitor.go @@ -1,11 +1,14 @@ package cmd import ( + "runtime" "fmt" - "github.com/rivo/tview" - "github.com/shirou/gopsutil/v3/cpu" - "github.com/shirou/gopsutil/v3/mem" - "github.com/shirou/gopsutil/v3/process" + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/shirou/gopsutil/v4/cpu" + "github.com/shirou/gopsutil/v4/mem" + "github.com/shirou/gopsutil/v4/process" "github.com/urfave/cli/v2" "sort" "time" @@ -26,55 +29,186 @@ $ goup profile `, } } -func profile(ctx *cli.Context) error { +type model struct { + processTable table.Model + cpuPercent float64 + memStats *mem.VirtualMemoryStat + err error +} + +type tickMsg struct{} + +func (m model) Init() tea.Cmd { + return tea.Batch( + tickCmd(), + ) +} - app := tview.NewApplication() - textView := tview.NewTextView().SetDynamicColors(true) +func tickCmd() tea.Cmd { + return tea.Tick(2*time.Second, func(t time.Time) tea.Msg { + return tickMsg{} + }) +} - go func() { - for { - // Fetch metrics - cpuPercent, _ := cpu.Percent(0, false) - memStats, _ := mem.VirtualMemory() +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + if msg.String() == "q" || msg.String() == "ctrl+c" { + return m, tea.Quit + } + case tickMsg: + var err error + cpuPercent, err := cpu.Percent(0, false) + if err != nil { + m.err = err + return m, nil + } + m.cpuPercent = cpuPercent[0] + + m.memStats, err = mem.VirtualMemory() + if err != nil { + m.err = err + return m, nil + } - // Fetch processes - procs, _ := process.Processes() - var procStats []string - for _, p := range procs { + // Update process table + procs, _ := process.Processes() + + // Pre-filter to only get processes with non-zero CPU usage + type procInfo struct { + name string + cpu float64 + io int32 + } + + procInfos := make([]procInfo, 0, 30) + for _, p := range procs { + cpu, _ := p.CPUPercent() + if cpu > 0.01 { // Only include processes with notable CPU usage name, _ := p.Name() - cpu, _ := p.CPUPercent() - procStats = append(procStats, fmt.Sprintf("%-20s %.2f%%", name, cpu)) + io, _ := p.IOnice() + procInfos = append(procInfos, procInfo{ + name: name, + cpu: cpu, + io: io, + }) } + } - // Sort processes by CPU usage - sort.Slice(procStats, func(i, j int) bool { - return procStats[i] > procStats[j] - }) + // Sort only the filtered processes + sort.Slice(procInfos, func(i, j int) bool { + return procInfos[i].cpu > procInfos[j].cpu + }) - // Display top 5 processes - topProcs := "" - for i := 0; i < 5 && i < len(procStats); i++ { - topProcs += procStats[i] + "\n" - } + // Take only top 30 + if len(procInfos) > 30 { + procInfos = procInfos[:30] + } - // Update display - stats := fmt.Sprintf( - "[yellow]CPU Usage:[white] %.2f%%\n[yellow]Memory Usage:[white] %.2f%% of %.2fGB\n\n[yellow]Top Processes:\n[white]%s", - cpuPercent[0], - memStats.UsedPercent, - float64(memStats.Total)/1e9, - topProcs, - ) - - app.QueueUpdateDraw(func() { - textView.SetText(stats) - }) - time.Sleep(1 * time.Second) + // Convert to table rows + rows := make([]table.Row, len(procInfos)) + for i, info := range procInfos { + rows[i] = table.Row{ + info.name, + fmt.Sprintf("%.2f%%", info.cpu), + fmt.Sprintf("%d", info.io), + } } - }() - if err := app.SetRoot(textView, true).Run(); err != nil { - return err + m.processTable.SetRows(rows) + return m, tickCmd() + } + + return m, nil +} + +func (m model) View() string { + if m.err != nil { + return fmt.Sprintf("Error: %v", m.err) } + + var memTotal float64 + var memUsed float64 + if m.memStats != nil { + memTotal = float64(m.memStats.Total) / 1e9 + memUsed = m.memStats.UsedPercent + } + + // Create styles + titleStyle := lipgloss.NewStyle(). + Bold(true). + Foreground(lipgloss.Color("205")). + MarginLeft(2) + + statsStyle := lipgloss.NewStyle(). + Foreground(lipgloss.Color("86")). + MarginLeft(2) + + docStyle := lipgloss.NewStyle(). + Padding(1, 2, 1, 2) + + // Create the header with stats + title := titleStyle.Render("System Monitor (press q to quit)") + stats := statsStyle.Render(fmt.Sprintf( + "CPU Usage: %.2f%% | Memory Usage: %.2f%% of %.2fGB", + m.cpuPercent, + memUsed, + memTotal, + )) + + // Create a border around the table + tableStyle := lipgloss.NewStyle(). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("240")). + Padding(0, 1) + + // Combine all elements + return docStyle.Render( + lipgloss.JoinVertical( + lipgloss.Left, + title, + stats, + "", // Empty line for spacing + tableStyle.Render(m.processTable.View()), + ), + ) +} + +func profile(ctx *cli.Context) error { + // Set GOMAXPROCS to limit CPU usage + runtime.GOMAXPROCS(2) + columns := []table.Column{ + {Title: "Process", Width: 30}, + {Title: "CPU%", Width: 10}, + {Title: "IO", Width: 10}, + } + + t := table.New( + table.WithColumns(columns), + table.WithFocused(true), + table.WithHeight(30), + ) + + s := table.DefaultStyles() + s.Header = s.Header. + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(lipgloss.Color("240")). + BorderBottom(true). + Bold(true) + t.SetStyles(s) + + m := model{ + processTable: t, + } + + p := tea.NewProgram( + m, + tea.WithAltScreen(), // Use alternate screen buffer + tea.WithMouseCellMotion(), // Enable mouse support + ) + if err := p.Start(); err != nil { + return fmt.Errorf("error running program: %v", err) + } + return nil } diff --git a/go.mod b/go.mod index 55e289e..2367690 100644 --- a/go.mod +++ b/go.mod @@ -3,28 +3,37 @@ module github.com/JoshuaGabriel/goup go 1.20 require ( - github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592 - github.com/shirou/gopsutil/v3 v3.24.5 + github.com/charmbracelet/bubbles v0.20.0 + github.com/charmbracelet/bubbletea v1.2.4 + github.com/charmbracelet/lipgloss v1.0.0 + github.com/shirou/gopsutil/v4 v4.24.11 github.com/urfave/cli/v2 v2.27.5 ) require ( + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/charmbracelet/x/ansi v0.4.5 // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect - github.com/gdamore/encoding v1.0.0 // indirect - github.com/gdamore/tcell/v2 v2.7.1 // indirect + github.com/ebitengine/purego v0.8.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.8.0 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index 68a934d..d1f55d7 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,24 @@ +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= +github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= +github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= +github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE= +github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM= +github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= +github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= +github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= +github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= -github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell/v2 v2.7.1 h1:TiCcmpWHiAU7F0rA2I3S2Y4mmLmO9KHxJ7E1QhYzQbc= -github.com/gdamore/tcell/v2 v2.7.1/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= +github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE= +github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -13,24 +27,28 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -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-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-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +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/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592 h1:YIJ+B1hePP6AgynC5TcqpO0H9k3SSoZa2BGyL6vDUzM= -github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.3/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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= -github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= -github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shirou/gopsutil/v4 v4.24.11 h1:WaU9xqGFKvFfsUv94SXcUPD7rCkU0vr/asVdQOBZNj8= +github.com/shirou/gopsutil/v4 v4.24.11/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= @@ -40,46 +58,17 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 10456c581b0fd0f9ccfdb2451fb795403a7524f4 Mon Sep 17 00:00:00 2001 From: Joshua Blanch Date: Mon, 23 Dec 2024 11:24:06 +0000 Subject: [PATCH 2/5] monitor: add network and disk usage into profile command Signed-off-by: Joshua Blanch --- cmd/monitor.go | 228 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 184 insertions(+), 44 deletions(-) diff --git a/cmd/monitor.go b/cmd/monitor.go index 4c548f2..d9e00be 100644 --- a/cmd/monitor.go +++ b/cmd/monitor.go @@ -3,11 +3,14 @@ package cmd import ( "runtime" "fmt" + "path/filepath" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/shirou/gopsutil/v4/cpu" + "github.com/shirou/gopsutil/v4/disk" "github.com/shirou/gopsutil/v4/mem" + "github.com/shirou/gopsutil/v4/net" "github.com/shirou/gopsutil/v4/process" "github.com/urfave/cli/v2" "sort" @@ -30,10 +33,16 @@ $ goup profile } } type model struct { - processTable table.Model - cpuPercent float64 - memStats *mem.VirtualMemoryStat - err error + processTable table.Model + diskTable table.Model + networkTable table.Model + cpuPercent float64 + memStats *mem.VirtualMemoryStat + diskStats map[string]disk.UsageStat + networkStats map[string]net.IOCountersStat + lastNetStats map[string]net.IOCountersStat + lastCheckTime time.Time + err error } type tickMsg struct{} @@ -58,6 +67,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } case tickMsg: var err error + + // CPU Usage cpuPercent, err := cpu.Percent(0, false) if err != nil { m.err = err @@ -65,12 +76,82 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } m.cpuPercent = cpuPercent[0] + // Memory Stats m.memStats, err = mem.VirtualMemory() if err != nil { m.err = err return m, nil } + // Disk Stats + partitions, err := disk.Partitions(false) + if err != nil { + m.err = err + return m, nil + } + + m.diskStats = make(map[string]disk.UsageStat) + for _, partition := range partitions { + usage, err := disk.Usage(partition.Mountpoint) + if err != nil { + continue + } + m.diskStats[partition.Mountpoint] = *usage + } + + // Network Stats + m.lastNetStats = m.networkStats + m.lastCheckTime = time.Now() + + netStats, err := net.IOCounters(true) + if err != nil { + m.err = err + return m, nil + } + + m.networkStats = make(map[string]net.IOCountersStat) + for _, stat := range netStats { + if stat.Name != "lo" { // Skip loopback interface + m.networkStats[stat.Name] = stat + } + } + + // Update disk table + var diskRows []table.Row + for path, usage := range m.diskStats { + diskName := filepath.Base(path) + usedGB := float64(usage.Used) / 1e9 + totalGB := float64(usage.Total) / 1e9 + diskRows = append(diskRows, table.Row{ + diskName, + fmt.Sprintf("%.1f GB", usedGB), + fmt.Sprintf("%.1f GB", totalGB), + fmt.Sprintf("%.1f%%", usage.UsedPercent), + }) + } + m.diskTable.SetRows(diskRows) + + // Update network table + var networkRows []table.Row + for iface, stat := range m.networkStats { + if m.lastNetStats != nil { + if lastStat, ok := m.lastNetStats[iface]; ok { + duration := time.Since(m.lastCheckTime).Seconds() + if duration > 0 { + bytesInPerSec := float64(stat.BytesRecv-lastStat.BytesRecv) / duration + bytesOutPerSec := float64(stat.BytesSent-lastStat.BytesSent) / duration + + networkRows = append(networkRows, table.Row{ + iface, + fmt.Sprintf("%.1f MB/s", bytesInPerSec/1e6), + fmt.Sprintf("%.1f MB/s", bytesOutPerSec/1e6), + }) + } + } + } + } + m.networkTable.SetRows(networkRows) + // Update process table procs, _ := process.Processes() @@ -134,7 +215,7 @@ func (m model) View() string { memUsed = m.memStats.UsedPercent } - // Create styles + // Styles titleStyle := lipgloss.NewStyle(). Bold(true). Foreground(lipgloss.Color("205")). @@ -144,61 +225,120 @@ func (m model) View() string { Foreground(lipgloss.Color("86")). MarginLeft(2) - docStyle := lipgloss.NewStyle(). - Padding(1, 2, 1, 2) + boxStyle := lipgloss.NewStyle(). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("240")). + Padding(0, 1). + MarginRight(2) + + sectionTitleStyle := lipgloss.NewStyle(). + Bold(true). + Foreground(lipgloss.Color("99")) - // Create the header with stats + // Header section title := titleStyle.Render("System Monitor (press q to quit)") stats := statsStyle.Render(fmt.Sprintf( - "CPU Usage: %.2f%% | Memory Usage: %.2f%% of %.2fGB", + "CPU Usage: %.2f%% | Memory: %.1f%% of %.1fGB used", m.cpuPercent, memUsed, memTotal, )) - // Create a border around the table - tableStyle := lipgloss.NewStyle(). - BorderStyle(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("240")). - Padding(0, 1) - - // Combine all elements - return docStyle.Render( - lipgloss.JoinVertical( - lipgloss.Left, - title, - stats, - "", // Empty line for spacing - tableStyle.Render(m.processTable.View()), - ), + // Create flexbox columns for tables + leftColumn := lipgloss.JoinVertical( + lipgloss.Left, + sectionTitleStyle.Render("Processes"), + boxStyle.Render(m.processTable.View()), + ) + + rightColumn := lipgloss.JoinVertical( + lipgloss.Left, + sectionTitleStyle.Render("Disk Usage"), + boxStyle.Render(m.diskTable.View()), + "", + sectionTitleStyle.Render("Network Activity"), + boxStyle.Render(m.networkTable.View()), + ) + + // Join columns side by side + tables := lipgloss.JoinHorizontal( + lipgloss.Top, + leftColumn, + rightColumn, + ) + + // Final layout + return lipgloss.JoinVertical( + lipgloss.Left, + title, + stats, + "", + tables, ) } func profile(ctx *cli.Context) error { // Set GOMAXPROCS to limit CPU usage runtime.GOMAXPROCS(2) - columns := []table.Column{ - {Title: "Process", Width: 30}, - {Title: "CPU%", Width: 10}, - {Title: "IO", Width: 10}, - } - - t := table.New( - table.WithColumns(columns), - table.WithFocused(true), - table.WithHeight(30), - ) - - s := table.DefaultStyles() - s.Header = s.Header. - BorderStyle(lipgloss.NormalBorder()). - BorderForeground(lipgloss.Color("240")). - BorderBottom(true). - Bold(true) - t.SetStyles(s) + + // Process table + processColumns := []table.Column{ + {Title: "Process", Width: 30}, + {Title: "CPU%", Width: 10}, + {Title: "IO", Width: 10}, + } + + processTable := table.New( + table.WithColumns(processColumns), + table.WithFocused(true), + table.WithHeight(20), + ) + + // Disk table + diskColumns := []table.Column{ + {Title: "Mount", Width: 15}, + {Title: "Used", Width: 10}, + {Title: "Total", Width: 10}, + {Title: "Usage%", Width: 10}, + } + + diskTable := table.New( + table.WithColumns(diskColumns), + table.WithHeight(10), + ) + + // Network table + networkColumns := []table.Column{ + {Title: "Interface", Width: 15}, + {Title: "Download", Width: 15}, + {Title: "Upload", Width: 15}, + } + + networkTable := table.New( + table.WithColumns(networkColumns), + table.WithHeight(8), + ) + + // Common table styles + s := table.DefaultStyles() + s.Header = s.Header. + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(lipgloss.Color("240")). + BorderBottom(true). + Bold(true) + + processTable.SetStyles(s) + diskTable.SetStyles(s) + networkTable.SetStyles(s) m := model{ - processTable: t, + processTable: processTable, + diskTable: diskTable, + networkTable: networkTable, + diskStats: make(map[string]disk.UsageStat), + networkStats: make(map[string]net.IOCountersStat), + lastNetStats: make(map[string]net.IOCountersStat), + lastCheckTime: time.Now(), } p := tea.NewProgram( From 8911bd44af5c453b845f56584fe395922404e452 Mon Sep 17 00:00:00 2001 From: Joshua Blanch Date: Mon, 23 Dec 2024 13:43:46 +0000 Subject: [PATCH 3/5] monitor: go fmt Signed-off-by: Joshua Blanch --- cmd/monitor.go | 121 +++++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/cmd/monitor.go b/cmd/monitor.go index d9e00be..4626bc7 100644 --- a/cmd/monitor.go +++ b/cmd/monitor.go @@ -1,9 +1,7 @@ package cmd import ( - "runtime" "fmt" - "path/filepath" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" @@ -13,6 +11,8 @@ import ( "github.com/shirou/gopsutil/v4/net" "github.com/shirou/gopsutil/v4/process" "github.com/urfave/cli/v2" + "path/filepath" + "runtime" "sort" "time" ) @@ -32,8 +32,9 @@ $ goup profile `, } } + type model struct { - processTable table.Model + processTable table.Model diskTable table.Model networkTable table.Model cpuPercent float64 @@ -67,7 +68,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } case tickMsg: var err error - + // CPU Usage cpuPercent, err := cpu.Percent(0, false) if err != nil { @@ -102,13 +103,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Network Stats m.lastNetStats = m.networkStats m.lastCheckTime = time.Now() - + netStats, err := net.IOCounters(true) if err != nil { m.err = err return m, nil } - + m.networkStats = make(map[string]net.IOCountersStat) for _, stat := range netStats { if stat.Name != "lo" { // Skip loopback interface @@ -140,7 +141,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if duration > 0 { bytesInPerSec := float64(stat.BytesRecv-lastStat.BytesRecv) / duration bytesOutPerSec := float64(stat.BytesSent-lastStat.BytesSent) / duration - + networkRows = append(networkRows, table.Row{ iface, fmt.Sprintf("%.1f MB/s", bytesInPerSec/1e6), @@ -154,14 +155,14 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Update process table procs, _ := process.Processes() - + // Pre-filter to only get processes with non-zero CPU usage type procInfo struct { name string cpu float64 io int32 } - + procInfos := make([]procInfo, 0, 30) for _, p := range procs { cpu, _ := p.CPUPercent() @@ -280,59 +281,59 @@ func (m model) View() string { func profile(ctx *cli.Context) error { // Set GOMAXPROCS to limit CPU usage runtime.GOMAXPROCS(2) - - // Process table - processColumns := []table.Column{ - {Title: "Process", Width: 30}, - {Title: "CPU%", Width: 10}, - {Title: "IO", Width: 10}, - } - - processTable := table.New( - table.WithColumns(processColumns), - table.WithFocused(true), - table.WithHeight(20), - ) - - // Disk table - diskColumns := []table.Column{ - {Title: "Mount", Width: 15}, - {Title: "Used", Width: 10}, - {Title: "Total", Width: 10}, - {Title: "Usage%", Width: 10}, - } - - diskTable := table.New( - table.WithColumns(diskColumns), - table.WithHeight(10), - ) - - // Network table - networkColumns := []table.Column{ - {Title: "Interface", Width: 15}, - {Title: "Download", Width: 15}, - {Title: "Upload", Width: 15}, - } - - networkTable := table.New( - table.WithColumns(networkColumns), - table.WithHeight(8), - ) - - // Common table styles - s := table.DefaultStyles() - s.Header = s.Header. - BorderStyle(lipgloss.NormalBorder()). - BorderForeground(lipgloss.Color("240")). - BorderBottom(true). - Bold(true) - - processTable.SetStyles(s) - diskTable.SetStyles(s) - networkTable.SetStyles(s) + + // Process table + processColumns := []table.Column{ + {Title: "Process", Width: 30}, + {Title: "CPU%", Width: 10}, + {Title: "IO", Width: 10}, + } + + processTable := table.New( + table.WithColumns(processColumns), + table.WithFocused(true), + table.WithHeight(20), + ) + + // Disk table + diskColumns := []table.Column{ + {Title: "Mount", Width: 15}, + {Title: "Used", Width: 10}, + {Title: "Total", Width: 10}, + {Title: "Usage%", Width: 10}, + } + + diskTable := table.New( + table.WithColumns(diskColumns), + table.WithHeight(10), + ) + + // Network table + networkColumns := []table.Column{ + {Title: "Interface", Width: 15}, + {Title: "Download", Width: 15}, + {Title: "Upload", Width: 15}, + } + + networkTable := table.New( + table.WithColumns(networkColumns), + table.WithHeight(8), + ) + + // Common table styles + s := table.DefaultStyles() + s.Header = s.Header. + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(lipgloss.Color("240")). + BorderBottom(true). + Bold(true) + + processTable.SetStyles(s) + diskTable.SetStyles(s) + networkTable.SetStyles(s) m := model{ - processTable: processTable, + processTable: processTable, diskTable: diskTable, networkTable: networkTable, diskStats: make(map[string]disk.UsageStat), From f6367861d12914dfbb10c1a93a02506fea6ab2c5 Mon Sep 17 00:00:00 2001 From: Joshua Blanch Date: Tue, 24 Dec 2024 00:08:34 +0000 Subject: [PATCH 4/5] scan: hello world tview example Signed-off-by: Joshua Blanch --- cmd/main.go | 1 + cmd/scan.go | 34 ++++++++++++++++++++++++++++++++++ go.mod | 4 ++++ go.sum | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 cmd/scan.go diff --git a/cmd/main.go b/cmd/main.go index 05c10cc..e4ad067 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,6 +19,7 @@ func Main(args []string) error { EnableBashCompletion: true, Commands: []*cli.Command{ cmdMonitor(), + cmdScan(), }, } diff --git a/cmd/scan.go b/cmd/scan.go new file mode 100644 index 0000000..5d1f100 --- /dev/null +++ b/cmd/scan.go @@ -0,0 +1,34 @@ +package cmd + +import ( + "fmt" + // "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" + // "github.com/shirou/gopsutil/v4/cpu" + // "github.com/shirou/gopsutil/v4/mem" + "github.com/urfave/cli/v2" + // "time" +) + +func cmdScan() *cli.Command { + return &cli.Command{ + Name: "scan", + Action: scanResource, + Usage: "Show resource usage of system", + Description: ` +Resource monitoring tools + +Examples: +# Monitor real time operations with tview +$ goup scan +`, + } +} + +func scanResource(ctx *cli.Context) error { + box := tview.NewBox().SetBorder(true).SetTitle("Hello, world!") + if err := tview.NewApplication().SetRoot(box, true).Run(); err != nil { + return fmt.Errorf("application error: %w", err) + } + return nil +} diff --git a/go.mod b/go.mod index 2367690..7bfa28d 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,8 @@ require ( github.com/charmbracelet/bubbles v0.20.0 github.com/charmbracelet/bubbletea v1.2.4 github.com/charmbracelet/lipgloss v1.0.0 + github.com/gdamore/tcell/v2 v2.7.4 + github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592 github.com/shirou/gopsutil/v4 v4.24.11 github.com/urfave/cli/v2 v2.27.5 ) @@ -17,6 +19,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/ebitengine/purego v0.8.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/gdamore/encoding v1.0.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect @@ -35,5 +38,6 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index d1f55d7..b5d18e1 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,10 @@ github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/ github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= +github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -31,6 +35,7 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +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/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= @@ -42,7 +47,10 @@ github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1n github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592 h1:YIJ+B1hePP6AgynC5TcqpO0H9k3SSoZa2BGyL6vDUzM= +github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3/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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -58,17 +66,50 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/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-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 656ceb348d287f0d3462f6722a0f7290d65d9afa Mon Sep 17 00:00:00 2001 From: Joshua Blanch Date: Tue, 24 Dec 2024 00:13:05 +0000 Subject: [PATCH 5/5] bump Signed-off-by: Joshua Blanch --- go.mod | 2 +- go.sum | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 7bfa28d..a415b71 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/charmbracelet/bubbles v0.20.0 github.com/charmbracelet/bubbletea v1.2.4 github.com/charmbracelet/lipgloss v1.0.0 - github.com/gdamore/tcell/v2 v2.7.4 github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592 github.com/shirou/gopsutil/v4 v4.24.11 github.com/urfave/cli/v2 v2.27.5 @@ -20,6 +19,7 @@ require ( github.com/ebitengine/purego v0.8.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/gdamore/encoding v1.0.0 // indirect + github.com/gdamore/tcell/v2 v2.7.4 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect diff --git a/go.sum b/go.sum index 842cb00..b5d18e1 100644 --- a/go.sum +++ b/go.sum @@ -47,7 +47,10 @@ github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1n github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592 h1:YIJ+B1hePP6AgynC5TcqpO0H9k3SSoZa2BGyL6vDUzM= +github.com/rivo/tview v0.0.0-20241103174730-c76f7879f592/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3/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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -63,6 +66,7 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -80,6 +84,7 @@ golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/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-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -101,5 +106,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=