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 <awly@tailscale.com>
This commit is contained in:
Andrew Lytvynov 2023-10-06 12:00:15 -07:00 committed by GitHub
parent b7988b3825
commit e6aa7b815d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 22 deletions

View File

@ -77,6 +77,10 @@ type Arguments struct {
AppStore bool AppStore bool
// Logf is a logger for update progress messages. // Logf is a logger for update progress messages.
Logf logger.Logf 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 // 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 // if this new version should be installed. When Confirm returns false, the
// update is aborted. // update is aborted.
@ -108,6 +112,12 @@ func NewUpdater(args Arguments) (*Updater, error) {
up := Updater{ up := Updater{
Arguments: args, Arguments: args,
} }
if up.Stdout == nil {
up.Stdout = os.Stdout
}
if up.Stderr == nil {
up.Stderr = os.Stderr
}
up.Update = up.getUpdateFunction() up.Update = up.getUpdateFunction()
if up.Update == nil { if up.Update == nil {
return nil, errors.ErrUnsupported return nil, errors.ErrUnsupported
@ -256,9 +266,9 @@ func (up *Updater) updateSynology() error {
// connected over tailscale ssh and this parent process dies. Otherwise, if // connected over tailscale ssh and this parent process dies. Otherwise, if
// you abort synopkg install mid-way, tailscaled is not restarted. // you abort synopkg install mid-way, tailscaled is not restarted.
cmd := exec.Command("nohup", "synopkg", "install", spkPath) cmd := exec.Command("nohup", "synopkg", "install", spkPath)
// Don't attach cmd.Stdout to os.Stdout because nohup will redirect that // Don't attach cmd.Stdout to Stdout because nohup will redirect that into
// into nohup.out file. synopkg doesn't have any progress output anyway, it // nohup.out file. synopkg doesn't have any progress output anyway, it just
// just spits out a JSON result when done. // spits out a JSON result when done.
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
if dsmVersion == 6 && bytes.Contains(out, []byte("error = [290]")) { if dsmVersion == 6 && bytes.Contains(out, []byte("error = [290]")) {
@ -369,15 +379,15 @@ func (up *Updater) updateDebLike() error {
// we're not updating them: // we're not updating them:
"-o", "APT::Get::List-Cleanup=0", "-o", "APT::Get::List-Cleanup=0",
) )
cmd.Stdout = os.Stdout cmd.Stdout = up.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return err return err
} }
cmd = exec.Command("apt-get", "install", "--yes", "--allow-downgrades", "tailscale="+ver) cmd = exec.Command("apt-get", "install", "--yes", "--allow-downgrades", "tailscale="+ver)
cmd.Stdout = os.Stdout cmd.Stdout = up.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return err 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 := exec.Command(packageManager, "install", "--assumeyes", fmt.Sprintf("tailscale-%s-1", ver))
cmd.Stdout = os.Stdout cmd.Stdout = up.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return err return err
} }
@ -577,8 +587,8 @@ func (up *Updater) updateAlpineLike() (err error) {
} }
cmd := exec.Command("apk", "upgrade", "tailscale") cmd := exec.Command("apk", "upgrade", "tailscale")
cmd.Stdout = os.Stdout cmd.Stdout = up.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return fmt.Errorf("failed tailscale update using apk: %w", err) 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 := exec.Command("sudo", "softwareupdate", "--install", newTailscale)
cmd.Stdout = os.Stdout cmd.Stdout = up.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return fmt.Errorf("can't install App Store update for Tailscale: %w", err) 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 := exec.Command(selfCopy, "update")
cmd.Env = append(os.Environ(), winMSIEnv+"="+msiTarget) cmd.Env = append(os.Environ(), winMSIEnv+"="+msiTarget)
cmd.Stdout = os.Stderr cmd.Stdout = up.Stderr
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return err return err
@ -743,8 +753,8 @@ func (up *Updater) installMSI(msi string) error {
for tries := 0; tries < 2; tries++ { for tries := 0; tries < 2; tries++ {
cmd := exec.Command("msiexec.exe", "/i", filepath.Base(msi), "/quiet", "/promptrestart", "/qn") cmd := exec.Command("msiexec.exe", "/i", filepath.Base(msi), "/quiet", "/promptrestart", "/qn")
cmd.Dir = filepath.Dir(msi) cmd.Dir = filepath.Dir(msi)
cmd.Stdout = os.Stdout cmd.Stdout = up.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
err = cmd.Run() err = cmd.Run()
if err == nil { 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. // Assume it's a downgrade, which msiexec won't permit. Uninstall our current version first.
up.Logf("Uninstalling current version %q for downgrade...", uninstallVersion) up.Logf("Uninstalling current version %q for downgrade...", uninstallVersion)
cmd = exec.Command("msiexec.exe", "/x", msiUUIDForVersion(uninstallVersion), "/norestart", "/qn") cmd = exec.Command("msiexec.exe", "/x", msiUUIDForVersion(uninstallVersion), "/norestart", "/qn")
cmd.Stdout = os.Stdout cmd.Stdout = up.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
err = cmd.Run() err = cmd.Run()
up.Logf("msiexec uninstall: %v", err) up.Logf("msiexec uninstall: %v", err)
@ -846,8 +856,8 @@ func (up *Updater) updateFreeBSD() (err error) {
} }
cmd := exec.Command("pkg", "upgrade", "tailscale") cmd := exec.Command("pkg", "upgrade", "tailscale")
cmd.Stdout = os.Stdout cmd.Stdout = up.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = up.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return fmt.Errorf("failed tailscale update using pkg: %w", err) return fmt.Errorf("failed tailscale update using pkg: %w", err)
} }

View File

@ -63,7 +63,9 @@ func runUpdate(ctx context.Context, args []string) error {
err := clientupdate.Update(clientupdate.Arguments{ err := clientupdate.Update(clientupdate.Arguments{
Version: ver, Version: ver,
AppStore: updateArgs.appStore, AppStore: updateArgs.appStore,
Logf: func(format string, args ...any) { fmt.Printf(format+"\n", args...) }, Logf: printf,
Stdout: Stdout,
Stderr: Stderr,
Confirm: confirmUpdate, Confirm: confirmUpdate,
}) })
if errors.Is(err, errors.ErrUnsupported) { if errors.Is(err, errors.ErrUnsupported) {