github.com/posener/gitfs@v1.2.2-0.20200410105819-ea4e48d73ab9/internal/glob/glob.go (about) 1 package glob 2 3 import ( 4 "path/filepath" 5 "strings" 6 7 "github.com/pkg/errors" 8 ) 9 10 // Patterns can glob-match files or directories. 11 type Patterns []string 12 13 // New returns a new glob pattern. It returns an error if any of the 14 // patterns is invalid. 15 func New(patterns ...string) (Patterns, error) { 16 if err := checkPatterns(patterns); err != nil { 17 return nil, err 18 } 19 return Patterns(patterns), nil 20 } 21 22 // Match a path to the defined patterns. If it is a file a full match 23 // is required. If it is a directory, only matching a prefix of any of 24 // the patterns is required. 25 func (p Patterns) Match(path string, isDir bool) bool { 26 if len(p) == 0 { 27 return true 28 } 29 path = filepath.Clean(path) 30 return (isDir && p.matchPrefix(path)) || (!isDir && p.matchFull(path)) 31 } 32 33 // matchFull finds a matching of the whole name to any of the patterns. 34 func (p Patterns) matchFull(name string) bool { 35 for _, pattern := range p { 36 if ok, _ := filepath.Match(pattern, name); ok { 37 return true 38 } 39 } 40 return false 41 } 42 43 // matchPrefix finds a matching of prefix to a prefix of any of the patterns. 44 func (p Patterns) matchPrefix(prefix string) bool { 45 parts := strings.Split(prefix, string(filepath.Separator)) 46 nextPattern: 47 for _, pattern := range p { 48 patternParts := strings.Split(pattern, string(filepath.Separator)) 49 if len(patternParts) < len(parts) { 50 continue 51 } 52 for i := 0; i < len(parts); i++ { 53 if ok, _ := filepath.Match(patternParts[i], parts[i]); !ok { 54 continue nextPattern 55 } 56 } 57 return true 58 } 59 return false 60 } 61 62 // checkPattens checks the validity of the patterns. 63 func checkPatterns(patterns []string) error { 64 var badPatterns []string 65 for _, pattern := range patterns { 66 _, err := filepath.Match(pattern, "x") 67 if err != nil { 68 badPatterns = append(badPatterns, pattern) 69 return errors.Wrap(err, pattern) 70 } 71 } 72 if len(badPatterns) > 0 { 73 return errors.Wrap(filepath.ErrBadPattern, strings.Join(badPatterns, ", ")) 74 } 75 return nil 76 }