diff --git a/cmd/notation/plugin/cmd.go b/cmd/notation/plugin/cmd.go index 17f3d3150..2500463e5 100644 --- a/cmd/notation/plugin/cmd.go +++ b/cmd/notation/plugin/cmd.go @@ -24,6 +24,7 @@ func Cmd() *cobra.Command { command.AddCommand( pluginListCommand(), pluginInstallCommand(nil), + pluginUninstallCommand(nil), ) return command diff --git a/cmd/notation/plugin/install.go b/cmd/notation/plugin/install.go index 524072d45..789b6239e 100644 --- a/cmd/notation/plugin/install.go +++ b/cmd/notation/plugin/install.go @@ -59,7 +59,7 @@ func pluginInstallCommand(opts *pluginInstallOpts) *cobra.Command { Long: `Install a Notation plugin Example - Install plugin from file system: - notation plugin install --file myPlugin.tar.gz --checksum 123abcd + notation plugin install --file myPlugin.tar.gz --checksum abcdef `, RunE: func(cmd *cobra.Command, args []string) error { return installPlugin(cmd, opts) @@ -139,7 +139,7 @@ func installPluginFromZip(ctx context.Context, zipPath string, force bool) error defer archive.Close() for _, f := range archive.File { fmode := f.Mode() - // only consider regular executable files in the zip + // only consider regular executable files if fmode.IsRegular() && osutil.IsOwnerExecutalbeFile(fmode) { fileInArchive, err := f.Open() if err != nil { diff --git a/cmd/notation/plugin/uninstall.go b/cmd/notation/plugin/uninstall.go new file mode 100644 index 000000000..d200f5071 --- /dev/null +++ b/cmd/notation/plugin/uninstall.go @@ -0,0 +1,72 @@ +package plugin + +import ( + "errors" + "fmt" + "os" + + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation/cmd/notation/internal/cmdutil" + "github.com/spf13/cobra" +) + +type pluginUninstallOpts struct { + pluginName string + confirmed bool +} + +func pluginUninstallCommand(opts *pluginUninstallOpts) *cobra.Command { + if opts == nil { + opts = &pluginUninstallOpts{} + } + command := &cobra.Command{ + Use: "uninstall [flags] ", + Short: "Uninstall plugin", + Long: `Uninstall a Notation plugin + +Example - Uninstall plugin: + notation plugin uninstall my-plugin +`, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return errors.New("plugin name is required") + } + opts.pluginName = args[0] + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + return unInstallPlugin(cmd, opts) + }, + } + + command.Flags().BoolVarP(&opts.confirmed, "yes", "y", false, "do not prompt for confirmation") + return command +} + +func unInstallPlugin(command *cobra.Command, opts *pluginUninstallOpts) error { + pluginName := opts.pluginName + existed, err := checkPluginExistence(command.Context(), pluginName) + if err != nil { + return fmt.Errorf("failed to check plugin existence, %w", err) + } + if !existed { + return fmt.Errorf("plugin %s does not exist", pluginName) + } + pluginPath, err := dir.PluginFS().SysPath(pluginName) + if err != nil { + return err + } + prompt := fmt.Sprintf("Are you sure you want to uninstall plugin %q?", pluginName) + confirmed, err := cmdutil.AskForConfirmation(os.Stdin, prompt, opts.confirmed) + if err != nil { + return err + } + if !confirmed { + return nil + } + err = os.RemoveAll(pluginPath) + if err == nil { + fmt.Printf("Successfully uninstalled plugin %s\n", pluginName) + } + return err +}