Browse Source

Upgrade from within GUI (fixes #190)

Jakob Borg 11 years ago
parent
commit
d812f559ef

File diff suppressed because it is too large
+ 0 - 0
auto/gui.files.go


+ 28 - 0
cmd/syncthing/gui.go

@@ -102,6 +102,7 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro
 	getRestMux.HandleFunc("/rest/discovery", restGetDiscovery)
 	getRestMux.HandleFunc("/rest/report", withModel(m, restGetReport))
 	getRestMux.HandleFunc("/rest/events", restGetEvents)
+	getRestMux.HandleFunc("/rest/upgrade", restGetUpgrade)
 
 	// The POST handlers
 	postRestMux := http.NewServeMux()
@@ -113,6 +114,7 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro
 	postRestMux.HandleFunc("/rest/error/clear", restClearErrors)
 	postRestMux.HandleFunc("/rest/discovery/hint", restPostDiscoveryHint)
 	postRestMux.HandleFunc("/rest/model/override", withModel(m, restPostOverride))
+	postRestMux.HandleFunc("/rest/upgrade", restPostUpgrade)
 
 	// A handler that splits requests between the two above and disables
 	// caching
@@ -427,6 +429,32 @@ func restGetEvents(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(eventSub.Since(since, nil))
 }
 
+func restGetUpgrade(w http.ResponseWriter, r *http.Request) {
+	rel, err := currentRelease()
+	if err != nil {
+		http.Error(w, err.Error(), 500)
+		return
+	}
+	res := make(map[string]interface{})
+	res["running"] = Version
+	res["latest"] = rel.Tag
+	res["newer"] = compareVersions(rel.Tag, Version) == 1
+
+	w.Header().Set("Content-Type", "application/json; charset=utf-8")
+	json.NewEncoder(w).Encode(res)
+}
+
+func restPostUpgrade(w http.ResponseWriter, r *http.Request) {
+	err := upgrade()
+	if err != nil {
+		l.Warnln(err)
+		http.Error(w, err.Error(), 500)
+		return
+	}
+
+	restPostRestart(w, r)
+}
+
 func getQR(w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	text := r.FormValue("text")

+ 33 - 0
cmd/syncthing/upgrade_common.go

@@ -0,0 +1,33 @@
+package main
+
+import (
+	"bytes"
+	"strconv"
+	"strings"
+)
+
+type githubRelease struct {
+	Tag      string        `json:"tag_name"`
+	Prelease bool          `json:"prerelease"`
+	Assets   []githubAsset `json:"assets"`
+}
+
+type githubAsset struct {
+	URL  string `json:"url"`
+	Name string `json:"name"`
+}
+
+func compareVersions(a, b string) int {
+	return bytes.Compare(versionParts(a), versionParts(b))
+}
+
+func versionParts(v string) []byte {
+	parts := strings.Split(v, "-")
+	fields := strings.Split(parts[0], ".")
+	res := make([]byte, len(fields))
+	for i, s := range fields {
+		v, _ := strconv.Atoi(s)
+		res[i] = byte(v)
+	}
+	return res
+}

+ 19 - 41
cmd/syncthing/upgrade_supported.go

@@ -2,7 +2,7 @@
 // All rights reserved. Use of this source code is governed by an MIT-style
 // license that can be found in the LICENSE file.
 
-// +build !solaris,!windows
+// +build !solaris,!windows,!noupgrade
 
 package main
 
@@ -19,24 +19,11 @@ import (
 	"path"
 	"path/filepath"
 	"runtime"
-	"strconv"
 	"strings"
 
-	"bytes"
 	"bitbucket.org/kardianos/osext"
 )
 
-type githubRelease struct {
-	Tag      string        `json:"tag_name"`
-	Prelease bool          `json:"prerelease"`
-	Assets   []githubAsset `json:"assets"`
-}
-
-type githubAsset struct {
-	URL  string `json:"url"`
-	Name string `json:"name"`
-}
-
 var GoArchExtra string // "", "v5", "v6", "v7"
 
 func upgrade() error {
@@ -49,20 +36,11 @@ func upgrade() error {
 		return err
 	}
 
-	resp, err := http.Get("https://api.github.com/repos/calmh/syncthing/releases?per_page=1")
+	rel, err := currentRelease()
 	if err != nil {
 		return err
 	}
 
-	var rels []githubRelease
-	json.NewDecoder(resp.Body).Decode(&rels)
-	resp.Body.Close()
-
-	if len(rels) != 1 {
-		return fmt.Errorf("Unexpected number of releases: %d", len(rels))
-	}
-	rel := rels[0]
-
 	switch compareVersions(rel.Tag, Version) {
 	case -1:
 		l.Okf("Current version %s is newer than latest release %s. Not upgrading.", Version, rel.Tag)
@@ -102,8 +80,23 @@ func upgrade() error {
 		}
 	}
 
-	l.Warnf("Found no asset for %q", expectedRelease)
-	return nil
+	return fmt.Errorf("Found no asset for %q", expectedRelease)
+}
+
+func currentRelease() (githubRelease, error) {
+	resp, err := http.Get("https://api.github.com/repos/calmh/syncthing/releases?per_page=1")
+	if err != nil {
+		return githubRelease{}, err
+	}
+
+	var rels []githubRelease
+	json.NewDecoder(resp.Body).Decode(&rels)
+	resp.Body.Close()
+
+	if len(rels) != 1 {
+		return githubRelease{}, fmt.Errorf("Unexpected number of releases: %d", len(rels))
+	}
+	return rels[0], nil
 }
 
 func readTarGZ(url string, dir string) (string, error) {
@@ -159,18 +152,3 @@ func readTarGZ(url string, dir string) (string, error) {
 
 	return "", fmt.Errorf("No upgrade found")
 }
-
-func compareVersions(a, b string) int {
-	return bytes.Compare(versionParts(a), versionParts(b))
-}
-
-func versionParts(v string) []byte {
-	parts := strings.Split(v, "-")
-	fields := strings.Split(parts[0], ".")
-	res := make([]byte, len(fields))
-	for i, s := range fields {
-		v, _ := strconv.Atoi(s)
-		res[i] = byte(v)
-	}
-	return res
-}

+ 8 - 2
cmd/syncthing/upgrade_unsupp.go

@@ -1,9 +1,15 @@
-// +build windows solaris
+// +build windows solaris noupgrade
 
 package main
 
 import "errors"
 
+var errUpgradeUnsupported = errors.New("Automatic upgrade not supported")
+
 func upgrade() error {
-	return errors.New("Upgrade currently unsupported on Windows")
+	return errUpgradeUnsupported
+}
+
+func currentRelease() (githubRelease, error) {
+	return githubRelease{}, errUpgradeUnsupported
 }

+ 21 - 0
gui/app.js

@@ -32,6 +32,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
     $scope.repos = {};
     $scope.reportData = {};
     $scope.reportPreview = false;
+    $scope.upgradeInfo = {};
 
     $scope.needActions = {
         'rm': 'Del',
@@ -336,6 +337,8 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
 
     $scope.restart = function () {
         restarting = true;
+        $scope.restartingHeader = "Restarting"
+        $scope.restartingBody = "Syncthing is restarting."
         $('#restarting').modal({backdrop: 'static', keyboard: false});
         $http.post(urlbase + '/restart');
         $scope.configInSync = true;
@@ -356,6 +359,18 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
         }
     };
 
+    $scope.upgrade = function () {
+        $scope.restartingHeader = "Upgrading"
+        $scope.restartingBody = "Syncthing is upgrading."
+        $('#restarting').modal({backdrop: 'static', keyboard: false});
+        $http.post(urlbase + '/upgrade').success(function () {
+            restarting = true;
+            $scope.restartingBody = "Syncthing is restarting into the new version."
+        }).error(function () {
+            $('#restarting').modal('hide');
+        });
+    };
+
     $scope.shutdown = function () {
         restarting = true;
         $http.post(urlbase + '/shutdown').success(function () {
@@ -606,6 +621,12 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
         $http.get(urlbase + '/report').success(function (data) {
             $scope.reportData = data;
         });
+
+        $http.get(urlbase + '/upgrade').success(function (data) {
+            $scope.upgradeInfo = data;
+        }).error(function () {
+            $scope.upgradeInfo = {};
+        });
     };
 
     $scope.acceptUR = function () {

+ 5 - 2
gui/index.html

@@ -96,6 +96,9 @@
     <div class="container">
       <span class="navbar-brand"><img class="logo" src="st-logo-128.png" width="32" height="32" /> Syncthing<small class="hidden-xs"> <span class="text-muted">|</span> {{thisNodeName()}}</small></span>
       <ul class="nav navbar-nav navbar-right">
+        <li ng-if="upgradeInfo.newer">
+          <button type="button" class="btn navbar-btn btn-default" href="" ng-click="upgrade()"><span class="glyphicon glyphicon-chevron-up"></span>&emsp;Upgrade to {{upgradeInfo.latest}}</button>
+        </li>
         <li class="dropdown">
           <a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit&nbsp;<b class="caret"></b></a>
           <ul class="dropdown-menu">
@@ -376,12 +379,12 @@
         <div class="modal-header alert alert-info">
           <h4 class="modal-title">
             <span class="glyphicon glyphicon-refresh"></span>
-            Restarting
+            {{restartingHeader}}
           </h4>
         </div>
         <div class="modal-body">
           <p>
-            Syncthing is restarting. Please hold&hellip;
+            {{restartingBody}} Please hold&hellip;
           </p>
         </div>
       </div>

Some files were not shown because too many files changed in this diff