Skip reinstalling existing plugins

This change introduces logic to skip installing plugins that already
exist, unless --reinstall is explicitly passed to `pulumi plugin install`.
This commit is contained in:
joeduffy 2018-02-17 11:42:27 -08:00
parent 548c22d014
commit 041e44beff
2 changed files with 47 additions and 2 deletions

View file

@ -18,6 +18,7 @@ import (
func newPluginInstallCmd() *cobra.Command {
var cloudURL string
var file string
var reinstall bool
var cmd = &cobra.Command{
Use: "install [KIND NAME VERSION]",
Args: cmdutil.MaximumNArgs(3),
@ -63,19 +64,26 @@ func newPluginInstallCmd() *cobra.Command {
// Target the cloud URL for downloads.
var releases cloud.Backend
if len(installs) > 0 && file != "" {
if len(installs) > 0 && file == "" {
releases = cloud.New(cmdutil.Diag(), cloud.ValueOrDefaultURL(cloudURL))
}
// Now for each kind, name, version pair, download it from the release website, and install it.
for _, install := range installs {
// If the plugin already exists, don't download it unless --reinstall was passed.
if !reinstall && workspace.HasPlugin(install) {
continue
}
// If we got here, actually try to do the download.
var source string
var tarball io.ReadCloser
var err error
if file == "" {
source = releases.CloudURL()
if tarball, err = releases.DownloadPlugin(install, true); err != nil {
return errors.Wrapf(err, "downloading %s from %s", install.String(), source)
return errors.Wrapf(err,
"downloading %s plugin %s from %s", install.Kind, install.String(), source)
}
} else {
source = file
@ -96,6 +104,8 @@ func newPluginInstallCmd() *cobra.Command {
"cloud-url", "c", "", "A cloud URL to download releases from")
cmd.PersistentFlags().StringVarP(&file,
"file", "f", "", "Install a plugin from a tarball file, instead of downloading it")
cmd.PersistentFlags().BoolVar(&reinstall,
"reinstall", false, "Reinstall a plugin even if it already exists")
return cmd
}

View file

@ -12,6 +12,7 @@ import (
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strings"
"time"
@ -35,11 +36,24 @@ type PluginInfo struct {
LastUsedTime time.Time // the last time the plugin was used.
}
// File gets the expected filename for this plugin.
func (info PluginInfo) File() string {
return info.FilePrefix() + info.FileSuffix()
}
// FilePrefix gets the expected default file prefix for the plugin.
func (info PluginInfo) FilePrefix() string {
return filePrefix(info.Kind, info.Name, info.Version)
}
// FileSuffix returns the suffix for the plugin (if any).
func (info PluginInfo) FileSuffix() string {
if runtime.GOOS == "windows" {
return ".exe"
}
return ""
}
// filePrefix gets the expected default file prefix for the plugin.
func filePrefix(kind PluginKind, name string, version *semver.Version) string {
prefix := fmt.Sprintf("pulumi-%s-%s", kind, name)
@ -49,6 +63,15 @@ func filePrefix(kind PluginKind, name string, version *semver.Version) string {
return prefix
}
// DefaultPath returns the path where this plugin is normally installed to.
func (info PluginInfo) DefaultPath() (string, error) {
dir, err := GetPluginDir()
if err != nil {
return "", err
}
return filepath.Join(dir, info.File()), nil
}
// Delete removes the plugin from the cache. It also deletes any supporting files in the cache, which includes
// any files that contain the same prefix as the plugin itself.
func (info PluginInfo) Delete() error {
@ -133,6 +156,18 @@ func IsPluginKind(k string) bool {
}
}
// HasPlugin returns true if the given plugin exists.
func HasPlugin(plug PluginInfo) bool {
path, err := plug.DefaultPath()
if err == nil {
_, err := os.Stat(path)
if err == nil {
return true
}
}
return false
}
// GetPluginDir returns the directory in which plugins on the current machine are managed.
func GetPluginDir() (string, error) {
home, err := homedir.Dir()