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  }