github.com/posener/gitfs@v1.2.2-0.20200410105819-ea4e48d73ab9/fsutil/glob.go (about) 1 package fsutil 2 3 import ( 4 "net/http" 5 "os" 6 "path/filepath" 7 8 globutil "github.com/posener/gitfs/internal/glob" 9 ) 10 11 // Glob return a filesystem that contain only files that match any of the provided 12 // patterns. If no patterns are provided, the original filesystem will be returned. 13 // An error will be returned if one of the patterns is invalid. 14 func Glob(fs http.FileSystem, patterns ...string) (http.FileSystem, error) { 15 if len(patterns) == 0 { 16 return fs, nil 17 } 18 p, err := globutil.New(patterns...) 19 if err != nil { 20 return nil, err 21 } 22 return &glob{FileSystem: fs, patterns: p}, nil 23 } 24 25 // glob is an object that play the role of an http.FileSystem and an http.File. 26 // it wraps an existing underlying http.FileSystem, but applies glob pattern 27 // matching on its files. 28 type glob struct { 29 http.FileSystem 30 http.File 31 root string 32 patterns globutil.Patterns 33 } 34 35 // Open a file, relative to root. If the file exists in the filesystem 36 // but does not match any of the patterns an os.ErrNotExist will be 37 // returned. If name is a directory, but it does not match the prefix 38 // of any of the patterns, and os.ErrNotExist will be returned. 39 func (g *glob) Open(name string) (http.File, error) { 40 path := filepath.Join(g.root, name) 41 f, err := g.FileSystem.Open(path) 42 if err != nil { 43 return nil, err 44 } 45 info, err := f.Stat() 46 if err != nil { 47 return nil, err 48 } 49 50 // Regular file, match name. 51 if !g.patterns.Match(path, info.IsDir()) { 52 return nil, os.ErrNotExist 53 } 54 return &glob{ 55 FileSystem: g.FileSystem, 56 File: f, 57 root: path, 58 patterns: g.patterns, 59 }, nil 60 } 61 62 // Readdir returns a list of files that match the patterns. 63 func (g *glob) Readdir(count int) ([]os.FileInfo, error) { 64 files, err := g.File.Readdir(count) 65 if err != nil { 66 return nil, err 67 } 68 ret := make([]os.FileInfo, 0, len(files)) 69 for _, file := range files { 70 path := filepath.Join(g.root, file.Name()) 71 if g.patterns.Match(path, file.IsDir()) { 72 ret = append(ret, file) 73 } 74 } 75 return ret, nil 76 }