diff --git a/plugin/manager.go b/plugin/manager.go index e55159bd..6b5d98b8 100644 --- a/plugin/manager.go +++ b/plugin/manager.go @@ -17,6 +17,7 @@ import ( "context" "errors" "io/fs" + "os" "path" "github.com/notaryproject/notation-go/dir" @@ -82,3 +83,16 @@ func (m *CLIManager) List(ctx context.Context) ([]string, error) { }) return plugins, nil } + +// Uninstall uninstalls a plugin on the system by its name +// If the plugin dir does not exist, os.ErrNotExist is returned. +func (m *CLIManager) Uninstall(ctx context.Context, name string) error { + pluginDirPath, err := m.pluginFS.SysPath(name) + if err != nil { + return err + } + if _, err := os.Stat(pluginDirPath); err != nil { + return err + } + return os.RemoveAll(pluginDirPath) +} diff --git a/plugin/manager_test.go b/plugin/manager_test.go index 86e906d0..b3b03488 100644 --- a/plugin/manager_test.go +++ b/plugin/manager_test.go @@ -17,6 +17,7 @@ import ( "context" "encoding/json" "io/fs" + "os" "reflect" "testing" "testing/fstest" @@ -87,6 +88,31 @@ func TestManager_List(t *testing.T) { }) } +func TestManager_Uninstall(t *testing.T) { + executor = testCommander{stdout: metadataJSON(validMetadata)} + mgr := NewCLIManager(mockfs.NewSysFSWithRootMock(fstest.MapFS{}, "./testdata/plugins")) + if err := os.MkdirAll("./testdata/plugins/toUninstall", 0777); err != nil { + t.Fatalf("failed to create toUninstall dir: %v", err) + } + defer os.RemoveAll("./testdata/plugins/toUninstall") + pluginFile, err := os.Create("./testdata/plugins/toUninstall/toUninstall") + if err != nil { + t.Fatalf("failed to create toUninstall file: %v", err) + } + if err := pluginFile.Close(); err != nil { + t.Fatalf("failed to close toUninstall file: %v", err) + } + // test uninstall valid plugin + if err := mgr.Uninstall(context.Background(), "toUninstall"); err != nil { + t.Fatalf("Manager.Uninstall() err %v, want nil", err) + } + // test uninstall non-exist plugin + expectedErrorMsg := "stat testdata/plugins/non-exist: no such file or directory" + if err := mgr.Uninstall(context.Background(), "non-exist"); err == nil || err.Error() != expectedErrorMsg { + t.Fatalf("Manager.Uninstall() err %v, want %s", err, expectedErrorMsg) + } +} + func metadataJSON(m proto.GetMetadataResponse) []byte { d, err := json.Marshal(m) if err != nil {