Skip to content

Commit

Permalink
feat: fancy progress bar for updates
Browse files Browse the repository at this point in the history
  • Loading branch information
tulilirockz committed Dec 2, 2024
1 parent 9b642c5 commit 49c6cae
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 14 deletions.
49 changes: 35 additions & 14 deletions cmd/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os/exec"
"strings"

"github.com/jedib0t/go-pretty/v6/progress"
"github.com/spf13/cobra"
"github.com/ublue-os/uupd/checks"
"github.com/ublue-os/uupd/drv"
Expand Down Expand Up @@ -80,87 +81,107 @@ func Update(cmd *cobra.Command, args []string) {
}

totalSteps := brewUpdate + systemUpdate + 1 + len(users) + 1 + len(users) // system + Brew + Flatpak (users + root) + Distrobox (users + root)
currentStep := 0
pw := lib.NewProgressWriter()
pw.SetNumTrackersExpected(1)
go pw.Render()
// -1 because 0 index
tracker := lib.NewIncrementTracker(&progress.Tracker{Message: "Updating", Units: progress.UnitsDefault, Total: int64(totalSteps - 1)}, totalSteps-1)
pw.AppendTracker(tracker.Tracker)

failures := make(map[string]Failure)

if updateAvailable {
currentStep++
log.Printf("[%d/%d] Updating System (%s)", currentStep, totalSteps, systemDriver.Name)
tracker.IncrementSection()
lib.ChangeTrackerMessageFancy(pw, tracker, "Updating System")
out, err := systemDriver.Update()
if err != nil {
failures[systemDriver.Name] = Failure{
err,
string(out),
}
tracker.IncrementSectionError()
} else {
tracker.IncrementSection()
}
}

if brewUpdate == 1 {
currentStep++
log.Printf("[%d/%d] Updating CLI Apps (Brew)", currentStep, totalSteps)
lib.ChangeTrackerMessageFancy(pw, tracker, "Updating CLI apps (Brew)")
out, err := drv.BrewUpdate(brewUid)
if err != nil {
failures["Brew"] = Failure{
err,
string(out),
}
tracker.IncrementSectionError()
} else {
tracker.IncrementSection()
}
}

// Run flatpak updates
currentStep++
log.Printf("[%d/%d] Updating System Apps (Flatpak)", currentStep, totalSteps)
lib.ChangeTrackerMessageFancy(pw, tracker, "Updating System Apps (Flatpak)")
flatpakCmd := exec.Command("/usr/bin/flatpak", "update", "-y")
out, err := flatpakCmd.CombinedOutput()
if err != nil {
failures["Flatpak"] = Failure{
err,
string(out),
}
tracker.IncrementSectionError()
} else {
tracker.IncrementSection()
}
for _, user := range users {
currentStep++
log.Printf("[%d/%d] Updating Apps for User: %s (Flatpak)", currentStep, totalSteps, user.Name)
lib.ChangeTrackerMessageFancy(pw, tracker, fmt.Sprintf("Updating Apps for User: %s (Flatpak)", user.Name))
out, err := lib.RunUID(user.UID, []string{"/usr/bin/flatpak", "update", "-y"}, nil)
if err != nil {
failures[fmt.Sprintf("Flatpak User: %s", user.Name)] = Failure{
err,
string(out),
}
tracker.IncrementSectionError()
} else {
tracker.IncrementSection()
}
}

// Run distrobox updates
currentStep++
log.Printf("[%d/%d] Updating System Distroboxes", currentStep, totalSteps)
lib.ChangeTrackerMessageFancy(pw, tracker, "Updating System Distroboxes")
// distrobox doesn't support sudo, run with systemd-run
out, err = lib.RunUID(0, []string{"/usr/bin/distrobox", "upgrade", "-a"}, nil)
if err != nil {
failures["Distrobox"] = Failure{
err,
string(out),
}
tracker.IncrementSectionError()
} else {
tracker.IncrementSection()
}
for _, user := range users {
currentStep++
log.Printf("[%d/%d] Updating Distroboxes for User: %s", currentStep, totalSteps, user.Name)
lib.ChangeTrackerMessageFancy(pw, tracker, fmt.Sprintf("Updating Distroboxes for User: %s", user.Name))
out, err := lib.RunUID(user.UID, []string{"/usr/bin/distrobox", "upgrade", "-a"}, nil)
if err != nil {
failures[fmt.Sprintf("Distrobox User: %s", user.Name)] = Failure{
err,
string(out),
}
tracker.IncrementSectionError()
} else {
tracker.IncrementSection()
}
}

