diff options
Diffstat (limited to 'commands')
-rw-r--r-- | commands/msgview/save.go | 22 | ||||
-rw-r--r-- | commands/msgview/save_test.go | 24 |
2 files changed, 44 insertions, 2 deletions
diff --git a/commands/msgview/save.go b/commands/msgview/save.go index 5bd4c188..170ef7c1 100644 --- a/commands/msgview/save.go +++ b/commands/msgview/save.go @@ -115,8 +115,9 @@ func (s Save) Execute(aerc *widgets.Aerc, args []string) error { return fmt.Errorf("This message has no attachments") } params.trailingSlash = true + names := make(map[string]struct{}) for _, pi := range parts { - if err := savePart(pi, path, mv, aerc, ¶ms); err != nil { + if err := savePart(pi, path, mv, aerc, ¶ms, names); err != nil { return err } } @@ -124,7 +125,7 @@ func (s Save) Execute(aerc *widgets.Aerc, args []string) error { } pi := mv.SelectedMessagePart() - return savePart(pi, path, mv, aerc, ¶ms) + return savePart(pi, path, mv, aerc, ¶ms, make(map[string]struct{})) } func savePart( @@ -133,6 +134,7 @@ func savePart( mv *widgets.MessageViewer, aerc *widgets.Aerc, params *saveParams, + names map[string]struct{}, ) error { if params.trailingSlash || isDirExists(path) { filename := generateFilename(pi.Part) @@ -147,6 +149,9 @@ func savePart( } } + path = getCollisionlessFilename(path, names) + names[path] = struct{}{} + if pathExists(path) && !params.force { return fmt.Errorf("%q already exists and -f not given", path) } @@ -181,6 +186,19 @@ func savePart( return nil } +func getCollisionlessFilename(path string, existing map[string]struct{}) string { + ext := filepath.Ext(path) + name := strings.TrimSuffix(path, ext) + _, exists := existing[path] + counter := 1 + for exists { + path = fmt.Sprintf("%s_%d%s", name, counter, ext) + counter++ + _, exists = existing[path] + } + return path +} + // isDir returns true if path is a directory and exists func isDirExists(path string) bool { pathinfo, err := os.Stat(path) diff --git a/commands/msgview/save_test.go b/commands/msgview/save_test.go new file mode 100644 index 00000000..d6b7e757 --- /dev/null +++ b/commands/msgview/save_test.go @@ -0,0 +1,24 @@ +package msgview + +import "testing" + +func TestGetCollisionlessFilename(t *testing.T) { + tests := []struct { + originalFilename string + expectedNewName string + existingFiles map[string]struct{} + }{ + {"test", "test", map[string]struct{}{}}, + {"test", "test", map[string]struct{}{"other-file": {}}}, + {"test.txt", "test.txt", map[string]struct{}{"test.log": {}}}, + {"test.txt", "test_1.txt", map[string]struct{}{"test.txt": {}}}, + {"test.txt", "test_2.txt", map[string]struct{}{"test.txt": {}, "test_1.txt": {}}}, + {"test.txt", "test_1.txt", map[string]struct{}{"test.txt": {}, "test_2.txt": {}}}, + } + for _, tt := range tests { + actual := getCollisionlessFilename(tt.originalFilename, tt.existingFiles) + if actual != tt.expectedNewName { + t.Errorf("expected %s, actual %s", tt.expectedNewName, actual) + } + } +} |