diff options
author | Sergio Arbeo <serabe@gmail.com> | 2016-12-19 10:42:14 +0100 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2016-12-19 10:42:14 +0100 |
commit | 1eb39394cdf09b26eb2f5c98225fb2912980e61f (patch) | |
tree | 25e7b370498733aba66688c5d53c29fcef6aa21c | |
parent | c9353b2bd7c1cbdf8f78dad6deac64ed2f2ed9eb (diff) | |
download | go-git-1eb39394cdf09b26eb2f5c98225fb2912980e61f.tar.gz |
Extract billy (#173)
* Extract billy
Billy is a new library directly extracted from go-git. It abstract
several storages systems in a filesystem interface.
More in github.com/src-d/billy
* Fix grouping in imports block
* Update billy to v1
* Re-remove fs_implementation example
-rw-r--r-- | fixtures/fixtures.go | 12 | ||||
-rw-r--r-- | plumbing/format/packfile/decoder_test.go | 3 | ||||
-rw-r--r-- | remote_test.go | 3 | ||||
-rw-r--r-- | repository.go | 3 | ||||
-rw-r--r-- | storage/filesystem/config_test.go | 3 | ||||
-rw-r--r-- | storage/filesystem/internal/dotgit/dotgit.go | 21 | ||||
-rw-r--r-- | storage/filesystem/internal/dotgit/dotgit_test.go | 3 | ||||
-rw-r--r-- | storage/filesystem/internal/dotgit/writers.go | 15 | ||||
-rw-r--r-- | storage/filesystem/internal/dotgit/writers_test.go | 3 | ||||
-rw-r--r-- | storage/filesystem/object.go | 7 | ||||
-rw-r--r-- | storage/filesystem/storage.go | 5 | ||||
-rw-r--r-- | storage/filesystem/storage_test.go | 3 | ||||
-rw-r--r-- | utils/fs/fs.go | 52 | ||||
-rw-r--r-- | utils/fs/memory/memory.go | 364 | ||||
-rw-r--r-- | utils/fs/memory/memory_test.go | 33 | ||||
-rw-r--r-- | utils/fs/os/os.go | 183 | ||||
-rw-r--r-- | utils/fs/os/os_test.go | 37 | ||||
-rw-r--r-- | utils/fs/test/fs_suite.go | 479 |
18 files changed, 46 insertions, 1183 deletions
diff --git a/fixtures/fixtures.go b/fixtures/fixtures.go index 00e7871..fdf852e 100644 --- a/fixtures/fixtures.go +++ b/fixtures/fixtures.go @@ -7,12 +7,12 @@ import ( "os" "path/filepath" - "github.com/alcortesm/tgz" - "gopkg.in/check.v1" "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/utils/fs" - osfs "gopkg.in/src-d/go-git.v4/utils/fs/os" + + "github.com/alcortesm/tgz" + "srcd.works/go-billy.v1" + osfs "srcd.works/go-billy.v1/os" ) var RootFolder = "" @@ -182,7 +182,7 @@ func (f *Fixture) Idx() *os.File { // DotGit creates a new temporary directory and unpacks the repository .git // directory into it. Multiple calls to DotGit returns different directories. -func (f *Fixture) DotGit() fs.Filesystem { +func (f *Fixture) DotGit() billy.Filesystem { fn := filepath.Join(RootFolder, DataFolder, fmt.Sprintf("git-%s.tgz", f.DotGitHash)) path, err := tgz.Extract(fn) if err != nil { @@ -193,7 +193,7 @@ func (f *Fixture) DotGit() fs.Filesystem { return osfs.New(path) } -func (f *Fixture) Worktree() fs.Filesystem { +func (f *Fixture) Worktree() billy.Filesystem { fn := filepath.Join(RootFolder, DataFolder, fmt.Sprintf("git-%s.tgz", f.DotGitHash)) git, err := tgz.Extract(fn) if err != nil { diff --git a/plumbing/format/packfile/decoder_test.go b/plumbing/format/packfile/decoder_test.go index eeb1e3d..10d3bc2 100644 --- a/plumbing/format/packfile/decoder_test.go +++ b/plumbing/format/packfile/decoder_test.go @@ -10,7 +10,8 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/storer" "gopkg.in/src-d/go-git.v4/storage/filesystem" "gopkg.in/src-d/go-git.v4/storage/memory" - fs "gopkg.in/src-d/go-git.v4/utils/fs/memory" + + fs "srcd.works/go-billy.v1/memory" . "gopkg.in/check.v1" ) diff --git a/remote_test.go b/remote_test.go index f75adee..47c8180 100644 --- a/remote_test.go +++ b/remote_test.go @@ -11,7 +11,8 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/storer" "gopkg.in/src-d/go-git.v4/storage/filesystem" "gopkg.in/src-d/go-git.v4/storage/memory" - osfs "gopkg.in/src-d/go-git.v4/utils/fs/os" + + osfs "srcd.works/go-billy.v1/os" . "gopkg.in/check.v1" ) diff --git a/repository.go b/repository.go index 7d964a4..b9afb9a 100644 --- a/repository.go +++ b/repository.go @@ -11,7 +11,8 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/storer" "gopkg.in/src-d/go-git.v4/storage/filesystem" "gopkg.in/src-d/go-git.v4/storage/memory" - osfs "gopkg.in/src-d/go-git.v4/utils/fs/os" + + osfs "srcd.works/go-billy.v1/os" ) var ( diff --git a/storage/filesystem/config_test.go b/storage/filesystem/config_test.go index b86eaee..6fbf826 100644 --- a/storage/filesystem/config_test.go +++ b/storage/filesystem/config_test.go @@ -6,7 +6,8 @@ import ( "gopkg.in/src-d/go-git.v4/fixtures" "gopkg.in/src-d/go-git.v4/storage/filesystem/internal/dotgit" - "gopkg.in/src-d/go-git.v4/utils/fs/os" + + "srcd.works/go-billy.v1/os" . "gopkg.in/check.v1" ) diff --git a/storage/filesystem/internal/dotgit/dotgit.go b/storage/filesystem/internal/dotgit/dotgit.go index 3405908..f9763d1 100644 --- a/storage/filesystem/internal/dotgit/dotgit.go +++ b/storage/filesystem/internal/dotgit/dotgit.go @@ -10,7 +10,8 @@ import ( "strings" "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/utils/fs" + + "srcd.works/go-billy.v1" ) const ( @@ -51,33 +52,33 @@ var ( // The DotGit type represents a local git repository on disk. This // type is not zero-value-safe, use the New function to initialize it. type DotGit struct { - fs fs.Filesystem + fs billy.Filesystem } // New returns a DotGit value ready to be used. The path argument must // be the absolute path of a git repository directory (e.g. // "/foo/bar/.git"). -func New(fs fs.Filesystem) *DotGit { +func New(fs billy.Filesystem) *DotGit { return &DotGit{fs: fs} } // ConfigWriter returns a file pointer for write to the config file -func (d *DotGit) ConfigWriter() (fs.File, error) { +func (d *DotGit) ConfigWriter() (billy.File, error) { return d.fs.Create(configPath) } // Config returns a file pointer for read to the config file -func (d *DotGit) Config() (fs.File, error) { +func (d *DotGit) Config() (billy.File, error) { return d.fs.Open(configPath) } // ShallowWriter returns a file pointer for write to the shallow file -func (d *DotGit) ShallowWriter() (fs.File, error) { +func (d *DotGit) ShallowWriter() (billy.File, error) { return d.fs.Create(shallowPath) } // Shallow returns a file pointer for read to the shallow file -func (d *DotGit) Shallow() (fs.File, error) { +func (d *DotGit) Shallow() (billy.File, error) { f, err := d.fs.Open(shallowPath) if err != nil { if os.IsNotExist(err) { @@ -124,7 +125,7 @@ func (d *DotGit) ObjectPacks() ([]plumbing.Hash, error) { } // ObjectPack returns a fs.File of the given packfile -func (d *DotGit) ObjectPack(hash plumbing.Hash) (fs.File, error) { +func (d *DotGit) ObjectPack(hash plumbing.Hash) (billy.File, error) { file := d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.pack", hash.String())) pack, err := d.fs.Open(file) @@ -140,7 +141,7 @@ func (d *DotGit) ObjectPack(hash plumbing.Hash) (fs.File, error) { } // ObjectPackIdx returns a fs.File of the index file for a given packfile -func (d *DotGit) ObjectPackIdx(hash plumbing.Hash) (fs.File, error) { +func (d *DotGit) ObjectPackIdx(hash plumbing.Hash) (billy.File, error) { file := d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.idx", hash.String())) idx, err := d.fs.Open(file) if err != nil { @@ -190,7 +191,7 @@ func (d *DotGit) Objects() ([]plumbing.Hash, error) { } // Object return a fs.File poiting the object file, if exists -func (d *DotGit) Object(h plumbing.Hash) (fs.File, error) { +func (d *DotGit) Object(h plumbing.Hash) (billy.File, error) { hash := h.String() file := d.fs.Join(objectsPath, hash[0:2], hash[2:40]) diff --git a/storage/filesystem/internal/dotgit/dotgit_test.go b/storage/filesystem/internal/dotgit/dotgit_test.go index b645a85..48f02f0 100644 --- a/storage/filesystem/internal/dotgit/dotgit_test.go +++ b/storage/filesystem/internal/dotgit/dotgit_test.go @@ -9,7 +9,8 @@ import ( "gopkg.in/src-d/go-git.v4/fixtures" "gopkg.in/src-d/go-git.v4/plumbing" - osfs "gopkg.in/src-d/go-git.v4/utils/fs/os" + + osfs "srcd.works/go-billy.v1/os" . "gopkg.in/check.v1" ) diff --git a/storage/filesystem/internal/dotgit/writers.go b/storage/filesystem/internal/dotgit/writers.go index 8e22a39..1cd893d 100644 --- a/storage/filesystem/internal/dotgit/writers.go +++ b/storage/filesystem/internal/dotgit/writers.go @@ -9,7 +9,8 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/format/idxfile" "gopkg.in/src-d/go-git.v4/plumbing/format/objfile" "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" - "gopkg.in/src-d/go-git.v4/utils/fs" + + "srcd.works/go-billy.v1" ) // PackWriter is a io.Writer that generates the packfile index simultaneously, @@ -21,15 +22,15 @@ import ( type PackWriter struct { Notify func(h plumbing.Hash, i idxfile.Idxfile) - fs fs.Filesystem - fr, fw fs.File + fs billy.Filesystem + fr, fw billy.File synced *syncedReader checksum plumbing.Hash index idxfile.Idxfile result chan error } -func newPackWrite(fs fs.Filesystem) (*PackWriter, error) { +func newPackWrite(fs billy.Filesystem) (*PackWriter, error) { fw, err := fs.TempFile(fs.Join(objectsPath, packPath), "tmp_pack_") if err != nil { return nil, err @@ -248,11 +249,11 @@ func (s *syncedReader) Close() error { type ObjectWriter struct { objfile.Writer - fs fs.Filesystem - f fs.File + fs billy.Filesystem + f billy.File } -func newObjectWriter(fs fs.Filesystem) (*ObjectWriter, error) { +func newObjectWriter(fs billy.Filesystem) (*ObjectWriter, error) { f, err := fs.TempFile(fs.Join(objectsPath, packPath), "tmp_obj_") if err != nil { return nil, err diff --git a/storage/filesystem/internal/dotgit/writers_test.go b/storage/filesystem/internal/dotgit/writers_test.go index c66613a..c546a3a 100644 --- a/storage/filesystem/internal/dotgit/writers_test.go +++ b/storage/filesystem/internal/dotgit/writers_test.go @@ -9,7 +9,8 @@ import ( "strconv" "gopkg.in/src-d/go-git.v4/fixtures" - osfs "gopkg.in/src-d/go-git.v4/utils/fs/os" + + osfs "srcd.works/go-billy.v1/os" . "gopkg.in/check.v1" ) diff --git a/storage/filesystem/object.go b/storage/filesystem/object.go index 836e7f3..e9b5bb7 100644 --- a/storage/filesystem/object.go +++ b/storage/filesystem/object.go @@ -11,7 +11,8 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/storer" "gopkg.in/src-d/go-git.v4/storage/filesystem/internal/dotgit" "gopkg.in/src-d/go-git.v4/storage/memory" - "gopkg.in/src-d/go-git.v4/utils/fs" + + "srcd.works/go-billy.v1" ) type ObjectStorage struct { @@ -261,7 +262,7 @@ func (i index) Decode(r io.Reader) error { } type packfileIter struct { - f fs.File + f billy.File d *packfile.Decoder t plumbing.ObjectType @@ -270,7 +271,7 @@ type packfileIter struct { total uint32 } -func newPackfileIter(f fs.File, t plumbing.ObjectType, seen map[plumbing.Hash]bool) (storer.EncodedObjectIter, error) { +func newPackfileIter(f billy.File, t plumbing.ObjectType, seen map[plumbing.Hash]bool) (storer.EncodedObjectIter, error) { s := packfile.NewScanner(f) _, total, err := s.Header() if err != nil { diff --git a/storage/filesystem/storage.go b/storage/filesystem/storage.go index e414428..a60d0f4 100644 --- a/storage/filesystem/storage.go +++ b/storage/filesystem/storage.go @@ -3,7 +3,8 @@ package filesystem import ( "gopkg.in/src-d/go-git.v4/storage/filesystem/internal/dotgit" - "gopkg.in/src-d/go-git.v4/utils/fs" + + "srcd.works/go-billy.v1" ) // Storage is an implementation of git.Storer that stores data on disk in the @@ -17,7 +18,7 @@ type Storage struct { } // NewStorage returns a new Storage backed by a given `fs.Filesystem` -func NewStorage(fs fs.Filesystem) (*Storage, error) { +func NewStorage(fs billy.Filesystem) (*Storage, error) { dir := dotgit.New(fs) o, err := newObjectStorage(dir) if err != nil { diff --git a/storage/filesystem/storage_test.go b/storage/filesystem/storage_test.go index c24d5d5..0e8ffb3 100644 --- a/storage/filesystem/storage_test.go +++ b/storage/filesystem/storage_test.go @@ -4,7 +4,8 @@ import ( "testing" "gopkg.in/src-d/go-git.v4/storage/test" - "gopkg.in/src-d/go-git.v4/utils/fs/os" + + "srcd.works/go-billy.v1/os" . "gopkg.in/check.v1" ) diff --git a/utils/fs/fs.go b/utils/fs/fs.go deleted file mode 100644 index 7e6c01f..0000000 --- a/utils/fs/fs.go +++ /dev/null @@ -1,52 +0,0 @@ -// Package fs interace and implementations used by storage/filesystem -package fs - -import ( - "errors" - "io" - "os" -) - -var ( - ErrClosed = errors.New("file: Writing on closed file.") - ErrReadOnly = errors.New("this is a read-only filesystem") - ErrNotSupported = errors.New("feature not supported") -) - -type Filesystem interface { - Create(filename string) (File, error) - Open(filename string) (File, error) - OpenFile(filename string, flag int, perm os.FileMode) (File, error) - Stat(filename string) (FileInfo, error) - ReadDir(path string) ([]FileInfo, error) - TempFile(dir, prefix string) (File, error) - Rename(from, to string) error - Remove(filename string) error - Join(elem ...string) string - Dir(path string) Filesystem - Base() string -} - -type File interface { - Filename() string - IsClosed() bool - io.Writer - io.Reader - io.Seeker - io.Closer -} - -type FileInfo os.FileInfo - -type BaseFile struct { - BaseFilename string - Closed bool -} - -func (f *BaseFile) Filename() string { - return f.BaseFilename -} - -func (f *BaseFile) IsClosed() bool { - return f.Closed -} diff --git a/utils/fs/memory/memory.go b/utils/fs/memory/memory.go deleted file mode 100644 index 54dd497..0000000 --- a/utils/fs/memory/memory.go +++ /dev/null @@ -1,364 +0,0 @@ -package memory - -import ( - "errors" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "time" - - "gopkg.in/src-d/go-git.v4/utils/fs" -) - -const separator = '/' - -// Memory a very convenient filesystem based on memory files -type Memory struct { - base string - s *storage - tempCount int -} - -//New returns a new Memory filesystem -func New() *Memory { - return &Memory{ - base: "/", - s: &storage{make(map[string]*file, 0)}, - } -} - -func (fs *Memory) Create(filename string) (fs.File, error) { - return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0) -} - -func (fs *Memory) Open(filename string) (fs.File, error) { - return fs.OpenFile(filename, os.O_RDONLY, 0) -} - -func (fs *Memory) OpenFile(filename string, flag int, perm os.FileMode) (fs.File, error) { - fullpath := fs.Join(fs.base, filename) - f, ok := fs.s.files[fullpath] - - if !ok && !isCreate(flag) { - return nil, os.ErrNotExist - } - - if f == nil { - fs.s.files[fullpath] = newFile(fs.base, fullpath, flag) - return fs.s.files[fullpath], nil - } - - n := newFile(fs.base, fullpath, flag) - n.content = f.content - - if isAppend(flag) { - n.position = int64(n.content.Len()) - } - - if isTruncate(flag) { - n.content.Truncate() - } - - return n, nil -} - -func (fs *Memory) Stat(filename string) (fs.FileInfo, error) { - fullpath := fs.Join(fs.base, filename) - - if _, ok := fs.s.files[filename]; ok { - return newFileInfo(fs.base, fullpath, fs.s.files[filename].content.Len()), nil - } - - info, err := fs.ReadDir(filename) - if err == nil && len(info) != 0 { - return newFileInfo(fs.base, fullpath, len(info)), nil - } - - return nil, os.ErrNotExist -} - -func (fs *Memory) ReadDir(base string) (entries []fs.FileInfo, err error) { - base = fs.Join(fs.base, base) - - appendedDirs := make(map[string]bool, 0) - for fullpath, f := range fs.s.files { - if !strings.HasPrefix(fullpath, base) { - continue - } - - fullpath, _ = filepath.Rel(base, fullpath) - parts := strings.Split(fullpath, string(separator)) - - if len(parts) == 1 { - entries = append(entries, &fileInfo{name: parts[0], size: f.content.Len()}) - continue - } - - if _, ok := appendedDirs[parts[0]]; ok { - continue - } - - entries = append(entries, &fileInfo{name: parts[0], isDir: true}) - appendedDirs[parts[0]] = true - } - - return -} - -var maxTempFiles = 1024 * 4 - -func (fs *Memory) TempFile(dir, prefix string) (fs.File, error) { - var fullpath string - for { - if fs.tempCount >= maxTempFiles { - return nil, errors.New("max. number of tempfiles reached") - } - - fullpath = fs.getTempFilename(dir, prefix) - if _, ok := fs.s.files[fullpath]; !ok { - break - } - } - - return fs.Create(fullpath) -} - -func (fs *Memory) getTempFilename(dir, prefix string) string { - fs.tempCount++ - filename := fmt.Sprintf("%s_%d_%d", prefix, fs.tempCount, time.Now().UnixNano()) - return fs.Join(fs.base, dir, filename) -} - -func (fs *Memory) Rename(from, to string) error { - from = fs.Join(fs.base, from) - to = fs.Join(fs.base, to) - - if _, ok := fs.s.files[from]; !ok { - return os.ErrNotExist - } - - fs.s.files[to] = fs.s.files[from] - fs.s.files[to].BaseFilename = to - delete(fs.s.files, from) - - return nil -} - -func (fs *Memory) Remove(filename string) error { - fullpath := fs.Join(fs.base, filename) - if _, ok := fs.s.files[fullpath]; !ok { - return os.ErrNotExist - } - - delete(fs.s.files, fullpath) - return nil -} - -func (fs *Memory) Join(elem ...string) string { - return filepath.Join(elem...) -} - -func (fs *Memory) Dir(path string) fs.Filesystem { - return &Memory{ - base: fs.Join(fs.base, path), - s: fs.s, - } -} - -func (fs *Memory) Base() string { - return fs.base -} - -type file struct { - fs.BaseFile - - content *content - position int64 - flag int -} - -func newFile(base, fullpath string, flag int) *file { - filename, _ := filepath.Rel(base, fullpath) - - return &file{ - BaseFile: fs.BaseFile{BaseFilename: filename}, - content: &content{}, - flag: flag, - } -} - -func (f *file) Read(b []byte) (int, error) { - n, err := f.ReadAt(b, f.position) - if err != nil { - return 0, err - } - - return n, err -} - -func (f *file) ReadAt(b []byte, off int64) (int, error) { - if f.IsClosed() { - return 0, fs.ErrClosed - } - - if !isReadAndWrite(f.flag) && !isReadOnly(f.flag) { - return 0, errors.New("read not supported") - } - - n, err := f.content.ReadAt(b, off) - f.position += int64(n) - - return n, err -} - -func (f *file) Seek(offset int64, whence int) (int64, error) { - if f.IsClosed() { - return 0, fs.ErrClosed - } - - switch whence { - case io.SeekCurrent: - f.position += offset - case io.SeekStart: - f.position = offset - case io.SeekEnd: - f.position = int64(f.content.Len()) - offset - } - - return f.position, nil -} - -func (f *file) Write(p []byte) (int, error) { - if f.IsClosed() { - return 0, fs.ErrClosed - } - - if !isReadAndWrite(f.flag) && !isWriteOnly(f.flag) { - return 0, errors.New("write not supported") - } - - n, err := f.content.WriteAt(p, f.position) - f.position += int64(n) - - return n, err -} - -func (f *file) Close() error { - if f.IsClosed() { - return errors.New("file already closed") - } - - f.Closed = true - return nil -} - -func (f *file) Open() error { - f.Closed = false - return nil -} - -type fileInfo struct { - name string - size int - isDir bool -} - -func newFileInfo(base, fullpath string, size int) *fileInfo { - filename, _ := filepath.Rel(base, fullpath) - - return &fileInfo{ - name: filename, - size: size, - } -} - -func (fi *fileInfo) Name() string { - return fi.name -} - -func (fi *fileInfo) Size() int64 { - return int64(fi.size) -} - -func (fi *fileInfo) Mode() os.FileMode { - return os.FileMode(0) -} - -func (*fileInfo) ModTime() time.Time { - return time.Now() -} - -func (fi *fileInfo) IsDir() bool { - return fi.isDir -} - -func (*fileInfo) Sys() interface{} { - return nil -} - -type storage struct { - files map[string]*file -} - -type content struct { - bytes []byte -} - -func (c *content) WriteAt(p []byte, off int64) (int, error) { - prev := len(c.bytes) - c.bytes = append(c.bytes[:off], p...) - if len(c.bytes) < prev { - c.bytes = c.bytes[:prev] - } - - return len(p), nil -} - -func (c *content) ReadAt(b []byte, off int64) (int, error) { - size := int64(len(c.bytes)) - if off >= size { - return 0, io.EOF - } - - l := int64(len(b)) - if off+l > size { - l = size - off - } - - n := copy(b, c.bytes[off:off+l]) - return n, nil -} - -func (c *content) Truncate() { - c.bytes = make([]byte, 0) -} - -func (c *content) Len() int { - return len(c.bytes) -} - -func isCreate(flag int) bool { - return flag&os.O_CREATE != 0 -} - -func isAppend(flag int) bool { - return flag&os.O_APPEND != 0 -} - -func isTruncate(flag int) bool { - return flag&os.O_TRUNC != 0 -} - -func isReadAndWrite(flag int) bool { - return flag&os.O_RDWR != 0 -} - -func isReadOnly(flag int) bool { - return flag == os.O_RDONLY -} - -func isWriteOnly(flag int) bool { - return flag&os.O_WRONLY != 0 -} diff --git a/utils/fs/memory/memory_test.go b/utils/fs/memory/memory_test.go deleted file mode 100644 index 4645fe7..0000000 --- a/utils/fs/memory/memory_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package memory - -import ( - "testing" - - . "gopkg.in/check.v1" - "gopkg.in/src-d/go-git.v4/utils/fs/test" -) - -func Test(t *testing.T) { TestingT(t) } - -type MemorySuite struct { - test.FilesystemSuite - path string -} - -var _ = Suite(&MemorySuite{}) - -func (s *MemorySuite) SetUpTest(c *C) { - s.FilesystemSuite.Fs = New() -} - -func (s *MemorySuite) TestTempFileMaxTempFiles(c *C) { - for i := 0; i < maxTempFiles; i++ { - f, err := s.FilesystemSuite.Fs.TempFile("", "") - c.Assert(err, IsNil) - c.Assert(f, NotNil) - } - - f, err := s.FilesystemSuite.Fs.TempFile("", "") - c.Assert(err, NotNil) - c.Assert(f, IsNil) -} diff --git a/utils/fs/os/os.go b/utils/fs/os/os.go deleted file mode 100644 index 5f9df67..0000000 --- a/utils/fs/os/os.go +++ /dev/null @@ -1,183 +0,0 @@ -package os - -import ( - "io/ioutil" - "os" - "path" - "path/filepath" - - "gopkg.in/src-d/go-git.v4/utils/fs" -) - -// OS a filesystem base on the os filesystem -type OS struct { - base string -} - -// New returns a new OS filesystem -func New(baseDir string) *OS { - return &OS{ - base: baseDir, - } -} - -// Create creates a file and opens it with standard permissions -// and modes O_RDWR, O_CREATE and O_TRUNC. -func (fs *OS) Create(filename string) (fs.File, error) { - return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) -} - -// OpenFile is equivalent to standard os.OpenFile. -// If flag os.O_CREATE is set, all parent directories will be created. -func (fs *OS) OpenFile(filename string, flag int, perm os.FileMode) (fs.File, error) { - fullpath := path.Join(fs.base, filename) - - if flag&os.O_CREATE != 0 { - if err := fs.createDir(fullpath); err != nil { - return nil, err - } - } - - f, err := os.OpenFile(fullpath, flag, perm) - if err != nil { - return nil, err - } - - filename, err = filepath.Rel(fs.base, fullpath) - if err != nil { - return nil, err - } - - return newOSFile(filename, f), nil -} - -func (fs *OS) createDir(fullpath string) error { - dir := filepath.Dir(fullpath) - if dir != "." { - if err := os.MkdirAll(dir, 0755); err != nil { - return err - } - } - - return nil -} - -// ReadDir returns the filesystem info for all the archives under the specified -// path. -func (ofs *OS) ReadDir(path string) ([]fs.FileInfo, error) { - fullpath := ofs.Join(ofs.base, path) - - l, err := ioutil.ReadDir(fullpath) - if err != nil { - return nil, err - } - - var s = make([]fs.FileInfo, len(l)) - for i, f := range l { - s[i] = f - } - - return s, nil -} - -func (fs *OS) Rename(from, to string) error { - from = fs.Join(fs.base, from) - to = fs.Join(fs.base, to) - - if err := fs.createDir(to); err != nil { - return err - } - - return os.Rename(from, to) -} - -// Open opens a file in read-only mode. -func (fs *OS) Open(filename string) (fs.File, error) { - return fs.OpenFile(filename, os.O_RDONLY, 0) -} - -// Stat returns the FileInfo structure describing file. -func (fs *OS) Stat(filename string) (fs.FileInfo, error) { - fullpath := fs.Join(fs.base, filename) - return os.Stat(fullpath) -} - -func (fs *OS) Remove(filename string) error { - fullpath := fs.Join(fs.base, filename) - return os.Remove(fullpath) -} - -func (fs *OS) TempFile(dir, prefix string) (fs.File, error) { - fullpath := fs.Join(fs.base, dir) - if err := fs.createDir(fullpath + string(os.PathSeparator)); err != nil { - return nil, err - } - - f, err := ioutil.TempFile(fullpath, prefix) - if err != nil { - return nil, err - } - - s, err := f.Stat() - if err != nil { - return nil, err - } - - filename, err := filepath.Rel(fs.base, fs.Join(fullpath, s.Name())) - if err != nil { - return nil, err - } - - return newOSFile(filename, f), nil -} - -// Join joins the specified elements using the filesystem separator. -func (fs *OS) Join(elem ...string) string { - return filepath.Join(elem...) -} - -// Dir returns a new Filesystem from the same type of fs using as baseDir the -// given path -func (fs *OS) Dir(path string) fs.Filesystem { - return New(fs.Join(fs.base, path)) -} - -// Base returns the base path of the filesytem -func (fs *OS) Base() string { - return fs.base -} - -// osFile represents a file in the os filesystem -type osFile struct { - fs.BaseFile - file *os.File -} - -func newOSFile(filename string, file *os.File) fs.File { - return &osFile{ - BaseFile: fs.BaseFile{BaseFilename: filename}, - file: file, - } -} - -func (f *osFile) Read(p []byte) (int, error) { - return f.file.Read(p) -} - -func (f *osFile) Seek(offset int64, whence int) (int64, error) { - return f.file.Seek(offset, whence) -} - -func (f *osFile) Write(p []byte) (int, error) { - return f.file.Write(p) -} - -func (f *osFile) Close() error { - f.BaseFile.Closed = true - - return f.file.Close() -} - -func (f *osFile) ReadAt(p []byte, off int64) (int, error) { - return f.file.ReadAt(p, off) -} diff --git a/utils/fs/os/os_test.go b/utils/fs/os/os_test.go deleted file mode 100644 index 5e8f5c1..0000000 --- a/utils/fs/os/os_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package os_test - -import ( - "io/ioutil" - stdos "os" - "path/filepath" - "testing" - - . "gopkg.in/check.v1" - "gopkg.in/src-d/go-git.v4/utils/fs/os" - "gopkg.in/src-d/go-git.v4/utils/fs/test" -) - -func Test(t *testing.T) { TestingT(t) } - -type OSSuite struct { - test.FilesystemSuite - path string -} - -var _ = Suite(&OSSuite{}) - -func (s *OSSuite) SetUpTest(c *C) { - s.path, _ = ioutil.TempDir(stdos.TempDir(), "go-git-os-fs-test") - s.FilesystemSuite.Fs = os.New(s.path) -} -func (s *OSSuite) TearDownTest(c *C) { - err := stdos.RemoveAll(s.path) - c.Assert(err, IsNil) -} - -func (s *OSSuite) TestOpenDoesNotCreateDir(c *C) { - _, err := s.Fs.Open("dir/non-existent") - c.Assert(err, NotNil) - _, err = stdos.Stat(filepath.Join(s.path, "dir")) - c.Assert(stdos.IsNotExist(err), Equals, true) -} diff --git a/utils/fs/test/fs_suite.go b/utils/fs/test/fs_suite.go deleted file mode 100644 index 91b2be5..0000000 --- a/utils/fs/test/fs_suite.go +++ /dev/null @@ -1,479 +0,0 @@ -package test - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "strings" - "testing" - - "bytes" - - . "gopkg.in/check.v1" - . "gopkg.in/src-d/go-git.v4/utils/fs" -) - -func Test(t *testing.T) { TestingT(t) } - -type FilesystemSuite struct { - Fs Filesystem -} - -func (s *FilesystemSuite) TestCreate(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo") -} - -func (s *FilesystemSuite) TestCreateDepth(c *C) { - f, err := s.Fs.Create("bar/foo") - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "bar/foo") -} - -func (s *FilesystemSuite) TestCreateDepthAbsolute(c *C) { - f, err := s.Fs.Create("/bar/foo") - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "bar/foo") -} - -func (s *FilesystemSuite) TestCreateOverwrite(c *C) { - for i := 0; i < 3; i++ { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - - l, err := f.Write([]byte(fmt.Sprintf("foo%d", i))) - c.Assert(err, IsNil) - c.Assert(l, Equals, 4) - - err = f.Close() - c.Assert(err, IsNil) - } - - f, err := s.Fs.Open("foo") - c.Assert(err, IsNil) - - wrote, err := ioutil.ReadAll(f) - c.Assert(err, IsNil) - c.Assert(string(wrote), DeepEquals, "foo2") -} - -func (s *FilesystemSuite) TestCreateClose(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - c.Assert(f.IsClosed(), Equals, false) - - _, err = f.Write([]byte("foo")) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - f, err = s.Fs.Open(f.Filename()) - c.Assert(err, IsNil) - - wrote, err := ioutil.ReadAll(f) - c.Assert(err, IsNil) - c.Assert(string(wrote), DeepEquals, "foo") - c.Assert(f.Close(), IsNil) -} - -func (s *FilesystemSuite) TestOpenFileNoTruncate(c *C) { - defaultMode := os.FileMode(0666) - - // Create when it does not exist - f, err := s.Fs.OpenFile("foo1", os.O_CREATE|os.O_WRONLY, defaultMode) - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo1") - s.testWriteClose(c, f, "foo1") - - f, err = s.Fs.OpenFile("foo1", os.O_RDONLY, defaultMode) - c.Assert(err, IsNil) - s.testReadClose(c, f, "foo1") - - // Create when it does exist - f, err = s.Fs.OpenFile("foo1", os.O_CREATE|os.O_WRONLY, defaultMode) - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo1") - s.testWriteClose(c, f, "bar") - - f, err = s.Fs.OpenFile("foo1", os.O_RDONLY, defaultMode) - c.Assert(err, IsNil) - s.testReadClose(c, f, "bar1") -} - -func (s *FilesystemSuite) TestOpenFileAppend(c *C) { - defaultMode := os.FileMode(0666) - - f, err := s.Fs.OpenFile("foo1", os.O_CREATE|os.O_WRONLY|os.O_APPEND, defaultMode) - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo1") - s.testWriteClose(c, f, "foo1") - - f, err = s.Fs.OpenFile("foo1", os.O_WRONLY|os.O_APPEND, defaultMode) - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo1") - s.testWriteClose(c, f, "bar1") - - f, err = s.Fs.OpenFile("foo1", os.O_RDONLY, defaultMode) - c.Assert(err, IsNil) - s.testReadClose(c, f, "foo1bar1") -} - -func (s *FilesystemSuite) TestOpenFileReadWrite(c *C) { - defaultMode := os.FileMode(0666) - - f, err := s.Fs.OpenFile("foo1", os.O_CREATE|os.O_TRUNC|os.O_RDWR, defaultMode) - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo1") - - written, err := f.Write([]byte("foobar")) - c.Assert(written, Equals, 6) - c.Assert(err, IsNil) - - _, err = f.Seek(0, os.SEEK_SET) - c.Assert(err, IsNil) - - written, err = f.Write([]byte("qux")) - c.Assert(written, Equals, 3) - c.Assert(err, IsNil) - - _, err = f.Seek(0, os.SEEK_SET) - c.Assert(err, IsNil) - - s.testReadClose(c, f, "quxbar") -} - -func (s *FilesystemSuite) TestOpenFile(c *C) { - defaultMode := os.FileMode(0666) - - f, err := s.Fs.OpenFile("foo1", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, defaultMode) - c.Assert(err, IsNil) - s.testWriteClose(c, f, "foo1") - - // Truncate if it exists - f, err = s.Fs.OpenFile("foo1", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, defaultMode) - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo1") - s.testWriteClose(c, f, "foo1overwritten") - - // Read-only if it exists - f, err = s.Fs.OpenFile("foo1", os.O_RDONLY, defaultMode) - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo1") - s.testReadClose(c, f, "foo1overwritten") - - // Create when it does exist - f, err = s.Fs.OpenFile("foo1", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, defaultMode) - c.Assert(err, IsNil) - c.Assert(f.Filename(), Equals, "foo1") - s.testWriteClose(c, f, "bar") - - f, err = s.Fs.OpenFile("foo1", os.O_RDONLY, defaultMode) - c.Assert(err, IsNil) - s.testReadClose(c, f, "bar") -} - -func (s *FilesystemSuite) testWriteClose(c *C, f File, content string) { - written, err := f.Write([]byte(content)) - c.Assert(written, Equals, len(content)) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) -} - -func (s *FilesystemSuite) testReadClose(c *C, f File, content string) { - read, err := ioutil.ReadAll(f) - c.Assert(err, IsNil) - c.Assert(string(read), Equals, content) - c.Assert(f.Close(), IsNil) -} - -func (s *FilesystemSuite) TestFileCreateReadSeek(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - - n, err := f.Write([]byte("0123456789abcdefghijklmnopqrstuvwxyz")) - c.Assert(err, IsNil) - c.Assert(n, Equals, 36) - - p, err := f.Seek(10, io.SeekStart) - c.Assert(err, IsNil) - c.Assert(int(p), Equals, 10) - - all, err := ioutil.ReadAll(f) - c.Assert(err, IsNil) - c.Assert(string(all), Equals, "abcdefghijklmnopqrstuvwxyz") - c.Assert(f.Close(), IsNil) -} - -func (s *FilesystemSuite) TestFileOpenReadSeek(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - - n, err := f.Write([]byte("0123456789abcdefghijklmnopqrstuvwxyz")) - c.Assert(err, IsNil) - c.Assert(n, Equals, 36) - - c.Assert(f.Close(), IsNil) - - f, err = s.Fs.Open("foo") - c.Assert(err, IsNil) - - p, err := f.Seek(10, io.SeekStart) - c.Assert(err, IsNil) - c.Assert(int(p), Equals, 10) - - all, err := ioutil.ReadAll(f) - c.Assert(err, IsNil) - c.Assert(string(all), Equals, "abcdefghijklmnopqrstuvwxyz") - c.Assert(f.Close(), IsNil) -} - -func (s *FilesystemSuite) TestFileCloseTwice(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - - c.Assert(f.Close(), IsNil) - c.Assert(f.Close(), NotNil) -} - -func (s *FilesystemSuite) TestReadDirAndDir(c *C) { - files := []string{"foo", "bar", "qux/baz", "qux/qux"} - for _, name := range files { - f, err := s.Fs.Create(name) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - } - - info, err := s.Fs.ReadDir("/") - c.Assert(err, IsNil) - c.Assert(info, HasLen, 3) - - info, err = s.Fs.ReadDir("/qux") - c.Assert(err, IsNil) - c.Assert(info, HasLen, 2) - - qux := s.Fs.Dir("/qux") - info, err = qux.ReadDir("/") - c.Assert(err, IsNil) - c.Assert(info, HasLen, 2) -} - -func (s *FilesystemSuite) TestReadDirFileInfo(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - n, err := f.Write([]byte{'F', 'O', 'O'}) - c.Assert(n, Equals, 3) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - info, err := s.Fs.ReadDir("/") - c.Assert(err, IsNil) - c.Assert(info, HasLen, 1) - - c.Assert(info[0].Size(), Equals, int64(3)) - c.Assert(info[0].IsDir(), Equals, false) - c.Assert(info[0].Name(), Equals, "foo") -} - -func (s *FilesystemSuite) TestReadDirFileInfoDirs(c *C) { - files := []string{"qux/baz/foo"} - for _, name := range files { - f, err := s.Fs.Create(name) - c.Assert(err, IsNil) - n, err := f.Write([]byte{'F', 'O', 'O'}) - c.Assert(n, Equals, 3) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - } - - info, err := s.Fs.ReadDir("qux") - c.Assert(err, IsNil) - c.Assert(info, HasLen, 1) - c.Assert(info[0].IsDir(), Equals, true) - c.Assert(info[0].Name(), Equals, "baz") - - info, err = s.Fs.ReadDir("qux/baz") - c.Assert(err, IsNil) - c.Assert(info, HasLen, 1) - c.Assert(info[0].Size(), Equals, int64(3)) - c.Assert(info[0].IsDir(), Equals, false) - c.Assert(info[0].Name(), Equals, "foo") -} - -func (s *FilesystemSuite) TestDirStat(c *C) { - files := []string{"foo", "bar", "qux/baz", "qux/qux"} - for _, name := range files { - f, err := s.Fs.Create(name) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - } - - qux := s.Fs.Dir("qux") - fi, err := qux.Stat("baz") - c.Assert(err, IsNil) - c.Assert(fi.Name(), Equals, "baz") - - fi, err = qux.Stat("/baz") - c.Assert(err, IsNil) - c.Assert(fi.Name(), Equals, "baz") -} - -func (s *FilesystemSuite) TestCreateInDir(c *C) { - dir := s.Fs.Dir("foo") - f, err := dir.Create("bar") - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - c.Assert(f.Filename(), Equals, "bar") -} - -func (s *FilesystemSuite) TestRename(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - err = s.Fs.Rename("foo", "bar") - c.Assert(err, IsNil) - - foo, err := s.Fs.Stat("foo") - c.Assert(foo, IsNil) - c.Assert(err, NotNil) - - bar, err := s.Fs.Stat("bar") - c.Assert(bar, NotNil) - c.Assert(err, IsNil) -} - -func (s *FilesystemSuite) TestTempFile(c *C) { - f, err := s.Fs.TempFile("", "bar") - c.Assert(err, IsNil) - - c.Assert(strings.HasPrefix(f.Filename(), "bar"), Equals, true) -} - -func (s *FilesystemSuite) TestTempFileWithPath(c *C) { - f, err := s.Fs.TempFile("foo", "bar") - c.Assert(err, IsNil) - c.Assert(strings.HasPrefix(f.Filename(), s.Fs.Join("foo", "bar")), Equals, true) -} - -func (s *FilesystemSuite) TestTempFileFullWithPath(c *C) { - f, err := s.Fs.TempFile("/foo", "bar") - c.Assert(err, IsNil) - c.Assert(strings.HasPrefix(f.Filename(), s.Fs.Join("foo", "bar")), Equals, true) -} - -func (s *FilesystemSuite) TestOpenAndWrite(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - foo, err := s.Fs.Open("foo") - c.Assert(foo, NotNil) - c.Assert(err, IsNil) - - n, err := foo.Write([]byte("foo")) - c.Assert(err, NotNil) - c.Assert(n, Equals, 0) -} - -func (s *FilesystemSuite) TestOpenAndStat(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - foo, err := s.Fs.Open("foo") - c.Assert(foo, NotNil) - c.Assert(foo.Filename(), Equals, "foo") - c.Assert(err, IsNil) - - stat, err := s.Fs.Stat("foo") - c.Assert(stat, NotNil) - c.Assert(err, IsNil) - c.Assert(stat.Name(), Equals, "foo") -} - -func (s *FilesystemSuite) TestRemove(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - err = s.Fs.Remove("foo") - c.Assert(err, IsNil) -} - -func (s *FilesystemSuite) TestRemoveNonExisting(c *C) { - c.Assert(s.Fs.Remove("NON-EXISTING"), NotNil) -} - -func (s *FilesystemSuite) TestRemoveTempFile(c *C) { - f, err := s.Fs.TempFile("test-dir", "test-prefix") - c.Assert(err, IsNil) - - fn := f.Filename() - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - c.Assert(s.Fs.Remove(fn), IsNil) -} - -func (s *FilesystemSuite) TestJoin(c *C) { - c.Assert(s.Fs.Join("foo", "bar"), Equals, "foo/bar") -} - -func (s *FilesystemSuite) TestBase(c *C) { - c.Assert(s.Fs.Base(), Not(Equals), "") -} - -func (s *FilesystemSuite) TestReadAtOnReadWrite(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - _, err = f.Write([]byte("abcdefg")) - c.Assert(err, IsNil) - rf, ok := f.(io.ReaderAt) - c.Assert(ok, Equals, true) - b := make([]byte, 3) - n, err := rf.ReadAt(b, 2) - c.Assert(err, IsNil) - c.Assert(n, Equals, 3) - c.Assert(string(b), Equals, "cde") - c.Assert(f.Close(), IsNil) -} - -func (s *FilesystemSuite) TestReadAtOnReadOnly(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - _, err = f.Write([]byte("abcdefg")) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - f, err = s.Fs.Open("foo") - c.Assert(err, IsNil) - rf, ok := f.(io.ReaderAt) - c.Assert(ok, Equals, true) - b := make([]byte, 3) - n, err := rf.ReadAt(b, 2) - c.Assert(err, IsNil) - c.Assert(n, Equals, 3) - c.Assert(string(b), Equals, "cde") - c.Assert(f.Close(), IsNil) -} - -func (s *FilesystemSuite) TestReadWriteLargeFile(c *C) { - f, err := s.Fs.Create("foo") - c.Assert(err, IsNil) - - size := 1 << 20 - - n, err := f.Write(bytes.Repeat([]byte("F"), size)) - c.Assert(err, IsNil) - c.Assert(n, Equals, size) - - err = f.Close() - c.Assert(err, IsNil) - - f, err = s.Fs.Open("foo") - c.Assert(err, IsNil) - b, err := ioutil.ReadAll(f) - c.Assert(err, IsNil) - c.Assert(len(b), Equals, size) -} |