|
|
@@ -653,6 +653,9 @@ func (up *Updater) updateAlpineLike() (err error) {
|
|
|
return fmt.Errorf(`failed to parse latest version from "apk info tailscale": %w`, err)
|
|
|
}
|
|
|
if !up.confirm(ver) {
|
|
|
+ if err := checkOutdatedAlpineRepo(up.Logf, ver, up.Track); err != nil {
|
|
|
+ up.Logf("failed to check whether Alpine release is outdated: %v", err)
|
|
|
+ }
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
@@ -690,6 +693,37 @@ func parseAlpinePackageVersion(out []byte) (string, error) {
|
|
|
return "", errors.New("tailscale version not found in output")
|
|
|
}
|
|
|
|
|
|
+var apkRepoVersionRE = regexp.MustCompile(`v[0-9]+\.[0-9]+`)
|
|
|
+
|
|
|
+func checkOutdatedAlpineRepo(logf logger.Logf, apkVer, track string) error {
|
|
|
+ latest, err := LatestTailscaleVersion(track)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if latest == apkVer {
|
|
|
+ // Actually on latest release.
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ f, err := os.Open("/etc/apk/repositories")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ defer f.Close()
|
|
|
+ // Read the first repo line. Typically, there are multiple repos that all
|
|
|
+ // contain the same version in the path, like:
|
|
|
+ // https://dl-cdn.alpinelinux.org/alpine/v3.20/main
|
|
|
+ // https://dl-cdn.alpinelinux.org/alpine/v3.20/community
|
|
|
+ s := bufio.NewScanner(f)
|
|
|
+ if !s.Scan() {
|
|
|
+ return s.Err()
|
|
|
+ }
|
|
|
+ alpineVer := apkRepoVersionRE.FindString(s.Text())
|
|
|
+ if alpineVer != "" {
|
|
|
+ logf("The latest Tailscale release for Linux is %q, but your apk repository only provides %q.\nYour Alpine version is %q, you may need to upgrade the system to get the latest Tailscale version: https://wiki.alpinelinux.org/wiki/Upgrading_Alpine", latest, apkVer, alpineVer)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
func (up *Updater) updateMacSys() error {
|
|
|
return errors.New("NOTREACHED: On MacSys builds, `tailscale update` is handled in Swift to launch the GUI updater")
|
|
|
}
|