// Copyright 2016-2018, Pulumi Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cmd import ( "fmt" "github.com/blang/semver" "github.com/hashicorp/go-multierror" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/pulumi/pulumi/pkg/backend/display" "github.com/pulumi/pulumi/pkg/diag/colors" "github.com/pulumi/pulumi/pkg/util/cmdutil" "github.com/pulumi/pulumi/pkg/workspace" ) func newPluginRmCmd() *cobra.Command { var all bool var yes bool var cmd = &cobra.Command{ Use: "rm [KIND [NAME [VERSION]]]", Args: cmdutil.MaximumNArgs(3), Short: "Remove one or more plugins from the download cache", Long: "Remove one or more plugins from the download cache.\n" + "\n" + "Specify KIND, NAME, and/or VERSION to narrow down what will be removed.\n" + "If none are specified, the entire cache will be cleared. If only KIND and\n" + "NAME are specified, but not VERSION, all versions of the plugin with the\n" + "given KIND and NAME will be removed. VERSION may be a range.\n" + "\n" + "This removal cannot be undone. If a deleted plugin is subsequently required\n" + "in order to execute a Pulumi program, it must be re-downloaded and installed\n" + "using the plugin install command.", Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error { opts := display.Options{ Color: cmdutil.GetGlobalColorization(), } // Parse the filters. var kind workspace.PluginKind var name string var version *semver.Range if len(args) > 0 { if !workspace.IsPluginKind(args[0]) { return errors.Errorf("unrecognized plugin kind: %s", kind) } kind = workspace.PluginKind(args[0]) } else if !all { return errors.Errorf("please pass --all if you'd like to remove all plugins") } if len(args) > 1 { name = args[1] } if len(args) > 2 { r, err := semver.ParseRange(args[2]) if err != nil { return errors.Wrap(err, "invalid plugin semver") } version = &r } // Now build a list of plugins that match. var deletes []workspace.PluginInfo plugins, err := workspace.GetPlugins() if err != nil { return errors.Wrap(err, "loading plugins") } for _, plugin := range plugins { if (kind == "" || plugin.Kind == kind) && (name == "" || plugin.Name == name) && (version == nil || (plugin.Version != nil && (*version)(*plugin.Version))) { deletes = append(deletes, plugin) } } if len(deletes) == 0 { return errors.New("no plugins found") } // Confirm that the user wants to do this (unless --yes was passed), and do the deletes. var suffix string if len(deletes) != 1 { suffix = "s" } fmt.Print( opts.Color.Colorize( fmt.Sprintf("%sThis will remove %d plugin%s from the cache:%s\n", colors.SpecAttention, len(deletes), suffix, colors.Reset))) for _, del := range deletes { fmt.Printf(" %s %s\n", del.Kind, del.String()) } if yes || confirmPrompt("", "yes", opts) { var result error for _, plugin := range deletes { if err := plugin.Delete(); err != nil { result = multierror.Append( result, errors.Wrapf(err, "failed to delete %s plugin %s", plugin.Kind, plugin)) } } if result != nil { return result } } return nil }), } cmd.PersistentFlags().BoolVarP( &all, "all", "a", false, "Remove all plugins") cmd.PersistentFlags().BoolVarP( &yes, "yes", "y", false, "Skip confirmation prompts, and proceed with removal anyway") return cmd }