Skip to content

Commit

Permalink
Merge pull request #18 from ajnavarro/subdir
Browse files Browse the repository at this point in the history
subdir: add subdir filesystem implementation
  • Loading branch information
smola authored Apr 12, 2017
2 parents dc2c24b + 73de279 commit b250a01
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 0 deletions.
59 changes: 59 additions & 0 deletions subdir/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package subdir

import (
"io"
"path/filepath"
"strings"

"gopkg.in/src-d/go-billy.v2"
)

type file struct {
billy.BaseFile

f billy.File
}

func newFile(f billy.File, filename string) billy.File {
return &file{
BaseFile: billy.BaseFile{BaseFilename: resolve(filename)},
f: f,
}
}

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

func (f *file) ReadAt(b []byte, off int64) (int, error) {
rf, ok := f.f.(io.ReaderAt)
if !ok {
return 0, billy.ErrNotSupported
}

return rf.ReadAt(b, off)
}

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

func (f *file) Write(p []byte) (int, error) {
return f.f.Write(p)
}

func (f *file) Close() error {
defer func() { f.Closed = true }()
return f.f.Close()
}

func resolve(path string) string {
rp := filepath.Clean(path)
if rp == "/" {
rp = "."
} else if strings.HasPrefix(rp, "/") {
rp = rp[1:]
}

return rp
}
40 changes: 40 additions & 0 deletions subdir/fileinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package subdir

import (
"os"
"time"

"gopkg.in/src-d/go-billy.v2"
)

type fileInfo struct {
filename string
fi billy.FileInfo
}

func newFileInfo(filename string, fi billy.FileInfo) billy.FileInfo {
return &fileInfo{filename, fi}
}

func (fi *fileInfo) Name() string {
return fi.filename
}
func (fi *fileInfo) Size() int64 {
return fi.fi.Size()
}

func (fi *fileInfo) Mode() os.FileMode {
return fi.fi.Mode()
}

func (fi *fileInfo) ModTime() time.Time {
return fi.fi.ModTime()
}

func (fi *fileInfo) IsDir() bool {
return fi.fi.IsDir()
}

func (fi *fileInfo) Sys() interface{} {
return fi.fi.Sys()
}
123 changes: 123 additions & 0 deletions subdir/subdir.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package subdir

import (
"os"
"path/filepath"
"strings"

"gopkg.in/src-d/go-billy.v2"
)

type subdirFs struct {
underlying billy.Filesystem
base string
}

// New creates a new filesystem wrapping up the given 'fs'.
// The created filesystem has its base in the given subdirectory
// of the underlying filesystem.
//
// This is particularly useful to implement the Dir method for
// other filesystems.
func New(fs billy.Filesystem, base string) billy.Filesystem {
return &subdirFs{fs, base}
}

func (s *subdirFs) underlyingPath(filename string) string {
return s.Join(s.Base(), filename)
}

func (s *subdirFs) Create(filename string) (billy.File, error) {
f, err := s.underlying.Create(s.underlyingPath(filename))
if err != nil {
return nil, err
}

return newFile(f, filename), nil
}

func (s *subdirFs) Open(filename string) (billy.File, error) {
f, err := s.underlying.Open(s.underlyingPath(filename))
if err != nil {
return nil, err
}

return newFile(f, filename), nil
}

func (s *subdirFs) OpenFile(filename string, flag int, mode os.FileMode) (
billy.File, error) {

f, err := s.underlying.OpenFile(s.underlyingPath(filename), flag, mode)
if err != nil {
return nil, err
}

return newFile(f, filename), nil
}

func (s *subdirFs) TempFile(dir, prefix string) (billy.File, error) {
f, err := s.underlying.TempFile(s.underlyingPath(dir), prefix)
if err != nil {
return nil, err
}

return newFile(f, s.Join(dir, filepath.Base(f.Filename()))), nil
}

func (s *subdirFs) Rename(from, to string) error {
return s.underlying.Rename(s.underlyingPath(from), s.underlyingPath(to))
}

func (s *subdirFs) Remove(path string) error {
return s.underlying.Remove(s.underlyingPath(path))
}

func (s *subdirFs) MkdirAll(filename string, perm os.FileMode) error {
fullpath := s.Join(s.base, filename)
return s.underlying.MkdirAll(fullpath, perm)
}

func (s *subdirFs) Stat(filename string) (billy.FileInfo, error) {
filename = removeLeadingSlash(filename)
fi, err := s.underlying.Stat(s.underlyingPath(filename))
if err != nil {
return nil, err
}

return newFileInfo(filename, fi), nil
}

func (s *subdirFs) ReadDir(path string) ([]billy.FileInfo, error) {
prefix := s.underlyingPath(path)
fis, err := s.underlying.ReadDir(prefix)
if err != nil {
return nil, err
}
for i := 0; i < len(fis); i++ {
rn := strings.Replace(fis[i].Name(), prefix, "", 1)
fis[i] = newFileInfo(rn, fis[i])
}

return fis, nil
}

func (s *subdirFs) Join(elem ...string) string {
return s.underlying.Join(elem...)
}

func (s *subdirFs) Dir(path string) billy.Filesystem {
return New(s, removeLeadingSlash(path))
}

func (s *subdirFs) Base() string {
return s.base
}

func removeLeadingSlash(path string) string {
if strings.HasPrefix(path, "/") {
return path[1:]
}

return path
}
39 changes: 39 additions & 0 deletions subdir/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package subdir

import (
"io/ioutil"
stdos "os"
"testing"

"gopkg.in/src-d/go-billy.v2"
"gopkg.in/src-d/go-billy.v2/osfs"
"gopkg.in/src-d/go-billy.v2/test"

. "gopkg.in/check.v1"
)

func Test(t *testing.T) { TestingT(t) }

type FilesystemSuite struct {
test.FilesystemSuite
cfs billy.Filesystem
path string
}

var _ = Suite(&FilesystemSuite{})

func (s *FilesystemSuite) SetUpTest(c *C) {
s.path, _ = ioutil.TempDir(stdos.TempDir(), "go-git-fs-test")
osFs := osfs.New(s.path)
s.cfs = New(osFs, "test-subdir")
s.FilesystemSuite.Fs = s.cfs
}

func (s *FilesystemSuite) TearDownTest(c *C) {
fi, err := ioutil.ReadDir(s.path)
c.Assert(err, IsNil)
c.Assert(len(fi) <= 1, Equals, true)

err = stdos.RemoveAll(s.path)
c.Assert(err, IsNil)
}

0 comments on commit b250a01

Please sign in to comment.