github.com/apex/up@v1.7.1/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 // we pass 0.0.0 here beause the OSS 60 // binary should always upgrade to Pro 61 // regardless of versions matching. 62 p.Store = &apex.Store{ 63 URL: releasesAPI, 64 Product: "up", 65 Version: "0.0.0", 66 Plan: "pro", 67 AccessKey: t.Token, 68 } 69 } 70 71 // fetch latest or specified release 72 r, err := getLatestOrSpecified(p, *target) 73 if err != nil { 74 return errors.Wrap(err, "fetching latest release") 75 } 76 77 // no updates 78 if r == nil { 79 util.LogPad("No updates available, you're good :)") 80 return nil 81 } 82 83 // find the tarball for this system 84 a := r.FindTarball(runtime.GOOS, runtime.GOARCH) 85 if a == nil { 86 return errors.Errorf("failed to find a binary for %s %s", runtime.GOOS, runtime.GOARCH) 87 } 88 89 // download tarball to a tmp dir 90 var tarball string 91 if util.IsCI() { 92 tarball, err = a.Download() 93 if err != nil { 94 return errors.Wrap(err, "downloading tarball") 95 } 96 } else { 97 tarball, err = a.DownloadProxy(progressreader.New) 98 if err != nil { 99 return errors.Wrap(err, "downloading tarball") 100 } 101 } 102 103 // determine path 104 path, err := exec.LookPath(os.Args[0]) 105 if err != nil { 106 return errors.Wrap(err, "looking up executable path") 107 } 108 dst := filepath.Dir(path) 109 110 // install it 111 if err := p.InstallTo(tarball, dst); err != nil { 112 return errors.Wrap(err, "installing") 113 } 114 115 term.ClearAll() 116 117 if strings.Contains(a.URL, "up/pro") { 118 util.LogPad("Updated %s to %s Pro", versionName(version), r.Version) 119 } else { 120 util.LogPad("Updated %s to %s OSS", versionName(version), r.Version) 121 } 122 123 stats.Track("Upgrade", map[string]interface{}{ 124 "from": version, 125 "to": r.Version, 126 "duration": time.Since(start).Round(time.Millisecond), 127 }) 128 129 return nil 130 }) 131 } 132 133 // getLatestOrSpecified returns the latest or specified release. 134 func getLatestOrSpecified(s update.Store, version string) (*update.Release, error) { 135 if version == "" { 136 return getLatest(s) 137 } 138 139 return s.GetRelease(version) 140 } 141 142 // getLatest returns the latest release, error, or nil when there is none. 143 func getLatest(s update.Store) (*update.Release, error) { 144 releases, err := s.LatestReleases() 145 146 if request.IsClient(err) { 147 return nil, errors.Wrap(err, "You're not subscribed to Up Pro") 148 } 149 150 if err != nil { 151 return nil, errors.Wrap(err, "fetching releases") 152 } 153 154 if len(releases) == 0 { 155 return nil, nil 156 } 157 158 return releases[0], nil 159 } 160 161 // versionName returns the humanized version name. 162 func versionName(s string) string { 163 if strings.Contains(s, "-pro") { 164 return strings.Replace(s, "-pro", "", 1) + " Pro" 165 } 166 167 return s + " OSS" 168 }