Skip to content

Commit e97e740

Browse files
committed
Support patterns starting with ** in ignore files
Fixes: podman-container-tools/buildah#6417 Signed-off-by: Šimon Brauner <sbrauner@redhat.com>
1 parent 498ccd1 commit e97e740

2 files changed

Lines changed: 41 additions & 6 deletions

File tree

storage/pkg/fileutils/fileutils.go

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,18 @@ func (pm *PatternMatcher) Patterns() []*Pattern {
164164
return pm.patterns
165165
}
166166

167-
// Pattern defines a single regexp used to filter file paths.
167+
type matchType int
168+
169+
const (
170+
unknownMatch matchType = iota
171+
regexpMatch
172+
suffixMatch
173+
)
174+
175+
// Pattern defines a single pattern used to filter file paths.
168176
type Pattern struct {
169177
cleanedPattern string
178+
matchType matchType
170179
regexp *regexp.Regexp
171180
exclusion bool
172181
}
@@ -181,18 +190,26 @@ func (p *Pattern) Exclusion() bool {
181190
}
182191

183192
func (p *Pattern) match(path string) (bool, error) {
184-
if p.regexp == nil {
193+
if p.matchType == unknownMatch {
185194
if err := p.compile(); err != nil {
186195
return false, filepath.ErrBadPattern
187196
}
188197
}
189198

190-
b := p.regexp.MatchString(path)
191-
192-
return b, nil
199+
switch p.matchType {
200+
case regexpMatch:
201+
return p.regexp.MatchString(path), nil
202+
case suffixMatch:
203+
suffix := p.cleanedPattern[2:]
204+
return strings.HasSuffix(path, suffix), nil
205+
default:
206+
return false, fmt.Errorf("unknown match type: %d", p.matchType)
207+
}
193208
}
194209

195210
func (p *Pattern) compile() error {
211+
p.matchType = regexpMatch
212+
196213
var regStrBuilder strings.Builder
197214
regStrBuilder.WriteString("^")
198215

@@ -209,17 +226,21 @@ func (p *Pattern) compile() error {
209226
escSL += bs
210227
}
211228

212-
for scan.Peek() != scanner.EOF {
229+
for i := 0; scan.Peek() != scanner.EOF; i++ {
213230
ch := scan.Next()
214231

215232
if ch == '*' {
233+
p.matchType = regexpMatch
234+
216235
if scan.Peek() == '*' {
217236
// is some flavor of "**"
218237
scan.Next()
219238

239+
slashEaten := false
220240
// Treat **/ as ** so eat the "/"
221241
if string(scan.Peek()) == sl {
222242
scan.Next()
243+
slashEaten = true
223244
}
224245

225246
if scan.Peek() == scanner.EOF {
@@ -233,13 +254,19 @@ func (p *Pattern) compile() error {
233254
regStrBuilder.WriteString(escSL)
234255
regStrBuilder.WriteString(")?")
235256
}
257+
258+
if i == 0 && !slashEaten {
259+
p.matchType = suffixMatch
260+
}
236261
} else {
237262
// is "*" so map it to anything but "/"
238263
regStrBuilder.WriteString("[^")
239264
regStrBuilder.WriteString(escSL)
240265
regStrBuilder.WriteString("]*")
241266
}
242267
} else if ch == '?' {
268+
p.matchType = regexpMatch
269+
243270
// "?" is any char except "/"
244271
regStrBuilder.WriteString("[^")
245272
regStrBuilder.WriteString(escSL)
@@ -259,12 +286,18 @@ func (p *Pattern) compile() error {
259286
continue
260287
}
261288
if scan.Peek() != scanner.EOF {
289+
p.matchType = regexpMatch
290+
262291
regStrBuilder.WriteString(bs)
263292
regStrBuilder.WriteRune(scan.Next())
264293
} else {
265294
return filepath.ErrBadPattern
266295
}
267296
} else {
297+
if ch == '[' || ch == ']' {
298+
p.matchType = regexpMatch
299+
}
300+
268301
regStrBuilder.WriteRune(ch)
269302
}
270303
}

storage/pkg/fileutils/fileutils_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ func TestMatches(t *testing.T) {
356356
{"abc/**", "abc/def/ghi", false, true},
357357
{"**/.foo", ".foo", false, true},
358358
{"**/.foo", "bar.foo", false, false},
359+
{"**.md", "README.md", false, true},
360+
{"**.md", "foo/README.md", false, true},
359361
}
360362

361363
if runtime.GOOS != windows {

0 commit comments

Comments
 (0)