diff options
-rw-r--r-- | utils/fs/fs.go | 46 | ||||
-rw-r--r-- | utils/fs/os.go | 128 | ||||
-rw-r--r-- | utils/fs/os_test.go | 153 |
3 files changed, 178 insertions, 149 deletions
diff --git a/utils/fs/fs.go b/utils/fs/fs.go index cfab692..4c97340 100644 --- a/utils/fs/fs.go +++ b/utils/fs/fs.go @@ -2,21 +2,49 @@ package fs import ( + "errors" "io" "os" ) -// FS interface represent an abstracted filesystem, so you can -// use NewRepositoryFromFS from any medium. -type FS interface { - Stat(path string) (os.FileInfo, error) - Open(path string) (ReadSeekCloser, error) - ReadDir(path string) ([]os.FileInfo, error) +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) + Rename(from, to string) error + Stat(filename string) (FileInfo, error) + ReadDir(path string) ([]FileInfo, error) Join(elem ...string) string + Dir(path string) Filesystem + Base() string } -// ReadSeekCloser is a Reader, Seeker and Closer. -type ReadSeekCloser interface { - io.ReadCloser +type File interface { + Filename() string + io.Writer + io.Reader io.Seeker + io.Closer +} + +type FileInfo os.FileInfo + +type BaseFile struct { + filename string + closed bool +} + +//Filename returns the filename from the File +func (f *BaseFile) Filename() string { + return f.filename +} + +//IsClosed returns if te file is closed +func (f *BaseFile) IsClosed() bool { + return f.closed } diff --git a/utils/fs/os.go b/utils/fs/os.go index 37ad75a..40942ba 100644 --- a/utils/fs/os.go +++ b/utils/fs/os.go @@ -3,34 +3,130 @@ package fs import ( "io/ioutil" "os" + "path" "path/filepath" ) -// OS is a simple FS implementation for the current host filesystem. -type OS struct{} - // NewOS returns a new OS. -func NewOS() FS { - return &OS{} +func NewOS() Filesystem { + return &OSClient{} +} + +// OSClient a filesystem based on OSClient +type OSClient struct { + RootDir string +} + +// NewOSClient returns a new OSClient +func NewOSClient(rootDir string) *OSClient { + return &OSClient{ + RootDir: rootDir, + } } -// Stat returns the filesystem info for a path. -func (o *OS) Stat(path string) (os.FileInfo, error) { - return os.Stat(path) +// Create creates a new GlusterFSFile +func (c *OSClient) Create(filename string) (File, error) { + fullpath := path.Join(c.RootDir, filename) + + dir := filepath.Dir(fullpath) + if dir != "." { + if err := os.MkdirAll(dir, 0755); err != nil { + return nil, err + } + } + + f, err := os.Create(fullpath) + if err != nil { + return nil, err + } + + return &OSFile{ + BaseFile: BaseFile{filename: fullpath}, + file: f, + }, nil +} + +// ReadDir returns the filesystem info for all the archives under the specified +// path. +func (c *OSClient) ReadDir(path string) ([]FileInfo, error) { + fullpath := c.Join(c.RootDir, path) + + l, err := ioutil.ReadDir(fullpath) + if err != nil { + return nil, err + } + + var s = make([]FileInfo, len(l)) + for i, f := range l { + s[i] = f + } + + return s, nil +} + +func (c *OSClient) Rename(from, to string) error { + if !filepath.IsAbs(from) { + from = c.Join(c.RootDir, from) + } + + if !filepath.IsAbs(to) { + to = c.Join(c.RootDir, to) + } + + return os.Rename(from, to) } -// Open returns a ReadSeekCloser for the specified path. -func (o *OS) Open(path string) (ReadSeekCloser, error) { - return os.Open(path) +func (c *OSClient) Open(filename string) (File, error) { + fullpath := c.Join(c.RootDir, filename) + + f, err := os.Open(fullpath) + if err != nil { + return nil, err + } + + return &OSFile{ + BaseFile: BaseFile{filename: fullpath}, + file: f, + }, nil } -// ReadDir returns the filesystem info for all the archives under the -// specified path. -func (o *OS) ReadDir(path string) ([]os.FileInfo, error) { - return ioutil.ReadDir(path) +func (c *OSClient) Stat(filename string) (FileInfo, error) { + fullpath := c.Join(c.RootDir, filename) + return os.Stat(fullpath) } // Join joins the specified elements using the filesystem separator. -func (o *OS) Join(elem ...string) string { +func (c *OSClient) Join(elem ...string) string { return filepath.Join(elem...) } + +func (c *OSClient) Dir(path string) Filesystem { + return NewOSClient(c.Join(c.RootDir, path)) +} + +func (c *OSClient) Base() string { + return c.RootDir +} + +type OSFile struct { + file *os.File + BaseFile +} + +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.closed = true + + return f.file.Close() +} diff --git a/utils/fs/os_test.go b/utils/fs/os_test.go index b6c00c6..c148265 100644 --- a/utils/fs/os_test.go +++ b/utils/fs/os_test.go @@ -5,147 +5,52 @@ import ( "os" "testing" - "github.com/alcortesm/tgz" . "gopkg.in/check.v1" ) func Test(t *testing.T) { TestingT(t) } -type FSImplSuite struct { - dir string -} +type WritersSuite struct{} -var _ = Suite(&FSImplSuite{}) +var _ = Suite(&WritersSuite{}) -func (s *FSImplSuite) SetUpSuite(c *C) { - dir, err := tgz.Extract("../../storage/filesystem/internal/dotgit/fixtures/spinnaker-gc.tgz") - c.Assert(err, IsNil) - s.dir = dir -} +func (s *WritersSuite) TestOSClient_Create(c *C) { + path := getTempDir() + client := NewOSClient(path) -func (s *FSImplSuite) TearDownSuite(c *C) { - err := os.RemoveAll(s.dir) + f, err := client.Create("foo") c.Assert(err, IsNil) + c.Assert(f.(*OSFile).file.Name(), Equals, f.GetFilename()) } -func (s *FSImplSuite) TestJoin(c *C) { - fs := NewOS() - for i, test := range [...]struct { - input []string - expected string - }{ - { - input: []string{}, - expected: "", - }, { - input: []string{"a"}, - expected: "a", - }, { - input: []string{"a", "b"}, - expected: "a/b", - }, { - input: []string{"a", "b", "c"}, - expected: "a/b/c", - }, - } { - obtained := fs.Join(test.input...) - com := Commentf("test %d:\n\tinput = %v", i, test.input) - c.Assert(obtained, Equals, test.expected, com) - } -} - -func (s *FSImplSuite) TestStat(c *C) { - fs := NewOS() - for i, path := range [...]string{ - ".git/index", - ".git/info/refs", - ".git/objects/pack/pack-584416f86235cac0d54bfabbdc399fb2b09a5269.pack", - } { - path := fs.Join(s.dir, path) - com := Commentf("test %d", i) - - real, err := os.Open(path) - c.Assert(err, IsNil, com) - - expected, err := real.Stat() - c.Assert(err, IsNil, com) - - obtained, err := fs.Stat(path) - c.Assert(err, IsNil, com) - - c.Assert(obtained, DeepEquals, expected, com) +func (s *WritersSuite) TestOSClient_Write(c *C) { + path := getTempDir() + client := NewOSClient(path) - err = real.Close() - c.Assert(err, IsNil, com) - } -} + f, err := client.Create("foo") + c.Assert(err, IsNil) + l, err := f.Write([]byte("foo")) + c.Assert(l, Equals, 3) + c.Assert(err, IsNil) -func (s *FSImplSuite) TestStatErrors(c *C) { - fs := NewOS() - for i, test := range [...]struct { - input string - errRegExp string - }{ - { - input: "bla", - errRegExp: ".*bla: no such file or directory", - }, { - input: "bla/foo", - errRegExp: ".*bla/foo: no such file or directory", - }, - } { - com := Commentf("test %d", i) - _, err := fs.Stat(test.input) - c.Assert(err, ErrorMatches, test.errRegExp, com) - } + wrote, _ := ioutil.ReadFile(f.(*OSFile).file.Name()) + c.Assert(wrote, DeepEquals, []byte("foo")) } -func (s *FSImplSuite) TestOpen(c *C) { - fs := NewOS() - for i, test := range [...]string{ - ".git/index", - ".git/info/refs", - ".git/objects/pack/pack-584416f86235cac0d54bfabbdc399fb2b09a5269.pack", - } { - com := Commentf("test %d", i) - path := fs.Join(s.dir, test) - - real, err := os.Open(path) - c.Assert(err, IsNil, com) - realData, err := ioutil.ReadAll(real) - c.Assert(err, IsNil, com) - err = real.Close() - c.Assert(err, IsNil, com) +func (s *WritersSuite) TestOSClient_Close(c *C) { + path := getTempDir() + client := NewOSClient(path) - obtained, err := fs.Open(path) - c.Assert(err, IsNil, com) - obtainedData, err := ioutil.ReadAll(obtained) - c.Assert(err, IsNil, com) - err = obtained.Close() - c.Assert(err, IsNil, com) + f, err := client.Create("foo") + c.Assert(err, IsNil) + f.Write([]byte("foo")) + c.Assert(f.Close(), IsNil) - c.Assert(obtainedData, DeepEquals, realData, com) - } + wrote, _ := ioutil.ReadFile(f.GetFilename()) + c.Assert(wrote, DeepEquals, []byte("foo")) } -func (s *FSImplSuite) TestReadDir(c *C) { - fs := NewOS() - for i, test := range [...]string{ - ".git/info", - ".", - "", - ".git/objects", - ".git/objects/pack", - } { - com := Commentf("test %d", i) - path := fs.Join(s.dir, test) - - expected, err := ioutil.ReadDir(path) - c.Assert(err, IsNil, com) - - obtained, err := fs.ReadDir(path) - c.Assert(err, IsNil, com) - - c.Assert(obtained, DeepEquals, expected, com) - } +func getTempDir() string { + dir, _ := ioutil.TempDir(os.TempDir(), "--OSClientTest--") + return dir } |