if len(failures) > 0 {
pw.SetAutoStop(false)
pw.Stop()
failedSystemsList := make([]string, 0, len(failures))
for systemName := range failures {
failedSystemsList = append(failedSystemsList, systemName)
}
failedSystemsStr := strings.Join(failedSystemsList, ", ")
lib.Notify("Updates failed", fmt.Sprintf("uupd failed to update: %s, consider seeing logs with `journalctl -exu uupd.service`", failedSystemsStr))

log.Printf("Updates Completed with Failures:")
for name, fail := range failures {
indentedOutput := "\t | "
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.22.9

require (
github.com/godbus/dbus/v5 v5.1.0
github.com/jedib0t/go-pretty/v6 v6.6.3
github.com/shirou/gopsutil/v4 v4.24.10
github.com/spf13/cobra v1.8.1
)
Expand All @@ -13,10 +14,13 @@ require (
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/term v0.17.0 // indirect
)
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jedib0t/go-pretty/v6 v6.6.3 h1:nGqgS0tgIO1Hto47HSaaK4ac/I/Bu7usmdD3qvs0WvM=
github.com/jedib0t/go-pretty/v6 v6.6.3/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil/v4 v4.24.10 h1:7VOzPtfw/5YDU+jLEoBwXwxJbQetULywoSV4RYY7HkM=
github.com/shirou/gopsutil/v4 v4.24.10/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8=
Expand All @@ -39,6 +45,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.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/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
84 changes: 84 additions & 0 deletions lib/percentmanager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package lib

import (
"github.com/jedib0t/go-pretty/v6/progress"
"github.com/jedib0t/go-pretty/v6/text"
"time"
)

type Incrementer struct {
doneIncrements int
MaxIncrements int
}

type IncrementTracker struct {
Tracker *progress.Tracker
incrementer *Incrementer
}

var CuteColors = progress.StyleColors{
Message: text.Colors{text.FgWhite},
Error: text.Colors{text.FgRed},
Percent: text.Colors{text.FgHiBlue},
Pinned: text.Colors{text.BgHiBlack, text.FgWhite, text.Bold},
Stats: text.Colors{text.FgHiBlack},
Time: text.Colors{text.FgBlue},
Tracker: text.Colors{text.FgHiBlue},
Value: text.Colors{text.FgBlue},
Speed: text.Colors{text.FgBlue},
}

func NewProgressWriter() progress.Writer {
pw := progress.NewWriter()
pw.SetTrackerLength(25)
pw.Style().Visibility.TrackerOverall = true
pw.Style().Visibility.Time = true
pw.Style().Visibility.Tracker = true
pw.Style().Visibility.Value = true
pw.SetMessageLength(32)
pw.SetSortBy(progress.SortByPercentDsc)
pw.SetStyle(progress.StyleBlocks)
pw.SetTrackerPosition(progress.PositionRight)
pw.SetUpdateFrequency(time.Millisecond * 100)
pw.Style().Options.PercentFormat = "%4.1f%%"
pw.Style().Colors = CuteColors
return pw
}

func NewIncrementTracker(tracker *progress.Tracker, max_increments int) *IncrementTracker {
return &IncrementTracker{
Tracker: tracker,
incrementer: &Incrementer{MaxIncrements: max_increments},
}
}

func ChangeTrackerMessageFancy(writer progress.Writer, tracker *IncrementTracker, message string) {
writer.SetMessageLength(len(message))
tracker.Tracker.UpdateMessage(message)
}

func (it *IncrementTracker) IncrementSection() {
var increment_step float64
if it.incrementer.doneIncrements == 0 {
increment_step = 1
} else {
increment_step = float64(it.Tracker.Total / int64(it.incrementer.MaxIncrements))
}
it.Tracker.Increment(int64(increment_step))
it.incrementer.doneIncrements++
}

func (it *IncrementTracker) IncrementSectionError() {
var increment_step float64
if it.incrementer.doneIncrements == 0 {
increment_step = 1
} else {
increment_step = float64(it.Tracker.Total / int64(it.incrementer.MaxIncrements))
}
it.Tracker.IncrementWithError(int64(increment_step))
it.incrementer.doneIncrements++
}

func (it *IncrementTracker) CurrentStep() int {
return it.incrementer.doneIncrements
}

0 comments on commit 49c6cae

Please sign in to comment.