Skip to content

Commit

Permalink
go-aah/aah#156 added Walk method, godoc update
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm committed May 9, 2018
1 parent f1d7dd1 commit 2a1f540
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 37 deletions.
28 changes: 22 additions & 6 deletions fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ package vfs

import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"strings"
)

var (
_ FileSystem = (*VFS)(nil)
var _ FileSystem = (*VFS)(nil)

// ErrNotExists = errors.New("file or directory does not exist")
// VFS errors
var (
ErrMountExists = errors.New("mount already exists")
ErrMountNotExists = errors.New("mount does not exist")
)

// VFS represents Virtual File System (VFS), it operates in-memory.
Expand Down Expand Up @@ -83,6 +84,21 @@ func (v *VFS) ReadDir(dirname string) ([]os.FileInfo, error) {
// VFS methods
//______________________________________________________________________________

// Walk method behaviour is same as `filepath.Walk`.
func (v *VFS) Walk(root string, walkFn filepath.WalkFunc) error {
info, err := v.Lstat(root)
if err == nil {
err = walk(v, root, info, walkFn)
} else {
err = walkFn(root, nil, err)
}

if err == filepath.SkipDir {
return nil
}
return err
}

// FindMount method finds the mounted virtual directory by mount path.
// if found then returns `Mount` instance otherwise nil and error.
//
Expand All @@ -95,7 +111,7 @@ func (v *VFS) FindMount(name string) (*Mount, error) {
return m, nil
}
}
return nil, &os.PathError{Op: "read", Path: name, Err: fmt.Errorf("mount not exist")}
return nil, &os.PathError{Op: "read", Path: name, Err: ErrMountNotExists}
}

// AddMount method used to mount physical directory as a virtual mounted directory.
Expand Down Expand Up @@ -128,7 +144,7 @@ func (v *VFS) AddMount(mountPath, physicalPath string) error {
}

if _, found := v.mounts[mp]; found {
return &os.PathError{Op: "addmount", Path: mp, Err: errors.New("already exists")}
return &os.PathError{Op: "addmount", Path: mp, Err: ErrMountExists}
}

v.mounts[mp] = &Mount{
Expand Down
41 changes: 21 additions & 20 deletions mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,30 +118,12 @@ func (m *Mount) Name() string {

// AddDir method is to add directory node into VFS from mounted source directory.
func (m *Mount) AddDir(mountPath string, fi os.FileInfo) error {
n, err := m.tree.findNode(m.cleanDir(mountPath))
switch {
case err != nil:
return err
case n == nil:
return nil
}

n.addChild(newNode(mountPath, fi))
return nil
return m.addNode(mountPath, fi, nil)
}

// AddFile method is to add file node into VFS from mounted source directory.
func (m *Mount) AddFile(mountPath string, fi os.FileInfo, data []byte) error {
n, err := m.tree.findNode(m.cleanDir(mountPath))
if err != nil {
return err
}

f := newNode(mountPath, fi)
f.data = data
n.addChild(f)

return nil
return m.addNode(mountPath, fi, data)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Expand Down Expand Up @@ -177,3 +159,22 @@ func (m Mount) openPhysical(name string) (File, error) {
func (m Mount) namePhysical(name string) string {
return filepath.Clean(filepath.FromSlash(filepath.Join(m.proot, name[len(m.vroot):])))
}

func (m *Mount) addNode(mountPath string, fi os.FileInfo, data []byte) error {
t, err := m.tree.findNode(m.cleanDir(mountPath))
switch {
case err != nil:
return err
case t == nil:
return nil
}

n := newNode(mountPath, fi)
if data != nil {
n.data = data
}
t.addChild(n)

return nil

}
10 changes: 0 additions & 10 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,6 @@ type gzipData struct {
spos int64
}

// aah vfs exposes transparent interaction for caller regardless of data bytes
// be it regular or gzip.
//
// Imitating `Read` same as `os.File.Read` for Gzip data; logic is from
// https://github.com/shurcooL/vfsgen
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 @@ -181,11 +176,6 @@ func (g *gzipData) Read(b []byte) (int, error) {
return size, err
}

// aah vfs exposes transparent interaction for caller regardless of data bytes
// be it regular or gzip.
//
// Imitating `Seek` same as `os.File.Seek` for Gzip data; logic is from
// https://github.com/shurcooL/vfsgen
func (g *gzipData) Seek(offset int64, whence int) (int64, error) {
switch whence {
case io.SeekStart:
Expand Down
61 changes: 60 additions & 1 deletion util.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (
"compress/gzip"
"fmt"
"os"
"path"
"path/filepath"
"sort"
"unicode/utf8"
)

Expand Down Expand Up @@ -59,8 +62,64 @@ func newFile(n *node) *file {
return f
}

// https://github.com/golang/tools/blob/master/godoc/static/gen.go
// readDirNames reads the directory named by dirname and returns
// a sorted list of directory entries.
func readDirNames(fs FileSystem, dirname string) ([]string, error) {
f, err := fs.Open(dirname)
if err != nil {
return nil, err
}
defer f.Close()

names, err := f.Readdirnames(-1)
if err != nil {
return nil, err
}

sort.Strings(names)
return names, nil
}

// walk recursively descends path.
func walk(fs FileSystem, fpath string, info os.FileInfo, walkFn filepath.WalkFunc) error {
err := walkFn(fpath, info, nil)
if err != nil {
if info.IsDir() && err == filepath.SkipDir {
return nil
}
return err
}

if !info.IsDir() {
return nil
}

names, err := readDirNames(fs, fpath)
if err != nil {
return walkFn(fpath, info, err)
}

for _, name := range names {
filename := path.Join(fpath, name)
fi, err := fs.Lstat(filename)
if err != nil {
if err := walkFn(filename, fi, err); err != nil && err != filepath.SkipDir {
return err
}
} else {
err = walk(fs, filename, fi, walkFn)
if err != nil {
if !fi.IsDir() || err != filepath.SkipDir {
return err
}
}
}
}
return nil
}

// sanitize prepares a valid UTF-8 string as a raw string constant.
// https://github.com/golang/tools/blob/master/godoc/static/gen.go
func sanitize(b []byte) []byte {
// Replace ` with `+"`"+`
b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1)
Expand Down

0 comments on commit 2a1f540

Please sign in to comment.