浏览代码

Merge pull request #750 from AudriusButkevicius/upgrades

Autoupgrades (fixes #727)
Audrius Butkevicius 11 年之前
父节点
当前提交
a76efd4166

+ 37 - 0
cmd/syncthing/main.go

@@ -620,6 +620,10 @@ nextFolder:
 		go standbyMonitor()
 	}
 
+	if cfg.Options.AutoUpgradeIntervalH > 0 {
+		go autoUpgrade()
+	}
+
 	events.Default.Log(events.StartupComplete, nil)
 	go generateEvents()
 
@@ -1172,3 +1176,36 @@ func standbyMonitor() {
 		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
+	}
+}

+ 8 - 0
gui/app.js

@@ -533,6 +533,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
         $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.tmpGUI = angular.copy($scope.config.GUI);
         $('#settings').modal();
     };
@@ -563,6 +564,13 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
                 $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;

+ 27 - 17
gui/index.html

@@ -606,26 +606,36 @@
                   <label translate for="MaxSendKbps">Outgoing Rate Limit (KiB/s)</label>
                   <input id="MaxSendKbps" class="form-control" type="number" ng-model="tmpOptions.MaxSendKbps">
                 </div>
-                <div class="form-group">
-                  <div class="checkbox">
-                    <label>
-                      <span translate>Enable UPnP</span> <input id="UPnPEnabled" type="checkbox" ng-model="tmpOptions.UPnPEnabled">
-                    </label>
+                <div class="col-md-6">
+                  <div class="form-group">
+                    <div class="checkbox">
+                      <label>
+                        <span translate>Enable UPnP</span> <input id="UPnPEnabled" type="checkbox" ng-model="tmpOptions.UPnPEnabled">
+                      </label>
+                    </div>
                   </div>
-                </div>
-
-                <div class="form-group">
-                  <div class="checkbox">
-                    <label>
-                      <span translate>Local Discovery</span> <input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.LocalAnnEnabled">
-                    </label>
+                  <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 class="form-group">
-                  <div class="checkbox">
-                    <label>
-                      <span translate>Global Discovery</span> <input id="GlobalAnnEnabled" type="checkbox" ng-model="tmpOptions.GlobalAnnEnabled">
-                    </label>
+                <div class="col-md-6">
+                  <div class="form-group">
+                    <div class="checkbox">
+                      <label>
+                        <span translate>Automatic upgrades</span> <input id="AutoUpgradeEnabled" type="checkbox" ng-model="tmpOptions.AutoUpgradeEnabled">
+                      </label>
+                    </div>
+                  </div>
+                  <div class="form-group">
+                    <div class="checkbox">
+                      <label>
+                        <span translate>Local Discovery</span> <input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.LocalAnnEnabled">
+                      </label>
+                    </div>
                   </div>
                 </div>
                 <div class="form-group">

文件差异内容过多而无法显示
+ 0 - 0
internal/auto/gui.files.go


+ 16 - 15
internal/config/config.go

