diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index 88419048..bf8d564c 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -1038,7 +1038,7 @@ func (s *apiService) getEvents(w http.ResponseWriter, r *http.Request, eventSub } func (s *apiService) getSystemUpgrade(w http.ResponseWriter, r *http.Request) { - if noUpgrade { + if noUpgradeFromEnv { http.Error(w, upgrade.ErrUpgradeUnsupported.Error(), 500) return } diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index a9da4ca4..5b8680db 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -60,6 +60,7 @@ var ( BuildHost = "unknown" BuildUser = "unknown" IsRelease bool + IsCandidate bool IsBeta bool LongVersion string allowedVersionExp = regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\.\d+)*(\+\d+-g[0-9a-f]+)?(-[^\s]+)?$`) @@ -99,14 +100,23 @@ func init() { } } - // Check for a clean release build. A release is something like "v0.1.2", - // with an optional suffix of letters and dot separated numbers like - // "-beta3.47". If there's more stuff, like a plus sign and a commit hash - // and so on, then it's not a release. If there's a dash anywhere in - // there, it's some kind of beta or prerelease version. + // Check for a clean release build. A release is something like + // "v0.1.2", with an optional suffix of letters and dot separated + // numbers like "-beta3.47". If there's more stuff, like a plus sign and + // a commit hash and so on, then it's not a release. If it has a dash in + // it, it's some sort of beta, release candidate or special build. If it + // has "-rc." in it, like "v0.14.35-rc.42", then it's a candidate build. + // + // So, every build that is not a stable release build has IsBeta = true. + // This is used to enable some extra debugging (the deadlock detector). + // + // Release candidate builds are also "betas" from this point of view and + // will have that debugging enabled. In addition, some features are + // forced for release candidates - auto upgrade, and usage reporting. exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z]+[\d\.]+)?$`) IsRelease = exp.MatchString(Version) + IsCandidate = strings.Contains(Version, "-rc.") IsBeta = strings.Contains(Version, "-") stamp, _ := strconv.Atoi(BuildStamp) @@ -207,9 +217,9 @@ The following are valid values for the STTRACE variable: // Environment options var ( - noUpgrade = os.Getenv("STNOUPGRADE") != "" - innerProcess = os.Getenv("STNORESTART") != "" || os.Getenv("STMONITORED") != "" - noDefaultFolder = os.Getenv("STNODEFAULTFOLDER") != "" + noUpgradeFromEnv = os.Getenv("STNOUPGRADE") != "" + innerProcess = os.Getenv("STNORESTART") != "" || os.Getenv("STMONITORED") != "" + noDefaultFolder = os.Getenv("STNODEFAULTFOLDER") != "" ) type RuntimeOptions struct { @@ -812,20 +822,26 @@ func syncthingMain(runtimeOptions RuntimeOptions) { } } + // Candidate builds always run with usage reporting. + + if IsCandidate { + l.Infoln("Anonymous usage reporting is always enabled for candidate releases.") + opts.URAccepted = usageReportVersion + // Unique ID will be set and config saved below if necessary. + } + if opts.URAccepted > 0 && opts.URAccepted < usageReportVersion { l.Infoln("Anonymous usage report has changed; revoking acceptance") opts.URAccepted = 0 opts.URUniqueID = "" cfg.SetOptions(opts) } - if opts.URAccepted >= usageReportVersion { - if opts.URUniqueID == "" { - // Previously the ID was generated from the node ID. We now need - // to generate a new one. - opts.URUniqueID = rand.String(8) - cfg.SetOptions(opts) - cfg.Save() - } + + if opts.URAccepted >= usageReportVersion && opts.URUniqueID == "" { + // Generate and save a new unique ID if it is missing. + opts.URUniqueID = rand.String(8) + cfg.SetOptions(opts) + cfg.Save() } // The usageReportingManager registers itself to listen to configuration @@ -837,8 +853,21 @@ func syncthingMain(runtimeOptions RuntimeOptions) { go standbyMonitor() } + // Candidate builds should auto upgrade. Make sure the option is set, + // unless we are in a build where it's disabled or the STNOUPGRADE + // environment variable is set. + + if IsCandidate && !upgrade.DisabledByCompilation && !noUpgradeFromEnv { + l.Infoln("Automatic upgrade is always enabled for candidate releases.") + if opts.AutoUpgradeIntervalH == 0 || opts.AutoUpgradeIntervalH > 24 { + opts.AutoUpgradeIntervalH = 12 + } + // We don't tweak the user's choice of upgrading to pre-releases or + // not, as otherwise they cannot step off the candidate channel. + } + if opts.AutoUpgradeIntervalH > 0 { - if noUpgrade { + if noUpgradeFromEnv { l.Infof("No automatic upgrades; STNOUPGRADE environment variable defined.") } else { go autoUpgrade(cfg) diff --git a/cmd/syncthing/usage_report.go b/cmd/syncthing/usage_report.go index 11cf0d92..c304177f 100644 --- a/cmd/syncthing/usage_report.go +++ b/cmd/syncthing/usage_report.go @@ -81,9 +81,10 @@ func (m *usageReportingManager) String() string { // reportData returns the data to be sent in a usage report. It's used in // various places, so not part of the usageReportingManager object. func reportData(cfg configIntf, m modelIntf) map[string]interface{} { + opts := cfg.Options() res := make(map[string]interface{}) res["urVersion"] = usageReportVersion - res["uniqueID"] = cfg.Options().URUniqueID + res["uniqueID"] = opts.URUniqueID res["version"] = Version res["longVersion"] = LongVersion res["platform"] = runtime.GOOS + "-" + runtime.GOARCH @@ -188,7 +189,7 @@ func reportData(cfg configIntf, m modelIntf) map[string]interface{} { res["deviceUses"] = deviceUses defaultAnnounceServersDNS, defaultAnnounceServersIP, otherAnnounceServers := 0, 0, 0 - for _, addr := range cfg.Options().GlobalAnnServers { + for _, addr := range opts.GlobalAnnServers { if addr == "default" || addr == "default-v4" || addr == "default-v6" { defaultAnnounceServersDNS++ } else { @@ -196,8 +197,8 @@ func reportData(cfg configIntf, m modelIntf) map[string]interface{} { } } res["announce"] = map[string]interface{}{ - "globalEnabled": cfg.Options().GlobalAnnEnabled, - "localEnabled": cfg.Options().LocalAnnEnabled, + "globalEnabled": opts.GlobalAnnEnabled, + "localEnabled": opts.LocalAnnEnabled, "defaultServersDNS": defaultAnnounceServersDNS, "defaultServersIP": defaultAnnounceServersIP, "otherServers": otherAnnounceServers, @@ -218,10 +219,11 @@ func reportData(cfg configIntf, m modelIntf) map[string]interface{} { "otherServers": otherRelayServers, } - res["usesRateLimit"] = cfg.Options().MaxRecvKbps > 0 || cfg.Options().MaxSendKbps > 0 + res["usesRateLimit"] = opts.MaxRecvKbps > 0 || opts.MaxSendKbps > 0 - res["upgradeAllowedManual"] = !(upgrade.DisabledByCompilation || noUpgrade) - res["upgradeAllowedAuto"] = !(upgrade.DisabledByCompilation || noUpgrade) && cfg.Options().AutoUpgradeIntervalH > 0 + res["upgradeAllowedManual"] = !(upgrade.DisabledByCompilation || noUpgradeFromEnv) + res["upgradeAllowedAuto"] = !(upgrade.DisabledByCompilation || noUpgradeFromEnv) && opts.AutoUpgradeIntervalH > 0 + res["upgradeAllowedPre"] = !(upgrade.DisabledByCompilation || noUpgradeFromEnv) && opts.AutoUpgradeIntervalH > 0 && opts.UpgradeToPreReleases return res }