github.com/kayoticsully/syncthing@v0.8.9-0.20140724133906-c45a2fdc03f8/cmd/syncthing/upgrade_supported.go (about)

     1  // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
     2  // All rights reserved. Use of this source code is governed by an MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build !solaris,!windows,!noupgrade
     6  
     7  package main
     8  
     9  import (
    10  	"archive/tar"
    11  	"compress/gzip"
    12  	"encoding/json"
    13  	"errors"
    14  	"fmt"
    15  	"io"
    16  	"io/ioutil"
    17  	"net/http"
    18  	"os"
    19  	"path"
    20  	"path/filepath"
    21  	"runtime"
    22  	"strings"
    23  
    24  	"bitbucket.org/kardianos/osext"
    25  )
    26  
    27  var GoArchExtra string // "", "v5", "v6", "v7"
    28  
    29  func upgrade() error {
    30  	if runtime.GOOS == "windows" {
    31  		return errors.New("Upgrade currently unsupported on Windows")
    32  	}
    33  
    34  	path, err := osext.Executable()
    35  	if err != nil {
    36  		return err
    37  	}
    38  
    39  	rel, err := currentRelease()
    40  	if err != nil {
    41  		return err
    42  	}
    43  
    44  	switch compareVersions(rel.Tag, Version) {
    45  	case -1:
    46  		l.Okf("Current version %s is newer than latest release %s. Not upgrading.", Version, rel.Tag)
    47  		return nil
    48  	case 0:
    49  		l.Okf("Already running the latest version, %s. Not upgrading.", Version)
    50  		return nil
    51  	default:
    52  		l.Infof("Attempting upgrade to %s...", rel.Tag)
    53  	}
    54  
    55  	expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", runtime.GOOS, runtime.GOARCH, GoArchExtra, rel.Tag)
    56  	for _, asset := range rel.Assets {
    57  		if strings.HasPrefix(asset.Name, expectedRelease) {
    58  			if strings.HasSuffix(asset.Name, ".tar.gz") {
    59  				l.Infof("Downloading %s...", asset.Name)
    60  				fname, err := readTarGZ(asset.URL, filepath.Dir(path))
    61  				if err != nil {
    62  					return err
    63  				}
    64  
    65  				old := path + "." + Version
    66  				err = os.Rename(path, old)
    67  				if err != nil {
    68  					return err
    69  				}
    70  				err = os.Rename(fname, path)
    71  				if err != nil {
    72  					return err
    73  				}
    74  
    75  				l.Okf("Upgraded %q to %s.", path, rel.Tag)
    76  				l.Okf("Previous version saved in %q.", old)
    77  
    78  				return nil
    79  			}
    80  		}
    81  	}
    82  
    83  	return fmt.Errorf("Found no asset for %q", expectedRelease)
    84  }
    85  
    86  func currentRelease() (githubRelease, error) {
    87  	resp, err := http.Get("https://api.github.com/repos/calmh/syncthing/releases?per_page=10")
    88  	if err != nil {
    89  		return githubRelease{}, err
    90  	}
    91  
    92  	var rels []githubRelease
    93  	json.NewDecoder(resp.Body).Decode(&rels)
    94  	resp.Body.Close()
    95  
    96  	if strings.Contains(Version, "-beta") {
    97  		// We are a beta version. Use whatever we can find that is newer-or-equal than current.
    98  		for _, rel := range rels {
    99  			if compareVersions(rel.Tag, Version) >= 0 {
   100  				return rel, nil
   101  			}
   102  		}
   103  		// We found nothing. Return the latest release and let the next layer decide.
   104  		return rels[0], nil
   105  	} else {
   106  		// We are a regular release. Only consider non-prerelease versions for upgrade.
   107  		for _, rel := range rels {
   108  			if !rel.Prerelease {
   109  				return rel, nil
   110  			}
   111  		}
   112  		return githubRelease{}, errors.New("no suitable release found")
   113  	}
   114  }
   115  
   116  func readTarGZ(url string, dir string) (string, error) {
   117  	req, err := http.NewRequest("GET", url, nil)
   118  	if err != nil {
   119  		return "", err
   120  	}
   121  
   122  	req.Header.Add("Accept", "application/octet-stream")
   123  	resp, err := http.DefaultClient.Do(req)
   124  	if err != nil {
   125  		return "", err
   126  	}
   127  	defer resp.Body.Close()
   128  
   129  	gr, err := gzip.NewReader(resp.Body)
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  
   134  	tr := tar.NewReader(gr)
   135  	if err != nil {
   136  		return "", err
   137  	}
   138  
   139  	// Iterate through the files in the archive.
   140  	for {
   141  		hdr, err := tr.Next()
   142  		if err == io.EOF {
   143  			// end of tar archive
   144  			break
   145  		}
   146  		if err != nil {
   147  			return "", err
   148  		}
   149  
   150  		if path.Base(hdr.Name) == "syncthing" {
   151  			of, err := ioutil.TempFile(dir, "syncthing")
   152  			if err != nil {
   153  				return "", err
   154  			}
   155  			io.Copy(of, tr)
   156  			err = of.Close()
   157  			if err != nil {
   158  				os.Remove(of.Name())
   159  				return "", err
   160  			}
   161  
   162  			os.Chmod(of.Name(), os.FileMode(hdr.Mode))
   163  			return of.Name(), nil
   164  		}
   165  	}
   166  
   167  	return "", fmt.Errorf("No upgrade found")
   168  }