diff --git a/src/cli/docs.go b/src/cli/docs.go index e055749..af4049d 100644 --- a/src/cli/docs.go +++ b/src/cli/docs.go @@ -18,7 +18,7 @@ Mark FILE(s) for deletion. -f, --force Bypass protections --v, --verbose Add additional information to the output +-v, --verbose Add additional information to the output --help Display this help and (without deleting anything) diff --git a/src/config/parse_test.go b/src/config/parse_test.go index 86d4312..a0ee41c 100644 --- a/src/config/parse_test.go +++ b/src/config/parse_test.go @@ -36,6 +36,7 @@ func TestParsingConfig(t *testing.T) { "*.partial", }, Soft: []string{ + "backups/", "*.bak", }, Protected: []string{ diff --git a/src/models/config.go b/src/models/config.go index b9d717b..5d3f17f 100644 --- a/src/models/config.go +++ b/src/models/config.go @@ -94,13 +94,16 @@ func (config Config) InteractiveThreshold() int { } func matchesPattern(pattern string, path string) bool { - // we put a wildcard at the start so that we don't have to match full - // paths - isAbsolutePath := strings.HasPrefix(path, "/") - if !isAbsolutePath { - pattern = "*" + pattern + // Normalize the pattern and path + normalizedPattern := filepath.Clean(pattern) + normalizedPath := filepath.Clean(path) + + // Check if the pattern matches the path + matched, _ := filepath.Match(normalizedPattern, normalizedPath) + if matched { + return true } - matched, _ := filepath.Match(pattern, path) - return matched + hasSuffix := strings.HasSuffix(normalizedPath, normalizedPattern) + return hasSuffix } diff --git a/src/models/config_test.go b/src/models/config_test.go index e6ca0cd..c5b82c8 100644 --- a/src/models/config_test.go +++ b/src/models/config_test.go @@ -56,6 +56,44 @@ func TestConfig(t *testing.T) { testedPath: "node_modules/", expectedResult: true, }, + { + name: "HardDeleteWithPrefix", + configPath: "valid.yml", + configFunction: models.Config.ShouldHardDelete, + testedPath: "./node_modules/", + expectedResult: true, + }, + { + name: "HardDeleteWithLongPrefix", + configPath: "valid.yml", + configFunction: models.Config.ShouldHardDelete, + testedPath: "./Documents/client/node_modules/", + expectedResult: true, + }, + { + // while we specified node_modules/ as a hard delete inside the + // config, test.txt does not match the hard delete config pattern + // so we expect the nested file to use the default soft-delete + name: "HardDeleteWithSuffix", + configPath: "valid.yml", + configFunction: models.Config.ShouldHardDelete, + testedPath: "node_modules/test.txt", + expectedResult: false, + }, + { + name: "HardDeleteWithLongSuffix", + configPath: "valid.yml", + configFunction: models.Config.ShouldHardDelete, + testedPath: "node_modules/sub_package/dist/test.txt", + expectedResult: false, + }, + { + name: "HardDeleteWithSuffixAndPrefix", + configPath: "valid.yml", + configFunction: models.Config.ShouldHardDelete, + testedPath: "/home/john_doe/Documents/client/node_modules/test.txt", + expectedResult: false, + }, { name: "NotHardDelete", configPath: "valid.yml", @@ -86,6 +124,20 @@ func TestConfig(t *testing.T) { testedPath: "file.bak", expectedResult: true, }, + { + name: "SoftDeleteWithPrefix", + configPath: "valid.yml", + configFunction: models.Config.ShouldSoftDelete, + testedPath: "./file.bak", + expectedResult: true, + }, + { + name: "SoftDeleteWithLongPrefix", + configPath: "valid.yml", + configFunction: models.Config.ShouldSoftDelete, + testedPath: "./.local/share/2rm/file.bak", + expectedResult: true, + }, { name: "NotSoftDelete", configPath: "valid.yml", @@ -116,6 +168,20 @@ func TestConfig(t *testing.T) { testedPath: ".ssh/", expectedResult: true, }, + { + name: "ProtectedWithPrefix", + configPath: "valid.yml", + configFunction: models.Config.IsProtected, + testedPath: "./.ssh/", + expectedResult: true, + }, + { + name: "ProtectedWithLongPrefix", + configPath: "valid.yml", + configFunction: models.Config.IsProtected, + testedPath: "./john-doe/crypto/.ssh/", + expectedResult: true, + }, { name: "NotProtected", configPath: "valid.yml", @@ -146,6 +212,20 @@ func TestConfig(t *testing.T) { testedPath: ".ssh/test.pem", expectedResult: true, }, + { + name: "OverwriteWithPrefix", + configPath: "valid.yml", + configFunction: models.Config.ShouldOverwrite, + testedPath: "./.ssh/test.pem", + expectedResult: true, + }, + { + name: "OverwriteWithLongPrefix", + configPath: "valid.yml", + configFunction: models.Config.ShouldOverwrite, + testedPath: "./john-doe/crypto/.ssh/test.pem", + expectedResult: true, + }, { name: "DontOverwrite", configPath: "valid.yml", diff --git a/src/patches/rm.go b/src/patches/rm.go index f16f819..2b39ddf 100644 --- a/src/patches/rm.go +++ b/src/patches/rm.go @@ -52,7 +52,7 @@ func RmPatch(arguments []string, config models.Config) { if shouldNotify { fileNames := strings.Join(filePaths, ", ") - err := beeep.Notify("2rm", "Finished deletion request '"+fileNames+"'", "") + err := beeep.Notify("2rm", "Completed deletion '"+fileNames+"'", "") if err != nil { panic(err) } @@ -81,7 +81,11 @@ func extractFilePaths(input []string) []string { for _, str := range input { if !strings.HasPrefix(str, "-") { - filePaths = append(filePaths, str) + if util.IsDirectory(str) && !strings.HasSuffix(str, "/") { + filePaths = append(filePaths, str+"/") + } else { + filePaths = append(filePaths, str) + } } } diff --git a/tests/assets/configs/valid.yml b/tests/assets/configs/valid.yml index cb5631b..cf200c6 100644 --- a/tests/assets/configs/valid.yml +++ b/tests/assets/configs/valid.yml @@ -8,6 +8,7 @@ hard: - ".next/" - "*.partial" soft: + - "backups/" - "*.bak" protected: - ".ssh/"