Skip to content

Commit

Permalink
go-aah/aah#156 vfs progress
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm committed May 8, 2018
1 parent 40aa319 commit f1d7dd1
Show file tree
Hide file tree
Showing 7 changed files with 699 additions and 1 deletion.
86 changes: 86 additions & 0 deletions file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) Jeevanandam M. (https://github.com/jeevatkm)
// aahframework.org/vfs source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package vfs

import (
"errors"
"fmt"
"io"
"os"
)

var _ File = (*file)(nil)
var _ Gziper = (*file)(nil)

// File struct represents the virtual file or directory.
//
// Implements interface `vfs.File`.
type file struct {
*node
rs io.ReadSeeker
pos int
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// File and Directory operations
//______________________________________________________________________________

func (f *file) Read(b []byte) (int, error) {
return f.rs.Read(b)
}

func (f *file) Seek(offset int64, whence int) (int64, error) {
return f.rs.Seek(offset, whence)
}

func (f *file) Readdir(count int) ([]os.FileInfo, error) {
if !f.IsDir() {
return []os.FileInfo{}, &os.PathError{Op: "read", Path: f.node.name, Err: errors.New("vfs: cannot find the specified path")}
}

if f.pos >= len(f.node.childInfos) && count > 0 {
return nil, io.EOF
}

if count <= 0 || count > len(f.node.childInfos)-f.pos {
count = len(f.node.childInfos) - f.pos
}

ci := f.node.childInfos[f.pos : f.pos+count]
f.pos += count

return ci, nil
}

func (f *file) Readdirnames(count int) (names []string, err error) {
var list []string
infos, err := f.Readdir(count)
if err != nil {
return list, err
}

for _, v := range infos {
list = append(list, v.Name())
}

return list, nil
}

func (f *file) Stat() (os.FileInfo, error) {
return f, nil
}

func (f *file) Close() error {
if f.IsGzip() {
return f.rs.(io.Closer).Close()
}
return nil
}

// String method Stringer interface.
func (f file) String() string {
return fmt.Sprintf(`file(name=%s dir=%v gzip=%v)`,
f.node.name, f.IsDir(), f.IsGzip())
}
141 changes: 141 additions & 0 deletions fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright (c) Jeevanandam M. (https://github.com/jeevatkm)
// aahframework.org/vfs source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package vfs

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

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

// ErrNotExists = errors.New("file or directory does not exist")
)

// VFS represents Virtual File System (VFS), it operates in-memory.
// if file/directory doesn't exists on in-memory then it tries physical file system.
//
// VFS implements `vfs.FileSystem`, its a combination of package `os` and `ioutil`
// focused on Read-Only operations.
//
// Single point of access for all mounted virtual directories in aah application.
type VFS struct {
mounts map[string]*Mount
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// VFS FileSystem interface methods
//______________________________________________________________________________

// Open method behaviour is same as `os.Open`.
func (v *VFS) Open(name string) (File, error) {
m, err := v.FindMount(name)
if err != nil {
return nil, err
}
return m.Open(name)
}

// Lstat method behaviour is same as `os.Lstat`.
func (v *VFS) Lstat(name string) (os.FileInfo, error) {
m, err := v.FindMount(name)
if err != nil {
return nil, err
}
return m.Lstat(name)
}

// Stat method behaviour is same as `os.Stat`
func (v *VFS) Stat(name string) (os.FileInfo, error) {
m, err := v.FindMount(name)
if err != nil {
return nil, err
}
return m.Stat(name)
}

// ReadFile method behaviour is same as `ioutil.ReadFile`.
func (v *VFS) ReadFile(filename string) ([]byte, error) {
m, err := v.FindMount(filename)
if err != nil {
return nil, err
}
return m.ReadFile(filename)
}

// ReadDir method behaviour is same as `ioutil.ReadDir`.
func (v *VFS) ReadDir(dirname string) ([]os.FileInfo, error) {
m, err := v.FindMount(dirname)
if err != nil {
return nil, err
}
return m.ReadDir(dirname)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// VFS methods
//______________________________________________________________________________

// FindMount method finds the mounted virtual directory by mount path.
// if found then returns `Mount` instance otherwise nil and error.
//
// Mount implements `vfs.FileSystem`, its a combination of package `os` and `ioutil`
// focused on Read-Only operations.
func (v *VFS) FindMount(name string) (*Mount, error) {
name = path.Clean(name)
for _, m := range v.mounts {
if m.vroot == name || strings.HasPrefix(name, m.tree.name+"/") {
return m, nil
}
}
return nil, &os.PathError{Op: "read", Path: name, Err: fmt.Errorf("mount not exist")}
}

// AddMount method used to mount physical directory as a virtual mounted directory.
//
// Basically aah scans and application source files and builds each file from
// mounted source dierctory into binary for single binary build.
func (v *VFS) AddMount(mountPath, physicalPath string) error {
pp, err := filepath.Abs(filepath.Clean(physicalPath))
if err != nil {
return err
}

fi, err := os.Lstat(pp)
if err != nil {
return err
}

if !fi.IsDir() {
return &os.PathError{Op: "addmount", Path: pp, Err: errors.New("is a file")}
}

mp := filepath.ToSlash(path.Clean(mountPath))
if mp == "" {
mp = path.Base(pp)
}
mp = path.Clean("/" + mp)

if v.mounts == nil {
v.mounts = make(map[string]*Mount)
}

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

v.mounts[mp] = &Mount{
vroot: mp,
proot: pp,
tree: newNode(mp, fi),
}

return nil
}
Loading

0 comments on commit f1d7dd1

Please sign in to comment.