github.com/IBM/fsgo@v0.0.0-20220920202152-e16fd2119d49/match.go (about) 1 // Copyright 2022 IBM Inc. All rights reserved 2 // Copyright © 2014 Steve Francia <spf@spf13.com> 3 // 4 // SPDX-License-Identifier: Apache2.0 5 package fsgo 6 7 import ( 8 "path/filepath" 9 "sort" 10 "strings" 11 ) 12 13 // Glob returns the names of all files matching pattern or nil 14 // if there is no matching file. The syntax of patterns is the same 15 // as in Match. The pattern may describe hierarchical names such as 16 // /usr/*/bin/ed (assuming the Separator is '/'). 17 // 18 // Glob ignores file system errors such as I/O errors reading directories. 19 // The only possible returned error is ErrBadPattern, when pattern 20 // is malformed. 21 // 22 // This was adapted from (http://golang.org/pkg/path/filepath) and uses several 23 // built-ins from that package. 24 func Glob(fs Fs, pattern string) (matches []string, err error) { 25 if !hasMeta(pattern) { 26 // Lstat not supported by a ll filesystems. 27 if _, err = lstatIfPossible(fs, pattern); err != nil { 28 return nil, nil 29 } 30 return []string{pattern}, nil 31 } 32 33 dir, file := filepath.Split(pattern) 34 switch dir { 35 case "": 36 dir = "." 37 case string(filepath.Separator): 38 // nothing 39 default: 40 dir = dir[0 : len(dir)-1] // chop off trailing separator 41 } 42 43 if !hasMeta(dir) { 44 return glob(fs, dir, file, nil) 45 } 46 47 var m []string 48 m, err = Glob(fs, dir) 49 if err != nil { 50 return 51 } 52 for _, d := range m { 53 matches, err = glob(fs, d, file, matches) 54 if err != nil { 55 return 56 } 57 } 58 return 59 } 60 61 // glob searches for files matching pattern in the directory dir 62 // and appends them to matches. If the directory cannot be 63 // opened, it returns the existing matches. New matches are 64 // added in lexicographical order. 65 func glob(fs Fs, dir, pattern string, matches []string) (m []string, e error) { 66 m = matches 67 fi, err := fs.Stat(dir) 68 if err != nil { 69 return 70 } 71 if !fi.IsDir() { 72 return 73 } 74 d, err := fs.Open(dir) 75 if err != nil { 76 return 77 } 78 defer d.Close() 79 80 names, _ := d.Readdirnames(-1) 81 sort.Strings(names) 82 83 for _, n := range names { 84 matched, err := filepath.Match(pattern, n) 85 if err != nil { 86 return m, err 87 } 88 if matched { 89 m = append(m, filepath.Join(dir, n)) 90 } 91 } 92 return 93 } 94 95 // hasMeta reports whether path contains any of the magic characters 96 // recognized by Match. 97 func hasMeta(path string) bool { 98 // TODO(niemeyer): Should other magic characters be added here? 99 return strings.ContainsAny(path, "*?[") 100 }