Merge pull request #750 from AudriusButkevicius/upgrades
Autoupgrades (fixes #727)
This commit is contained in:
@@ -620,6 +620,10 @@ nextFolder:
|
|||||||
go standbyMonitor()
|
go standbyMonitor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.Options.AutoUpgradeIntervalH > 0 {
|
||||||
|
go autoUpgrade()
|
||||||
|
}
|
||||||
|
|
||||||
events.Default.Log(events.StartupComplete, nil)
|
events.Default.Log(events.StartupComplete, nil)
|
||||||
go generateEvents()
|
go generateEvents()
|
||||||
|
|
||||||
@@ -1172,3 +1176,36 @@ func standbyMonitor() {
|
|||||||
now = time.Now()
|
now = time.Now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func autoUpgrade() {
|
||||||
|
var skipped bool
|
||||||
|
interval := time.Duration(cfg.Options.AutoUpgradeIntervalH) * time.Hour
|
||||||
|
for {
|
||||||
|
if skipped {
|
||||||
|
time.Sleep(interval)
|
||||||
|
} else {
|
||||||
|
skipped = true
|
||||||
|
}
|
||||||
|
|
||||||
|
rel, err := upgrade.LatestRelease(strings.Contains(Version, "-beta"))
|
||||||
|
if err != nil {
|
||||||
|
l.Warnln("Automatic upgrade:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if upgrade.CompareVersions(rel.Tag, Version) <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Infof("Automatic upgrade (current %q < latest %q)", Version, rel.Tag)
|
||||||
|
err = upgrade.UpgradeTo(rel, GoArchExtra)
|
||||||
|
if err != nil {
|
||||||
|
l.Warnln("Automatic upgrade:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l.Warnf("Automatically upgraded to version %q. Restarting in 1 minute.", rel.Tag)
|
||||||
|
time.Sleep(time.Minute)
|
||||||
|
stop <- exitUpgrading
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -533,6 +533,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
|
|||||||
$scope.tmpOptions = angular.copy($scope.config.Options);
|
$scope.tmpOptions = angular.copy($scope.config.Options);
|
||||||
$scope.tmpOptions.UREnabled = ($scope.tmpOptions.URAccepted > 0);
|
$scope.tmpOptions.UREnabled = ($scope.tmpOptions.URAccepted > 0);
|
||||||
$scope.tmpOptions.DeviceName = $scope.thisDevice().Name;
|
$scope.tmpOptions.DeviceName = $scope.thisDevice().Name;
|
||||||
|
$scope.tmpOptions.AutoUpgradeEnabled = ($scope.tmpOptions.AutoUpgradeIntervalH > 0);
|
||||||
$scope.tmpGUI = angular.copy($scope.config.GUI);
|
$scope.tmpGUI = angular.copy($scope.config.GUI);
|
||||||
$('#settings').modal();
|
$('#settings').modal();
|
||||||
};
|
};
|
||||||
@@ -563,6 +564,13 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
|
|||||||
$scope.tmpOptions.URAccepted = -1;
|
$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
|
// Check if protocol will need to be changed on restart
|
||||||
if ($scope.config.GUI.UseTLS !== $scope.tmpGUI.UseTLS) {
|
if ($scope.config.GUI.UseTLS !== $scope.tmpGUI.UseTLS) {
|
||||||
$scope.protocolChanged = true;
|
$scope.protocolChanged = true;
|
||||||
|
|||||||
@@ -606,26 +606,36 @@
|
|||||||
<label translate for="MaxSendKbps">Outgoing Rate Limit (KiB/s)</label>
|
<label translate for="MaxSendKbps">Outgoing Rate Limit (KiB/s)</label>
|
||||||
<input id="MaxSendKbps" class="form-control" type="number" ng-model="tmpOptions.MaxSendKbps">
|
<input id="MaxSendKbps" class="form-control" type="number" ng-model="tmpOptions.MaxSendKbps">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="col-md-6">
|
||||||
<div class="checkbox">
|
<div class="form-group">
|
||||||
<label>
|
<div class="checkbox">
|
||||||
<span translate>Enable UPnP</span> <input id="UPnPEnabled" type="checkbox" ng-model="tmpOptions.UPnPEnabled">
|
<label>
|
||||||
</label>
|
<span translate>Enable UPnP</span> <input id="UPnPEnabled" type="checkbox" ng-model="tmpOptions.UPnPEnabled">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<span translate>Global Discovery</span> <input id="GlobalAnnEnabled" type="checkbox" ng-model="tmpOptions.GlobalAnnEnabled">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<span translate>Local Discovery</span> <input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.LocalAnnEnabled">
|
<span translate>Automatic upgrades</span> <input id="AutoUpgradeEnabled" type="checkbox" ng-model="tmpOptions.AutoUpgradeEnabled">
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<div class="checkbox">
|
||||||
<div class="checkbox">
|
<label>
|
||||||
<label>
|
<span translate>Local Discovery</span> <input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.LocalAnnEnabled">
|
||||||
<span translate>Global Discovery</span> <input id="GlobalAnnEnabled" type="checkbox" ng-model="tmpOptions.GlobalAnnEnabled">
|
</label>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -118,21 +118,22 @@ type FolderDeviceConfiguration struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OptionsConfiguration struct {
|
type OptionsConfiguration struct {
|
||||||
ListenAddress []string `xml:"listenAddress" default:"0.0.0.0:22000"`
|
ListenAddress []string `xml:"listenAddress" default:"0.0.0.0:22000"`
|
||||||
GlobalAnnServer string `xml:"globalAnnounceServer" default:"announce.syncthing.net:22026"`
|
GlobalAnnServer string `xml:"globalAnnounceServer" default:"announce.syncthing.net:22026"`
|
||||||
GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" default:"true"`
|
GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" default:"true"`
|
||||||
LocalAnnEnabled bool `xml:"localAnnounceEnabled" default:"true"`
|
LocalAnnEnabled bool `xml:"localAnnounceEnabled" default:"true"`
|
||||||
LocalAnnPort int `xml:"localAnnouncePort" default:"21025"`
|
LocalAnnPort int `xml:"localAnnouncePort" default:"21025"`
|
||||||
LocalAnnMCAddr string `xml:"localAnnounceMCAddr" default:"[ff32::5222]:21026"`
|
LocalAnnMCAddr string `xml:"localAnnounceMCAddr" default:"[ff32::5222]:21026"`
|
||||||
MaxSendKbps int `xml:"maxSendKbps"`
|
MaxSendKbps int `xml:"maxSendKbps"`
|
||||||
MaxRecvKbps int `xml:"maxRecvKbps"`
|
MaxRecvKbps int `xml:"maxRecvKbps"`
|
||||||
ReconnectIntervalS int `xml:"reconnectionIntervalS" default:"60"`
|
ReconnectIntervalS int `xml:"reconnectionIntervalS" default:"60"`
|
||||||
StartBrowser bool `xml:"startBrowser" default:"true"`
|
StartBrowser bool `xml:"startBrowser" default:"true"`
|
||||||
UPnPEnabled bool `xml:"upnpEnabled" default:"true"`
|
UPnPEnabled bool `xml:"upnpEnabled" default:"true"`
|
||||||
UPnPLease int `xml:"upnpLeaseMinutes" default:"0"`
|
UPnPLease int `xml:"upnpLeaseMinutes" default:"0"`
|
||||||
UPnPRenewal int `xml:"upnpRenewalMinutes" default:"30"`
|
UPnPRenewal int `xml:"upnpRenewalMinutes" default:"30"`
|
||||||
URAccepted int `xml:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
|
URAccepted int `xml:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
|
||||||
RestartOnWakeup bool `xml:"restartOnWakeup" default:"true"`
|
RestartOnWakeup bool `xml:"restartOnWakeup" default:"true"`
|
||||||
|
AutoUpgradeIntervalH int `xml:"autoUpgradeIntervalH" default:"12"` // 0 for off
|
||||||
|
|
||||||
Deprecated_RescanIntervalS int `xml:"rescanIntervalS,omitempty" json:"-"`
|
Deprecated_RescanIntervalS int `xml:"rescanIntervalS,omitempty" json:"-"`
|
||||||
Deprecated_UREnabled bool `xml:"urEnabled,omitempty" json:"-"`
|
Deprecated_UREnabled bool `xml:"urEnabled,omitempty" json:"-"`
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"bitbucket.org/kardianos/osext"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Release struct {
|
type Release struct {
|
||||||
@@ -26,8 +28,34 @@ var (
|
|||||||
ErrVersionUpToDate = errors.New("current version is up to date")
|
ErrVersionUpToDate = errors.New("current version is up to date")
|
||||||
ErrVersionUnknown = errors.New("couldn't fetch release information")
|
ErrVersionUnknown = errors.New("couldn't fetch release information")
|
||||||
ErrUpgradeUnsupported = errors.New("upgrade unsupported")
|
ErrUpgradeUnsupported = errors.New("upgrade unsupported")
|
||||||
|
ErrUpgradeInProgress = errors.New("upgrade already in progress")
|
||||||
|
upgradeUnlocked = make(chan bool, 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
upgradeUnlocked <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
// A wrapper around actual implementations
|
||||||
|
func UpgradeTo(rel Release, archExtra string) error {
|
||||||
|
select {
|
||||||
|
case <-upgradeUnlocked:
|
||||||
|
path, err := osext.Executable()
|
||||||
|
if err != nil {
|
||||||
|
upgradeUnlocked <- true
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = upgradeTo(path, rel, archExtra)
|
||||||
|
// If we've failed to upgrade, unlock so that another attempt could be made
|
||||||
|
if err != nil {
|
||||||
|
upgradeUnlocked <- true
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
default:
|
||||||
|
return ErrUpgradeInProgress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns 1 if a>b, -1 if a<b and 0 if they are equal
|
// Returns 1 if a>b, -1 if a<b and 0 if they are equal
|
||||||
func CompareVersions(a, b string) int {
|
func CompareVersions(a, b string) int {
|
||||||
arel, apre := versionParts(a)
|
arel, apre := versionParts(a)
|
||||||
|
|||||||
@@ -19,17 +19,10 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"bitbucket.org/kardianos/osext"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Upgrade to the given release, saving the previous binary with a ".old" extension.
|
// Upgrade to the given release, saving the previous binary with a ".old" extension.
|
||||||
func UpgradeTo(rel Release, archExtra string) error {
|
func upgradeTo(path string, rel Release, archExtra string) error {
|
||||||
path, err := osext.Executable()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
osName := runtime.GOOS
|
osName := runtime.GOOS
|
||||||
if osName == "darwin" {
|
if osName == "darwin" {
|
||||||
// We call the darwin release bundles macosx because that makes more
|
// We call the darwin release bundles macosx because that makes more
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
package upgrade
|
package upgrade
|
||||||
|
|
||||||
func UpgradeTo(rel Release, extra string) error {
|
func upgradeTo(path string, rel Release, extra string) error {
|
||||||
return ErrUpgradeUnsupported
|
return ErrUpgradeUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,17 +19,10 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"bitbucket.org/kardianos/osext"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Upgrade to the given release, saving the previous binary with a ".old" extension.
|
// Upgrade to the given release, saving the previous binary with a ".old" extension.
|
||||||
func UpgradeTo(rel Release, archExtra string) error {
|
func upgradeTo(path string, rel Release, archExtra string) error {
|
||||||
path, err := osext.Executable()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", runtime.GOOS, runtime.GOARCH, archExtra, rel.Tag)
|
expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", runtime.GOOS, runtime.GOARCH, archExtra, rel.Tag)
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugf("expected release asset %q", expectedRelease)
|
l.Debugf("expected release asset %q", expectedRelease)
|
||||||
|
|||||||
Reference in New Issue
Block a user