From 3b7ebeba2ea6c40ac369e6fb2f335e3ee7b20ee7 Mon Sep 17 00:00:00 2001 From: Andrew Lytvynov Date: Thu, 24 Aug 2023 16:23:13 -0600 Subject: [PATCH] clientupdate: remove Arch support (#9081) An Arch Linux maintainer asked us to not implement "tailscale update" on Arch-based distros: https://github.com/tailscale/tailscale/issues/6995#issuecomment-1687080106 Return an error to the user if they try to run "tailscale update". Updates #6995 Signed-off-by: Andrew Lytvynov --- clientupdate/clientupdate.go | 61 ++---------------- clientupdate/clientupdate_test.go | 102 ------------------------------ 2 files changed, 6 insertions(+), 157 deletions(-) diff --git a/clientupdate/clientupdate.go b/clientupdate/clientupdate.go index b55623f8e..5355d01c3 100644 --- a/clientupdate/clientupdate.go +++ b/clientupdate/clientupdate.go @@ -403,61 +403,12 @@ func updateDebianAptSourcesListBytes(was []byte, dstTrack string) (newContent [] return buf.Bytes(), nil } -func (up *updater) updateArchLike() (err error) { - if up.Version != "" { - return errors.New("installing a specific version on Arch-based distros is not supported") - } - if err := requireRoot(); err != nil { - return err - } - - defer func() { - if err != nil { - err = fmt.Errorf(`%w; you can try updating using "pacman --sync --refresh tailscale"`, err) - } - }() - - out, err := exec.Command("pacman", "--sync", "--refresh", "--info", "tailscale").CombinedOutput() - if err != nil { - return fmt.Errorf("failed checking pacman for latest tailscale version: %w, output: %q", err, out) - } - ver, err := parsePacmanVersion(out) - if err != nil { - return err - } - if !up.confirm(ver) { - return nil - } - - cmd := exec.Command("pacman", "--sync", "--noconfirm", "tailscale") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed tailscale update using pacman: %w", err) - } - return nil -} - -func parsePacmanVersion(out []byte) (string, error) { - for _, line := range strings.Split(string(out), "\n") { - // The line we're looking for looks like this: - // Version : 1.44.2-1 - if !strings.HasPrefix(line, "Version") { - continue - } - parts := strings.SplitN(line, ":", 2) - if len(parts) != 2 { - return "", fmt.Errorf("version output from pacman is malformed: %q, cannot determine upgrade version", line) - } - ver := strings.TrimSpace(parts[1]) - // Trim the Arch patch version. - ver = strings.Split(ver, "-")[0] - if ver == "" { - return "", fmt.Errorf("version output from pacman is malformed: %q, cannot determine upgrade version", line) - } - return ver, nil - } - return "", fmt.Errorf("could not find latest version of tailscale via pacman") +func (up *updater) updateArchLike() error { + // Arch maintainer asked us not to implement "tailscale update" or + // auto-updates on Arch-based distros: + // https://github.com/tailscale/tailscale/issues/6995#issuecomment-1687080106 + return errors.New(`individual package updates are not supported on Arch-based distros, only full-system updates are: https://wiki.archlinux.org/title/System_maintenance#Partial_upgrades_are_unsupported. +you can use "pacman --sync --refresh --sysupgrade" or "pacman -Syu" to upgrade the system, including Tailscale.`) } const yumRepoConfigFile = "/etc/yum.repos.d/tailscale.repo" diff --git a/clientupdate/clientupdate_test.go b/clientupdate/clientupdate_test.go index 83aa6a07e..c6fa18234 100644 --- a/clientupdate/clientupdate_test.go +++ b/clientupdate/clientupdate_test.go @@ -157,108 +157,6 @@ func TestParseSoftwareupdateList(t *testing.T) { } } -func TestParsePacmanVersion(t *testing.T) { - tests := []struct { - desc string - out string - want string - wantErr bool - }{ - { - desc: "valid version", - out: ` -:: Synchronizing package databases... - endeavouros is up to date - core is up to date - extra is up to date - multilib is up to date -Repository : extra -Name : tailscale -Version : 1.44.2-1 -Description : A mesh VPN that makes it easy to connect your devices, wherever they are. -Architecture : x86_64 -URL : https://tailscale.com -Licenses : MIT -Groups : None -Provides : None -Depends On : glibc -Optional Deps : None -Conflicts With : None -Replaces : None -Download Size : 7.98 MiB -Installed Size : 32.47 MiB -Packager : Christian Heusel -Build Date : Tue 18 Jul 2023 12:28:37 PM PDT -Validated By : MD5 Sum SHA-256 Sum Signature -`, - want: "1.44.2", - }, - { - desc: "version without Arch patch number", - out: ` -... snip ... -Name : tailscale -Version : 1.44.2 -Description : A mesh VPN that makes it easy to connect your devices, wherever they are. -... snip ... -`, - want: "1.44.2", - }, - { - desc: "missing version", - out: ` -... snip ... -Name : tailscale -Description : A mesh VPN that makes it easy to connect your devices, wherever they are. -... snip ... -`, - wantErr: true, - }, - { - desc: "empty version", - out: ` -... snip ... -Name : tailscale -Version : -Description : A mesh VPN that makes it easy to connect your devices, wherever they are. -... snip ... -`, - wantErr: true, - }, - { - desc: "empty input", - out: "", - wantErr: true, - }, - { - desc: "sneaky version in description", - out: ` -... snip ... -Name : tailscale -Description : A mesh VPN that makes it easy to connect your devices, wherever they are. Version : 1.2.3 -Version : 1.44.2 -... snip ... -`, - want: "1.44.2", - }, - } - - for _, tt := range tests { - t.Run(tt.desc, func(t *testing.T) { - got, err := parsePacmanVersion([]byte(tt.out)) - if err == nil && tt.wantErr { - t.Fatalf("got nil error and version %q, want non-nil error", got) - } - if err != nil && !tt.wantErr { - t.Fatalf("got error: %q, want nil", err) - } - if got != tt.want { - t.Fatalf("got version: %q, want %q", got, tt.want) - } - }) - } -} - func TestUpdateYUMRepoTrack(t *testing.T) { tests := []struct { desc string