Skip to content

Commit

Permalink
go-aah/aah#156 helper methods added easy access on vfs
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm committed May 12, 2018
1 parent f9b0085 commit bbad512
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 6 deletions.
44 changes: 43 additions & 1 deletion fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ func (v *VFS) ReadDir(dirname string) ([]os.FileInfo, error) {
return m.ReadDir(dirname)
}

// Glob method somewhat similar to `filepath.Glob`, since aah vfs does pattern
// match only on `filepath.Base` value.
func (v *VFS) Glob(pattern string) ([]string, error) {
m, err := v.FindMount(pattern)
if err != nil {
return nil, err
}
return m.Glob(pattern)
}

// IsExists method is helper to find existence.
func (v *VFS) IsExists(name string) bool {
_, err := v.Lstat(name)
return err == nil
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// VFS methods
//______________________________________________________________________________
Expand All @@ -94,7 +110,9 @@ func (v *VFS) Walk(root string, walkFn filepath.WalkFunc) error {
if len(m.tree.childs) == 0 {
// virutal is empty, move on with physical filesystem
proot := filepath.Join(m.proot, strings.TrimPrefix(root, m.vroot))
return filepath.Walk(proot, walkFn)
return filepath.Walk(proot, func(fpath string, fi os.FileInfo, err error) error {
return walkFn(m.toVirtualPath(fpath), fi, err)
})
}

info, err := m.Lstat(root)
Expand All @@ -110,6 +128,30 @@ func (v *VFS) Walk(root string, walkFn filepath.WalkFunc) error {
return err
}

// Dirs method returns directories path recursively for given root path.
func (v *VFS) Dirs(root string) ([]string, error) {
var dirs []string
err := v.Walk(root, func(fpath string, fi os.FileInfo, err error) error {
if fi.IsDir() {
dirs = append(dirs, fpath)
}
return nil
})
return dirs, err
}

// File method returns directories path recursively for given root path.
func (v *VFS) Files(root string) ([]string, error) {
var files []string
err := v.Walk(root, func(fpath string, fi os.FileInfo, err error) error {
if !fi.IsDir() {
files = append(files, fpath)
}
return nil
})
return files, err
}

// FindMount method finds the mounted virtual directory by mount path.
// if found then returns `Mount` instance otherwise nil and error.
//
Expand Down
50 changes: 45 additions & 5 deletions mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (m Mount) Open(name string) (File, error) {
func (m Mount) Lstat(name string) (os.FileInfo, error) {
f, err := m.open(name)
if os.IsNotExist(err) {
return os.Lstat(m.namePhysical(name))
return os.Lstat(m.toPhysicalPath(name))
}
return f, err
}
Expand All @@ -53,7 +53,7 @@ func (m Mount) Lstat(name string) (os.FileInfo, error) {
func (m Mount) Stat(name string) (os.FileInfo, error) {
f, err := m.open(name)
if os.IsNotExist(err) {
return os.Stat(m.namePhysical(name))
return os.Stat(m.toPhysicalPath(name))
}
return f, err
}
Expand Down Expand Up @@ -85,7 +85,7 @@ func (m Mount) ReadFile(name string) ([]byte, error) {
func (m Mount) ReadDir(dirname string) ([]os.FileInfo, error) {
f, err := m.open(dirname)
if os.IsNotExist(err) {
return ioutil.ReadDir(m.namePhysical(dirname))
return ioutil.ReadDir(m.toPhysicalPath(dirname))
}

if !f.IsDir() {
Expand All @@ -98,6 +98,42 @@ func (m Mount) ReadDir(dirname string) ([]os.FileInfo, error) {
return list, nil
}

// Glob method somewhat similar to `filepath.Glob`, since aah vfs does pattern
// match only on `filepath.Base` value.
func (m Mount) Glob(pattern string) ([]string, error) {
var matches []string
f, err := m.open(pattern)
if os.IsNotExist(err) {
flist, err := filepath.Glob(m.toPhysicalPath(pattern))
if err != nil {
return nil, err
}
for _, p := range flist {
matches = append(matches, m.toVirtualPath(p))
}
return matches, nil
}

base := path.Base(pattern)
for _, c := range f.childs {
match, err := filepath.Match(base, c.Name())
if err != nil {
return nil, err
}
if match {
matches = append(matches, c.Path)
}
}

return matches, nil
}

// IsExists method is helper to find existence.
func (m Mount) IsExists(name string) bool {
_, err := m.Lstat(name)
return err == nil
}

// String method Stringer interface.
func (m Mount) String() string {
return fmt.Sprintf("mount(%s => %s)", m.vroot, m.proot)
Expand Down Expand Up @@ -145,17 +181,21 @@ func (m Mount) open(name string) (*file, error) {
}

func (m Mount) openPhysical(name string) (File, error) {
pname := m.namePhysical(name)
pname := m.toPhysicalPath(name)
if _, err := os.Lstat(pname); os.IsNotExist(err) {
return nil, err
}
return os.Open(pname)
}

func (m Mount) namePhysical(name string) string {
func (m Mount) toPhysicalPath(name string) string {
return filepath.Clean(filepath.FromSlash(filepath.Join(m.proot, name[len(m.vroot):])))
}

func (m *Mount) toVirtualPath(name string) string {
return filepath.Clean(filepath.ToSlash(filepath.Join(m.vroot, name[len(m.proot):])))
}

func (m *Mount) addNode(fi os.FileInfo, data []byte) error {
mountPath := fi.(*NodeInfo).Path
t, err := m.tree.findNode(m.cleanDir(mountPath))
Expand Down
4 changes: 4 additions & 0 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ type gzipData struct {
spos int64
}

// Imitate regular read in gzip reader
// https://github.com/shurcooL/vfsgen/blob/master/generator.go
func (g *gzipData) Read(b []byte) (int, error) {
if g.rpos > g.spos { // to the beginning
if err := g.r.Reset(bytes.NewReader(g.n.data)); err != nil {
Expand All @@ -193,6 +195,8 @@ func (g *gzipData) Read(b []byte) (int, error) {
return size, err
}

// Imitate regular seek in gzip reader
// https://github.com/shurcooL/vfsgen/blob/master/generator.go
func (g *gzipData) Seek(offset int64, whence int) (int64, error) {
switch whence {
case io.SeekStart:
Expand Down
96 changes: 96 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,108 @@ package vfs
import (
"bytes"
"compress/gzip"
"io/ioutil"
"os"
"path"
"path/filepath"
"sort"
)

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Package methods for proxy to OS calls.
//______________________________________________________________________________

// Open method calls `os.Open` if fs == nil otherwise VFS.
//
// NOTE: Use VFS instance directly `aah.AppVFS().*`. This is created to prevent
// repetition code in consumimg libraries of aah.
func Open(fs *VFS, name string) (File, error) {
if fs == nil {
return os.Open(name)
}
return fs.Open(name)
}

// Lstat method calls `os.Lstat` if fs == nil otherwise VFS.
//
// NOTE: Use VFS instance directly `aah.AppVFS().*`. This is created to prevent
// repetition code in consumimg libraries of aah.
func Lstat(fs *VFS, name string) (os.FileInfo, error) {
if fs == nil {
return os.Lstat(name)
}
return fs.Lstat(name)
}

// Stat method calls `os.Stat` if fs == nil otherwise VFS.
//
// NOTE: Use VFS instance directly `aah.AppVFS().*`. This is created to prevent
// repetition code in consumimg libraries of aah.
func Stat(fs *VFS, name string) (os.FileInfo, error) {
if fs == nil {
return os.Stat(name)
}
return fs.Stat(name)
}

// ReadFile method calls `ioutil.ReadFile` if fs == nil otherwise VFS.
//
// NOTE: Use VFS instance directly `aah.AppVFS().*`. This is created to prevent
// repetition code in consumimg libraries of aah.
func ReadFile(fs *VFS, filename string) ([]byte, error) {
if fs == nil {
return ioutil.ReadFile(filename)
}
return fs.ReadFile(filename)
}

// ReadDir method calls `ioutil.ReadDir` if fs == nil otherwise VFS.
//
// NOTE: Use VFS instance directly `aah.AppVFS().*`. This is created to prevent
// repetition code in consumimg libraries of aah.
func ReadDir(fs *VFS, dirname string) ([]os.FileInfo, error) {
if fs == nil {
return ioutil.ReadDir(dirname)
}
return fs.ReadDir(dirname)
}

// Glob method calls `filepath.Glob` if fs == nil otherwise VFS.
//
// NOTE: Use VFS instance directly `aah.AppVFS().*`. This is created to prevent
// repetition code in consumimg libraries of aah.
func Glob(fs *VFS, pattern string) ([]string, error) {
if fs == nil {
return filepath.Glob(pattern)
}
return fs.Glob(pattern)
}

// IsExists method is helper to find existence.
//
// NOTE: Use VFS instance directly `aah.AppVFS().*`. This is created to prevent
// repetition code in consumimg libraries of aah.
func IsExists(fs *VFS, name string) bool {
var err error
if fs == nil {
_, err = os.Lstat(name)
} else {
_, err = fs.Lstat(name)
}
return err == nil
}

// Walk method calls `filepath.Walk` if fs == nil otherwise VFS.
//
// NOTE: Use VFS instance directly `aah.AppVFS().*`. This is created to prevent
// repetition code in consumimg libraries of aah.
func Walk(fs *VFS, root string, walkFn filepath.WalkFunc) error {
if fs == nil {
return filepath.Walk(root, walkFn)
}
return fs.Walk(root, walkFn)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Package unexported methods
//______________________________________________________________________________
Expand Down
2 changes: 2 additions & 0 deletions vfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type FileSystem interface {
Stat(name string) (os.FileInfo, error)
ReadFile(filename string) ([]byte, error)
ReadDir(dirname string) ([]os.FileInfo, error)
Glob(pattern string) ([]string, error)
IsExists(name string) bool
}

// File interface returned by a vfs.FileSystem's Open method.
Expand Down

0 comments on commit bbad512

Please sign in to comment.