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 }