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  }