@@ -61,12 +61,56 @@ func NewPatternMatcher(patterns []string) (*PatternMatcher, error) {
6161// The "file" argument should be a slash-delimited path.
6262//
6363// Matches is not safe to call concurrently.
64+ //
65+ // This implementation is buggy (it only checks a single parent dir against the
66+ // pattern) and will be removed soon. Use either MatchesOrParentMatches or
67+ // MatchesUsingParentResult instead.
6468func (pm * PatternMatcher ) Matches (file string ) (bool , error ) {
6569 matched := false
6670 file = filepath .FromSlash (file )
6771 parentPath := filepath .Dir (file )
6872 parentPathDirs := strings .Split (parentPath , string (os .PathSeparator ))
6973
74+ for _ , pattern := range pm .patterns {
75+ // Skip evaluation if this is an inclusion and the filename
76+ // already matched the pattern, or it's an exclusion and it has
77+ // not matched the pattern yet.
78+ if pattern .exclusion != matched {
79+ continue
80+ }
81+
82+ match , err := pattern .match (file )
83+ if err != nil {
84+ return false , err
85+ }
86+
87+ if ! match && parentPath != "." {
88+ // Check to see if the pattern matches one of our parent dirs.
89+ if len (pattern .dirs ) <= len (parentPathDirs ) {
90+ match , _ = pattern .match (strings .Join (parentPathDirs [:len (pattern .dirs )], string (os .PathSeparator )))
91+ }
92+ }
93+
94+ if match {
95+ matched = ! pattern .exclusion
96+ }
97+ }
98+
99+ return matched , nil
100+ }
101+
102+ // MatchesOrParentMatches returns true if "file" matches any of the patterns
103+ // and isn't excluded by any of the subsequent patterns.
104+ //
105+ // The "file" argument should be a slash-delimited path.
106+ //
107+ // Matches is not safe to call concurrently.
108+ func (pm * PatternMatcher ) MatchesOrParentMatches (file string ) (bool , error ) {
109+ matched := false
110+ file = filepath .FromSlash (file )
111+ parentPath := filepath .Dir (file )
112+ parentPathDirs := strings .Split (parentPath , string (os .PathSeparator ))
113+
70114 for _ , pattern := range pm .patterns {
71115 // Skip evaluation if this is an inclusion and the filename
72116 // already matched the pattern, or it's an exclusion and it has
@@ -249,6 +293,9 @@ func (p *Pattern) compile() error {
249293
250294// Matches returns true if file matches any of the patterns
251295// and isn't excluded by any of the subsequent patterns.
296+ //
297+ // This implementation is buggy (it only checks a single parent dir against the
298+ // pattern) and will be removed soon. Use MatchesOrParentMatches instead.
252299func Matches (file string , patterns []string ) (bool , error ) {
253300 pm , err := NewPatternMatcher (patterns )
254301 if err != nil {
@@ -264,6 +311,23 @@ func Matches(file string, patterns []string) (bool, error) {
264311 return pm .Matches (file )
265312}
266313
314+ // MatchesOrParentMatches returns true if file matches any of the patterns
315+ // and isn't excluded by any of the subsequent patterns.
316+ func MatchesOrParentMatches (file string , patterns []string ) (bool , error ) {
317+ pm , err := NewPatternMatcher (patterns )
318+ if err != nil {
319+ return false , err
320+ }
321+ file = filepath .Clean (file )
322+
323+ if file == "." {
324+ // Don't let them exclude everything, kind of silly.
325+ return false , nil
326+ }
327+
328+ return pm .MatchesOrParentMatches (file )
329+ }
330+
267331// CopyFile copies from src to dst until either EOF is reached
268332// on src or an error occurs. It verifies src exists and removes
269333// the dst if it exists.
0 commit comments