package xtfs import ( "io/fs" "os" "path" ) // XTFS is an eXTended File System type XTFS struct { fs fs.FS root string doCache bool cache map[string]bool } func (x *XTFS) apn(name string) string { return path.Join(x.root, name) } func (x *XTFS) exists(name string) bool { if has, ok := x.cache[name]; ok && x.doCache { return has } _, err := os.Stat(x.apn(name)) if err != nil { x.cache[name] = false return false } x.cache[name] = true return true } // Open opens an fs.File, preferring disk func (x *XTFS) Open(name string) (fs.File, error) { if x.exists(name) { return os.Open(x.apn(name)) } return x.fs.Open(name) } // Option is a functional option for an XTFS type Option func(*XTFS) error // New returns a new XTFS func New(root string, fs fs.FS, opts ...Option) (*XTFS, error) { x := &XTFS{ fs: fs, root: root, doCache: true, cache: make(map[string]bool), } for _, opt := range opts { if err := opt(x); err != nil { return x, err } } return x, nil } // WithSub sets a fs.Sub for an XTFS func WithSub(sub string) Option { return func(x *XTFS) (err error) { x.fs, err = fs.Sub(x.fs, sub) return } } // WithCaching sets a caching mode for an XTFS // Caching avoids subsequent os.Stat to determine if a file exists on disk // See bench.txt for differences in usage func WithCaching(doCache bool) Option { return func(x *XTFS) error { x.doCache = doCache return nil } }