Browse Source

cmd/tailscale/cli: set Sparkle auto-update on macsys (#9952)

On `tailscale set --auto-update`, set the Sparkle plist option for it.
Also make macsys report not supporting auto-updates over c2n, since they
will be triggered by Sparkle locally.

Updates #755

Signed-off-by: Andrew Lytvynov <[email protected]>
Andrew Lytvynov 2 years ago
parent
commit
d3bc575f35
3 changed files with 30 additions and 4 deletions
  1. 3 1
      clientupdate/clientupdate.go
  2. 18 3
      cmd/tailscale/cli/set.go
  3. 9 0
      version/prop.go

+ 3 - 1
clientupdate/clientupdate.go

@@ -202,7 +202,9 @@ func (up *Updater) getUpdateFunction() (fn updateFunction, canAutoUpdate bool) {
 			// support auto-updates.
 			return up.updateMacAppStore, false
 		case version.IsMacSysExt():
-			return up.updateMacSys, true
+			// Macsys update func kicks off Sparkle. Auto-updates are done by
+			// Sparkle.
+			return up.updateMacSys, false
 		default:
 			return nil, false
 		}

+ 18 - 3
cmd/tailscale/cli/set.go

@@ -9,6 +9,7 @@ import (
 	"flag"
 	"fmt"
 	"net/netip"
+	"os/exec"
 
 	"github.com/peterbourgon/ff/v3/ffcli"
 	"tailscale.com/clientupdate"
@@ -17,6 +18,7 @@ import (
 	"tailscale.com/net/tsaddr"
 	"tailscale.com/safesocket"
 	"tailscale.com/types/views"
+	"tailscale.com/version"
 )
 
 var setCmd = &ffcli.Command{
@@ -157,9 +159,22 @@ func runSet(ctx context.Context, args []string) (retErr error) {
 		}
 	}
 	if maskedPrefs.AutoUpdateSet {
-		_, err := clientupdate.NewUpdater(clientupdate.Arguments{ForAutoUpdate: true})
-		if errors.Is(err, errors.ErrUnsupported) {
-			return errors.New("automatic updates are not supported on this platform")
+		// On macsys, tailscaled will set the Sparkle auto-update setting. It
+		// does not use clientupdate.
+		if version.IsMacSysExt() {
+			apply := "0"
+			if maskedPrefs.AutoUpdate.Apply {
+				apply = "1"
+			}
+			out, err := exec.Command("defaults", "write", "io.tailscale.ipn.macsys", "SUAutomaticallyUpdate", apply).CombinedOutput()
+			if err != nil {
+				return fmt.Errorf("failed to enable automatic updates: %v, %q", err, out)
+			}
+		} else {
+			_, err := clientupdate.NewUpdater(clientupdate.Arguments{ForAutoUpdate: true})
+			if errors.Is(err, errors.ErrUnsupported) {
+				return errors.New("automatic updates are not supported on this platform")
+			}
 		}
 	}
 	checkPrefs := curPrefs.Clone()

+ 9 - 0
version/prop.go

@@ -59,6 +59,9 @@ func IsMacSysExt() bool {
 		return false
 	}
 	return isMacSysExt.Get(func() bool {
+		if strings.Contains(os.Getenv("HOME"), "/Containers/io.tailscale.ipn.macsys/") {
+			return true
+		}
 		exe, err := os.Executable()
 		if err != nil {
 			return false
@@ -76,6 +79,12 @@ func IsMacAppStore() bool {
 		return false
 	}
 	return isMacAppStore.Get(func() bool {
+		// Both macsys and app store versions can run CLI executable with
+		// suffix /Contents/MacOS/Tailscale. Check $HOME to filter out running
+		// as macsys.
+		if strings.Contains(os.Getenv("HOME"), "/Containers/io.tailscale.ipn.macsys/") {
+			return false
+		}
 		exe, err := os.Executable()
 		if err != nil {
 			return false