Added afero proxy to ricefs.

Added mechanism to copy afero dir (temporarily) to a local directory.
This commit is contained in:
Sander Schobers 2018-08-03 08:49:46 +02:00
commit dd37d56253
3 changed files with 229 additions and 0 deletions

74
ricefs/file.go Normal file
View File

@ -0,0 +1,74 @@
package ricefs
import (
"io"
"os"
"github.com/GeertJohan/go.rice"
"github.com/spf13/afero"
)
var _ afero.File = &file{}
type file struct {
f *rice.File
info os.FileInfo
}
func (f *file) Close() error { return f.f.Close() }
func (f *file) Read(p []byte) (int, error) { return f.f.Read(p) }
func (f *file) ReadAt(p []byte, off int64) (int, error) {
_, err := f.Seek(off, io.SeekStart)
if nil != err {
return 0, err
}
return f.Read(p)
}
func (f *file) Seek(off int64, whence int) (int64, error) { return f.f.Seek(off, whence) }
func (f *file) Write(p []byte) (int, error) { return 0, ErrReadOnly }
func (f *file) WriteAt(p []byte, off int64) (int, error) { return 0, ErrReadOnly }
func (f *file) Name() string {
i, err := f.Stat()
if nil != err {
return ""
}
return i.Name()
}
func (f *file) Readdir(n int) ([]os.FileInfo, error) { return f.f.Readdir(n) }
func (f *file) Readdirnames(n int) ([]string, error) {
var dirs, err = f.Readdir(n)
if nil != err {
return nil, err
}
var names = make([]string, len(dirs))
for i, dir := range dirs {
names[i] = dir.Name()
}
return names, nil
}
func (f *file) Stat() (os.FileInfo, error) {
if nil == f.info {
i, err := f.f.Stat()
if nil != err {
return nil, err
}
f.info = i
}
return f.info, nil
}
func (f *file) Sync() error { return ErrReadOnly }
func (f *file) Truncate(size int64) error { return ErrReadOnly }
func (f *file) WriteString(s string) (int, error) { return 0, ErrReadOnly }

84
ricefs/fs.go Normal file
View File

@ -0,0 +1,84 @@
package ricefs
import (
"errors"
"os"
"time"
rice "github.com/GeertJohan/go.rice"
"github.com/spf13/afero"
)
var _ afero.Fs = &RiceFs{}
func NewFs(b *rice.Box) *RiceFs {
return &RiceFs{b}
}
type RiceFs struct {
Box *rice.Box
}
// ErrReadOnly is returned when a write method is accessed.
var ErrReadOnly = errors.New("file system is read-only")
// ErrUseOpen is returned when trying to use OpenFile, use Open to open the (read-only) file.
var ErrUseOpen = errors.New("use Open method instead, non-read-only perms are not supported")
// Create is not supported for a RiceFs.
func (f *RiceFs) Create(name string) (afero.File, error) {
return nil, ErrReadOnly
}
// Mkdir is not supported for a RiceFs.
func (f *RiceFs) Mkdir(name string, perm os.FileMode) error {
return ErrReadOnly
}
// MkdirAll is not supported for a RiceFs.
func (f *RiceFs) MkdirAll(path string, perm os.FileMode) error {
return ErrReadOnly
}
// Open opens a file, returning it or an error, if any happens.
func (f *RiceFs) Open(name string) (afero.File, error) {
fBox, err := f.Box.Open(name)
if nil != err {
return nil, err
}
return &file{f: fBox}, nil
}
// OpenFile is not supported for a RiceFs.
func (f *RiceFs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
return nil, ErrUseOpen
}
// Remove is not supported for a RiceFs.
func (f *RiceFs) Remove(name string) error { return ErrReadOnly }
// RemoveAll is not supported for a RiceFs.
func (f *RiceFs) RemoveAll(path string) error { return ErrReadOnly }
// Rename is not supported for a RiceFs.
func (f *RiceFs) Rename(oldname, newname string) error { return ErrReadOnly }
// Stat returns a FileInfo describing the named file, or an error, if any happens.
func (f *RiceFs) Stat(name string) (os.FileInfo, error) {
fBox, err := f.Box.Open(name)
if nil != err {
return nil, err
}
return fBox.Stat()
}
// Name returns the name of the file system
func (f *RiceFs) Name() string {
return "Rice FS"
}
// Chmod is not supported for a RiceFs.
func (f *RiceFs) Chmod(name string, mode os.FileMode) error { return ErrReadOnly }
// Chtimes is not supported for a RiceFs.
func (f *RiceFs) Chtimes(name string, atime time.Time, mtime time.Time) error { return ErrReadOnly }

71
vfs/copydir.go Normal file
View File

@ -0,0 +1,71 @@
package vfs
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/spf13/afero"
)
type CopyDir interface {
Retrieve(name string) (string, error)
Path(name string) string
Open(name string) (*os.File, error)
Destroy() error
}
var _ CopyDir = &copyDir{}
type copyDir struct {
fs afero.Fs
path string
}
func NewCopyDir(fs afero.Fs) (CopyDir, error) {
dir, err := ioutil.TempDir("", "vfsCopy")
if nil != err {
return nil, err
}
return &copyDir{fs, dir}, nil
}
func (d *copyDir) Retrieve(name string) (string, error) {
var path = d.Path(name)
if _, err := os.Stat(path); os.IsNotExist(err) {
var dir = filepath.Dir(path)
os.MkdirAll(dir, 0744)
dst, err := os.Create(path)
if nil != err {
return path, err
}
defer dst.Close()
src, err := d.fs.Open(name)
if nil != err {
return path, err
}
defer src.Close()
_, err = io.Copy(dst, src)
if nil != err {
return path, err
}
}
return path, nil
}
func (d *copyDir) Path(name string) string {
return filepath.Join(d.path, name)
}
func (d *copyDir) Open(name string) (*os.File, error) {
path, err := d.Retrieve(name)
if nil != err {
return nil, err
}
return os.Open(path)
}
func (d *copyDir) Destroy() error {
return os.RemoveAll(d.path)
}