diff --git a/tools/filesystem/filesystem.go b/tools/filesystem/filesystem.go index 128861e6..b3a3bc0c 100644 --- a/tools/filesystem/filesystem.go +++ b/tools/filesystem/filesystem.go @@ -8,7 +8,6 @@ import ( "mime/multipart" "net/http" "os" - "path" "path/filepath" "regexp" "sort" @@ -276,6 +275,8 @@ func (s *System) Delete(fileKey string) error { } // DeletePrefix deletes everything starting with the specified prefix. +// +// The prefix could be subpath (ex. "/a/b/") or filename prefix (ex. "/a/b/file_"). func (s *System) DeletePrefix(prefix string) []error { failed := []error{} @@ -285,7 +286,14 @@ func (s *System) DeletePrefix(prefix string) []error { } dirsMap := map[string]struct{}{} - dirsMap[prefix] = struct{}{} + + var isPrefixDir bool + + // treat the prefix as directory only if it ends with trailing slash + if strings.HasSuffix(prefix, "/") { + isPrefixDir = true + dirsMap[strings.TrimRight(prefix, "/")] = struct{}{} + } // delete all files with the prefix // --- @@ -303,8 +311,11 @@ func (s *System) DeletePrefix(prefix string) []error { if err := s.Delete(obj.Key); err != nil { failed = append(failed, err) - } else { - dirsMap[path.Dir(obj.Key)] = struct{}{} + } else if isPrefixDir { + slashIdx := strings.LastIndex(obj.Key, "/") + if slashIdx > -1 { + dirsMap[obj.Key[:slashIdx]] = struct{}{} + } } } // --- diff --git a/tools/filesystem/filesystem_test.go b/tools/filesystem/filesystem_test.go index 7b57b549..57e880ca 100644 --- a/tools/filesystem/filesystem_test.go +++ b/tools/filesystem/filesystem_test.go @@ -101,7 +101,7 @@ func TestFileSystemDelete(t *testing.T) { } } -func TestFileSystemDeletePrefix(t *testing.T) { +func TestFileSystemDeletePrefixWithoutTrailingSlash(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -115,7 +115,7 @@ func TestFileSystemDeletePrefix(t *testing.T) { t.Fatal("Expected error, got nil", errs) } - if errs := fs.DeletePrefix("missing/"); len(errs) != 0 { + if errs := fs.DeletePrefix("missing"); len(errs) != 0 { t.Fatalf("Not existing prefix shouldn't error, got %v", errs) } @@ -123,13 +123,50 @@ func TestFileSystemDeletePrefix(t *testing.T) { t.Fatalf("Expected nil, got errors %v", errs) } - // ensure that the test/ files are deleted + // ensure that the test/* files are deleted if exists, _ := fs.Exists("test/sub1.txt"); exists { t.Fatalf("Expected test/sub1.txt to be deleted") } if exists, _ := fs.Exists("test/sub2.txt"); exists { t.Fatalf("Expected test/sub2.txt to be deleted") } + + // the test directory should remain since the prefix didn't have trailing slash + if _, err := os.Stat(filepath.Join(dir, "test")); os.IsNotExist(err) { + t.Fatal("Expected the prefix dir to remain") + } +} + +func TestFileSystemDeletePrefixWithTrailingSlash(t *testing.T) { + dir := createTestDir(t) + defer os.RemoveAll(dir) + + fs, err := filesystem.NewLocal(dir) + if err != nil { + t.Fatal(err) + } + defer fs.Close() + + if errs := fs.DeletePrefix("missing/"); len(errs) != 0 { + t.Fatalf("Not existing prefix shouldn't error, got %v", errs) + } + + if errs := fs.DeletePrefix("test/"); len(errs) != 0 { + t.Fatalf("Expected nil, got errors %v", errs) + } + + // ensure that the test/* files are deleted + if exists, _ := fs.Exists("test/sub1.txt"); exists { + t.Fatalf("Expected test/sub1.txt to be deleted") + } + if exists, _ := fs.Exists("test/sub2.txt"); exists { + t.Fatalf("Expected test/sub2.txt to be deleted") + } + + // the test directory should be also deleted since the prefix has trailing slash + if _, err := os.Stat(filepath.Join(dir, "test")); !os.IsNotExist(err) { + t.Fatal("Expected the prefix dir to be deleted") + } } func TestFileSystemUploadMultipart(t *testing.T) {