Skip to content

Commit afdb4f9

Browse files
committed
[STEP-2135] Allow non-existent paths in compat FilterPaths
v1 pathutil.FilterPaths did not touch the filesystem, so callers could filter synthetic or relative paths that do not exist on disk. The v2 compat adapter was stat-ing every path up-front, which surfaced a not-exist error and broke drop-in migration for call sites that feed lexical inputs (e.g. steps-cocoapods-install main_test.go). Stat opportunistically instead: if the path does not exist, fall through with a nil DirEntry. Purely path-based filters (Base, Extension, Regexp, Component, ComponentWithExtension, InDirectory) keep working unchanged; filters that consult the DirEntry (IsDirectory, DirectoryContainsFile, FileContains) still error when the DirEntry is needed but unavailable. Stat errors other than ErrNotExist continue to surface. Tests split: one covering the v1-parity lexical case, one asserting the DirEntry-needing filter still errors on a missing path.
1 parent fd3b781 commit afdb4f9

2 files changed

Lines changed: 26 additions & 5 deletions

File tree

pathutil/path_filter_compat.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,27 @@ import (
99

1010
// FilterPaths applies filters to an explicit list of OS paths and returns
1111
// the ones that pass every filter, preserving input order. Each path is
12-
// stat-ed to build an fs.DirEntry for the filter callbacks; a missing path
13-
// surfaces the stat error.
12+
// stat-ed opportunistically so filters that consult fs.DirEntry (e.g.
13+
// IsDirectoryFilter) work; paths that do not exist on disk are still fed
14+
// to the filters with a nil DirEntry, matching v1's purely lexical
15+
// behavior for path-only filters. Stat errors other than "not exist"
16+
// surface to the caller.
1417
//
1518
// This adapter preserves the v1 go-utils pathutil.FilterPaths signature so
1619
// callers can migrate by import-path rename only. Prefer FilterFS in new code.
1720
func FilterPaths(paths []string, filters ...FilterFunc) ([]string, error) {
1821
var filtered []string
1922
for _, pth := range paths {
23+
var d fs.DirEntry
2024
info, err := os.Lstat(pth)
21-
if err != nil {
25+
switch {
26+
case err == nil:
27+
d = fs.FileInfoToDirEntry(info)
28+
case errors.Is(err, fs.ErrNotExist):
29+
// Leave d nil; path-only filters still work.
30+
default:
2231
return nil, err
2332
}
24-
d := fs.FileInfoToDirEntry(info)
2533

2634
keep, err := runFilters(pth, d, filters)
2735
if err != nil {

pathutil/path_filter_compat_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,20 @@ func TestFilterPaths(t *testing.T) {
4646
}, got)
4747
}
4848

49-
func TestFilterPaths_missingPathErrors(t *testing.T) {
49+
func TestFilterPaths_missingPath_pathOnlyFilters(t *testing.T) {
50+
// v1 parity: purely lexical filters work against paths that do not
51+
// exist on disk. IsDirectoryFilter is not used here so no stat is needed.
52+
got, err := FilterPaths(
53+
[]string{"./Podfile", "/nowhere/Podfile.lock"},
54+
BaseFilter("Podfile", true),
55+
)
56+
require.NoError(t, err)
57+
require.Equal(t, []string{"./Podfile"}, got)
58+
}
59+
60+
func TestFilterPaths_missingPath_dirEntryFilterErrors(t *testing.T) {
61+
// Filters that consult the DirEntry (IsDirectoryFilter) still error on
62+
// missing paths because there is nothing to inspect.
5063
_, err := FilterPaths([]string{"/does/not/exist/ever"}, IsDirectoryFilter(false))
5164
require.Error(t, err)
5265
}

0 commit comments

Comments
 (0)