sdk/iox/globfs.go

99 lines
1.9 KiB
Go
Raw Permalink Normal View History

package iox
import (
"io/fs"
"os"
"path"
)
type GlobFS struct {
base fs.FS
patterns []string
}
// NewGlobFS creates a new GlobFS that exposes only files matching any of the given glob patterns.
func NewGlobFS(base fs.FS, patterns ...string) *GlobFS {
return &GlobFS{base: base, patterns: patterns}
}
// match reports whether the given path matches any of the configured patterns.
func (g *GlobFS) match(name string) bool {
for _, pat := range g.patterns {
if matched, _ := path.Match(pat, name); matched {
return true
}
}
return false
}
func (g *GlobFS) contains(dir string) bool {
queue := []string{dir}
visited := make(map[string]struct{})
for len(queue) > 0 {
current := queue[0]
queue = queue[1:] // dequeue
// Prevent visiting same dir multiple times
if _, seen := visited[current]; seen {
continue
}
visited[current] = struct{}{}
entries, err := fs.ReadDir(g.base, current)
if err != nil {
continue
}
for _, entry := range entries {
rel := path.Join(current, entry.Name())
if g.match(rel) {
return true
}
if entry.IsDir() {
queue = append(queue, rel)
}
}
}
return false
}
func (g *GlobFS) Open(name string) (fs.File, error) {
if g.match(name) {
return g.base.Open(name)
}
fi, err := fs.Stat(g.base, name)
if err != nil || !fi.IsDir() {
return nil, fs.ErrNotExist
}
if g.contains(name) {
return g.base.Open(name)
}
return nil, fs.ErrNotExist
}
func (g *GlobFS) ReadDir(name string) ([]fs.DirEntry, error) {
if g.match(name) {
return fs.ReadDir(g.base, name)
}
entries, err := fs.ReadDir(g.base, name)
if err != nil {
return nil, err
}
var children []fs.DirEntry
for _, entry := range entries {
rel := path.Join(name, entry.Name())
if g.match(rel) {
children = append(children, entry)
}
if entry.IsDir() && g.contains(rel) {
children = append(children, entry)
}
}
if len(children) == 0 {
return nil, os.ErrNotExist
}
return children, nil
}