diff --git a/pkg/build/stage/dependencies.go b/pkg/build/stage/dependencies.go index 1b6f79d16d..318d2fa5ca 100644 --- a/pkg/build/stage/dependencies.go +++ b/pkg/build/stage/dependencies.go @@ -339,7 +339,7 @@ func generateChecksumCommand(from string, includePaths, excludePaths []string, r var nameIncludeArgs []string for _, includePath := range includePaths { - formattedPath := formatIncludeAndExcludePath(includePath) + formattedPath := util.SafeTrimGlobsAndSlashesFromPath(includePath) nameIncludeArgs = append( nameIncludeArgs, fmt.Sprintf("-wholename \"%s\"", path.Join(from, formattedPath)), @@ -353,7 +353,7 @@ func generateChecksumCommand(from string, includePaths, excludePaths []string, r var nameExcludeArgs []string for _, excludePath := range excludePaths { - formattedPath := formatIncludeAndExcludePath(excludePath) + formattedPath := util.SafeTrimGlobsAndSlashesFromPath(excludePath) nameExcludeArgs = append( nameExcludeArgs, fmt.Sprintf("! -wholename \"%s\"", path.Join(from, formattedPath)), @@ -388,10 +388,6 @@ func generateChecksumCommand(from string, includePaths, excludePaths []string, r return command } -func formatIncludeAndExcludePath(path string) string { - return strings.TrimRight(path, "*/") -} - func getDependencyImportID(dependencyImport *config.DependencyImport) string { return util.Sha256Hash( "Type", string(dependencyImport.Type), diff --git a/pkg/path_matcher/common.go b/pkg/path_matcher/common.go index 5933af912d..c264dce31e 100644 --- a/pkg/path_matcher/common.go +++ b/pkg/path_matcher/common.go @@ -46,7 +46,7 @@ func hasUniversalGlob(globs []string) bool { return true } - if trimRightAsterisks(glob) == "" { + if util.SafeTrimGlobsAndSlashesFromFilepath(glob) == "" { return true } } @@ -70,8 +70,8 @@ func isPathMatched(filePath, glob string) bool { // The previous glob with the universal part `**/*` (path/*/dir/**/*). for _, g := range []string{ glob, - trimRightAsterisks(glob), - filepath.Join(trimRightAsterisks(glob), "**", "*"), + util.SafeTrimGlobsAndSlashesFromFilepath(glob), + filepath.Join(util.SafeTrimGlobsAndSlashesFromFilepath(glob), "**", "*"), } { matched, err := doublestar.PathMatch(g, filePath) if err != nil { @@ -86,10 +86,6 @@ func isPathMatched(filePath, glob string) bool { return false } -func trimRightAsterisks(pattern string) string { - return strings.TrimRight(pattern, "*\\/") -} - func formatPaths(paths []string) []string { var result []string for _, path := range paths { diff --git a/pkg/util/path.go b/pkg/util/path.go index 73b81a9c28..7d0122133d 100644 --- a/pkg/util/path.go +++ b/pkg/util/path.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "os/user" + "path" "path/filepath" "runtime" "strings" @@ -151,3 +152,23 @@ func FilepathsWithParents(path string) []string { return res } + +// SafeTrimGlobsAndSlashesFromFilepath trims any trailing globs and/or slashes from the path, +// while ignoring globs that are part of a directory or file name. +func SafeTrimGlobsAndSlashesFromFilepath(p string) string { + return filepath.FromSlash(SafeTrimGlobsAndSlashesFromPath(p)) +} + +func SafeTrimGlobsAndSlashesFromPath(p string) string { + parts := SplitFilepath(p) + for i := len(parts) - 1; i >= 0; i-- { + if partWOGlobs := strings.TrimRight(parts[i], "*"); partWOGlobs != "" { + parts = parts[:i+1] + break + } else { + parts = parts[:i] + } + } + + return path.Join(parts...) +} diff --git a/pkg/util/path_test.go b/pkg/util/path_test.go new file mode 100644 index 0000000000..5c113f9d2c --- /dev/null +++ b/pkg/util/path_test.go @@ -0,0 +1,57 @@ +package util + +import ( + "testing" +) + +func TestSafeTrimGlobsAndSlashes(t *testing.T) { + tests := []struct { + name string + path string + want string + }{ + { + name: "globs", + path: "**/*", + want: "", + }, + { + name: "empty path", + path: "", + want: "", + }, + { + name: "path", + path: "path", + want: "path", + }, + { + name: "path with trailing slash", + path: "path/", + want: "path", + }, + { + name: "path with globs and slashes", + path: "path/**/*", + want: "path", + }, + { + name: "path with glob as part of a directory or file name 1", + path: "path/name-*", + want: "path/name-*", + }, + { + name: "path with glob as part of a directory or file name 2", + path: "path/*.tmp", + want: "path/*.tmp", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := SafeTrimGlobsAndSlashesFromPath(tt.path); got != tt.want { + t.Errorf("SafeTrimGlobsAndSlashesFromPath() = %v, want %v", got, tt.want) + } + }) + } +}