From adfbc33c90404c0b429523913142c0e22d026d88 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:24:16 +0000 Subject: [PATCH 1/8] Initial plan From e6f92b8b2bc3fec31641d2b6da9b40bbf5956109 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:33:30 +0000 Subject: [PATCH 2/8] Handle exclude pattern directory skip Co-authored-by: kcq <1099414+kcq@users.noreply.github.com> --- pkg/util/fsutil/fsutil.go | 5 ++++ pkg/util/fsutil/fsutil_test.go | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 pkg/util/fsutil/fsutil_test.go diff --git a/pkg/util/fsutil/fsutil.go b/pkg/util/fsutil/fsutil.go index 3a2487ba..a2cd7fdd 100644 --- a/pkg/util/fsutil/fsutil.go +++ b/pkg/util/fsutil/fsutil.go @@ -833,6 +833,11 @@ func copyFileObjectHandler( isIgnored = true break } + + if strings.HasSuffix(xpattern, "/**") && strings.TrimSuffix(xpattern, "/**") == path { + isIgnored = true + break + } } /* if _, ok := ignorePaths[path]; ok { diff --git a/pkg/util/fsutil/fsutil_test.go b/pkg/util/fsutil/fsutil_test.go new file mode 100644 index 00000000..1815f9be --- /dev/null +++ b/pkg/util/fsutil/fsutil_test.go @@ -0,0 +1,44 @@ +package fsutil + +import ( + "errors" + "os" + "path/filepath" + "testing" +) + +func TestCopyDirExcludesWholeDirectoryWhenPatternHasDoubleStar(t *testing.T) { + src := t.TempDir() + dst := t.TempDir() + + excludedDir := filepath.Join(src, "var", "lib", "postgresql", "data") + if err := os.MkdirAll(excludedDir, 0o755); err != nil { + t.Fatalf("failed to create excluded dir: %v", err) + } + + excludedFile := filepath.Join(excludedDir, "file.txt") + if err := os.WriteFile(excludedFile, []byte("x"), 0o644); err != nil { + t.Fatalf("failed to create excluded file: %v", err) + } + + keepFile := filepath.Join(src, "keep.txt") + if err := os.WriteFile(keepFile, []byte("y"), 0o644); err != nil { + t.Fatalf("failed to create keep file: %v", err) + } + + pattern := filepath.Join(excludedDir, "**") + if err, _ := CopyDir(false, src, dst, true, true, []string{pattern}, nil, nil); err != nil { + t.Fatalf("CopyDir returned error: %v", err) + } + + excludedTarget := filepath.Join(dst, "var", "lib", "postgresql", "data") + if _, err := os.Stat(excludedTarget); err == nil { + t.Fatalf("expected excluded directory %q to be skipped", excludedTarget) + } else if !errors.Is(err, os.ErrNotExist) { + t.Fatalf("unexpected error checking excluded directory: %v", err) + } + + if _, err := os.Stat(filepath.Join(dst, "keep.txt")); err != nil { + t.Fatalf("expected kept file to be copied, got error: %v", err) + } +} From 2404a10ef13bfd306f0fe9293133127bf2102786 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:34:49 +0000 Subject: [PATCH 3/8] Refine exclude pattern matching Co-authored-by: kcq <1099414+kcq@users.noreply.github.com> --- pkg/util/fsutil/fsutil.go | 10 +++++----- pkg/util/fsutil/fsutil_test.go | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/util/fsutil/fsutil.go b/pkg/util/fsutil/fsutil.go index a2cd7fdd..90ce6ccf 100644 --- a/pkg/util/fsutil/fsutil.go +++ b/pkg/util/fsutil/fsutil.go @@ -823,18 +823,18 @@ func copyFileObjectHandler( var isIgnored bool for _, xpattern := range excludePatterns { - found, err := doublestar.Match(xpattern, path) + matched, err := doublestar.Match(xpattern, path) if err != nil { log.Warnf("copyFileObjectHandler - [%v] excludePatterns Match error - %v\n", path, err) //should only happen when the pattern is malformed continue } - if found { - isIgnored = true - break + + if !matched && strings.HasSuffix(xpattern, "/**") && strings.TrimSuffix(xpattern, "/**") == path { + matched = true } - if strings.HasSuffix(xpattern, "/**") && strings.TrimSuffix(xpattern, "/**") == path { + if matched { isIgnored = true break } diff --git a/pkg/util/fsutil/fsutil_test.go b/pkg/util/fsutil/fsutil_test.go index 1815f9be..a4fb6f39 100644 --- a/pkg/util/fsutil/fsutil_test.go +++ b/pkg/util/fsutil/fsutil_test.go @@ -27,8 +27,10 @@ func TestCopyDirExcludesWholeDirectoryWhenPatternHasDoubleStar(t *testing.T) { } pattern := filepath.Join(excludedDir, "**") - if err, _ := CopyDir(false, src, dst, true, true, []string{pattern}, nil, nil); err != nil { + if err, errs := CopyDir(false, src, dst, true, true, []string{pattern}, nil, nil); err != nil { t.Fatalf("CopyDir returned error: %v", err) + } else if len(errs) > 0 { + t.Fatalf("CopyDir returned copy errors: %v", errs) } excludedTarget := filepath.Join(dst, "var", "lib", "postgresql", "data") From 5e85d0584d08fb7214cad488b8b52ee928d7db94 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:35:38 +0000 Subject: [PATCH 4/8] Extract recursive exclude suffix constant Co-authored-by: kcq <1099414+kcq@users.noreply.github.com> --- pkg/util/fsutil/fsutil.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/util/fsutil/fsutil.go b/pkg/util/fsutil/fsutil.go index 90ce6ccf..c7a580ac 100644 --- a/pkg/util/fsutil/fsutil.go +++ b/pkg/util/fsutil/fsutil.go @@ -805,6 +805,7 @@ func copyFileObjectHandler( excludePatterns []string, ignoreDirNames, ignoreFileNames map[string]struct{}, errs *[]error) filepath.WalkFunc { var foCount uint64 + const recursivePatternSuffix = "/**" return func(path string, info os.FileInfo, err error) error { foCount++ @@ -830,7 +831,7 @@ func copyFileObjectHandler( continue } - if !matched && strings.HasSuffix(xpattern, "/**") && strings.TrimSuffix(xpattern, "/**") == path { + if !matched && strings.HasSuffix(xpattern, recursivePatternSuffix) && strings.TrimSuffix(xpattern, recursivePatternSuffix) == path { matched = true } From 9701c80313bf4a199929ecbd7e46e91a68a8f5e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:36:49 +0000 Subject: [PATCH 5/8] Improve exclude pattern readability Co-authored-by: kcq <1099414+kcq@users.noreply.github.com> --- pkg/util/fsutil/fsutil.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/util/fsutil/fsutil.go b/pkg/util/fsutil/fsutil.go index c7a580ac..9a213d28 100644 --- a/pkg/util/fsutil/fsutil.go +++ b/pkg/util/fsutil/fsutil.go @@ -831,7 +831,10 @@ func copyFileObjectHandler( continue } - if !matched && strings.HasSuffix(xpattern, recursivePatternSuffix) && strings.TrimSuffix(xpattern, recursivePatternSuffix) == path { + shouldIgnoreRecursivePattern := strings.HasSuffix(xpattern, recursivePatternSuffix) && + strings.TrimSuffix(xpattern, recursivePatternSuffix) == path + + if !matched && shouldIgnoreRecursivePattern { matched = true } From c3c5af5cc051e100070344fea4f55c9ce3f7b378 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:37:49 +0000 Subject: [PATCH 6/8] Simplify exclude pattern matching logic Co-authored-by: kcq <1099414+kcq@users.noreply.github.com> --- pkg/util/fsutil/fsutil.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/util/fsutil/fsutil.go b/pkg/util/fsutil/fsutil.go index 9a213d28..3d5ea758 100644 --- a/pkg/util/fsutil/fsutil.go +++ b/pkg/util/fsutil/fsutil.go @@ -834,9 +834,7 @@ func copyFileObjectHandler( shouldIgnoreRecursivePattern := strings.HasSuffix(xpattern, recursivePatternSuffix) && strings.TrimSuffix(xpattern, recursivePatternSuffix) == path - if !matched && shouldIgnoreRecursivePattern { - matched = true - } + matched = matched || shouldIgnoreRecursivePattern if matched { isIgnored = true From bd31561074287c78c1c908ca01781af4fd68c412 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:38:54 +0000 Subject: [PATCH 7/8] Trim recursive pattern once when matching Co-authored-by: kcq <1099414+kcq@users.noreply.github.com> --- pkg/util/fsutil/fsutil.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/util/fsutil/fsutil.go b/pkg/util/fsutil/fsutil.go index 3d5ea758..3bb85a6a 100644 --- a/pkg/util/fsutil/fsutil.go +++ b/pkg/util/fsutil/fsutil.go @@ -831,10 +831,10 @@ func copyFileObjectHandler( continue } - shouldIgnoreRecursivePattern := strings.HasSuffix(xpattern, recursivePatternSuffix) && - strings.TrimSuffix(xpattern, recursivePatternSuffix) == path - - matched = matched || shouldIgnoreRecursivePattern + if !matched && strings.HasSuffix(xpattern, recursivePatternSuffix) { + trimmedPattern := strings.TrimSuffix(xpattern, recursivePatternSuffix) + matched = trimmedPattern == path + } if matched { isIgnored = true From d56637a5dd20f398f3370431b411f426c483fbea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:40:09 +0000 Subject: [PATCH 8/8] Clean recursive pattern comparison Co-authored-by: kcq <1099414+kcq@users.noreply.github.com> --- pkg/util/fsutil/fsutil.go | 4 ++-- pkg/util/fsutil/fsutil_test.go | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/util/fsutil/fsutil.go b/pkg/util/fsutil/fsutil.go index 3bb85a6a..07242b80 100644 --- a/pkg/util/fsutil/fsutil.go +++ b/pkg/util/fsutil/fsutil.go @@ -832,8 +832,8 @@ func copyFileObjectHandler( } if !matched && strings.HasSuffix(xpattern, recursivePatternSuffix) { - trimmedPattern := strings.TrimSuffix(xpattern, recursivePatternSuffix) - matched = trimmedPattern == path + trimmedPattern := filepath.Clean(strings.TrimSuffix(xpattern, recursivePatternSuffix)) + matched = trimmedPattern == filepath.Clean(path) } if matched { diff --git a/pkg/util/fsutil/fsutil_test.go b/pkg/util/fsutil/fsutil_test.go index a4fb6f39..95d7d86b 100644 --- a/pkg/util/fsutil/fsutil_test.go +++ b/pkg/util/fsutil/fsutil_test.go @@ -26,8 +26,12 @@ func TestCopyDirExcludesWholeDirectoryWhenPatternHasDoubleStar(t *testing.T) { t.Fatalf("failed to create keep file: %v", err) } - pattern := filepath.Join(excludedDir, "**") - if err, errs := CopyDir(false, src, dst, true, true, []string{pattern}, nil, nil); err != nil { + pattern := excludedDir + "/**" + clone := false + copyRelPath := true + skipErrors := true + + if err, errs := CopyDir(clone, src, dst, copyRelPath, skipErrors, []string{pattern}, nil, nil); err != nil { t.Fatalf("CopyDir returned error: %v", err) } else if len(errs) > 0 { t.Fatalf("CopyDir returned copy errors: %v", errs)