github.com/webonyx/up@v0.7.4-0.20180808230834-91b94e551323/internal/cli/upgrade/upgrade.go (about) 1 package upgrade 2 3 import ( 4 "os" 5 "os/exec" 6 "path/filepath" 7 "runtime" 8 "strings" 9 "time" 10 11 "github.com/pkg/errors" 12 "github.com/tj/go-update" 13 "github.com/tj/go-update/stores/apex" 14 "github.com/tj/go-update/stores/github" 15 "github.com/tj/go/env" 16 "github.com/tj/go/http/request" 17 "github.com/tj/go/term" 18 "github.com/tj/kingpin" 19 20 "github.com/apex/up/internal/cli/root" 21 "github.com/apex/up/internal/progressreader" 22 "github.com/apex/up/internal/stats" 23 "github.com/apex/up/internal/userconfig" 24 "github.com/apex/up/internal/util" 25 ) 26 27 var releasesAPI = env.GetDefault("APEX_RELEASES_API", "https://releases.apex.sh") 28 29 func init() { 30 cmd := root.Command("upgrade", "Install the latest or specified version of Up.") 31 cmd.Example(`up upgrade`, "Upgrade to the latest version available.") 32 cmd.Example(`up upgrade -t 0.4.4`, "Upgrade to the specified version.") 33 target := cmd.Flag("target", "Target version for upgrade.").Short('t').String() 34 35 cmd.Action(func(_ *kingpin.ParseContext) error { 36 version := root.Cmd.GetVersion() 37 start := time.Now() 38 39 term.HideCursor() 40 defer term.ShowCursor() 41 42 var config userconfig.Config 43 if err := config.Load(); err != nil { 44 return errors.Wrap(err, "loading user config") 45 } 46 47 // open-source edition 48 p := &update.Manager{ 49 Command: "up", 50 Store: &github.Store{ 51 Owner: "apex", 52 Repo: "up", 53 Version: version, 54 }, 55 } 56 57 // commercial edition 58 if t := config.GetActiveTeam(); t != nil { 59 p.Store = &apex.Store{ 60 URL: releasesAPI, 61 Product: "up", 62 Version: normalizeVersion(version), 63 Plan: "pro", 64 AccessKey: t.Token, 65 } 66 } 67 68 // fetch latest or specified release 69 r, err := getLatestOrSpecified(p, *target) 70 if err != nil { 71 return errors.Wrap(err, "fetching latest release") 72 } 73 74 // no updates 75 if r == nil { 76 util.LogPad("No updates available, you're good :)") 77 return nil 78 } 79 80 // find the tarball for this system 81 a := r.FindTarball(runtime.GOOS, runtime.GOARCH) 82 if a == nil { 83 return errors.Errorf("failed to find a binary for %s %s", runtime.GOOS, runtime.GOARCH) 84 } 85 86 // download tarball to a tmp dir 87 var tarball string 88 if util.IsCI() { 89 tarball, err = a.Download() 90 if err != nil { 91 return errors.Wrap(err, "downloading tarball") 92 } 93 } else { 94 tarball, err = a.DownloadProxy(progressreader.New) 95 if err != nil { 96 return errors.Wrap(err, "downloading tarball") 97 } 98 } 99 100 // determine path 101 path, err := exec.LookPath(os.Args[0]) 102 if err != nil { 103 return errors.Wrap(err, "looking up executable path") 104 } 105 dst := filepath.Dir(path) 106 107 // install it 108 if err := p.InstallTo(tarball, dst); err != nil { 109 return errors.Wrap(err, "installing") 110 } 111 112 term.ClearAll() 113 114 if strings.Contains(a.URL, "up/pro") { 115 util.LogPad("Updated %s to %s Pro", versionName(version), r.Version) 116 } else { 117 util.LogPad("Updated %s to %s OSS", versionName(version), r.Version) 118 } 119 120 stats.Track("Upgrade", map[string]interface{}{ 121 "from": version, 122 "to": r.Version, 123 "duration": time.Since(start).Round(time.Millisecond), 124 }) 125 126 return nil 127 }) 128 } 129 130 // getLatestOrSpecified returns the latest or specified release. 131 func getLatestOrSpecified(s update.Store, version string) (*update.Release, error) { 132 if version == "" { 133 return getLatest(s) 134 } 135 136 return s.GetRelease(version) 137 } 138 139 // getLatest returns the latest release, error, or nil when there is none. 140 func getLatest(s update.Store) (*update.Release, error) { 141 releases, err := s.LatestReleases() 142 143 if request.IsClient(err) { 144 return nil, errors.Wrap(err, "You're not subscribed to Up Pro") 145 } 146 147 if err != nil { 148 return nil, errors.Wrap(err, "fetching releases") 149 } 150 151 if len(releases) == 0 { 152 return nil, nil 153 } 154 155 return releases[0], nil 156 } 157 158 // normalizeVersion returns the version without "-pro". 159 func normalizeVersion(s string) string { 160 return strings.Replace(s, "-pro", "", -1) 161 } 162 163 // versionName returns the humanized version name. 164 func versionName(s string) string { 165 if strings.Contains(s, "-pro") { 166 return strings.Replace(s, "-pro", "", 1) + " Pro" 167 } 168 169 return s + " OSS" 170 }