@@ -84,9 +84,9 @@ func NewPatternMatcher(patterns []string) (*PatternMatcher, error) {
84
84
//
85
85
// Matches is not safe to call concurrently.
86
86
//
87
- // This implementation is buggy (it only checks a single parent dir against the
88
- // pattern) and will be removed soon. Use either MatchesOrParentMatches or
89
- // MatchesUsingParentResult instead.
87
+ // Deprecated: This implementation is buggy (it only checks a single parent dir
88
+ // against the pattern) and will be removed soon. Use either
89
+ // MatchesOrParentMatches or MatchesUsingParentResults instead.
90
90
func (pm * PatternMatcher ) Matches (file string ) (bool , error ) {
91
91
matched := false
92
92
file = filepath .FromSlash (file )
@@ -172,6 +172,11 @@ func (pm *PatternMatcher) MatchesOrParentMatches(file string) (bool, error) {
172
172
// The "file" argument should be a slash-delimited path.
173
173
//
174
174
// MatchesUsingParentResult is not safe to call concurrently.
175
+ //
176
+ // Deprecated: this function does behave correctly in some cases (see
177
+ // https://github.com/docker/buildx/issues/850).
178
+ //
179
+ // Use MatchesUsingParentResults instead.
175
180
func (pm * PatternMatcher ) MatchesUsingParentResult (file string , parentMatched bool ) (bool , error ) {
176
181
matched := parentMatched
177
182
file = filepath .FromSlash (file )
@@ -196,6 +201,78 @@ func (pm *PatternMatcher) MatchesUsingParentResult(file string, parentMatched bo
196
201
return matched , nil
197
202
}
198
203
204
+ // MatchInfo tracks information about parent dir matches while traversing a
205
+ // filesystem.
206
+ type MatchInfo struct {
207
+ parentMatched []bool
208
+ }
209
+
210
+ // MatchesUsingParentResults returns true if "file" matches any of the patterns
211
+ // and isn't excluded by any of the subsequent patterns. The functionality is
212
+ // the same as Matches, but as an optimization, the caller passes in
213
+ // intermediate results from matching the parent directory.
214
+ //
215
+ // The "file" argument should be a slash-delimited path.
216
+ //
217
+ // MatchesUsingParentResults is not safe to call concurrently.
218
+ func (pm * PatternMatcher ) MatchesUsingParentResults (file string , parentMatchInfo MatchInfo ) (bool , MatchInfo , error ) {
219
+ parentMatched := parentMatchInfo .parentMatched
220
+ if len (parentMatched ) != 0 && len (parentMatched ) != len (pm .patterns ) {
221
+ return false , MatchInfo {}, errors .New ("wrong number of values in parentMatched" )
222
+ }
223
+
224
+ file = filepath .FromSlash (file )
225
+ matched := false
226
+
227
+ matchInfo := MatchInfo {
228
+ parentMatched : make ([]bool , len (pm .patterns )),
229
+ }
230
+ for i , pattern := range pm .patterns {
231
+ match := false
232
+ // If the parent matched this pattern, we don't need to recheck.
233
+ if len (parentMatched ) != 0 {
234
+ match = parentMatched [i ]
235
+ }
236
+
237
+ if ! match {
238
+ // Skip evaluation if this is an inclusion and the filename
239
+ // already matched the pattern, or it's an exclusion and it has
240
+ // not matched the pattern yet.
241
+ if pattern .exclusion != matched {
242
+ continue
243
+ }
244
+
245
+ var err error
246
+ match , err = pattern .match (file )
247
+ if err != nil {
248
+ return false , matchInfo , err
249
+ }
250
+
251
+ // If the zero value of MatchInfo was passed in, we don't have
252
+ // any information about the parent dir's match results, and we
253
+ // apply the same logic as MatchesOrParentMatches.
254
+ if len (parentMatched ) == 0 {
255
+ if parentPath := filepath .Dir (file ); parentPath != "." {
256
+ parentPathDirs := strings .Split (parentPath , string (os .PathSeparator ))
257
+ // Check to see if the pattern matches one of our parent dirs.
258
+ for i := range parentPathDirs {
259
+ match , _ = pattern .match (strings .Join (parentPathDirs [:i + 1 ], string (os .PathSeparator )))
260
+ if match {
261
+ break
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+ matchInfo .parentMatched [i ] = match
268
+
269
+ if match {
270
+ matched = ! pattern .exclusion
271
+ }
272
+ }
273
+ return matched , matchInfo , nil
274
+ }
275
+
199
276
// Exclusions returns true if any of the patterns define exclusions
200
277
func (pm * PatternMatcher ) Exclusions () bool {
201
278
return pm .exclusions
0 commit comments