mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-09 14:50:56 +00:00
cmd/syncthing, gui, lib/config, lib/upgrade: Add option to upgrade to pre-releases
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3939
This commit is contained in:
parent
e03be9158b
commit
35e87e23fd
@ -1042,7 +1042,8 @@ func (s *apiService) getSystemUpgrade(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, upgrade.ErrUpgradeUnsupported.Error(), 500)
|
||||
return
|
||||
}
|
||||
rel, err := upgrade.LatestRelease(s.cfg.Options().ReleasesURL, Version)
|
||||
opts := s.cfg.Options()
|
||||
rel, err := upgrade.LatestRelease(opts.ReleasesURL, Version, opts.UpgradeToPreReleases)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
@ -1083,7 +1084,8 @@ func (s *apiService) getLang(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (s *apiService) postSystemUpgrade(w http.ResponseWriter, r *http.Request) {
|
||||
rel, err := upgrade.LatestRelease(s.cfg.Options().ReleasesURL, Version)
|
||||
opts := s.cfg.Options()
|
||||
rel, err := upgrade.LatestRelease(opts.ReleasesURL, Version, opts.UpgradeToPreReleases)
|
||||
if err != nil {
|
||||
l.Warnln("getting latest release:", err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
|
@ -481,8 +481,8 @@ func debugFacilities() string {
|
||||
|
||||
func checkUpgrade() upgrade.Release {
|
||||
cfg, _ := loadConfig()
|
||||
releasesURL := cfg.Options().ReleasesURL
|
||||
release, err := upgrade.LatestRelease(releasesURL, Version)
|
||||
opts := cfg.Options()
|
||||
release, err := upgrade.LatestRelease(opts.ReleasesURL, Version, opts.UpgradeToPreReleases)
|
||||
if err != nil {
|
||||
l.Fatalln("Upgrade:", err)
|
||||
}
|
||||
@ -1158,8 +1158,8 @@ func autoUpgrade(cfg *config.Wrapper) {
|
||||
l.Infof("Connected to device %s with a newer version (current %q < remote %q). Checking for upgrades.", data["id"], Version, data["clientVersion"])
|
||||
case <-timer.C:
|
||||
}
|
||||
|
||||
rel, err := upgrade.LatestRelease(cfg.Options().ReleasesURL, Version)
|
||||
opts := cfg.Options()
|
||||
rel, err := upgrade.LatestRelease(opts.ReleasesURL, Version, opts.UpgradeToPreReleases)
|
||||
if err == upgrade.ErrUpgradeUnsupported {
|
||||
events.Default.Unsubscribe(sub)
|
||||
return
|
||||
|
@ -26,6 +26,7 @@
|
||||
"Be careful!": "Be careful!",
|
||||
"Bugs": "Bugs",
|
||||
"CPU Utilization": "CPU Utilization",
|
||||
"Candidate releases": "Candidate releases",
|
||||
"Changelog": "Changelog",
|
||||
"Clean out after": "Clean out after",
|
||||
"Close": "Close",
|
||||
@ -81,6 +82,7 @@
|
||||
"GUI Authentication Password": "GUI Authentication Password",
|
||||
"GUI Authentication User": "GUI Authentication User",
|
||||
"GUI Listen Addresses": "GUI Listen Addresses",
|
||||
"GUI Theme": "GUI Theme",
|
||||
"Generate": "Generate",
|
||||
"Global Changes": "Global Changes",
|
||||
"Global Discovery": "Global Discovery",
|
||||
@ -120,6 +122,7 @@
|
||||
"Newest First": "Newest First",
|
||||
"No": "No",
|
||||
"No File Versioning": "No File Versioning",
|
||||
"No upgrades": "No upgrades",
|
||||
"Normal": "Normal",
|
||||
"Notice": "Notice",
|
||||
"OK": "OK",
|
||||
@ -181,6 +184,7 @@
|
||||
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
|
||||
"Smallest First": "Smallest First",
|
||||
"Source Code": "Source Code",
|
||||
"Stable releases only": "Stable releases only",
|
||||
"Staggered File Versioning": "Staggered File Versioning",
|
||||
"Start Browser": "Start Browser",
|
||||
"Statistics": "Statistics",
|
||||
@ -234,6 +238,7 @@
|
||||
"Upgrading": "Upgrading",
|
||||
"Upload Rate": "Upload Rate",
|
||||
"Uptime": "Uptime",
|
||||
"Usage reporting is always enabled for candidate releases.": "Usage reporting is always enabled for candidate releases.",
|
||||
"Use HTTPS for GUI": "Use HTTPS for GUI",
|
||||
"Version": "Version",
|
||||
"Versions Path": "Versions Path",
|
||||
|
@ -1004,7 +1004,13 @@ angular.module('syncthing.core')
|
||||
$scope.tmpOptions = angular.copy($scope.config.options);
|
||||
$scope.tmpOptions.urEnabled = ($scope.tmpOptions.urAccepted > 0);
|
||||
$scope.tmpOptions.deviceName = $scope.thisDevice().name;
|
||||
$scope.tmpOptions.autoUpgradeEnabled = ($scope.tmpOptions.autoUpgradeIntervalH > 0);
|
||||
$scope.tmpOptions.upgrades = "none";
|
||||
if ($scope.tmpOptions.autoUpgradeIntervalH > 0) {
|
||||
$scope.tmpOptions.upgrades = "stable";
|
||||
}
|
||||
if ($scope.tmpOptions.upgradeToPreReleases) {
|
||||
$scope.tmpOptions.upgrades = "candidate";
|
||||
}
|
||||
$scope.tmpGUI = angular.copy($scope.config.gui);
|
||||
$('#settings').modal();
|
||||
};
|
||||
@ -1028,6 +1034,20 @@ angular.module('syncthing.core')
|
||||
var changed = !angular.equals($scope.config.options, $scope.tmpOptions) || !angular.equals($scope.config.gui, $scope.tmpGUI);
|
||||
var themeChanged = $scope.config.gui.theme !== $scope.tmpGUI.theme;
|
||||
if (changed) {
|
||||
// Check if auto-upgrade has been enabled or disabled. This
|
||||
// also has an effect on usage reporting, so do the check
|
||||
// for that later.
|
||||
if ($scope.tmpOptions.upgrades == "candidate") {
|
||||
$scope.tmpOptions.autoUpgradeIntervalH = $scope.tmpOptions.autoUpgradeIntervalH || 12;
|
||||
$scope.tmpOptions.upgradeToPreReleases = true;
|
||||
$scope.tmpOptions.urEnabled = true;
|
||||
} else if ($scope.tmpOptions.upgrades == "stable") {
|
||||
$scope.tmpOptions.autoUpgradeIntervalH = $scope.tmpOptions.autoUpgradeIntervalH || 12;
|
||||
$scope.tmpOptions.upgradeToPreReleases = false;
|
||||
} else {
|
||||
$scope.tmpOptions.autoUpgradeIntervalH = 0;
|
||||
}
|
||||
|
||||
// Check if usage reporting has been enabled or disabled
|
||||
if ($scope.tmpOptions.urEnabled && $scope.tmpOptions.urAccepted <= 0) {
|
||||
$scope.tmpOptions.urAccepted = 1000;
|
||||
@ -1035,13 +1055,6 @@ angular.module('syncthing.core')
|
||||
$scope.tmpOptions.urAccepted = -1;
|
||||
}
|
||||
|
||||
// Check if auto-upgrade has been enabled or disabled
|
||||
if ($scope.tmpOptions.autoUpgradeEnabled) {
|
||||
$scope.tmpOptions.autoUpgradeIntervalH = $scope.tmpOptions.autoUpgradeIntervalH || 12;
|
||||
} else {
|
||||
$scope.tmpOptions.autoUpgradeIntervalH = 0;
|
||||
}
|
||||
|
||||
// Check if protocol will need to be changed on restart
|
||||
if ($scope.config.gui.useTLS !== $scope.tmpGUI.useTLS) {
|
||||
$scope.protocolChanged = true;
|
||||
|
@ -107,19 +107,24 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" ng-if="upgradeInfo">
|
||||
<label translate>Automatic upgrades</label> <a href="https://docs.syncthing.net/users/releases.html" target="_blank"><span class="fa fa-fw fa-book"></span> <span translate>Help</span></a>
|
||||
<select class="form-control" ng-model="tmpOptions.upgrades">
|
||||
<option value="none" translate>No upgrades</option>
|
||||
<option value="stable" translate>Stable releases only</option>
|
||||
<option value="candidate" translate>Candidate releases</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<div class="checkbox" ng-if="tmpOptions.upgrades != 'candidate'">
|
||||
<label>
|
||||
<input id="UREnabled" type="checkbox" ng-model="tmpOptions.urEnabled"> <span translate>Anonymous Usage Reporting</span> (<a href="" translate data-toggle="modal" data-target="#urPreview">Preview</a>)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" ng-if="upgradeInfo">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input id="AutoUpgradeEnabled" type="checkbox" ng-model="tmpOptions.autoUpgradeEnabled"> <span translate>Automatic upgrades</span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="help-block" ng-if="tmpOptions.upgrades == 'candidate'">
|
||||
<span translate>Usage reporting is always enabled for candidate releases.</span> (<a href="" translate data-toggle="modal" data-target="#urPreview">Preview</a>)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
@ -133,7 +138,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-if="themes.length > 1">
|
||||
<label>GUI Theme</label>
|
||||
<label translate>GUI Theme</label>
|
||||
<select class="form-control" ng-model="tmpGUI.theme">
|
||||
<option ng-repeat="theme in themes.sort()" value="{{ theme }}">
|
||||
{{ themeName(theme) }}
|
||||
|
@ -30,6 +30,7 @@ type OptionsConfiguration struct {
|
||||
URInitialDelayS int `xml:"urInitialDelayS" json:"urInitialDelayS" default:"1800"`
|
||||
RestartOnWakeup bool `xml:"restartOnWakeup" json:"restartOnWakeup" default:"true"`
|
||||
AutoUpgradeIntervalH int `xml:"autoUpgradeIntervalH" json:"autoUpgradeIntervalH" default:"12"` // 0 for off
|
||||
UpgradeToPreReleases bool `xml:"upgradeToPreReleases" json:"upgradeToPreReleases"` // when auto upgrades are enabled
|
||||
KeepTemporariesH int `xml:"keepTemporariesH" json:"keepTemporariesH" default:"24"` // 0 for off
|
||||
CacheIgnoredFiles bool `xml:"cacheIgnoredFiles" json:"cacheIgnoredFiles" default:"false"`
|
||||
ProgressUpdateIntervalS int `xml:"progressUpdateIntervalS" json:"progressUpdateIntervalS" default:"5"`
|
||||
|
@ -84,10 +84,10 @@ func insecureGet(url, version string) (*http.Response, error) {
|
||||
return insecureHTTP.Do(req)
|
||||
}
|
||||
|
||||
// FetchLatestReleases returns the latest releases, including prereleases or
|
||||
// not depending on the argument
|
||||
func FetchLatestReleases(releasesURL, version string) []Release {
|
||||
resp, err := insecureGet(releasesURL, version)
|
||||
// FetchLatestReleases returns the latest releases. The "current" parameter
|
||||
// is used for setting the User-Agent only.
|
||||
func FetchLatestReleases(releasesURL, current string) []Release {
|
||||
resp, err := insecureGet(releasesURL, current)
|
||||
if err != nil {
|
||||
l.Infoln("Couldn't fetch release information:", err)
|
||||
return nil
|
||||
@ -119,24 +119,22 @@ func (s SortByRelease) Less(i, j int) bool {
|
||||
return CompareVersions(s[i].Tag, s[j].Tag) > 0
|
||||
}
|
||||
|
||||
func LatestRelease(releasesURL, version string) (Release, error) {
|
||||
rels := FetchLatestReleases(releasesURL, version)
|
||||
return SelectLatestRelease(version, rels)
|
||||
func LatestRelease(releasesURL, current string, upgradeToPreReleases bool) (Release, error) {
|
||||
rels := FetchLatestReleases(releasesURL, current)
|
||||
return SelectLatestRelease(rels, current, upgradeToPreReleases)
|
||||
}
|
||||
|
||||
func SelectLatestRelease(version string, rels []Release) (Release, error) {
|
||||
func SelectLatestRelease(rels []Release, current string, upgradeToPreReleases bool) (Release, error) {
|
||||
if len(rels) == 0 {
|
||||
return Release{}, ErrNoVersionToSelect
|
||||
}
|
||||
|
||||
// Sort the releases, lowest version number first
|
||||
sort.Sort(sort.Reverse(SortByRelease(rels)))
|
||||
// Check for a beta build
|
||||
beta := strings.Contains(version, "-")
|
||||
|
||||
var selected Release
|
||||
for _, rel := range rels {
|
||||
switch CompareVersions(rel.Tag, version) {
|
||||
switch CompareVersions(rel.Tag, current) {
|
||||
case Older, MajorOlder:
|
||||
// This is older than what we're already running
|
||||
continue
|
||||
@ -145,7 +143,7 @@ func SelectLatestRelease(version string, rels []Release) (Release, error) {
|
||||
// We've found a new major version. That's fine, but if we've
|
||||
// already found a minor upgrade that is acceptable we should go
|
||||
// with that one first and then revisit in the future.
|
||||
if selected.Tag != "" && CompareVersions(selected.Tag, version) == Newer {
|
||||
if selected.Tag != "" && CompareVersions(selected.Tag, current) == Newer {
|
||||
return selected, nil
|
||||
}
|
||||
// else it may be viable, do the needful below
|
||||
@ -154,7 +152,7 @@ func SelectLatestRelease(version string, rels []Release) (Release, error) {
|
||||
// New minor release, do the usual processing
|
||||
}
|
||||
|
||||
if rel.Prerelease && !beta {
|
||||
if rel.Prerelease && !upgradeToPreReleases {
|
||||
continue
|
||||
}
|
||||
for _, asset := range rel.Assets {
|
||||
|
@ -58,7 +58,7 @@ func TestCompareVersions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestErrorRelease(t *testing.T) {
|
||||
_, err := SelectLatestRelease("v0.11.0-beta", nil)
|
||||
_, err := SelectLatestRelease(nil, "v0.11.0-beta", false)
|
||||
if err == nil {
|
||||
t.Error("Should return an error when no release were available")
|
||||
}
|
||||
@ -67,21 +67,24 @@ func TestErrorRelease(t *testing.T) {
|
||||
func TestSelectedRelease(t *testing.T) {
|
||||
testcases := []struct {
|
||||
current string
|
||||
upgradeToPre bool
|
||||
candidates []string
|
||||
selected string
|
||||
}{
|
||||
// Within the same "major" (minor, in this case) select the newest
|
||||
{"v0.12.24", []string{"v0.12.23", "v0.12.24", "v0.12.25", "v0.12.26"}, "v0.12.26"},
|
||||
// Do no select beta versions when we are not a beta
|
||||
{"v0.12.24", []string{"v0.12.26", "v0.12.27-beta.42"}, "v0.12.26"},
|
||||
// Do select beta versions when we are a beta
|
||||
{"v0.12.24-beta.0", []string{"v0.12.26", "v0.12.27-beta.42"}, "v0.12.27-beta.42"},
|
||||
{"v0.12.24", false, []string{"v0.12.23", "v0.12.24", "v0.12.25", "v0.12.26"}, "v0.12.26"},
|
||||
// Do no select beta versions when we are not allowed to
|
||||
{"v0.12.24", false, []string{"v0.12.26", "v0.12.27-beta.42"}, "v0.12.26"},
|
||||
{"v0.12.24-beta.0", false, []string{"v0.12.26", "v0.12.27-beta.42"}, "v0.12.26"},
|
||||
// Do select beta versions when we can
|
||||
{"v0.12.24", true, []string{"v0.12.26", "v0.12.27-beta.42"}, "v0.12.27-beta.42"},
|
||||
{"v0.12.24-beta.0", true, []string{"v0.12.26", "v0.12.27-beta.42"}, "v0.12.27-beta.42"},
|
||||
// Select the best within the current major when there is a minor upgrade available
|
||||
{"v0.12.24", []string{"v0.12.23", "v0.12.24", "v0.12.25", "v0.13.0"}, "v0.12.25"},
|
||||
{"v1.12.24", []string{"v1.12.23", "v1.12.24", "v1.14.2", "v2.0.0"}, "v1.14.2"},
|
||||
{"v0.12.24", false, []string{"v0.12.23", "v0.12.24", "v0.12.25", "v0.13.0"}, "v0.12.25"},
|
||||
{"v1.12.24", false, []string{"v1.12.23", "v1.12.24", "v1.14.2", "v2.0.0"}, "v1.14.2"},
|
||||
// Select the next major when we are at the best minor
|
||||
{"v0.12.25", []string{"v0.12.23", "v0.12.24", "v0.12.25", "v0.13.0"}, "v0.13.0"},
|
||||
{"v1.14.2", []string{"v0.12.23", "v0.12.24", "v1.14.2", "v2.0.0"}, "v2.0.0"},
|
||||
{"v0.12.25", true, []string{"v0.12.23", "v0.12.24", "v0.12.25", "v0.13.0"}, "v0.13.0"},
|
||||
{"v1.14.2", true, []string{"v0.12.23", "v0.12.24", "v1.14.2", "v2.0.0"}, "v2.0.0"},
|
||||
}
|
||||
|
||||
for i, tc := range testcases {
|
||||
@ -99,7 +102,7 @@ func TestSelectedRelease(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check the selection
|
||||
sel, err := SelectLatestRelease(tc.current, rels)
|
||||
sel, err := SelectLatestRelease(rels, tc.current, tc.upgradeToPre)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error:", err)
|
||||
}
|
||||
|
@ -18,6 +18,6 @@ func upgradeToURL(archiveName, binary, url string) error {
|
||||
return ErrUpgradeUnsupported
|
||||
}
|
||||
|
||||
func LatestRelease(releasesURL, version string) (Release, error) {
|
||||
func LatestRelease(releasesURL, current string, upgradeToPreRelease bool) (Release, error) {
|
||||
return Release{}, ErrUpgradeUnsupported
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user