@@ -118,21 +118,22 @@ type FolderDeviceConfiguration struct {
 }
 
 type OptionsConfiguration struct {
-	ListenAddress      []string `xml:"listenAddress" default:"0.0.0.0:22000"`
-	GlobalAnnServer    string   `xml:"globalAnnounceServer" default:"announce.syncthing.net:22026"`
-	GlobalAnnEnabled   bool     `xml:"globalAnnounceEnabled" default:"true"`
-	LocalAnnEnabled    bool     `xml:"localAnnounceEnabled" default:"true"`
-	LocalAnnPort       int      `xml:"localAnnouncePort" default:"21025"`
-	LocalAnnMCAddr     string   `xml:"localAnnounceMCAddr" default:"[ff32::5222]:21026"`
-	MaxSendKbps        int      `xml:"maxSendKbps"`
-	MaxRecvKbps        int      `xml:"maxRecvKbps"`
-	ReconnectIntervalS int      `xml:"reconnectionIntervalS" default:"60"`
-	StartBrowser       bool     `xml:"startBrowser" default:"true"`
-	UPnPEnabled        bool     `xml:"upnpEnabled" default:"true"`
-	UPnPLease          int      `xml:"upnpLeaseMinutes" default:"0"`
-	UPnPRenewal        int      `xml:"upnpRenewalMinutes" default:"30"`
-	URAccepted         int      `xml:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
-	RestartOnWakeup    bool     `xml:"restartOnWakeup" default:"true"`
+	ListenAddress        []string `xml:"listenAddress" default:"0.0.0.0:22000"`
+	GlobalAnnServer      string   `xml:"globalAnnounceServer" default:"announce.syncthing.net:22026"`
+	GlobalAnnEnabled     bool     `xml:"globalAnnounceEnabled" default:"true"`
+	LocalAnnEnabled      bool     `xml:"localAnnounceEnabled" default:"true"`
+	LocalAnnPort         int      `xml:"localAnnouncePort" default:"21025"`
+	LocalAnnMCAddr       string   `xml:"localAnnounceMCAddr" default:"[ff32::5222]:21026"`
+	MaxSendKbps          int      `xml:"maxSendKbps"`
+	MaxRecvKbps          int      `xml:"maxRecvKbps"`
+	ReconnectIntervalS   int      `xml:"reconnectionIntervalS" default:"60"`
+	StartBrowser         bool     `xml:"startBrowser" default:"true"`
+	UPnPEnabled          bool     `xml:"upnpEnabled" default:"true"`
+	UPnPLease            int      `xml:"upnpLeaseMinutes" default:"0"`
+	UPnPRenewal          int      `xml:"upnpRenewalMinutes" default:"30"`
+	URAccepted           int      `xml:"urAccepted"` // Accepted usage reporting version; 0 for off (undecided), -1 for off (permanently)
+	RestartOnWakeup      bool     `xml:"restartOnWakeup" default:"true"`
+	AutoUpgradeIntervalH int      `xml:"autoUpgradeIntervalH" default:"12"` // 0 for off
 
 	Deprecated_RescanIntervalS int    `xml:"rescanIntervalS,omitempty" json:"-"`
 	Deprecated_UREnabled       bool   `xml:"urEnabled,omitempty" json:"-"`

+ 28 - 0
internal/upgrade/upgrade_common.go

@@ -9,6 +9,8 @@ import (
 	"errors"
 	"strconv"
 	"strings"
+
+	"bitbucket.org/kardianos/osext"
 )
 
 type Release struct {
@@ -26,8 +28,34 @@ var (
 	ErrVersionUpToDate    = errors.New("current version is up to date")
 	ErrVersionUnknown     = errors.New("couldn't fetch release information")
 	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
 func CompareVersions(a, b string) int {
 	arel, apre := versionParts(a)

+ 1 - 8
internal/upgrade/upgrade_supported.go

@@ -19,17 +19,10 @@ import (
 	"path/filepath"
 	"runtime"
 	"strings"
-
-	"bitbucket.org/kardianos/osext"
 )
 
 // Upgrade to the given release, saving the previous binary with a ".old" extension.
-func UpgradeTo(rel Release, archExtra string) error {
-	path, err := osext.Executable()
-	if err != nil {
-		return err
-	}
-
+func upgradeTo(path string, rel Release, archExtra string) error {
 	osName := runtime.GOOS
 	if osName == "darwin" {
 		// We call the darwin release bundles macosx because that makes more

+ 1 - 1
internal/upgrade/upgrade_unsupp.go

@@ -6,7 +6,7 @@
 
 package upgrade
 
-func UpgradeTo(rel Release, extra string) error {
+func upgradeTo(path string, rel Release, extra string) error {
 	return ErrUpgradeUnsupported
 }
 

+ 1 - 8
internal/upgrade/upgrade_windows.go

@@ -19,17 +19,10 @@ import (
 	"path/filepath"
 	"runtime"
 	"strings"
-
-	"bitbucket.org/kardianos/osext"
 )
 
 // Upgrade to the given release, saving the previous binary with a ".old" extension.
-func UpgradeTo(rel Release, archExtra string) error {
-	path, err := osext.Executable()
-	if err != nil {
-		return err
-	}
-
+func upgradeTo(path string, rel Release, archExtra string) error {
 	expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", runtime.GOOS, runtime.GOARCH, archExtra, rel.Tag)
 	if debug {
 		l.Debugf("expected release asset %q", expectedRelease)

部分文件因为文件数量过多而无法显示