From d64b17aecc8c1ff7e016c2ba5ddad870eabf3b8f Mon Sep 17 00:00:00 2001 From: Tulip Blossom Date: Sun, 15 Dec 2024 19:02:35 -0300 Subject: [PATCH 1/6] feat: initial testing for system and filelock + adaptations --- cmd/update.go | 16 +++++++----- drv/brew.go | 33 +++++------------------ drv/generic.go | 5 ---- drv/system.go | 39 ++++++++++++++++------------ drv/system_test.go | 46 ++++++++++++++++++++++++++++++++ justfile | 8 ++++++ pkg/filelock/filelock.go | 49 ++++++++++++++++++++--------------- pkg/filelock/filelock_test.go | 48 ++++++++++++++++++++++++++++++++++ 8 files changed, 169 insertions(+), 75 deletions(-) create mode 100644 drv/system_test.go create mode 100644 pkg/filelock/filelock_test.go diff --git a/cmd/update.go b/cmd/update.go index 84c13f3..d0f636c 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -15,17 +15,21 @@ import ( ) func Update(cmd *cobra.Command, args []string) { - lock, err := filelock.AcquireLock() + lockfile, err := filelock.OpenLockfile(filelock.GetDefaultLockfile()) if err != nil { - slog.Error(fmt.Sprintf("%v, is uupd already running?", err)) + slog.Error("Failed creating and opening lockfile. Is uupd already running?", slog.Any("error", err)) return } - defer func() { - err := filelock.ReleaseLock(lock) + defer func(lockfile *os.File) { + err := filelock.ReleaseLock(lockfile) if err != nil { - slog.Error("Failed releasing lock") + slog.Error("Failed releasing lock", slog.Any("error", err)) } - }() + }(lockfile) + if err := filelock.AcquireLock(lockfile, filelock.TimeoutConfig{Tries: 5}); err != nil { + slog.Error(fmt.Sprintf("%v, is uupd already running?", err)) + return + } hwCheck, err := cmd.Flags().GetBool("hw-check") if err != nil { diff --git a/drv/brew.go b/drv/brew.go index f934d91..5f880e5 100644 --- a/drv/brew.go +++ b/drv/brew.go @@ -50,8 +50,9 @@ func (up BrewUpdater) Update() (*[]CommandOutput, error) { tmpout.Context = "Brew Update" tmpout.Cli = cli tmpout.Failure = err != nil - if err != nil { - tmpout.SetFailureContext("Brew update") + if failure := err != nil; failure { + tmpout.Failure = failure + tmpout.Context = "Brew Update" final_output = append(final_output, *tmpout) return &final_output, err } @@ -86,30 +87,10 @@ func (up BrewUpdater) New(config UpdaterInitConfiguration) (BrewUpdater, error) } up.Config.logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) - brewPrefix, exists := up.Config.Environment["HOMEBREW_PREFIX"] - if !exists || brewPrefix == "" { - up.BrewPrefix = "/home/linuxbrew/.linuxbrew" - } else { - up.BrewPrefix = brewPrefix - } - brewRepo, exists := up.Config.Environment["HOMEBREW_REPOSITORY"] - if !exists || brewRepo == "" { - up.BrewRepo = fmt.Sprintf("%s/Homebrew", up.BrewPrefix) - } else { - up.BrewRepo = brewRepo - } - brewCellar, exists := up.Config.Environment["HOMEBREW_CELLAR"] - if !exists || brewCellar == "" { - up.BrewCellar = fmt.Sprintf("%s/Cellar", up.BrewPrefix) - } else { - up.BrewCellar = brewCellar - } - brewPath, exists := up.Config.Environment["HOMEBREW_PATH"] - if !exists || brewPath == "" { - up.BrewPath = fmt.Sprintf("%s/bin/brew", up.BrewPrefix) - } else { - up.BrewPath = brewPath - } + up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_PREFIX", "/home/linuxbrew/.linuxbrew") + up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_REPOSITORY", fmt.Sprintf("%s/Homebrew", up.BrewPrefix)) + up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_CELLAR", fmt.Sprintf("%s/Cellar", up.BrewPrefix)) + up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_PATH", fmt.Sprintf("%s/bin/brew", up.BrewPrefix)) if up.Config.DryRun { return up, nil diff --git a/drv/generic.go b/drv/generic.go index ae0e4c7..70ec784 100644 --- a/drv/generic.go +++ b/drv/generic.go @@ -60,11 +60,6 @@ func (output CommandOutput) New(out []byte, err error) *CommandOutput { } } -func (out *CommandOutput) SetFailureContext(context string) { - out.Failure = true - out.Context = context -} - type DriverConfiguration struct { Title string Description string diff --git a/drv/system.go b/drv/system.go index 3cf6cc6..9b13c1d 100644 --- a/drv/system.go +++ b/drv/system.go @@ -43,27 +43,33 @@ type SystemUpdater struct { BinaryPath string } +// Checks if it is at least a month old considering how that works +func IsOutdatedOneMonthTimestamp(current time.Time, target time.Time) bool { + return target.Before(current.AddDate(0, -1, 0)) +} + func (up SystemUpdater) Outdated() (bool, error) { if up.Config.DryRun { return false, nil } - oneMonthAgo := time.Now().AddDate(0, -1, 0) - var timestamp time.Time + cmd := exec.Command(up.BinaryPath, "status", "--format=json") out, err := cmd.CombinedOutput() if err != nil { return false, err } + var status bootcStatus err = json.Unmarshal(out, &status) if err != nil { return false, err } - timestamp, err = time.Parse(time.RFC3339Nano, status.Status.Booted.Image.Timestamp) + + timestamp, err := time.Parse(time.RFC3339Nano, status.Status.Booted.Image.Timestamp) if err != nil { return false, nil } - return timestamp.Before(oneMonthAgo), nil + return IsOutdatedOneMonthTimestamp(time.Now(), timestamp), nil } func (up SystemUpdater) Update() (*[]CommandOutput, error) { @@ -75,9 +81,8 @@ func (up SystemUpdater) Update() (*[]CommandOutput, error) { cmd = exec.Command(cli[0], cli[1:]...) out, err := session.RunLog(up.Config.logger, slog.LevelDebug, cmd) tmpout := CommandOutput{}.New(out, err) - if err != nil { - tmpout.SetFailureContext("System update") - } + tmpout.Failure = err != nil + tmpout.Context = "System Update" finalOutput = append(finalOutput, *tmpout) return &finalOutput, err } @@ -89,6 +94,14 @@ func (up SystemUpdater) Steps() int { return 0 } +func EnvOrFallback(environment EnvironmentMap, key string, fallback string) string { + validCase, exists := environment[key] + if exists && validCase != "" { + return validCase + } + return fallback +} + func (up SystemUpdater) New(config UpdaterInitConfiguration) (SystemUpdater, error) { up.Config = DriverConfiguration{ Title: "System", @@ -98,16 +111,7 @@ func (up SystemUpdater) New(config UpdaterInitConfiguration) (SystemUpdater, err Environment: config.Environment, } up.Config.logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) - if up.Config.DryRun { - return up, nil - } - - bootcBinaryPath, exists := up.Config.Environment["UUPD_BOOTC_BINARY"] - if !exists || bootcBinaryPath == "" { - up.BinaryPath = "/usr/bin/bootc" - } else { - up.BinaryPath = bootcBinaryPath - } + up.BinaryPath = EnvOrFallback(config.Environment, "UUPD_BOOTC_BINARY", "/usr/bin/bootc") return up, nil } @@ -122,6 +126,7 @@ func (up SystemUpdater) Check() (bool, error) { if err != nil { return true, err } + updateNecessary := !strings.Contains(string(out), "No changes in:") up.Config.logger.Debug("Executed update check", slog.String("output", string(out)), slog.Bool("update", updateNecessary)) return updateNecessary, nil diff --git a/drv/system_test.go b/drv/system_test.go new file mode 100644 index 0000000..8893dc9 --- /dev/null +++ b/drv/system_test.go @@ -0,0 +1,46 @@ +package drv_test + +import ( + "testing" + + "github.com/ublue-os/uupd/drv" + appLogging "github.com/ublue-os/uupd/pkg/logging" +) + +func InitBaseConfig() drv.SystemUpdater { + var initConfiguration = drv.UpdaterInitConfiguration{ + DryRun: false, + Ci: false, + Verbose: false, + Environment: nil, + Logger: appLogging.NewMuteLogger(), + } + driv, _ := drv.SystemUpdater{}.New(initConfiguration) + return driv +} + +func TestProperSteps(t *testing.T) { + systemUpdater := InitBaseConfig() + systemUpdater.Config.Enabled = false + + if systemUpdater.Steps() != 0 { + t.Fatalf("Expected no steps when module is disabled") + } + + systemUpdater.Config.Enabled = true + if systemUpdater.Steps() == 0 { + t.Fatalf("Expected steps to be added") + } +} + +func TestFallBack(t *testing.T) { + var environment drv.EnvironmentMap = drv.EnvironmentMap{ + "TEST_FALLBACK_GOOD": "true", + } + if value := drv.EnvOrFallback(environment, "TEST_FALLBACK_GOOD", "FALSE"); value != "true" { + t.Fatalf("Getting the proper value fails, %s", value) + } + if value := drv.EnvOrFallback(environment, "TEST_FALLBACK_BAD", "FALSE"); value != "FALSE" { + t.Fatalf("Getting the fallback fails, %s", value) + } +} diff --git a/justfile b/justfile index 1d16408..dea3859 100644 --- a/justfile +++ b/justfile @@ -76,3 +76,11 @@ lint: release: goreleaser + +test: + go test -v -cover ./... + +test-interactive: + #!/usr/bin/env bash + t="/tmp/go-cover.$$.tmp" + go test -v -coverprofile=$t ./... $@ && go tool cover -html=$t && unlink $t diff --git a/pkg/filelock/filelock.go b/pkg/filelock/filelock.go index 88d6147..a9ffe76 100644 --- a/pkg/filelock/filelock.go +++ b/pkg/filelock/filelock.go @@ -1,20 +1,14 @@ package filelock import ( - "fmt" - "io" + "errors" "os" "syscall" "time" ) -const fileLockPath string = "/run/uupd.lock" - func IsFileLocked(file *os.File) bool { - lock := syscall.Flock_t{ - Type: syscall.F_WRLCK, - Whence: io.SeekStart, - } + lock := syscall.Flock_t{} err := syscall.FcntlFlock(file.Fd(), syscall.F_GETLK, &lock) if err != nil { return false @@ -22,34 +16,47 @@ func IsFileLocked(file *os.File) bool { return lock.Type != syscall.F_UNLCK } -func AcquireLock() (*os.File, error) { - file, err := os.OpenFile(fileLockPath, os.O_RDONLY|os.O_CREATE|os.O_TRUNC, 0600) +func GetDefaultLockfile() string { + return "/run/uupd.lock" +} + +func OpenLockfile(filepath string) (*os.File, error) { + file, err := os.OpenFile(filepath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666) if err != nil { return nil, err } + return file, err +} + +type TimeoutConfig struct { + Tries int +} - timeout := 5.0 - startTime := time.Now() - var lockFile *os.File +func AcquireLock(file *os.File, timeout TimeoutConfig) error { + maxTries := timeout.Tries + tries := 0 + fileLocked := false - for time.Since(startTime).Seconds() < timeout { - err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) - if err == nil { - lockFile = file + for tries < maxTries { + err := syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) + if fileLocked = err == nil; fileLocked { break } + tries += 1 time.Sleep(1 * time.Second) } - if lockFile == nil { - file.Close() - return nil, fmt.Errorf("Could not acquire lock at %s", fileLockPath) + if !fileLocked { + return errors.New("Could not acquire lock to file") } - return lockFile, nil + return nil } func ReleaseLock(file *os.File) error { + if err := syscall.Flock(int(file.Fd()), syscall.LOCK_UN); err != nil { + return err + } return syscall.Close(int(file.Fd())) } diff --git a/pkg/filelock/filelock_test.go b/pkg/filelock/filelock_test.go new file mode 100644 index 0000000..86d5373 --- /dev/null +++ b/pkg/filelock/filelock_test.go @@ -0,0 +1,48 @@ +package filelock_test + +import ( + "testing" + + "github.com/ublue-os/uupd/pkg/filelock" +) + +const LockForTest = "/tmp/uupd-sigmatest.lock" + +var defaultTimeout = filelock.TimeoutConfig{1} + +func TestFullLock(t *testing.T) { + file, err := filelock.OpenLockfile(LockForTest) + if err != nil { + t.Fatalf("Failed even opening the file, %v", err) + } + defer file.Close() + err = filelock.AcquireLock(file, defaultTimeout) + if err != nil { + t.Fatalf("Failed acquiring lock file, %v", err) + } + err = filelock.ReleaseLock(file) + if err != nil { + t.Fatal("Failed releasing lock file") + } +} + +func TestLockAcquired(t *testing.T) { + file1, err := filelock.OpenLockfile(LockForTest) + if err != nil { + t.Fatalf("Failed even opening the file, %v", err) + } + defer file1.Close() + err = filelock.AcquireLock(file1, defaultTimeout) + if err != nil { + t.Fatalf("Failed acquiring lock file, %v", err) + } + file2, err := filelock.OpenLockfile(LockForTest) + if err != nil { + t.Fatalf("Failed even opening the file, %v", err) + } + defer file2.Close() + err = filelock.AcquireLock(file2, defaultTimeout) + if err == nil { + t.Fatalf("Expected failing to lock file, %v", err) + } +} From 8731b3cb8aeeb825d25e1fbec915eabda2571ae5 Mon Sep 17 00:00:00 2001 From: Tulip Blossom Date: Sun, 15 Dec 2024 22:41:40 -0300 Subject: [PATCH 2/6] feat: enable both system modules for imageOutdated and updateCheck + move drivers to their own modules --- cmd/imageOutdated.go | 20 ++++- cmd/update.go | 56 +++++--------- cmd/updateCheck.go | 40 +++------- drv/{ => brew}/brew.go | 17 ++--- drv/{ => distrobox}/distrobox.go | 17 ++--- drv/{ => flatpak}/flatpak.go | 17 ++--- drv/{ => generic}/generic.go | 12 ++- drv/generic/generic_test.go | 19 +++++ drv/{rpm-ostree.go => rpmostree/rpmostree.go} | 36 ++------- drv/{ => system}/system.go | 75 ++++++++++++++----- drv/system/system_test.go | 35 +++++++++ drv/system_test.go | 46 ------------ uupd.spec | 3 +- 13 files changed, 186 insertions(+), 207 deletions(-) rename drv/{ => brew}/brew.go (87%) rename drv/{ => distrobox}/distrobox.go (88%) rename drv/{ => flatpak}/flatpak.go (89%) rename drv/{ => generic}/generic.go (87%) create mode 100644 drv/generic/generic_test.go rename drv/{rpm-ostree.go => rpmostree/rpmostree.go} (75%) rename drv/{ => system}/system.go (60%) create mode 100644 drv/system/system_test.go delete mode 100644 drv/system_test.go diff --git a/cmd/imageOutdated.go b/cmd/imageOutdated.go index 2e3e9bb..43b90a3 100644 --- a/cmd/imageOutdated.go +++ b/cmd/imageOutdated.go @@ -4,15 +4,27 @@ import ( "log/slog" "github.com/spf13/cobra" - "github.com/ublue-os/uupd/drv" + "github.com/ublue-os/uupd/drv/generic" + "github.com/ublue-os/uupd/drv/system" ) func ImageOutdated(cmd *cobra.Command, args []string) { - systemUpdater, err := drv.SystemUpdater{}.New(drv.UpdaterInitConfiguration{}) + initConfiguration := generic.UpdaterInitConfiguration{}.New() + initConfiguration.Ci = false + initConfiguration.DryRun = false + initConfiguration.Verbose = false + + mainSystemDriver, _, _, err := system.InitializeSystemDriver(*initConfiguration) if err != nil { - slog.Error("Failed getting system driver", slog.Any("error", err)) + slog.Error("Failed") return } - println(systemUpdater.Outdated) + systemOutdated, err := mainSystemDriver.Outdated() + + if err != nil { + slog.Error("Failed checking if system is out of date") + } + + println(systemOutdated) } diff --git a/cmd/update.go b/cmd/update.go index d0f636c..28ede9d 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -8,7 +8,12 @@ import ( "github.com/jedib0t/go-pretty/v6/progress" "github.com/spf13/cobra" "github.com/ublue-os/uupd/checks" - "github.com/ublue-os/uupd/drv" + "github.com/ublue-os/uupd/drv/brew" + "github.com/ublue-os/uupd/drv/distrobox" + "github.com/ublue-os/uupd/drv/flatpak" + drv "github.com/ublue-os/uupd/drv/generic" + "github.com/ublue-os/uupd/drv/system" + "github.com/ublue-os/uupd/pkg/filelock" "github.com/ublue-os/uupd/pkg/percent" "github.com/ublue-os/uupd/pkg/session" @@ -68,56 +73,29 @@ func Update(cmd *cobra.Command, args []string) { initConfiguration.DryRun = dryRun initConfiguration.Verbose = verboseRun - brewUpdater, err := drv.BrewUpdater{}.New(*initConfiguration) + brewUpdater, err := brew.BrewUpdater{}.New(*initConfiguration) brewUpdater.Config.Enabled = err == nil - flatpakUpdater, err := drv.FlatpakUpdater{}.New(*initConfiguration) + flatpakUpdater, err := flatpak.FlatpakUpdater{}.New(*initConfiguration) flatpakUpdater.Config.Enabled = err == nil flatpakUpdater.SetUsers(users) - distroboxUpdater, err := drv.DistroboxUpdater{}.New(*initConfiguration) + distroboxUpdater, err := distrobox.DistroboxUpdater{}.New(*initConfiguration) distroboxUpdater.Config.Enabled = err == nil distroboxUpdater.SetUsers(users) - var enableUpd bool = true - - rpmOstreeUpdater, err := drv.RpmOstreeUpdater{}.New(*initConfiguration) - if err != nil { - enableUpd = false - } - - systemUpdater, err := drv.SystemUpdater{}.New(*initConfiguration) - if err != nil { - enableUpd = false - } - - isBootc, err := drv.BootcCompatible(systemUpdater.BinaryPath) - if err != nil { - isBootc = false - } - - if !isBootc { - slog.Debug("Using rpm-ostree fallback as system driver") - } - - systemUpdater.Config.Enabled = isBootc && enableUpd - rpmOstreeUpdater.Config.Enabled = !isBootc && enableUpd - - // The system driver to be applied needs to have the correct "enabled" value since it will NOT update from here onwards. - var mainSystemDriver drv.SystemUpdateDriver = &systemUpdater - if !isBootc { - mainSystemDriver = &rpmOstreeUpdater - } + mainSystemDriver, mainSystemDriverConfig, _, err := system.InitializeSystemDriver(*initConfiguration) - enableUpd, err = mainSystemDriver.Check() + enableUpd, err := mainSystemDriver.Check() if err != nil { slog.Error("Failed checking for updates") } + mainSystemDriverConfig.Enabled = mainSystemDriverConfig.Enabled && enableUpd - slog.Debug("System Updater module status", slog.Bool("enabled", enableUpd)) + slog.Debug("System Updater module status", slog.Bool("enabled", mainSystemDriverConfig.Enabled)) totalSteps := brewUpdater.Steps() + flatpakUpdater.Steps() + distroboxUpdater.Steps() - if enableUpd { + if mainSystemDriverConfig.Enabled { totalSteps += mainSystemDriver.Steps() } pw := percent.NewProgressWriter() @@ -169,9 +147,9 @@ func Update(cmd *cobra.Command, args []string) { // This section is ugly but we cant really do much about it. // Using interfaces doesn't preserve the "Config" struct state and I dont know any other way to make this work without cursed workarounds. - if enableUpd { - slog.Debug(fmt.Sprintf("%s module", systemUpdater.Config.Title), slog.String("module_name", systemUpdater.Config.Title), slog.Any("module_configuration", systemUpdater.Config)) - percent.ChangeTrackerMessageFancy(pw, tracker, progressEnabled, percent.TrackerMessage{Title: systemUpdater.Config.Title, Description: systemUpdater.Config.Description}) + if mainSystemDriverConfig.Enabled { + slog.Debug(fmt.Sprintf("%s module", mainSystemDriverConfig.Title), slog.String("module_name", mainSystemDriverConfig.Title), slog.Any("module_configuration", mainSystemDriverConfig)) + percent.ChangeTrackerMessageFancy(pw, tracker, progressEnabled, percent.TrackerMessage{Title: mainSystemDriverConfig.Title, Description: mainSystemDriverConfig.Description}) var out *[]drv.CommandOutput out, err = mainSystemDriver.Update() outputs = append(outputs, *out...) diff --git a/cmd/updateCheck.go b/cmd/updateCheck.go index b8950b4..a2d4f68 100644 --- a/cmd/updateCheck.go +++ b/cmd/updateCheck.go @@ -4,42 +4,20 @@ import ( "log/slog" "github.com/spf13/cobra" - "github.com/ublue-os/uupd/drv" + "github.com/ublue-os/uupd/drv/generic" + "github.com/ublue-os/uupd/drv/system" ) func UpdateCheck(cmd *cobra.Command, args []string) { - var enableUpd bool = true + initConfiguration := generic.UpdaterInitConfiguration{}.New() + initConfiguration.Ci = false + initConfiguration.DryRun = false + initConfiguration.Verbose = false - initConfiguration := drv.UpdaterInitConfiguration{}.New() - rpmOstreeUpdater, err := drv.RpmOstreeUpdater{}.New(*initConfiguration) + mainSystemDriver, _, _, err := system.InitializeSystemDriver(*initConfiguration) if err != nil { - enableUpd = false - } - - systemUpdater, err := drv.SystemUpdater{}.New(*initConfiguration) - if err != nil { - enableUpd = false - } - - isBootc, err := drv.BootcCompatible(systemUpdater.BinaryPath) - if err != nil { - isBootc = false - } - - if !isBootc { - slog.Debug("Using rpm-ostree fallback as system driver") - } - - systemUpdater.Config.Enabled = isBootc && enableUpd - rpmOstreeUpdater.Config.Enabled = !isBootc && enableUpd - - var mainSystemDriver drv.SystemUpdateDriver - if !isBootc { - slog.Debug("Using the rpm-ostree driver") - mainSystemDriver = &rpmOstreeUpdater - } else { - slog.Debug("Using the bootc driver") - mainSystemDriver = &systemUpdater + slog.Error("Failed") + return } updateAvailable, err := mainSystemDriver.Check() diff --git a/drv/brew.go b/drv/brew/brew.go similarity index 87% rename from drv/brew.go rename to drv/brew/brew.go index 5f880e5..1abf928 100644 --- a/drv/brew.go +++ b/drv/brew/brew.go @@ -1,4 +1,4 @@ -package drv +package brew import ( "fmt" @@ -7,6 +7,7 @@ import ( "strings" "syscall" + . "github.com/ublue-os/uupd/drv/generic" "github.com/ublue-os/uupd/pkg/session" ) @@ -45,7 +46,7 @@ func (up BrewUpdater) Update() (*[]CommandOutput, error) { } cli := []string{up.BrewPath, "update"} - out, err := session.RunUID(up.Config.logger, slog.LevelDebug, up.BaseUser, cli, up.Config.Environment) + out, err := session.RunUID(up.Config.Logger, slog.LevelDebug, up.BaseUser, cli, up.Config.Environment) tmpout := CommandOutput{}.New(out, err) tmpout.Context = "Brew Update" tmpout.Cli = cli @@ -58,7 +59,7 @@ func (up BrewUpdater) Update() (*[]CommandOutput, error) { } cli = []string{up.BrewPath, "upgrade"} - out, err = session.RunUID(up.Config.logger, slog.LevelDebug, up.BaseUser, cli, up.Config.Environment) + out, err = session.RunUID(up.Config.Logger, slog.LevelDebug, up.BaseUser, cli, up.Config.Environment) tmpout = CommandOutput{}.New(out, err) tmpout.Context = "Brew Upgrade" tmpout.Cli = cli @@ -85,7 +86,7 @@ func (up BrewUpdater) New(config UpdaterInitConfiguration) (BrewUpdater, error) DryRun: config.DryRun, Environment: config.Environment, } - up.Config.logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) + up.Config.Logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_PREFIX", "/home/linuxbrew/.linuxbrew") up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_REPOSITORY", fmt.Sprintf("%s/Homebrew", up.BrewPrefix)) @@ -104,11 +105,3 @@ func (up BrewUpdater) New(config UpdaterInitConfiguration) (BrewUpdater, error) return up, nil } - -func (up *BrewUpdater) Logger() *slog.Logger { - return up.Config.logger -} - -func (up *BrewUpdater) SetLogger(logger *slog.Logger) { - up.Config.logger = logger -} diff --git a/drv/distrobox.go b/drv/distrobox/distrobox.go similarity index 88% rename from drv/distrobox.go rename to drv/distrobox/distrobox.go index 5db751c..213d6ac 100644 --- a/drv/distrobox.go +++ b/drv/distrobox/distrobox.go @@ -1,9 +1,10 @@ -package drv +package distrobox import ( "log/slog" "strings" + . "github.com/ublue-os/uupd/drv/generic" "github.com/ublue-os/uupd/pkg/percent" "github.com/ublue-os/uupd/pkg/session" ) @@ -38,7 +39,7 @@ func (up DistroboxUpdater) New(config UpdaterInitConfiguration) (DistroboxUpdate DryRun: config.DryRun, Environment: config.Environment, } - up.Config.logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) + up.Config.Logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) up.usersEnabled = false up.Tracker = nil @@ -78,7 +79,7 @@ func (up DistroboxUpdater) Update() (*[]CommandOutput, error) { percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) cli := []string{up.binaryPath, "upgrade", "-a"} - out, err := session.RunUID(up.Config.logger, slog.LevelDebug, 0, cli, nil) + out, err := session.RunUID(up.Config.Logger, slog.LevelDebug, 0, cli, nil) tmpout := CommandOutput{}.New(out, err) tmpout.Context = up.Config.Description tmpout.Cli = cli @@ -91,7 +92,7 @@ func (up DistroboxUpdater) Update() (*[]CommandOutput, error) { context := *up.Config.UserDescription + " " + user.Name percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: *up.Config.UserDescription + " " + user.Name}) cli := []string{up.binaryPath, "upgrade", "-a"} - out, err := session.RunUID(up.Config.logger, slog.LevelDebug, user.UID, cli, nil) + out, err := session.RunUID(up.Config.Logger, slog.LevelDebug, user.UID, cli, nil) tmpout = CommandOutput{}.New(out, err) tmpout.Context = context tmpout.Cli = cli @@ -100,11 +101,3 @@ func (up DistroboxUpdater) Update() (*[]CommandOutput, error) { } return &finalOutput, nil } - -func (up *DistroboxUpdater) Logger() *slog.Logger { - return up.Config.logger -} - -func (up *DistroboxUpdater) SetLogger(logger *slog.Logger) { - up.Config.logger = logger -} diff --git a/drv/flatpak.go b/drv/flatpak/flatpak.go similarity index 89% rename from drv/flatpak.go rename to drv/flatpak/flatpak.go index 1c42e1c..e8cc311 100644 --- a/drv/flatpak.go +++ b/drv/flatpak/flatpak.go @@ -1,10 +1,11 @@ -package drv +package flatpak import ( "log/slog" "os/exec" "strings" + . "github.com/ublue-os/uupd/drv/generic" "github.com/ublue-os/uupd/pkg/percent" "github.com/ublue-os/uupd/pkg/session" ) @@ -39,7 +40,7 @@ func (up FlatpakUpdater) New(config UpdaterInitConfiguration) (FlatpakUpdater, e DryRun: config.DryRun, Environment: config.Environment, } - up.Config.logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) + up.Config.Logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) up.usersEnabled = false up.Tracker = nil @@ -80,7 +81,7 @@ func (up FlatpakUpdater) Update() (*[]CommandOutput, error) { percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) cli := []string{up.binaryPath, "update", "-y", "--noninteractive"} flatpakCmd := exec.Command(cli[0], cli[1:]...) - out, err := session.RunLog(up.Config.logger, slog.LevelDebug, flatpakCmd) + out, err := session.RunLog(up.Config.Logger, slog.LevelDebug, flatpakCmd) tmpout := CommandOutput{}.New(out, err) tmpout.Context = up.Config.Description tmpout.Cli = cli @@ -93,7 +94,7 @@ func (up FlatpakUpdater) Update() (*[]CommandOutput, error) { context := *up.Config.UserDescription + " " + user.Name percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: context}) cli := []string{up.binaryPath, "update", "-y"} - out, err := session.RunUID(up.Config.logger, slog.LevelDebug, user.UID, cli, nil) + out, err := session.RunUID(up.Config.Logger, slog.LevelDebug, user.UID, cli, nil) tmpout = CommandOutput{}.New(out, err) tmpout.Context = context tmpout.Cli = cli @@ -102,11 +103,3 @@ func (up FlatpakUpdater) Update() (*[]CommandOutput, error) { } return &finalOutput, nil } - -func (up *FlatpakUpdater) Logger() *slog.Logger { - return up.Config.logger -} - -func (up *FlatpakUpdater) SetLogger(logger *slog.Logger) { - up.Config.logger = logger -} diff --git a/drv/generic.go b/drv/generic/generic.go similarity index 87% rename from drv/generic.go rename to drv/generic/generic.go index 70ec784..73f36f5 100644 --- a/drv/generic.go +++ b/drv/generic/generic.go @@ -1,4 +1,4 @@ -package drv +package generic import ( "log/slog" @@ -20,6 +20,14 @@ type UpdaterInitConfiguration struct { Logger *slog.Logger } +func EnvOrFallback(environment EnvironmentMap, key string, fallback string) string { + validCase, exists := environment[key] + if exists && validCase != "" { + return validCase + } + return fallback +} + func GetEnvironment(data []string, getkeyval func(item string) (key, val string)) map[string]string { items := make(map[string]string) for _, item := range data { @@ -67,7 +75,7 @@ type DriverConfiguration struct { MultiUser bool DryRun bool Environment EnvironmentMap `json:"-"` - logger *slog.Logger `json:"-"` + Logger *slog.Logger `json:"-"` UserDescription *string } diff --git a/drv/generic/generic_test.go b/drv/generic/generic_test.go new file mode 100644 index 0000000..94d45fb --- /dev/null +++ b/drv/generic/generic_test.go @@ -0,0 +1,19 @@ +package generic_test + +import ( + "testing" + + "github.com/ublue-os/uupd/drv/generic" +) + +func TestFallBack(t *testing.T) { + var environment generic.EnvironmentMap = generic.EnvironmentMap{ + "TEST_FALLBACK_GOOD": "true", + } + if value := generic.EnvOrFallback(environment, "TEST_FALLBACK_GOOD", "FALSE"); value != "true" { + t.Fatalf("Getting the proper value fails, %s", value) + } + if value := generic.EnvOrFallback(environment, "TEST_FALLBACK_BAD", "FALSE"); value != "FALSE" { + t.Fatalf("Getting the fallback fails, %s", value) + } +} diff --git a/drv/rpm-ostree.go b/drv/rpmostree/rpmostree.go similarity index 75% rename from drv/rpm-ostree.go rename to drv/rpmostree/rpmostree.go index 23cb540..e401a0a 100644 --- a/drv/rpm-ostree.go +++ b/drv/rpmostree/rpmostree.go @@ -1,15 +1,17 @@ -package drv +package rpmostree // Temporary: WILL get removed at some point. // FIXME: Remove this on Spring 2025 when we all move to dnf5 and bootc ideally import ( "encoding/json" - "github.com/ublue-os/uupd/pkg/session" "log/slog" "os/exec" "strings" "time" + + . "github.com/ublue-os/uupd/drv/generic" + "github.com/ublue-os/uupd/pkg/session" ) type rpmOstreeStatus struct { @@ -31,7 +33,7 @@ func (up RpmOstreeUpdater) Outdated() (bool, error) { var timestamp time.Time cmd := exec.Command(up.BinaryPath, "status", "--json", "--booted") - out, err := session.RunLog(up.Config.logger, slog.LevelDebug, cmd) + out, err := session.RunLog(up.Config.Logger, slog.LevelDebug, cmd) if err != nil { return false, err } @@ -50,7 +52,7 @@ func (up RpmOstreeUpdater) Update() (*[]CommandOutput, error) { var cmd *exec.Cmd binaryPath := up.BinaryPath cli := []string{binaryPath, "upgrade"} - out, err := session.RunLog(up.Config.logger, slog.LevelDebug, cmd) + out, err := session.RunLog(up.Config.Logger, slog.LevelDebug, cmd) tmpout := CommandOutput{}.New(out, err) tmpout.Cli = cli tmpout.Failure = err != nil @@ -66,20 +68,6 @@ func (up RpmOstreeUpdater) Steps() int { return 0 } -func BootcCompatible(binaryPath string) (bool, error) { - cmd := exec.Command(binaryPath, "status", "--format=json") - out, err := cmd.CombinedOutput() - if err != nil { - return false, nil - } - var status bootcStatus - err = json.Unmarshal(out, &status) - if err != nil { - return false, nil - } - return !(status.Status.Booted.Incompatible || status.Status.Staged.Incompatible), nil -} - func (up RpmOstreeUpdater) New(config UpdaterInitConfiguration) (RpmOstreeUpdater, error) { up.Config = DriverConfiguration{ Title: "System", @@ -88,7 +76,7 @@ func (up RpmOstreeUpdater) New(config UpdaterInitConfiguration) (RpmOstreeUpdate DryRun: config.DryRun, Environment: config.Environment, } - up.Config.logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) + up.Config.Logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) if up.Config.DryRun { return up, nil } @@ -117,14 +105,6 @@ func (up RpmOstreeUpdater) Check() (bool, error) { } updateNecessary := strings.Contains(string(out), "AvailableUpdate") - up.Config.logger.Debug("Executed update check", slog.String("output", string(out)), slog.Bool("update", updateNecessary)) + up.Config.Logger.Debug("Executed update check", slog.String("output", string(out)), slog.Bool("update", updateNecessary)) return updateNecessary, nil } - -func (up *RpmOstreeUpdater) Logger() *slog.Logger { - return up.Config.logger -} - -func (up *RpmOstreeUpdater) SetLogger(logger *slog.Logger) { - up.Config.logger = logger -} diff --git a/drv/system.go b/drv/system/system.go similarity index 60% rename from drv/system.go rename to drv/system/system.go index 9b13c1d..a12a604 100644 --- a/drv/system.go +++ b/drv/system/system.go @@ -1,4 +1,4 @@ -package drv +package system import ( "encoding/json" @@ -7,6 +7,8 @@ import ( "strings" "time" + . "github.com/ublue-os/uupd/drv/generic" + "github.com/ublue-os/uupd/drv/rpmostree" "github.com/ublue-os/uupd/pkg/session" ) @@ -34,8 +36,6 @@ type SystemUpdateDriver interface { Outdated() (bool, error) Check() (bool, error) Update() (*[]CommandOutput, error) - Logger() *slog.Logger - SetLogger(value *slog.Logger) } type SystemUpdater struct { @@ -77,9 +77,9 @@ func (up SystemUpdater) Update() (*[]CommandOutput, error) { var cmd *exec.Cmd binaryPath := up.BinaryPath cli := []string{binaryPath, "upgrade", "--quiet"} - up.Config.logger.Debug("Executing update", slog.Any("cli", cli)) + up.Config.Logger.Debug("Executing update", slog.Any("cli", cli)) cmd = exec.Command(cli[0], cli[1:]...) - out, err := session.RunLog(up.Config.logger, slog.LevelDebug, cmd) + out, err := session.RunLog(up.Config.Logger, slog.LevelDebug, cmd) tmpout := CommandOutput{}.New(out, err) tmpout.Failure = err != nil tmpout.Context = "System Update" @@ -94,14 +94,6 @@ func (up SystemUpdater) Steps() int { return 0 } -func EnvOrFallback(environment EnvironmentMap, key string, fallback string) string { - validCase, exists := environment[key] - if exists && validCase != "" { - return validCase - } - return fallback -} - func (up SystemUpdater) New(config UpdaterInitConfiguration) (SystemUpdater, error) { up.Config = DriverConfiguration{ Title: "System", @@ -110,7 +102,7 @@ func (up SystemUpdater) New(config UpdaterInitConfiguration) (SystemUpdater, err DryRun: config.DryRun, Environment: config.Environment, } - up.Config.logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) + up.Config.Logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) up.BinaryPath = EnvOrFallback(config.Environment, "UUPD_BOOTC_BINARY", "/usr/bin/bootc") return up, nil @@ -128,14 +120,59 @@ func (up SystemUpdater) Check() (bool, error) { } updateNecessary := !strings.Contains(string(out), "No changes in:") - up.Config.logger.Debug("Executed update check", slog.String("output", string(out)), slog.Bool("update", updateNecessary)) + up.Config.Logger.Debug("Executed update check", slog.String("output", string(out)), slog.Bool("update", updateNecessary)) return updateNecessary, nil } -func (up *SystemUpdater) Logger() *slog.Logger { - return up.Config.logger +func BootcCompatible(binaryPath string) (bool, error) { + cmd := exec.Command(binaryPath, "status", "--format=json") + out, err := cmd.CombinedOutput() + if err != nil { + return false, nil + } + var status bootcStatus + err = json.Unmarshal(out, &status) + if err != nil { + return false, nil + } + return !(status.Status.Booted.Incompatible || status.Status.Staged.Incompatible), nil } -func (up *SystemUpdater) SetLogger(logger *slog.Logger) { - up.Config.logger = logger +func InitializeSystemDriver(initConfiguration UpdaterInitConfiguration) (SystemUpdateDriver, DriverConfiguration, bool, error) { + var enableUpd bool = true + + rpmOstreeUpdater, err := rpmostree.RpmOstreeUpdater{}.New(initConfiguration) + if err != nil { + enableUpd = false + } + + systemUpdater, err := SystemUpdater{}.New(initConfiguration) + if err != nil { + enableUpd = false + } + + isBootc, err := BootcCompatible(systemUpdater.BinaryPath) + if err != nil { + isBootc = false + } + + if !isBootc { + slog.Debug("Using rpm-ostree fallback as system driver") + } + + // The system driver to be applied needs to have the correct "enabled" value since it will NOT update from here onwards. + systemUpdater.Config.Enabled = systemUpdater.Config.Enabled && isBootc && enableUpd + rpmOstreeUpdater.Config.Enabled = rpmOstreeUpdater.Config.Enabled && !isBootc && enableUpd + + var finalConfig DriverConfiguration + var mainSystemDriver SystemUpdateDriver + if isBootc { + mainSystemDriver = &systemUpdater + finalConfig = systemUpdater.Config + } else { + mainSystemDriver = &rpmOstreeUpdater + finalConfig = systemUpdater.Config + } + + return mainSystemDriver, finalConfig, isBootc, err } diff --git a/drv/system/system_test.go b/drv/system/system_test.go new file mode 100644 index 0000000..ce162e0 --- /dev/null +++ b/drv/system/system_test.go @@ -0,0 +1,35 @@ +package system_test + +import ( + "testing" + + "github.com/ublue-os/uupd/drv/generic" + "github.com/ublue-os/uupd/drv/system" + appLogging "github.com/ublue-os/uupd/pkg/logging" +) + +func InitBaseConfig() system.SystemUpdater { + var initConfiguration = generic.UpdaterInitConfiguration{ + DryRun: false, + Ci: false, + Verbose: false, + Environment: nil, + Logger: appLogging.NewMuteLogger(), + } + driv, _ := system.SystemUpdater{}.New(initConfiguration) + return driv +} + +func TestProperSteps(t *testing.T) { + systemUpdater := InitBaseConfig() + systemUpdater.Config.Enabled = false + + if systemUpdater.Steps() != 0 { + t.Fatalf("Expected no steps when module is disabled") + } + + systemUpdater.Config.Enabled = true + if systemUpdater.Steps() == 0 { + t.Fatalf("Expected steps to be added") + } +} diff --git a/drv/system_test.go b/drv/system_test.go deleted file mode 100644 index 8893dc9..0000000 --- a/drv/system_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package drv_test - -import ( - "testing" - - "github.com/ublue-os/uupd/drv" - appLogging "github.com/ublue-os/uupd/pkg/logging" -) - -func InitBaseConfig() drv.SystemUpdater { - var initConfiguration = drv.UpdaterInitConfiguration{ - DryRun: false, - Ci: false, - Verbose: false, - Environment: nil, - Logger: appLogging.NewMuteLogger(), - } - driv, _ := drv.SystemUpdater{}.New(initConfiguration) - return driv -} - -func TestProperSteps(t *testing.T) { - systemUpdater := InitBaseConfig() - systemUpdater.Config.Enabled = false - - if systemUpdater.Steps() != 0 { - t.Fatalf("Expected no steps when module is disabled") - } - - systemUpdater.Config.Enabled = true - if systemUpdater.Steps() == 0 { - t.Fatalf("Expected steps to be added") - } -} - -func TestFallBack(t *testing.T) { - var environment drv.EnvironmentMap = drv.EnvironmentMap{ - "TEST_FALLBACK_GOOD": "true", - } - if value := drv.EnvOrFallback(environment, "TEST_FALLBACK_GOOD", "FALSE"); value != "true" { - t.Fatalf("Getting the proper value fails, %s", value) - } - if value := drv.EnvOrFallback(environment, "TEST_FALLBACK_BAD", "FALSE"); value != "FALSE" { - t.Fatalf("Getting the fallback fails, %s", value) - } -} diff --git a/uupd.spec b/uupd.spec index af02be7..f57ed99 100644 --- a/uupd.spec +++ b/uupd.spec @@ -39,8 +39,7 @@ install -Dpm 644 %{name}.timer %{buildroot}%{_unitdir}/%{name}.timer install -Dpm 644 %{name}.rules %{buildroot}%{_sysconfdir}/polkit-1/rules.d/%{name}.rules %check -# go test should be here if you have tests, e.g. -# go test -v ./... +go test -v ./... %post %systemd_post %{name}.timer From e4b2d7892635e6cb4c185926f56f7aba15c584d3 Mon Sep 17 00:00:00 2001 From: Tulip Blossom Date: Mon, 16 Dec 2024 02:38:59 -0300 Subject: [PATCH 3/6] feat(testing): add basic tests for most modules --- cmd/update.go | 6 +-- drv/brew/brew_test.go | 35 +++++++++++++++ drv/distrobox/distrobox.go | 7 +-- drv/distrobox/distrobox_test.go | 56 ++++++++++++++++++++++++ drv/flatpak/flatpak.go | 7 +-- drv/flatpak/flatpak_test.go | 56 ++++++++++++++++++++++++ drv/generic/generic.go | 13 ++---- drv/generic/generic_test.go | 21 +++++++++ drv/rpmostree/rpmostree.go | 19 +++------ drv/rpmostree/rpmostree_test.go | 35 +++++++++++++++ drv/system/system.go | 7 +-- justfile | 18 ++++++-- pkg/filelock/filelock.go | 6 +-- pkg/percent/incrementer.go | 29 +++++++++++++ pkg/percent/incrementer_test.go | 52 +++++++++++++++++++++++ pkg/percent/progressmanager.go | 31 +------------- pkg/session/session.go | 58 +++++++++++++------------ pkg/session/session_test.go | 75 +++++++++++++++++++++++++++++++++ 18 files changed, 422 insertions(+), 109 deletions(-) create mode 100644 drv/brew/brew_test.go create mode 100644 drv/distrobox/distrobox_test.go create mode 100644 drv/flatpak/flatpak_test.go create mode 100644 drv/rpmostree/rpmostree_test.go create mode 100644 pkg/percent/incrementer.go create mode 100644 pkg/percent/incrementer_test.go create mode 100644 pkg/session/session_test.go diff --git a/cmd/update.go b/cmd/update.go index 28ede9d..055efad 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -84,7 +84,7 @@ func Update(cmd *cobra.Command, args []string) { distroboxUpdater.Config.Enabled = err == nil distroboxUpdater.SetUsers(users) - mainSystemDriver, mainSystemDriverConfig, _, err := system.InitializeSystemDriver(*initConfiguration) + mainSystemDriver, mainSystemDriverConfig, _, _ := system.InitializeSystemDriver(*initConfiguration) enableUpd, err := mainSystemDriver.Check() if err != nil { @@ -137,7 +137,7 @@ func Update(cmd *cobra.Command, args []string) { if systemOutdated { const OUTDATED_WARNING = "There hasn't been an update in over a month. Consider rebooting or running updates manually" - err := session.Notify("System Warning", OUTDATED_WARNING) + err := session.Notify(users, "System Warning", OUTDATED_WARNING) if err != nil { slog.Error("Failed showing warning notification") } @@ -167,7 +167,6 @@ func Update(cmd *cobra.Command, args []string) { if flatpakUpdater.Config.Enabled { slog.Debug(fmt.Sprintf("%s module", flatpakUpdater.Config.Title), slog.String("module_name", flatpakUpdater.Config.Title), slog.Any("module_configuration", flatpakUpdater.Config)) - percent.ChangeTrackerMessageFancy(pw, tracker, progressEnabled, percent.TrackerMessage{Title: flatpakUpdater.Config.Title, Description: flatpakUpdater.Config.Description}) var out *[]drv.CommandOutput out, err = flatpakUpdater.Update() outputs = append(outputs, *out...) @@ -176,7 +175,6 @@ func Update(cmd *cobra.Command, args []string) { if distroboxUpdater.Config.Enabled { slog.Debug(fmt.Sprintf("%s module", distroboxUpdater.Config.Title), slog.String("module_name", distroboxUpdater.Config.Title), slog.Any("module_configuration", distroboxUpdater.Config)) - percent.ChangeTrackerMessageFancy(pw, tracker, progressEnabled, percent.TrackerMessage{Title: distroboxUpdater.Config.Title, Description: distroboxUpdater.Config.Description}) var out *[]drv.CommandOutput out, err = distroboxUpdater.Update() outputs = append(outputs, *out...) diff --git a/drv/brew/brew_test.go b/drv/brew/brew_test.go new file mode 100644 index 0000000..d622250 --- /dev/null +++ b/drv/brew/brew_test.go @@ -0,0 +1,35 @@ +package brew_test + +import ( + "testing" + + "github.com/ublue-os/uupd/drv/brew" + "github.com/ublue-os/uupd/drv/generic" + appLogging "github.com/ublue-os/uupd/pkg/logging" +) + +func InitBaseConfig() brew.BrewUpdater { + var initConfiguration = generic.UpdaterInitConfiguration{ + DryRun: false, + Ci: false, + Verbose: false, + Environment: nil, + Logger: appLogging.NewMuteLogger(), + } + driv, _ := brew.BrewUpdater{}.New(initConfiguration) + return driv +} + +func TestProperSteps(t *testing.T) { + brewUpdater := InitBaseConfig() + brewUpdater.Config.Enabled = false + + if brewUpdater.Steps() != 0 { + t.Fatalf("Expected no steps when module is disabled") + } + + brewUpdater.Config.Enabled = true + if brewUpdater.Steps() == 0 { + t.Fatalf("Expected steps to be added") + } +} diff --git a/drv/distrobox/distrobox.go b/drv/distrobox/distrobox.go index 213d6ac..85818ed 100644 --- a/drv/distrobox/distrobox.go +++ b/drv/distrobox/distrobox.go @@ -43,12 +43,7 @@ func (up DistroboxUpdater) New(config UpdaterInitConfiguration) (DistroboxUpdate up.usersEnabled = false up.Tracker = nil - binaryPath, exists := up.Config.Environment["UUPD_DISTROBOX_BINARY"] - if !exists || binaryPath == "" { - up.binaryPath = "/usr/bin/distrobox" - } else { - up.binaryPath = binaryPath - } + up.binaryPath = EnvOrFallback(up.Config.Environment, "UUPD_DISTROBOX_BINARY", "/usr/bin/distrobox") return up, nil } diff --git a/drv/distrobox/distrobox_test.go b/drv/distrobox/distrobox_test.go new file mode 100644 index 0000000..77d3b27 --- /dev/null +++ b/drv/distrobox/distrobox_test.go @@ -0,0 +1,56 @@ +package distrobox_test + +import ( + "log" + "testing" + + "github.com/ublue-os/uupd/drv/distrobox" + "github.com/ublue-os/uupd/drv/generic" + appLogging "github.com/ublue-os/uupd/pkg/logging" + "github.com/ublue-os/uupd/pkg/session" +) + +func InitBaseConfig() distrobox.DistroboxUpdater { + var initConfiguration = generic.UpdaterInitConfiguration{ + DryRun: false, + Ci: false, + Verbose: false, + Environment: nil, + Logger: appLogging.NewMuteLogger(), + } + driv, _ := distrobox.DistroboxUpdater{}.New(initConfiguration) + return driv +} + +func TestProperSteps(t *testing.T) { + updater := InitBaseConfig() + updater.Config.Enabled = false + + if updater.Steps() != 0 { + t.Fatalf("Expected no steps when module is disabled") + } + + updater.Config.Enabled = true + if updater.Steps() == 0 { + t.Fatalf("Expected steps to be added") + } +} + +func TestProperUserSteps(t *testing.T) { + updater := InitBaseConfig() + + mockUser := []session.User{ + {UID: 0, Name: "root"}, + {UID: 1, Name: "roote"}, + {UID: 2, Name: "rooto"}, + } + updater.SetUsers(mockUser) + + if reported := updater.Steps(); reported != 1+len(mockUser) { + log.Fatalf("Incorrect number of steps for users: %d", reported) + } + updater.Config.Enabled = false + if reported := updater.Steps(); reported != 0 { + log.Fatalf("Incorrect number of steps for users: %d", reported) + } +} diff --git a/drv/flatpak/flatpak.go b/drv/flatpak/flatpak.go index e8cc311..3a99c56 100644 --- a/drv/flatpak/flatpak.go +++ b/drv/flatpak/flatpak.go @@ -44,12 +44,7 @@ func (up FlatpakUpdater) New(config UpdaterInitConfiguration) (FlatpakUpdater, e up.usersEnabled = false up.Tracker = nil - binaryPath, exists := up.Config.Environment["UUPD_FLATPAK_BINARY"] - if !exists || binaryPath == "" { - up.binaryPath = "/usr/bin/flatpak" - } else { - up.binaryPath = binaryPath - } + up.binaryPath = EnvOrFallback(up.Config.Environment, "UUPD_FLATPAK_BINARY", "/usr/bin/flatpak") return up, nil } diff --git a/drv/flatpak/flatpak_test.go b/drv/flatpak/flatpak_test.go new file mode 100644 index 0000000..6974b6f --- /dev/null +++ b/drv/flatpak/flatpak_test.go @@ -0,0 +1,56 @@ +package flatpak_test + +import ( + "log" + "testing" + + "github.com/ublue-os/uupd/drv/flatpak" + "github.com/ublue-os/uupd/drv/generic" + appLogging "github.com/ublue-os/uupd/pkg/logging" + "github.com/ublue-os/uupd/pkg/session" +) + +func InitBaseConfig() flatpak.FlatpakUpdater { + var initConfiguration = generic.UpdaterInitConfiguration{ + DryRun: false, + Ci: false, + Verbose: false, + Environment: nil, + Logger: appLogging.NewMuteLogger(), + } + driv, _ := flatpak.FlatpakUpdater{}.New(initConfiguration) + return driv +} + +func TestProperSteps(t *testing.T) { + updater := InitBaseConfig() + updater.Config.Enabled = false + + if updater.Steps() != 0 { + t.Fatalf("Expected no steps when module is disabled") + } + + updater.Config.Enabled = true + if updater.Steps() == 0 { + t.Fatalf("Expected steps to be added") + } +} + +func TestProperUserSteps(t *testing.T) { + updater := InitBaseConfig() + + mockUser := []session.User{ + {UID: 0, Name: "root"}, + {UID: 1, Name: "roote"}, + {UID: 2, Name: "rooto"}, + } + updater.SetUsers(mockUser) + + if reported := updater.Steps(); reported != 1+len(mockUser) { + log.Fatalf("Incorrect number of steps for users: %d", reported) + } + updater.Config.Enabled = false + if reported := updater.Steps(); reported != 0 { + log.Fatalf("Incorrect number of steps for users: %d", reported) + } +} diff --git a/drv/generic/generic.go b/drv/generic/generic.go index 73f36f5..e885f48 100644 --- a/drv/generic/generic.go +++ b/drv/generic/generic.go @@ -28,11 +28,11 @@ func EnvOrFallback(environment EnvironmentMap, key string, fallback string) stri return fallback } -func GetEnvironment(data []string, getkeyval func(item string) (key, val string)) map[string]string { +func GetEnvironment(data []string) map[string]string { items := make(map[string]string) for _, item := range data { - key, val := getkeyval(item) - items[key] = val + splits := strings.Split(item, "=") + items[splits[0]] = splits[1] } return items } @@ -40,12 +40,7 @@ func GetEnvironment(data []string, getkeyval func(item string) (key, val string) func (up UpdaterInitConfiguration) New() *UpdaterInitConfiguration { up.DryRun = false up.Ci = false - up.Environment = GetEnvironment(os.Environ(), func(item string) (key, val string) { - splits := strings.Split(item, "=") - key = splits[0] - val = splits[1] - return - }) + up.Environment = GetEnvironment(os.Environ()) up.Logger = slog.Default() return &up diff --git a/drv/generic/generic_test.go b/drv/generic/generic_test.go index 94d45fb..e07b3d2 100644 --- a/drv/generic/generic_test.go +++ b/drv/generic/generic_test.go @@ -1,6 +1,7 @@ package generic_test import ( + "log" "testing" "github.com/ublue-os/uupd/drv/generic" @@ -17,3 +18,23 @@ func TestFallBack(t *testing.T) { t.Fatalf("Getting the fallback fails, %s", value) } } + +func TestProperEnvironment(t *testing.T) { + valuesExpected := map[string]string{ + "SIGMA": "true", + "CHUD": "false", + "AMOGUS": "sus", + "NOTHING": "", + } + + for key, value := range valuesExpected { + testmap := generic.GetEnvironment([]string{key + "=" + value}) + valuegot, exists := testmap[key] + if !exists { + log.Fatalf("Could not get environment variable at all: %s", key) + } + if valuegot != value { + log.Fatalf("Value gotten from variable was not expected: Got %s, Expected %s", valuegot, value) + } + } +} diff --git a/drv/rpmostree/rpmostree.go b/drv/rpmostree/rpmostree.go index e401a0a..637b786 100644 --- a/drv/rpmostree/rpmostree.go +++ b/drv/rpmostree/rpmostree.go @@ -25,11 +25,15 @@ type RpmOstreeUpdater struct { BinaryPath string } +// Checks if it is at least a month old considering how that works +func IsOutdatedOneMonthTimestamp(current time.Time, target time.Time) bool { + return target.Before(current.AddDate(0, -1, 0)) +} + func (up RpmOstreeUpdater) Outdated() (bool, error) { if up.Config.DryRun { return false, nil } - oneMonthAgo := time.Now().AddDate(0, -1, 0) var timestamp time.Time cmd := exec.Command(up.BinaryPath, "status", "--json", "--booted") @@ -44,7 +48,7 @@ func (up RpmOstreeUpdater) Outdated() (bool, error) { } timestamp = time.Unix(status.Deployments[0].Timestamp, 0).UTC() - return timestamp.Before(oneMonthAgo), nil + return IsOutdatedOneMonthTimestamp(time.Now(), timestamp), nil } func (up RpmOstreeUpdater) Update() (*[]CommandOutput, error) { @@ -77,16 +81,7 @@ func (up RpmOstreeUpdater) New(config UpdaterInitConfiguration) (RpmOstreeUpdate Environment: config.Environment, } up.Config.Logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) - if up.Config.DryRun { - return up, nil - } - - binaryPath, exists := up.Config.Environment["UUPD_RPMOSTREE_BINARY"] - if !exists || binaryPath == "" { - up.BinaryPath = "/usr/bin/rpm-ostree" - } else { - up.BinaryPath = binaryPath - } + up.BinaryPath = EnvOrFallback(up.Config.Environment, "UUPD_RPMOSTREE_BINARY", "/usr/bin/rpm-ostree") return up, nil } diff --git a/drv/rpmostree/rpmostree_test.go b/drv/rpmostree/rpmostree_test.go new file mode 100644 index 0000000..56c1522 --- /dev/null +++ b/drv/rpmostree/rpmostree_test.go @@ -0,0 +1,35 @@ +package rpmostree_test + +import ( + "testing" + + "github.com/ublue-os/uupd/drv/generic" + "github.com/ublue-os/uupd/drv/rpmostree" + appLogging "github.com/ublue-os/uupd/pkg/logging" +) + +func InitBaseConfig() rpmostree.RpmOstreeUpdater { + var initConfiguration = generic.UpdaterInitConfiguration{ + DryRun: false, + Ci: false, + Verbose: false, + Environment: nil, + Logger: appLogging.NewMuteLogger(), + } + driv, _ := rpmostree.RpmOstreeUpdater{}.New(initConfiguration) + return driv +} + +func TestProperSteps(t *testing.T) { + rpmostreeUpdater := InitBaseConfig() + rpmostreeUpdater.Config.Enabled = false + + if rpmostreeUpdater.Steps() != 0 { + t.Fatalf("Expected no steps when module is disabled") + } + + rpmostreeUpdater.Config.Enabled = true + if rpmostreeUpdater.Steps() == 0 { + t.Fatalf("Expected steps to be added") + } +} diff --git a/drv/system/system.go b/drv/system/system.go index a12a604..55649c3 100644 --- a/drv/system/system.go +++ b/drv/system/system.go @@ -43,11 +43,6 @@ type SystemUpdater struct { BinaryPath string } -// Checks if it is at least a month old considering how that works -func IsOutdatedOneMonthTimestamp(current time.Time, target time.Time) bool { - return target.Before(current.AddDate(0, -1, 0)) -} - func (up SystemUpdater) Outdated() (bool, error) { if up.Config.DryRun { return false, nil @@ -69,7 +64,7 @@ func (up SystemUpdater) Outdated() (bool, error) { if err != nil { return false, nil } - return IsOutdatedOneMonthTimestamp(time.Now(), timestamp), nil + return rpmostree.IsOutdatedOneMonthTimestamp(time.Now(), timestamp), nil } func (up SystemUpdater) Update() (*[]CommandOutput, error) { diff --git a/justfile b/justfile index dea3859..f66e4f4 100644 --- a/justfile +++ b/justfile @@ -77,10 +77,20 @@ lint: release: goreleaser -test: - go test -v -cover ./... +test directory="": + #!/usr/bin/env bash + if [ "{{directory}}" != "" ] ; then + go test -v -cover ./{{directory}}/... + else + go test -v -cover ./... + fi -test-interactive: +test-coverage directory="": #!/usr/bin/env bash t="/tmp/go-cover.$$.tmp" - go test -v -coverprofile=$t ./... $@ && go tool cover -html=$t && unlink $t + + if [ "{{directory}}" != "" ] ; then + go test -v -coverprofile=$t ./{{directory}}/... $@ && go tool cover -html=$t && unlink $t + else + go test -v -coverprofile=$t ./... $@ && go tool cover -html=$t && unlink $t + fi diff --git a/pkg/filelock/filelock.go b/pkg/filelock/filelock.go index a9ffe76..3300a53 100644 --- a/pkg/filelock/filelock.go +++ b/pkg/filelock/filelock.go @@ -21,11 +21,7 @@ func GetDefaultLockfile() string { } func OpenLockfile(filepath string) (*os.File, error) { - file, err := os.OpenFile(filepath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666) - if err != nil { - return nil, err - } - return file, err + return os.OpenFile(filepath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666) } type TimeoutConfig struct { diff --git a/pkg/percent/incrementer.go b/pkg/percent/incrementer.go new file mode 100644 index 0000000..ebbf36f --- /dev/null +++ b/pkg/percent/incrementer.go @@ -0,0 +1,29 @@ +package percent + +import "github.com/jedib0t/go-pretty/v6/progress" + +type Incrementer struct { + DoneIncrements int + MaxIncrements int +} + +type IncrementTracker struct { + Tracker *progress.Tracker + Incrementer *Incrementer +} + +func (it *IncrementTracker) IncrementSection(err error) { + if int64(it.Incrementer.DoneIncrements)+int64(1) > int64(it.Incrementer.MaxIncrements) { + return + } + it.Incrementer.DoneIncrements += 1 + if err == nil { + it.Tracker.Increment(1) + } else { + it.Tracker.IncrementWithError(1) + } +} + +func (it *IncrementTracker) CurrentStep() int { + return it.Incrementer.DoneIncrements +} diff --git a/pkg/percent/incrementer_test.go b/pkg/percent/incrementer_test.go new file mode 100644 index 0000000..954f430 --- /dev/null +++ b/pkg/percent/incrementer_test.go @@ -0,0 +1,52 @@ +package percent_test + +import ( + "math" + "testing" + + "github.com/jedib0t/go-pretty/v6/progress" + "github.com/ublue-os/uupd/pkg/percent" +) + +func InitIncrementer(max int) percent.IncrementTracker { + tracker := progress.Tracker{Message: "Updating", Units: progress.UnitsDefault, Total: int64(max)} + incrementer := percent.Incrementer{ + MaxIncrements: max, + DoneIncrements: 0, + } + return percent.IncrementTracker{ + Tracker: &tracker, + Incrementer: &incrementer, + } +} + +func TestOverflow(t *testing.T) { + max := 3 + tracker := InitIncrementer(max) + + iter := 0 + for iter < max { + tracker.IncrementSection(nil) + iter++ + } + // +1 so that it overflows + tracker.IncrementSection(nil) + + if tracker.CurrentStep() > max { + t.Fatalf("Incremented with overflow. Expected: %d, Got: %d", max, tracker.CurrentStep()) + } +} + +func TestProperIncrement(t *testing.T) { + num := math.MaxInt8 + tracker := InitIncrementer(num) + + iter := 0 + for iter < num { + if tracker.CurrentStep() != iter { + t.Fatalf("Misstep increment. Expected: %d, Got: %d", iter, tracker.CurrentStep()) + } + tracker.IncrementSection(nil) + iter++ + } +} diff --git a/pkg/percent/progressmanager.go b/pkg/percent/progressmanager.go index d85aee2..ab945a1 100644 --- a/pkg/percent/progressmanager.go +++ b/pkg/percent/progressmanager.go @@ -14,16 +14,6 @@ import ( "github.com/ublue-os/uupd/pkg/session" ) -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}, @@ -100,7 +90,7 @@ func NewProgressWriter() progress.Writer { func NewIncrementTracker(tracker *progress.Tracker, max_increments int) *IncrementTracker { return &IncrementTracker{ Tracker: tracker, - incrementer: &Incrementer{MaxIncrements: max_increments}, + Incrementer: &Incrementer{MaxIncrements: max_increments}, } } @@ -126,25 +116,6 @@ func ChangeTrackerMessageFancy(writer progress.Writer, tracker *IncrementTracker tracker.Tracker.UpdateMessage(finalMessage) } -func (it *IncrementTracker) IncrementSection(err error) { - var increment_step float64 - if it.incrementer.doneIncrements == 0 { - increment_step = 1 - } else { - increment_step = float64(it.Tracker.Total / int64(it.incrementer.MaxIncrements)) - } - if err == nil { - it.Tracker.Increment(int64(increment_step)) - } else { - it.Tracker.IncrementWithError(int64(increment_step)) - } - it.incrementer.doneIncrements++ -} - -func (it *IncrementTracker) CurrentStep() int { - return it.incrementer.doneIncrements -} - func ResetOscProgress() { // OSC escape sequence to reset all previous OSC progress hints to 0%. // Documentation is on https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC diff --git a/pkg/session/session.go b/pkg/session/session.go index bbc5c1f..5f9bacc 100644 --- a/pkg/session/session.go +++ b/pkg/session/session.go @@ -2,6 +2,7 @@ package session import ( "bufio" + "context" "fmt" "io" "log/slog" @@ -26,13 +27,17 @@ func RunLog(logger *slog.Logger, level slog.Level, command *exec.Cmd) ([]byte, e stderr, _ := command.StderrPipe() multiReader := io.MultiReader(stdout, stderr) - command.Start() + if err := command.Wait(); err != nil { + logger.Warn("Error occoured starting external command", slog.Any("error", err)) + } scanner := bufio.NewScanner(multiReader) scanner.Split(bufio.ScanLines) for scanner.Scan() { - logger.With(slog.Bool("subcommand", true)).Log(nil, level, scanner.Text()) + logger.With(slog.Bool("subcommand", true)).Log(context.TODO(), level, scanner.Text()) + } + if err := command.Wait(); err != nil { + logger.Warn("Error occoured while waiting for external command", slog.Any("error", err)) } - command.Wait() return scanner.Bytes(), scanner.Err() } @@ -56,6 +61,23 @@ func RunUID(logger *slog.Logger, level slog.Level, uid int, command []string, en return RunLog(logger, level, cmd) } +func ParseUserFromVariant(uidVariant dbus.Variant, nameVariant dbus.Variant) (User, error) { + uid, ok := uidVariant.Value().(uint32) + if !ok { + return User{}, fmt.Errorf("invalid UID type, expected uint32") + } + + name, ok := nameVariant.Value().(string) + if !ok { + return User{}, fmt.Errorf("invalid Name type, expected string") + } + + return User{ + UID: int(uid), + Name: name, + }, nil +} + func ListUsers() ([]User, error) { conn, err := dbus.SystemBus() if err != nil { @@ -72,38 +94,20 @@ func ListUsers() ([]User, error) { var users []User for _, data := range resp { - if len(data) < 2 { - return []User{}, fmt.Errorf("Malformed dbus response") - } - uidVariant := data[0] - nameVariant := data[1] - - uid, ok := uidVariant.Value().(uint32) - if !ok { - return []User{}, fmt.Errorf("invalid UID type, expected uint32") + parsed, err := ParseUserFromVariant(data[0], data[1]) + if err != nil { + return nil, err } - name, ok := nameVariant.Value().(string) - if !ok { - return []User{}, fmt.Errorf("invalid Name type, expected string") - } - - users = append(users, User{ - UID: int(uid), - Name: name, - }) + users = append(users, parsed) } return users, nil } -func Notify(summary string, body string) error { - users, err := ListUsers() - if err != nil { - return err - } +func Notify(users []User, summary string, body string) error { for _, user := range users { // we don't care if these exit - _, _ = RunUID(slog.Default(), slog.LevelDebug, user.UID, []string{"/usr/bin/notify-send", "--app-name", "uupd", summary, body}, nil) + _, _ = RunUID(nil, slog.LevelDebug, user.UID, []string{"/usr/bin/notify-send", "--app-name", "uupd", summary, body}, nil) } return nil } diff --git a/pkg/session/session_test.go b/pkg/session/session_test.go new file mode 100644 index 0000000..68935c8 --- /dev/null +++ b/pkg/session/session_test.go @@ -0,0 +1,75 @@ +package session_test + +import ( + "fmt" + "math" + "testing" + + "github.com/godbus/dbus/v5" + "github.com/ublue-os/uupd/pkg/session" +) + +func TestUserParsingInvalidUID(t *testing.T) { + t.Parallel() + testVariants := []dbus.Variant{ + dbus.MakeVariant(0.3), + dbus.MakeVariant(-1), + dbus.MakeVariant(math.MaxInt), + dbus.MakeVariant(math.MinInt), + } + + userName := dbus.MakeVariant("root") + for _, uidVariant := range testVariants { + t.Run(fmt.Sprintf("variant: %v", uidVariant.Value()), func(t *testing.T) { + t.Parallel() + _, err := session.ParseUserFromVariant(uidVariant, userName) + if err == nil { + t.Fatalf("Parser accepted invalid input: %v %v", uidVariant, userName) + } + }) + } +} + +func TestUserParsingInvalidName(t *testing.T) { + t.Parallel() + testVariants := []dbus.Variant{ + dbus.MakeVariant(0.3), + dbus.MakeVariant(-1), + dbus.MakeVariant(math.MaxInt), + dbus.MakeVariant(math.MinInt), + } + + uidVariant := dbus.MakeVariant(uint32(0)) + for _, nameVariant := range testVariants { + t.Run(fmt.Sprintf("variant: %v", uidVariant.Value()), func(t *testing.T) { + t.Parallel() + _, err := session.ParseUserFromVariant(uidVariant, nameVariant) + if err == nil { + t.Fatalf("Parser accepted invalid input: %v", err) + } + }) + } +} + +func TestUserParsingValidUser(t *testing.T) { + t.Parallel() + testVariants := []struct { + UidVariant dbus.Variant + NameVariant dbus.Variant + }{ + {dbus.MakeVariant(uint32(0)), dbus.MakeVariant("root")}, + {dbus.MakeVariant(uint32(10)), dbus.MakeVariant("bob")}, + {dbus.MakeVariant(uint32(20)), dbus.MakeVariant("beatryz")}, + {dbus.MakeVariant(uint32(math.MaxUint16)), dbus.MakeVariant("zorg_the_destroyer")}, + } + + for _, variant := range testVariants { + t.Run(fmt.Sprintf("variant: %v", variant.NameVariant.Value()), func(t *testing.T) { + t.Parallel() + _, err := session.ParseUserFromVariant(variant.UidVariant, variant.NameVariant) + if err != nil { + t.Fatalf("Parser rejected valid input: %v", err) + } + }) + } +} From 68ca8d686190d62b06e4b51d51541bd1263f0dd9 Mon Sep 17 00:00:00 2001 From: Tulip Blossom Date: Sat, 21 Dec 2024 00:55:25 -0300 Subject: [PATCH 4/6] chore: remove progress bar and dependencies --- cmd/root.go | 17 ----- cmd/update.go | 40 +++--------- drv/brew/brew.go | 6 +- drv/distrobox/distrobox.go | 16 ++--- drv/flatpak/flatpak.go | 16 ++--- drv/generic/generic.go | 8 --- go.mod | 4 -- go.sum | 8 --- pkg/logging/userHandler.go | 8 ++- pkg/percent/colorpicker.go | 70 -------------------- pkg/percent/incrementer.go | 22 ++----- pkg/percent/incrementer_test.go | 13 +--- pkg/percent/progressmanager.go | 112 ++------------------------------ pkg/session/session.go | 9 +-- uupd.service | 2 +- 15 files changed, 55 insertions(+), 296 deletions(-) delete mode 100644 pkg/percent/colorpicker.go diff --git a/cmd/root.go b/cmd/root.go index f8e476d..5a7fa43 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -9,10 +9,8 @@ import ( "path" "path/filepath" - "github.com/jedib0t/go-pretty/v6/text" "github.com/spf13/cobra" appLogging "github.com/ublue-os/uupd/pkg/logging" - "golang.org/x/term" ) func assertRoot(cmd *cobra.Command, args []string) { @@ -118,19 +116,4 @@ func init() { rootCmd.PersistentFlags().StringVar(&fLogFile, "log-file", "-", "File where user-facing logs will be written to") rootCmd.PersistentFlags().StringVar(&fLogLevel, "log-level", "info", "Log level for user-facing logs") rootCmd.PersistentFlags().BoolVar(&fNoLogging, "quiet", false, "Make logs quiet") - - interactiveProgress := true - if fLogFile != "-" { - interactiveProgress = false - } - isTerminal := term.IsTerminal(int(os.Stdout.Fd())) - if !isTerminal { - interactiveProgress = false - } - if !text.ANSICodesSupported { - interactiveProgress = false - text.DisableColors() - } - - rootCmd.Flags().BoolP("no-progress", "p", !interactiveProgress, "Do not show progress bars") } diff --git a/cmd/update.go b/cmd/update.go index 055efad..2f22aa7 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -5,7 +5,6 @@ import ( "log/slog" "os" - "github.com/jedib0t/go-pretty/v6/progress" "github.com/spf13/cobra" "github.com/ublue-os/uupd/checks" "github.com/ublue-os/uupd/drv/brew" @@ -98,34 +97,15 @@ func Update(cmd *cobra.Command, args []string) { if mainSystemDriverConfig.Enabled { totalSteps += mainSystemDriver.Steps() } - pw := percent.NewProgressWriter() - pw.SetNumTrackersExpected(1) - pw.SetAutoStop(false) - progressEnabled, err := cmd.Flags().GetBool("no-progress") - if err != nil { - slog.Error("Failed to get no-progress flag", "error", err) - return - } - // Move this to its actual boolean value (~no-progress) - progressEnabled = !progressEnabled - - if progressEnabled { - go pw.Render() - percent.ResetOscProgress() - } + // FIXME: check if is interactive + percent.ResetOscProgress() // -1 because 0 index - tracker := percent.NewIncrementTracker(&progress.Tracker{Message: "Updating", Units: progress.UnitsDefault, Total: int64(totalSteps - 1)}, totalSteps-1) - pw.AppendTracker(tracker.Tracker) + tracker := &percent.Incrementer{MaxIncrements: totalSteps - 1} - var trackerConfig = &drv.TrackerConfiguration{ - Tracker: tracker, - Writer: &pw, - Progress: progressEnabled, - } - flatpakUpdater.Tracker = trackerConfig - distroboxUpdater.Tracker = trackerConfig + flatpakUpdater.Tracker = tracker + distroboxUpdater.Tracker = tracker var outputs = []drv.CommandOutput{} @@ -149,7 +129,7 @@ func Update(cmd *cobra.Command, args []string) { if mainSystemDriverConfig.Enabled { slog.Debug(fmt.Sprintf("%s module", mainSystemDriverConfig.Title), slog.String("module_name", mainSystemDriverConfig.Title), slog.Any("module_configuration", mainSystemDriverConfig)) - percent.ChangeTrackerMessageFancy(pw, tracker, progressEnabled, percent.TrackerMessage{Title: mainSystemDriverConfig.Title, Description: mainSystemDriverConfig.Description}) + percent.ReportStatusChange(tracker, percent.TrackerMessage{Title: mainSystemDriverConfig.Title, Description: mainSystemDriverConfig.Description}) var out *[]drv.CommandOutput out, err = mainSystemDriver.Update() outputs = append(outputs, *out...) @@ -158,7 +138,7 @@ func Update(cmd *cobra.Command, args []string) { if brewUpdater.Config.Enabled { slog.Debug(fmt.Sprintf("%s module", brewUpdater.Config.Title), slog.String("module_name", brewUpdater.Config.Title), slog.Any("module_configuration", brewUpdater.Config)) - percent.ChangeTrackerMessageFancy(pw, tracker, progressEnabled, percent.TrackerMessage{Title: brewUpdater.Config.Title, Description: brewUpdater.Config.Description}) + percent.ReportStatusChange(tracker, percent.TrackerMessage{Title: brewUpdater.Config.Title, Description: brewUpdater.Config.Description}) var out *[]drv.CommandOutput out, err = brewUpdater.Update() outputs = append(outputs, *out...) @@ -181,10 +161,8 @@ func Update(cmd *cobra.Command, args []string) { tracker.IncrementSection(err) } - if progressEnabled { - pw.Stop() - percent.ResetOscProgress() - } + // FIXME: detect interactive session + percent.ResetOscProgress() if verboseRun { slog.Info("Verbose run requested") diff --git a/drv/brew/brew.go b/drv/brew/brew.go index 1abf928..0fc0e93 100644 --- a/drv/brew/brew.go +++ b/drv/brew/brew.go @@ -89,9 +89,9 @@ func (up BrewUpdater) New(config UpdaterInitConfiguration) (BrewUpdater, error) up.Config.Logger = config.Logger.With(slog.String("module", strings.ToLower(up.Config.Title))) up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_PREFIX", "/home/linuxbrew/.linuxbrew") - up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_REPOSITORY", fmt.Sprintf("%s/Homebrew", up.BrewPrefix)) - up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_CELLAR", fmt.Sprintf("%s/Cellar", up.BrewPrefix)) - up.BrewPrefix = EnvOrFallback(up.Config.Environment, "HOMEBREW_PATH", fmt.Sprintf("%s/bin/brew", up.BrewPrefix)) + up.BrewRepo = EnvOrFallback(up.Config.Environment, "HOMEBREW_REPOSITORY", fmt.Sprintf("%s/Homebrew", up.BrewPrefix)) + up.BrewCellar = EnvOrFallback(up.Config.Environment, "HOMEBREW_CELLAR", fmt.Sprintf("%s/Cellar", up.BrewPrefix)) + up.BrewPath = EnvOrFallback(up.Config.Environment, "HOMEBREW_PATH", fmt.Sprintf("%s/bin/brew", up.BrewPrefix)) if up.Config.DryRun { return up, nil diff --git a/drv/distrobox/distrobox.go b/drv/distrobox/distrobox.go index 85818ed..70a99fa 100644 --- a/drv/distrobox/distrobox.go +++ b/drv/distrobox/distrobox.go @@ -11,7 +11,7 @@ import ( type DistroboxUpdater struct { Config DriverConfiguration - Tracker *TrackerConfiguration + Tracker *percent.Incrementer binaryPath string users []session.User usersEnabled bool @@ -61,18 +61,18 @@ func (up DistroboxUpdater) Update() (*[]CommandOutput, error) { var finalOutput = []CommandOutput{} if up.Config.DryRun { - percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) - up.Tracker.Tracker.IncrementSection(nil) + percent.ReportStatusChange(up.Tracker, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) + up.Tracker.IncrementSection(nil) var err error = nil for _, user := range up.users { - up.Tracker.Tracker.IncrementSection(err) - percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: *up.Config.UserDescription + " " + user.Name}) + up.Tracker.IncrementSection(err) + percent.ReportStatusChange(up.Tracker, percent.TrackerMessage{Title: up.Config.Title, Description: *up.Config.UserDescription + " " + user.Name}) } return &finalOutput, nil } - percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) + percent.ReportStatusChange(up.Tracker, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) cli := []string{up.binaryPath, "upgrade", "-a"} out, err := session.RunUID(up.Config.Logger, slog.LevelDebug, 0, cli, nil) tmpout := CommandOutput{}.New(out, err) @@ -83,9 +83,9 @@ func (up DistroboxUpdater) Update() (*[]CommandOutput, error) { err = nil for _, user := range up.users { - up.Tracker.Tracker.IncrementSection(err) + up.Tracker.IncrementSection(err) context := *up.Config.UserDescription + " " + user.Name - percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: *up.Config.UserDescription + " " + user.Name}) + percent.ReportStatusChange(up.Tracker, percent.TrackerMessage{Title: up.Config.Title, Description: *up.Config.UserDescription + " " + user.Name}) cli := []string{up.binaryPath, "upgrade", "-a"} out, err := session.RunUID(up.Config.Logger, slog.LevelDebug, user.UID, cli, nil) tmpout = CommandOutput{}.New(out, err) diff --git a/drv/flatpak/flatpak.go b/drv/flatpak/flatpak.go index 3a99c56..7cbfd79 100644 --- a/drv/flatpak/flatpak.go +++ b/drv/flatpak/flatpak.go @@ -12,7 +12,7 @@ import ( type FlatpakUpdater struct { Config DriverConfiguration - Tracker *TrackerConfiguration + Tracker *percent.Incrementer binaryPath string users []session.User usersEnabled bool @@ -62,18 +62,18 @@ func (up FlatpakUpdater) Update() (*[]CommandOutput, error) { var finalOutput = []CommandOutput{} if up.Config.DryRun { - percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) - up.Tracker.Tracker.IncrementSection(nil) + percent.ReportStatusChange(up.Tracker, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) + up.Tracker.IncrementSection(nil) var err error = nil for _, user := range up.users { - up.Tracker.Tracker.IncrementSection(err) - percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: *up.Config.UserDescription + " " + user.Name}) + up.Tracker.IncrementSection(err) + percent.ReportStatusChange(up.Tracker, percent.TrackerMessage{Title: up.Config.Title, Description: *up.Config.UserDescription + " " + user.Name}) } return &finalOutput, nil } - percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) + percent.ReportStatusChange(up.Tracker, percent.TrackerMessage{Title: up.Config.Title, Description: up.Config.Description}) cli := []string{up.binaryPath, "update", "-y", "--noninteractive"} flatpakCmd := exec.Command(cli[0], cli[1:]...) out, err := session.RunLog(up.Config.Logger, slog.LevelDebug, flatpakCmd) @@ -85,9 +85,9 @@ func (up FlatpakUpdater) Update() (*[]CommandOutput, error) { err = nil for _, user := range up.users { - up.Tracker.Tracker.IncrementSection(err) + up.Tracker.IncrementSection(err) context := *up.Config.UserDescription + " " + user.Name - percent.ChangeTrackerMessageFancy(*up.Tracker.Writer, up.Tracker.Tracker, up.Tracker.Progress, percent.TrackerMessage{Title: up.Config.Title, Description: context}) + percent.ReportStatusChange(up.Tracker, percent.TrackerMessage{Title: up.Config.Title, Description: context}) cli := []string{up.binaryPath, "update", "-y"} out, err := session.RunUID(up.Config.Logger, slog.LevelDebug, user.UID, cli, nil) tmpout = CommandOutput{}.New(out, err) diff --git a/drv/generic/generic.go b/drv/generic/generic.go index e885f48..512847c 100644 --- a/drv/generic/generic.go +++ b/drv/generic/generic.go @@ -5,8 +5,6 @@ import ( "os" "strings" - "github.com/jedib0t/go-pretty/v6/progress" - "github.com/ublue-os/uupd/pkg/percent" "github.com/ublue-os/uupd/pkg/session" ) @@ -74,12 +72,6 @@ type DriverConfiguration struct { UserDescription *string } -type TrackerConfiguration struct { - Tracker *percent.IncrementTracker - Writer *progress.Writer - Progress bool -} - type UpdateDriver interface { Steps() int Check() (bool, error) diff --git a/go.mod b/go.mod index cc7f8bf..0128381 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,8 @@ 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 - golang.org/x/term v0.26.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -16,9 +14,7 @@ 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 diff --git a/go.sum b/go.sum index e589ba7..a12d58d 100644 --- a/go.sum +++ b/go.sum @@ -12,18 +12,12 @@ 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= @@ -45,8 +39,6 @@ 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.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/logging/userHandler.go b/pkg/logging/userHandler.go index 1452a6b..e828218 100644 --- a/pkg/logging/userHandler.go +++ b/pkg/logging/userHandler.go @@ -96,7 +96,13 @@ func (h *UserHandler) Handle(ctx context.Context, r slog.Record) error { colorize(lightGray, r.Time.Format(timeFormat)), level, colorize(white, r.Message), - colorize(darkGray, "\n"+trimmedBytes), + colorize(darkGray, + func() string { + if len(trimmedBytes) > 0 && trimmedBytes != "{}" { + return colorize(darkGray, "\n"+trimmedBytes) + } + return "" + }()), ) return nil diff --git a/pkg/percent/colorpicker.go b/pkg/percent/colorpicker.go deleted file mode 100644 index 32043e4..0000000 --- a/pkg/percent/colorpicker.go +++ /dev/null @@ -1,70 +0,0 @@ -package percent - -import ( - "math" - - . "github.com/jedib0t/go-pretty/v6/text" -) - -// Accent color portal return as of xdg-desktop-portal-gnome 47.1 -type Accent struct { - Type string `json:"type"` - Data []struct { - Type string `json:"type"` - Data [3]float64 `json:"data"` - } `json:"data"` -} - -// Colors taken straight from GNOME 47 accent colors using this command: -// busctl --user call org.freedesktop.portal.Desktop /org/freedesktop/portal/desktop org.freedesktop.portal.Settings ReadOne 'ss' 'org.freedesktop.appearance' 'accent-color' -// This is as close as we can map the colors as possible afaik - Pink and Magenta DO look a like, and thats kind of a problem -var colorMap = map[Color][3]float64{ - FgHiBlack: {0, 0, 0}, - FgHiBlue: {0.207843, 0.517647, 0.894118}, - FgHiCyan: {0.129412, 0.564706, 0.643137}, - FgHiGreen: {0.227451, 0.580392, 0.290196}, - FgHiYellow: {0.784314, 0.533333, 0}, - FgHiRed: {0.901961, 0.176471, 0.258824}, - FgHiMagenta: {0.568627, 0.254902, 0.67451}, - FgHiWhite: {0.435294, 0.513726, 0.588235}, -} - -// Calculates the Euclidean distance between two colors -func colorDistance(c1, c2 [3]float64) float64 { - return math.Sqrt( - math.Pow(c1[0]-c2[0], 2) + - math.Pow(c1[1]-c2[1], 2) + - math.Pow(c1[2]-c2[2], 2), - ) -} - -func findClosestColor(rgb [3]float64) (Color, Color) { - var closestColor Color - minDistance := math.MaxFloat64 - - for color, predefinedRGB := range colorMap { - distance := colorDistance(rgb, predefinedRGB) - if distance < minDistance { - minDistance = distance - closestColor = color - } - } - - nonHiColor, isHiColor := hiToNonHiMap[closestColor] - if isHiColor { - return closestColor, nonHiColor - } - - return closestColor, closestColor -} - -var hiToNonHiMap = map[Color]Color{ - FgHiBlack: FgBlack, - FgHiRed: FgRed, - FgHiGreen: FgGreen, - FgHiYellow: FgYellow, - FgHiBlue: FgBlue, - FgHiMagenta: FgMagenta, - FgHiCyan: FgCyan, - FgHiWhite: FgWhite, -} diff --git a/pkg/percent/incrementer.go b/pkg/percent/incrementer.go index ebbf36f..725c7d4 100644 --- a/pkg/percent/incrementer.go +++ b/pkg/percent/incrementer.go @@ -1,29 +1,17 @@ package percent -import "github.com/jedib0t/go-pretty/v6/progress" - type Incrementer struct { DoneIncrements int MaxIncrements int } -type IncrementTracker struct { - Tracker *progress.Tracker - Incrementer *Incrementer -} - -func (it *IncrementTracker) IncrementSection(err error) { - if int64(it.Incrementer.DoneIncrements)+int64(1) > int64(it.Incrementer.MaxIncrements) { +func (it *Incrementer) IncrementSection(err error) { + if int64(it.DoneIncrements)+int64(1) > int64(it.MaxIncrements) { return } - it.Incrementer.DoneIncrements += 1 - if err == nil { - it.Tracker.Increment(1) - } else { - it.Tracker.IncrementWithError(1) - } + it.DoneIncrements += 1 } -func (it *IncrementTracker) CurrentStep() int { - return it.Incrementer.DoneIncrements +func (it *Incrementer) CurrentStep() int { + return it.DoneIncrements } diff --git a/pkg/percent/incrementer_test.go b/pkg/percent/incrementer_test.go index 954f430..0d1422b 100644 --- a/pkg/percent/incrementer_test.go +++ b/pkg/percent/incrementer_test.go @@ -4,20 +4,11 @@ import ( "math" "testing" - "github.com/jedib0t/go-pretty/v6/progress" "github.com/ublue-os/uupd/pkg/percent" ) -func InitIncrementer(max int) percent.IncrementTracker { - tracker := progress.Tracker{Message: "Updating", Units: progress.UnitsDefault, Total: int64(max)} - incrementer := percent.Incrementer{ - MaxIncrements: max, - DoneIncrements: 0, - } - return percent.IncrementTracker{ - Tracker: &tracker, - Incrementer: &incrementer, - } +func InitIncrementer(max int) percent.Incrementer { + return percent.Incrementer{MaxIncrements: max} } func TestOverflow(t *testing.T) { diff --git a/pkg/percent/progressmanager.go b/pkg/percent/progressmanager.go index ab945a1..a14f26a 100644 --- a/pkg/percent/progressmanager.go +++ b/pkg/percent/progressmanager.go @@ -1,119 +1,21 @@ package percent import ( - "encoding/json" - "fmt" "log/slog" - "math" - "os" - "strconv" - "time" - - "github.com/jedib0t/go-pretty/v6/progress" - "github.com/jedib0t/go-pretty/v6/text" - "github.com/ublue-os/uupd/pkg/session" ) -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 - - var targetUser int - baseUser, exists := os.LookupEnv("SUDO_UID") - if !exists || baseUser == "" { - targetUser = 0 - } else { - var err error - targetUser, err = strconv.Atoi(baseUser) - if err != nil { - slog.Error("Failed parsing provided user as UID", slog.String("user_value", baseUser)) - return pw - } - } - - if targetUser != 0 { - var accentColorSet progress.StyleColors - // Get accent color: https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html - cli := []string{"busctl", "--user", "--json=short", "call", "org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", "org.freedesktop.portal.Settings", "ReadOne", "ss", "org.freedesktop.appearance", "accent-color"} - out, err := session.RunUID(nil, slog.LevelDebug, targetUser, cli, nil) - if err != nil { - return pw - } - var accent Accent - err = json.Unmarshal(out, &accent) - if err != nil { - return pw - } - - raw_color := accent.Data[0].Data - - highlightColor, lowColor := findClosestColor(raw_color) - - validHighlightColor := text.Colors{highlightColor} - validLowColor := text.Colors{lowColor} - - accentColorSet.Percent = validHighlightColor - accentColorSet.Tracker = validHighlightColor - accentColorSet.Time = validLowColor - accentColorSet.Value = validLowColor - accentColorSet.Speed = validLowColor - pw.Style().Colors = accentColorSet - } - return pw -} - -func NewIncrementTracker(tracker *progress.Tracker, max_increments int) *IncrementTracker { - return &IncrementTracker{ - Tracker: tracker, - Incrementer: &Incrementer{MaxIncrements: max_increments}, - } -} - type TrackerMessage struct { Title string Description string } -func ChangeTrackerMessageFancy(writer progress.Writer, tracker *IncrementTracker, progress bool, message TrackerMessage) { - if !progress { - slog.Info("Updating", - slog.String("title", message.Title), - slog.String("description", message.Description), - slog.Int64("progress", tracker.Tracker.Value()), - slog.Int64("total", tracker.Tracker.Total), - ) - return - } - percentage := math.Round((float64(tracker.Tracker.Value()) / float64(tracker.Tracker.Total)) * 100) - fmt.Printf("\033]9;4;1;%d\a", int(percentage)) - finalMessage := fmt.Sprintf("Updating %s (%s)", message.Description, message.Title) - writer.SetMessageLength(len(finalMessage)) - tracker.Tracker.UpdateMessage(finalMessage) +func ReportStatusChange(tracker *Incrementer, message TrackerMessage) { + slog.Info("Updating", + slog.String("title", message.Title), + slog.String("description", message.Description), + slog.Int("progress", tracker.CurrentStep()), + slog.Int("total", tracker.MaxIncrements), + ) } func ResetOscProgress() { diff --git a/pkg/session/session.go b/pkg/session/session.go index 5f9bacc..12fe655 100644 --- a/pkg/session/session.go +++ b/pkg/session/session.go @@ -26,17 +26,18 @@ func RunLog(logger *slog.Logger, level slog.Level, command *exec.Cmd) ([]byte, e stdout, _ := command.StdoutPipe() stderr, _ := command.StderrPipe() multiReader := io.MultiReader(stdout, stderr) + actuallogger := slog.Default() - if err := command.Wait(); err != nil { - logger.Warn("Error occoured starting external command", slog.Any("error", err)) + if err := command.Start(); err != nil { + actuallogger.Warn("Error occoured starting external command", slog.Any("error", err)) } scanner := bufio.NewScanner(multiReader) scanner.Split(bufio.ScanLines) for scanner.Scan() { - logger.With(slog.Bool("subcommand", true)).Log(context.TODO(), level, scanner.Text()) + actuallogger.Log(context.TODO(), level, scanner.Text()) } if err := command.Wait(); err != nil { - logger.Warn("Error occoured while waiting for external command", slog.Any("error", err)) + actuallogger.Warn("Error occoured while waiting for external command", slog.Any("error", err)) } return scanner.Bytes(), scanner.Err() diff --git a/uupd.service b/uupd.service index 6bbf5a0..4f71287 100644 --- a/uupd.service +++ b/uupd.service @@ -3,4 +3,4 @@ Description=Universal Blue Update Oneshot Service [Service] Type=oneshot -ExecStart=/usr/bin/uupd -c +ExecStart=/usr/bin/uupd --log-level debug From 8cdf02a59f7b70929dbf7a5ded49299607ae1eee Mon Sep 17 00:00:00 2001 From: Tulip Blossom Date: Sat, 21 Dec 2024 00:58:50 -0300 Subject: [PATCH 5/6] chore: explicitly log to json on service --- uupd.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uupd.service b/uupd.service index 4f71287..aac4cba 100644 --- a/uupd.service +++ b/uupd.service @@ -3,4 +3,4 @@ Description=Universal Blue Update Oneshot Service [Service] Type=oneshot -ExecStart=/usr/bin/uupd --log-level debug +ExecStart=/usr/bin/uupd --log-level debug --json --hw-check From 66738afdc539fe25b90cb09b610c75ede7de96a0 Mon Sep 17 00:00:00 2001 From: Tulip Blossom Date: Sat, 21 Dec 2024 01:28:13 -0300 Subject: [PATCH 6/6] chore(spec): change requires to recommends on uupd spec --- uupd.spec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uupd.spec b/uupd.spec index f57ed99..946bf4f 100644 --- a/uupd.spec +++ b/uupd.spec @@ -14,9 +14,9 @@ License: Apache-2.0 BuildRequires: golang BuildRequires: systemd-rpm-macros -Requires: bootc -Requires: distrobox -Requires: flatpak +Recommends: bootc +Recommends: distrobox +Recommends: flatpak Requires: libnotify Requires: systemd Provides: %{name} = %{version}