@@ -8,25 +8,57 @@ import (
88)
99
1010type pattern struct {
11- pattern string
12- regex * regexp.Regexp
11+ pattern string
12+ regex * regexp.Regexp
13+ leftAnchoredLiteral bool
1314}
1415
1516// newPattern creates a new pattern struct from a gitignore-style pattern string
1617func newPattern (patternStr string ) (pattern , error ) {
17- patternRegex , err := buildPatternRegex (patternStr )
18- if err != nil {
19- return pattern {}, err
18+ pat := pattern {pattern : patternStr }
19+
20+ if ! strings .ContainsAny (patternStr , "*?\\ " ) && patternStr [0 ] == os .PathSeparator {
21+ pat .leftAnchoredLiteral = true
22+ } else {
23+ patternRegex , err := buildPatternRegex (patternStr )
24+ if err != nil {
25+ return pattern {}, err
26+ }
27+ pat .regex = patternRegex
2028 }
2129
22- return pattern {
23- pattern : patternStr ,
24- regex : patternRegex ,
25- }, nil
30+ return pat , nil
2631}
2732
2833// match tests if the path provided matches the pattern
2934func (p pattern ) match (testPath string ) (bool , error ) {
35+ if p .leftAnchoredLiteral {
36+ prefix := p .pattern
37+
38+ // Strip the leading slash as we're anchored to the root already
39+ if prefix [0 ] == os .PathSeparator {
40+ prefix = prefix [1 :]
41+ }
42+
43+ // If the pattern ends with a slash we can do a simple prefix match
44+ if prefix [len (prefix )- 1 ] == os .PathSeparator {
45+ return strings .HasPrefix (testPath , prefix ), nil
46+ }
47+
48+ // If the strings are the same length, check for an exact match
49+ if len (testPath ) == len (prefix ) {
50+ return testPath == prefix , nil
51+ }
52+
53+ // Otherwise check if the test path is a subdirectory of the pattern
54+ if len (testPath ) > len (prefix ) && testPath [len (prefix )] == os .PathSeparator {
55+ return testPath [:len (prefix )] == prefix , nil
56+ }
57+
58+ // Otherwise the test path must be shorter than the pattern, so it can't match
59+ return false , nil
60+ }
61+
3062 return p .regex .MatchString (testPath ), nil
3163}
3264
0 commit comments