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  }