From f1a80e3f2e34e744ce4b87211a1bcf85e9eb01f2 Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Fri, 31 Mar 2023 10:37:32 -0500 Subject: [PATCH 01/15] Add Masterminds/semver for plugin version comparison Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index cf101a5eb..4b0114dde 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect + github.com/Masterminds/semver v1.5.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-ldap/ldap/v3 v3.4.4 // indirect diff --git a/go.sum b/go.sum index 3751358f2..7beb80273 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= From 83fe95875f18f4c63f92734cd64adcb2cc03e61f Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Fri, 31 Mar 2023 10:38:20 -0500 Subject: [PATCH 02/15] Add: plugin install and remove subcommands Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 212 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index 1effeedaf..2f9d16b6e 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -1,10 +1,16 @@ package main import ( + "encoding/json" + "errors" "fmt" + "io" "os" + "os/exec" + "strings" "text/tabwriter" + "github.com/Masterminds/semver" "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/plugin/proto" @@ -17,6 +23,8 @@ func pluginCommand() *cobra.Command { Short: "Manage plugins", } cmd.AddCommand(pluginListCommand()) + cmd.AddCommand(pluginInstallCommand()) + cmd.AddCommand(pluginRemoveCommand()) return cmd } @@ -36,6 +44,44 @@ Example - List installed Notation plugins: } } +func pluginInstallCommand() *cobra.Command { + var force bool + + cmd := &cobra.Command{ + Use: "install [flags] ", + Aliases: []string{"add"}, + Short: "Install a plugin", + Long: `Install a plugin + + Example - Install a Notation plugin: + notation plugin install +`, + RunE: func(cmd *cobra.Command, args []string) error { + return installPlugin(cmd, args, force) + }, + } + + cmd.Flags().BoolVarP(&force, "force", "f", false, "Overwrite existing plugin files without prompting") + + return cmd +} + +func pluginRemoveCommand() *cobra.Command { + return &cobra.Command{ + Use: "remove [flags] ", + Aliases: []string{"rm", "uninstall", "delete"}, + Short: "Remove a plugin", + Long: `Remove a plugin + + Example - Remove a Notation plugin: + notation plugin remove +`, + RunE: func(cmd *cobra.Command, args []string) error { + return removePlugin(cmd, args) + }, + } +} + func listPlugins(command *cobra.Command) error { mgr := plugin.NewCLIManager(dir.PluginFS()) pluginNames, err := mgr.List(command.Context()) @@ -62,3 +108,169 @@ func listPlugins(command *cobra.Command) error { } return tw.Flush() } + +func installPlugin(command *cobra.Command, args []string, force bool) error { + if len(args) != 1 { + return errors.New("missing plugin package") + } + + pluginPath := args[0] + + var pluginBinary string + // if plugin contains a file path split and select the last element in the array + if strings.Contains(pluginPath, "/") { + pluginBinary = strings.Split(pluginPath, "/")[len(strings.Split(pluginPath, "/"))-1] + } else { + pluginBinary = pluginPath + } + + // get plugin metadata + cmd := exec.Command("./"+pluginPath, "get-plugin-metadata") + + output, err := cmd.Output() + if err != nil { + panic(err) + } + + var newPlugin map[string]interface{} + err = json.Unmarshal([]byte(output), &newPlugin) + if err != nil { + return err + } + + pluginName := newPlugin["name"].(string) + newPluginVersion := newPlugin["version"].(string) + newSemVersion, err := semver.NewVersion(newPluginVersion) + if err != nil { + return err + } + + // get plugin directory + pluginDir, err := dir.PluginFS().SysPath(pluginName) + if err != nil { + panic(err) + } + + // Check if plugin directory exists + _, err = os.Stat(pluginDir) + + // create the directory, if not exist + if os.IsNotExist(err) { + if err := os.MkdirAll(pluginDir, 0755); err != nil { + return err + } + } + + // Check if plugin exists + _, err = os.Stat(pluginDir + "/" + pluginBinary) + + // copy plugin, if not exist + if os.IsNotExist(err) { + copyPlugin(pluginPath, pluginDir+"/"+pluginBinary) + } + + // overwrite plugin, if force flag is set + if err == nil && force { + fmt.Printf("Overwriting plugin %s in directory %s\n", pluginBinary, pluginDir) + copyPlugin(pluginPath, pluginDir+"/"+pluginBinary) + } + + // if plugin exists and force flag is not set, get plugin metadata + if err == nil && !force { + cmd := exec.Command(pluginDir+"/"+pluginBinary, "get-plugin-metadata") + + output, err := cmd.Output() + if err != nil { + return err + } + + var currentPlugin map[string]interface{} + err = json.Unmarshal([]byte(output), ¤tPlugin) + if err != nil { + return err + } + + // check if new plugin version is greater than current plugin version + currentPluginVersion := currentPlugin["version"].(string) + currentVersion, err := semver.NewVersion(currentPluginVersion) + if err != nil { + return err + } + + // copy plugin, if new plugin version is greater than current plugin version + if newSemVersion.GreaterThan(currentVersion) { + var confirm string + + fmt.Printf("Detected new version %s. Current version is %s.\nDo you want to overwrite the plugin %s? [y/N]: ", newSemVersion.String(), currentVersion.String(), pluginName) + fmt.Scanln(&confirm) + + if strings.ToLower(confirm) != "y" { + fmt.Println("Operation cancelled.") + return nil + } + + fmt.Printf("Copying plugin %s to directory %s...\n", pluginName, pluginDir) + copyPlugin(pluginPath, pluginDir+"/"+pluginBinary) + } + + // do not copy plugin, if new plugin version is less than or equal to current plugin version + if newSemVersion.LessThan(currentVersion) || newSemVersion.Equal(currentVersion) { + fmt.Println("Current version is greater than or equal to new version. Skipping plugin installation.\nUse --force flag to overwrite the plugin.") + } + } + + return nil +} + +func removePlugin(command *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("missing plugin name") + } + + pluginName := args[0] + + // get plugin directory + pluginDir, err := dir.PluginFS().SysPath(pluginName) + if err != nil { + return err + } + + // Check if plugin directory exists + _, err = os.Stat(pluginDir) + if os.IsNotExist(err) { + return errors.New("plugin does not exist") + } + + // remove plugin directory + err = os.RemoveAll(pluginDir) + if err != nil { + return err + } + + return nil +} + +func copyPlugin(src, dest string) error { + sourceFile, err := os.Open(src) + if err != nil { + return err + } + + sourceFileInfo, err := sourceFile.Stat() + if err != nil { + return err + } + fileMode := sourceFileInfo.Mode() + + destFile, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileMode) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, sourceFile) + if err != nil { + return err + } + return nil +} From bcc841d23aaa593998ebc1a69110b019f0ee1f57 Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 10 Apr 2023 13:17:05 -0500 Subject: [PATCH 03/15] Replace panic err with return err Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index 2f9d16b6e..e3c68088d 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -129,7 +129,7 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { output, err := cmd.Output() if err != nil { - panic(err) + return err } var newPlugin map[string]interface{} @@ -148,7 +148,7 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { // get plugin directory pluginDir, err := dir.PluginFS().SysPath(pluginName) if err != nil { - panic(err) + return err } // Check if plugin directory exists From 046a59fac2a831aa2c3241baeae3e5fb51eeb635 Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Thu, 13 Apr 2023 14:21:01 -0500 Subject: [PATCH 04/15] Change prompt to use AskForConfirmation Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index e3c68088d..a2c1802a5 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -14,6 +14,7 @@ import ( "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/plugin/proto" + "github.com/notaryproject/notation/cmd/notation/internal/cmdutil" "github.com/spf13/cobra" ) @@ -199,13 +200,13 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { // copy plugin, if new plugin version is greater than current plugin version if newSemVersion.GreaterThan(currentVersion) { - var confirm string - - fmt.Printf("Detected new version %s. Current version is %s.\nDo you want to overwrite the plugin %s? [y/N]: ", newSemVersion.String(), currentVersion.String(), pluginName) - fmt.Scanln(&confirm) + prompt := fmt.Sprintf("Are you sure you want to overwrite plugin %s v%s with v%s?", pluginName, currentVersion.String(), newSemVersion.String()) + confimred, err := cmdutil.AskForConfirmation(os.Stdin, prompt, false) + if err != nil { + return err + } - if strings.ToLower(confirm) != "y" { - fmt.Println("Operation cancelled.") + if !confimred { return nil } From c75a993baf736e90f96dc7a8f2805c493ee31a6b Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 17 Apr 2023 10:59:47 -0500 Subject: [PATCH 05/15] Update cmd/notation/plugin.go Co-authored-by: Pritesh Bandi Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index a2c1802a5..98c2b7b3e 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -55,7 +55,7 @@ func pluginInstallCommand() *cobra.Command { Long: `Install a plugin Example - Install a Notation plugin: - notation plugin install + notation plugin install `, RunE: func(cmd *cobra.Command, args []string) error { return installPlugin(cmd, args, force) From 52a6aa726478e66873afb156b283760d7239ad08 Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 17 Apr 2023 11:10:55 -0500 Subject: [PATCH 06/15] Update cmd/notation/plugin.go Co-authored-by: Pritesh Bandi Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index 98c2b7b3e..f7cdeae3b 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -117,13 +117,7 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { pluginPath := args[0] - var pluginBinary string - // if plugin contains a file path split and select the last element in the array - if strings.Contains(pluginPath, "/") { - pluginBinary = strings.Split(pluginPath, "/")[len(strings.Split(pluginPath, "/"))-1] - } else { - pluginBinary = pluginPath - } +pluginName := filepath.Base(pluginPath) // get plugin metadata cmd := exec.Command("./"+pluginPath, "get-plugin-metadata") From 38ae3cfdeecc03417a74fcd6526cdbdae20d1cd7 Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 17 Apr 2023 11:11:09 -0500 Subject: [PATCH 07/15] Update cmd/notation/plugin.go Co-authored-by: Pritesh Bandi Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index f7cdeae3b..dadc404ec 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -120,7 +120,7 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { pluginName := filepath.Base(pluginPath) // get plugin metadata - cmd := exec.Command("./"+pluginPath, "get-plugin-metadata") + cmd := exec.Command("pluginPath, "get-plugin-metadata") output, err := cmd.Output() if err != nil { From 7d02ddbe546914d34f71873941e2e87f8e11aff9 Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 17 Apr 2023 13:39:18 -0500 Subject: [PATCH 08/15] Replace strings.Contains with filepath.Base Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index dadc404ec..08ff1b717 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -7,7 +7,7 @@ import ( "io" "os" "os/exec" - "strings" + "path/filepath" "text/tabwriter" "github.com/Masterminds/semver" @@ -117,10 +117,10 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { pluginPath := args[0] -pluginName := filepath.Base(pluginPath) + pluginBinary := filepath.Base(pluginPath) // get plugin metadata - cmd := exec.Command("pluginPath, "get-plugin-metadata") + cmd := exec.Command(pluginPath, "get-plugin-metadata") output, err := cmd.Output() if err != nil { From f1107a00c78c2f871203f57f27d10571143b2701 Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 17 Apr 2023 14:27:22 -0500 Subject: [PATCH 09/15] Add pluginDestPath var Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index 08ff1b717..650141f12 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -115,12 +115,12 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { return errors.New("missing plugin package") } - pluginPath := args[0] + pluginSrcPath := args[0] - pluginBinary := filepath.Base(pluginPath) + pluginBinary := filepath.Base(pluginSrcPath) // get plugin metadata - cmd := exec.Command(pluginPath, "get-plugin-metadata") + cmd := exec.Command(pluginSrcPath, "get-plugin-metadata") output, err := cmd.Output() if err != nil { @@ -156,23 +156,25 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } } + pluginDestPath := pluginDir + "/" + pluginBinary + // Check if plugin exists - _, err = os.Stat(pluginDir + "/" + pluginBinary) + _, err = os.Stat(pluginDestPath) // copy plugin, if not exist if os.IsNotExist(err) { - copyPlugin(pluginPath, pluginDir+"/"+pluginBinary) + copyPlugin(pluginSrcPath, pluginDestPath) } // overwrite plugin, if force flag is set if err == nil && force { fmt.Printf("Overwriting plugin %s in directory %s\n", pluginBinary, pluginDir) - copyPlugin(pluginPath, pluginDir+"/"+pluginBinary) + copyPlugin(pluginSrcPath, pluginDestPath) } // if plugin exists and force flag is not set, get plugin metadata if err == nil && !force { - cmd := exec.Command(pluginDir+"/"+pluginBinary, "get-plugin-metadata") + cmd := exec.Command(pluginDestPath, "get-plugin-metadata") output, err := cmd.Output() if err != nil { @@ -205,7 +207,7 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } fmt.Printf("Copying plugin %s to directory %s...\n", pluginName, pluginDir) - copyPlugin(pluginPath, pluginDir+"/"+pluginBinary) + copyPlugin(pluginSrcPath, pluginDestPath) } // do not copy plugin, if new plugin version is less than or equal to current plugin version From 9aaa49de68cd948dd2b786a4548dbbb92e42c7e9 Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 17 Apr 2023 15:15:25 -0500 Subject: [PATCH 10/15] Update cmd/notation/plugin.go Co-authored-by: Shiwei Zhang Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index 650141f12..e7eea98a6 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -239,12 +239,7 @@ func removePlugin(command *cobra.Command, args []string) error { } // remove plugin directory - err = os.RemoveAll(pluginDir) - if err != nil { - return err - } - - return nil + return os.RemoveAll(pluginDir) } func copyPlugin(src, dest string) error { From f8423cd60c6e4e2326e9034a8ed3ce8b524ba15b Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 17 Apr 2023 15:18:58 -0500 Subject: [PATCH 11/15] Update cmd/notation/plugin.go Co-authored-by: Shiwei Zhang Signed-off-by: Josh Duffney Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index e7eea98a6..8b516eed6 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -62,7 +62,7 @@ func pluginInstallCommand() *cobra.Command { }, } - cmd.Flags().BoolVarP(&force, "force", "f", false, "Overwrite existing plugin files without prompting") + cmd.Flags().BoolVarP(&force, "force", "f", false, "overwrite existing plugin files without prompting") return cmd } From e4d7ef5f0b4d53f2e1a218350742fab9f09c21ff Mon Sep 17 00:00:00 2001 From: Joshua Duffney Date: Wed, 7 Jun 2023 14:15:57 -0500 Subject: [PATCH 12/15] Mod: replace exec.Command with GetMetadata method Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 66 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index 8b516eed6..f4e470868 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -1,14 +1,13 @@ package main import ( - "encoding/json" "errors" "fmt" "io" "os" - "os/exec" "path/filepath" "text/tabwriter" + "strings" "github.com/Masterminds/semver" "github.com/notaryproject/notation-go/dir" @@ -116,26 +115,18 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } pluginSrcPath := args[0] - pluginBinary := filepath.Base(pluginSrcPath) + pluginName := splitPluginName(pluginBinary) // get plugin metadata - cmd := exec.Command(pluginSrcPath, "get-plugin-metadata") - - output, err := cmd.Output() - if err != nil { - return err + pl, err := plugin.NewCLIPlugin(command.Context(), pluginName, pluginSrcPath) + newPluginMetadata := &proto.GetMetadataResponse{} + resp, err := pl.GetMetadata(command.Context(), &proto.GetMetadataRequest{}) + if err == nil { + newPluginMetadata = resp } - var newPlugin map[string]interface{} - err = json.Unmarshal([]byte(output), &newPlugin) - if err != nil { - return err - } - - pluginName := newPlugin["name"].(string) - newPluginVersion := newPlugin["version"].(string) - newSemVersion, err := semver.NewVersion(newPluginVersion) + newVersion, err := semver.NewVersion(newPluginMetadata.Version) if err != nil { return err } @@ -174,29 +165,26 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { // if plugin exists and force flag is not set, get plugin metadata if err == nil && !force { - cmd := exec.Command(pluginDestPath, "get-plugin-metadata") - - output, err := cmd.Output() - if err != nil { - return err - } + mgr := plugin.NewCLIManager(dir.PluginFS()) + currentPlugin, err := mgr.Get(command.Context(), pluginName) - var currentPlugin map[string]interface{} - err = json.Unmarshal([]byte(output), ¤tPlugin) - if err != nil { - return err + currentPluginMetadata := &proto.GetMetadataResponse{} + if err == nil { + resp, err := currentPlugin.GetMetadata(command.Context(), &proto.GetMetadataRequest{}) + if err == nil { + currentPluginMetadata = resp + } } - // check if new plugin version is greater than current plugin version - currentPluginVersion := currentPlugin["version"].(string) - currentVersion, err := semver.NewVersion(currentPluginVersion) + // convert version to semver + currentVersion, err := semver.NewVersion(currentPluginMetadata.Version) if err != nil { return err } // copy plugin, if new plugin version is greater than current plugin version - if newSemVersion.GreaterThan(currentVersion) { - prompt := fmt.Sprintf("Are you sure you want to overwrite plugin %s v%s with v%s?", pluginName, currentVersion.String(), newSemVersion.String()) + if newVersion.GreaterThan(currentVersion) { + prompt := fmt.Sprintf("Are you sure you want to overwrite plugin %s v%s with v%s?", pluginName, currentVersion.String(), newVersion.String()) confimred, err := cmdutil.AskForConfirmation(os.Stdin, prompt, false) if err != nil { return err @@ -211,7 +199,7 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } // do not copy plugin, if new plugin version is less than or equal to current plugin version - if newSemVersion.LessThan(currentVersion) || newSemVersion.Equal(currentVersion) { + if newVersion.LessThan(currentVersion) || newVersion.Equal(currentVersion) { fmt.Println("Current version is greater than or equal to new version. Skipping plugin installation.\nUse --force flag to overwrite the plugin.") } } @@ -266,3 +254,15 @@ func copyPlugin(src, dest string) error { } return nil } + +func splitPluginName (p string) string { + parts := strings.Split(p, "-") + result := strings.Join(parts[1:3], "-") + ext := filepath.Ext(p) + + if ext != "" { + result = strings.TrimSuffix(result, ".exe") + } + + return result +} From 7f9d96fe25c330c79cb9c61266ec9ae492111098 Mon Sep 17 00:00:00 2001 From: Joshua Duffney Date: Fri, 9 Jun 2023 09:59:16 -0500 Subject: [PATCH 13/15] Mod: replace Mastermind/semver with golang/x/mod/semver Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 22 +++++++--------------- go.mod | 3 +-- go.sum | 2 -- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index f4e470868..e6ec6b6b6 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -9,12 +9,12 @@ import ( "text/tabwriter" "strings" - "github.com/Masterminds/semver" "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/plugin/proto" "github.com/notaryproject/notation/cmd/notation/internal/cmdutil" "github.com/spf13/cobra" + "golang.org/x/mod/semver" ) func pluginCommand() *cobra.Command { @@ -126,11 +126,6 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { newPluginMetadata = resp } - newVersion, err := semver.NewVersion(newPluginMetadata.Version) - if err != nil { - return err - } - // get plugin directory pluginDir, err := dir.PluginFS().SysPath(pluginName) if err != nil { @@ -176,15 +171,12 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } } - // convert version to semver - currentVersion, err := semver.NewVersion(currentPluginMetadata.Version) - if err != nil { - return err - } + // Compare plugin versions + compare := semver.Compare("v"+newPluginMetadata.Version, "v"+currentPluginMetadata.Version) // copy plugin, if new plugin version is greater than current plugin version - if newVersion.GreaterThan(currentVersion) { - prompt := fmt.Sprintf("Are you sure you want to overwrite plugin %s v%s with v%s?", pluginName, currentVersion.String(), newVersion.String()) + if compare == 1 { + prompt := fmt.Sprintf("Are you sure you want to overwrite plugin %s_v%s with v%s?", pluginName, currentPluginMetadata.Version, newPluginMetadata.Version) confimred, err := cmdutil.AskForConfirmation(os.Stdin, prompt, false) if err != nil { return err @@ -199,8 +191,8 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } // do not copy plugin, if new plugin version is less than or equal to current plugin version - if newVersion.LessThan(currentVersion) || newVersion.Equal(currentVersion) { - fmt.Println("Current version is greater than or equal to new version. Skipping plugin installation.\nUse --force flag to overwrite the plugin.") + if compare == -1 || compare == 0 { + fmt.Println("Skipping plugin installation. The current version is equal to or higher than the new version.\nTo overwrite the plugin, use the --force flag.") } } diff --git a/go.mod b/go.mod index 4b0114dde..c8ae07620 100644 --- a/go.mod +++ b/go.mod @@ -11,12 +11,12 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 + golang.org/x/mod v0.8.0 oras.land/oras-go/v2 v2.0.2 ) require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect - github.com/Masterminds/semver v1.5.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-ldap/ldap/v3 v3.4.4 // indirect @@ -25,7 +25,6 @@ require ( github.com/veraison/go-cose v1.0.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/crypto v0.6.0 // indirect - golang.org/x/mod v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.5.0 // indirect ) diff --git a/go.sum b/go.sum index 7beb80273..3751358f2 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,6 @@ github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= From 209f159082f98c4d14cd3cdb10a14bf6f5186f9b Mon Sep 17 00:00:00 2001 From: Joshua Duffney Date: Mon, 12 Jun 2023 10:14:44 -0500 Subject: [PATCH 14/15] Mod:check args length in &cobra.Command{Args:} Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index e6ec6b6b6..458af98e4 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -56,6 +56,12 @@ func pluginInstallCommand() *cobra.Command { Example - Install a Notation plugin: notation plugin install `, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("missing plugin package") + } + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { return installPlugin(cmd, args, force) }, @@ -76,6 +82,12 @@ func pluginRemoveCommand() *cobra.Command { Example - Remove a Notation plugin: notation plugin remove `, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("missing plugin name") + } + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { return removePlugin(cmd, args) }, @@ -110,9 +122,6 @@ func listPlugins(command *cobra.Command) error { } func installPlugin(command *cobra.Command, args []string, force bool) error { - if len(args) != 1 { - return errors.New("missing plugin package") - } pluginSrcPath := args[0] pluginBinary := filepath.Base(pluginSrcPath) @@ -200,9 +209,6 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } func removePlugin(command *cobra.Command, args []string) error { - if len(args) != 1 { - return errors.New("missing plugin name") - } pluginName := args[0] From 3eb146c202f2e6a75d4184f5c79d43cd42bc80e5 Mon Sep 17 00:00:00 2001 From: Joshua Duffney Date: Mon, 12 Jun 2023 16:10:47 -0500 Subject: [PATCH 15/15] Mod: use osutil.CopyToDir Signed-off-by: Joshua Duffney --- cmd/notation/plugin.go | 100 ++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 56 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index 458af98e4..3e6116ace 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -3,7 +3,6 @@ package main import ( "errors" "fmt" - "io" "os" "path/filepath" "text/tabwriter" @@ -13,6 +12,7 @@ import ( "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/plugin/proto" "github.com/notaryproject/notation/cmd/notation/internal/cmdutil" + "github.com/notaryproject/notation/internal/osutil" "github.com/spf13/cobra" "golang.org/x/mod/semver" ) @@ -140,35 +140,23 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { if err != nil { return err } + //pluginDestPath := pluginDir + "\\" + pluginBinary - // Check if plugin directory exists - _, err = os.Stat(pluginDir) - - // create the directory, if not exist - if os.IsNotExist(err) { - if err := os.MkdirAll(pluginDir, 0755); err != nil { - return err - } - } - - pluginDestPath := pluginDir + "/" + pluginBinary - - // Check if plugin exists - _, err = os.Stat(pluginDestPath) - - // copy plugin, if not exist - if os.IsNotExist(err) { - copyPlugin(pluginSrcPath, pluginDestPath) - } - - // overwrite plugin, if force flag is set - if err == nil && force { - fmt.Printf("Overwriting plugin %s in directory %s\n", pluginBinary, pluginDir) - copyPlugin(pluginSrcPath, pluginDestPath) + pluginExists, err := exists(pluginDir+"/"+pluginBinary) + if err != nil { + return err } - // if plugin exists and force flag is not set, get plugin metadata - if err == nil && !force { + if pluginExists { + // if force == true, overwrite plugin + if force { + fmt.Printf("Overwriting plugin %s in directory %s\n", pluginBinary, pluginDir) + if _, err := osutil.CopyToDir(pluginSrcPath,pluginDir); err != nil { + return err + } + return nil + } + // get existing plugin metadata mgr := plugin.NewCLIManager(dir.PluginFS()) currentPlugin, err := mgr.Get(command.Context(), pluginName) @@ -176,7 +164,7 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { if err == nil { resp, err := currentPlugin.GetMetadata(command.Context(), &proto.GetMetadataRequest{}) if err == nil { - currentPluginMetadata = resp + currentPluginMetadata = resp } } @@ -196,7 +184,9 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } fmt.Printf("Copying plugin %s to directory %s...\n", pluginName, pluginDir) - copyPlugin(pluginSrcPath, pluginDestPath) + if _, err := osutil.CopyToDir(pluginSrcPath,pluginDir); err != nil { + return err + } } // do not copy plugin, if new plugin version is less than or equal to current plugin version @@ -205,6 +195,14 @@ func installPlugin(command *cobra.Command, args []string, force bool) error { } } + if !pluginExists { + fmt.Printf("Copying plugin %s to directory %s...\n", pluginName, pluginDir) + _, err :=osutil.CopyToDir(pluginSrcPath,pluginDir) + if err != nil { + return err + } + } + return nil } @@ -218,39 +216,18 @@ func removePlugin(command *cobra.Command, args []string) error { return err } - // Check if plugin directory exists - _, err = os.Stat(pluginDir) - if os.IsNotExist(err) { - return errors.New("plugin does not exist") - } - - // remove plugin directory - return os.RemoveAll(pluginDir) -} - -func copyPlugin(src, dest string) error { - sourceFile, err := os.Open(src) - if err != nil { - return err - } - - sourceFileInfo, err := sourceFile.Stat() + // Check if plugin directory exists + pluginExists, err := exists(pluginDir) if err != nil { return err } - fileMode := sourceFileInfo.Mode() - destFile, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileMode) - if err != nil { - return err + if !pluginExists { + return errors.New("plugin does not exist") } - defer destFile.Close() - _, err = io.Copy(destFile, sourceFile) - if err != nil { - return err - } - return nil + // remove plugin directory + return os.RemoveAll(pluginDir) } func splitPluginName (p string) string { @@ -264,3 +241,14 @@ func splitPluginName (p string) string { return result } + +func exists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +}