From e6aa7b815d2dca9af1d803b3585eff96be045af3 Mon Sep 17 00:00:00 2001 From: Andrew Lytvynov Date: Fri, 6 Oct 2023 12:00:15 -0700 Subject: [PATCH] clientupdate,cmd/tailscale/cli: use cli.Stdout/Stderr (#9694) In case cli.Stdout/Stderr get overriden, all CLI output should use them instead of os.Stdout/Stderr. Update the `update` command to follow this pattern. Updates #cleanup Signed-off-by: Andrew Lytvynov --- clientupdate/clientupdate.go | 52 +++++++++++++++++++++--------------- cmd/tailscale/cli/update.go | 4 ++- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/clientupdate/clientupdate.go b/clientupdate/clientupdate.go index b788c7321..f313dc0dd 100644 --- a/clientupdate/clientupdate.go +++ b/clientupdate/clientupdate.go @@ -77,6 +77,10 @@ type Arguments struct { AppStore bool // Logf is a logger for update progress messages. Logf logger.Logf + // Stdout and Stderr should be used for output instead of os.Stdout and + // os.Stderr. + Stdout io.Writer + Stderr io.Writer // Confirm is called when a new version is available and should return true // if this new version should be installed. When Confirm returns false, the // update is aborted. @@ -108,6 +112,12 @@ func NewUpdater(args Arguments) (*Updater, error) { up := Updater{ Arguments: args, } + if up.Stdout == nil { + up.Stdout = os.Stdout + } + if up.Stderr == nil { + up.Stderr = os.Stderr + } up.Update = up.getUpdateFunction() if up.Update == nil { return nil, errors.ErrUnsupported @@ -256,9 +266,9 @@ func (up *Updater) updateSynology() error { // connected over tailscale ssh and this parent process dies. Otherwise, if // you abort synopkg install mid-way, tailscaled is not restarted. cmd := exec.Command("nohup", "synopkg", "install", spkPath) - // Don't attach cmd.Stdout to os.Stdout because nohup will redirect that - // into nohup.out file. synopkg doesn't have any progress output anyway, it - // just spits out a JSON result when done. + // Don't attach cmd.Stdout to Stdout because nohup will redirect that into + // nohup.out file. synopkg doesn't have any progress output anyway, it just + // spits out a JSON result when done. out, err := cmd.CombinedOutput() if err != nil { if dsmVersion == 6 && bytes.Contains(out, []byte("error = [290]")) { @@ -369,15 +379,15 @@ func (up *Updater) updateDebLike() error { // we're not updating them: "-o", "APT::Get::List-Cleanup=0", ) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stdout + cmd.Stderr = up.Stderr if err := cmd.Run(); err != nil { return err } cmd = exec.Command("apt-get", "install", "--yes", "--allow-downgrades", "tailscale="+ver) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stdout + cmd.Stderr = up.Stderr if err := cmd.Run(); err != nil { return err } @@ -491,8 +501,8 @@ func (up *Updater) updateFedoraLike(packageManager string) func() error { } cmd := exec.Command(packageManager, "install", "--assumeyes", fmt.Sprintf("tailscale-%s-1", ver)) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stdout + cmd.Stderr = up.Stderr if err := cmd.Run(); err != nil { return err } @@ -577,8 +587,8 @@ func (up *Updater) updateAlpineLike() (err error) { } cmd := exec.Command("apk", "upgrade", "tailscale") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stdout + cmd.Stderr = up.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("failed tailscale update using apk: %w", err) } @@ -634,8 +644,8 @@ func (up *Updater) updateMacAppStore() error { } cmd := exec.Command("sudo", "softwareupdate", "--install", newTailscale) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stdout + cmd.Stderr = up.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("can't install App Store update for Tailscale: %w", err) } @@ -726,8 +736,8 @@ func (up *Updater) updateWindows() error { cmd := exec.Command(selfCopy, "update") cmd.Env = append(os.Environ(), winMSIEnv+"="+msiTarget) - cmd.Stdout = os.Stderr - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stderr + cmd.Stderr = up.Stderr cmd.Stdin = os.Stdin if err := cmd.Start(); err != nil { return err @@ -743,8 +753,8 @@ func (up *Updater) installMSI(msi string) error { for tries := 0; tries < 2; tries++ { cmd := exec.Command("msiexec.exe", "/i", filepath.Base(msi), "/quiet", "/promptrestart", "/qn") cmd.Dir = filepath.Dir(msi) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stdout + cmd.Stderr = up.Stderr cmd.Stdin = os.Stdin err = cmd.Run() if err == nil { @@ -757,8 +767,8 @@ func (up *Updater) installMSI(msi string) error { // Assume it's a downgrade, which msiexec won't permit. Uninstall our current version first. up.Logf("Uninstalling current version %q for downgrade...", uninstallVersion) cmd = exec.Command("msiexec.exe", "/x", msiUUIDForVersion(uninstallVersion), "/norestart", "/qn") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stdout + cmd.Stderr = up.Stderr cmd.Stdin = os.Stdin err = cmd.Run() up.Logf("msiexec uninstall: %v", err) @@ -846,8 +856,8 @@ func (up *Updater) updateFreeBSD() (err error) { } cmd := exec.Command("pkg", "upgrade", "tailscale") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdout = up.Stdout + cmd.Stderr = up.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("failed tailscale update using pkg: %w", err) } diff --git a/cmd/tailscale/cli/update.go b/cmd/tailscale/cli/update.go index 5ee47ac97..212615169 100644 --- a/cmd/tailscale/cli/update.go +++ b/cmd/tailscale/cli/update.go @@ -63,7 +63,9 @@ func runUpdate(ctx context.Context, args []string) error { err := clientupdate.Update(clientupdate.Arguments{ Version: ver, AppStore: updateArgs.appStore, - Logf: func(format string, args ...any) { fmt.Printf(format+"\n", args...) }, + Logf: printf, + Stdout: Stdout, + Stderr: Stderr, Confirm: confirmUpdate, }) if errors.Is(err, errors.ErrUnsupported) {