Skip to content

Commit 290d167

Browse files
authored
Merge pull request #7 from LandonTClipp/file
Adding pathlib.File
2 parents 355b6fe + acf3d82 commit 290d167

File tree

3 files changed

+110
-7
lines changed

3 files changed

+110
-7
lines changed

file.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package pathlib
2+
3+
import "github.com/spf13/afero"
4+
5+
// File represents a file in the filesystem. It inherits the afero.File interface
6+
// but might also include additional functionality.
7+
type File struct {
8+
afero.File
9+
}

path.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,21 @@ func (p *Path) MkdirAll(perm os.FileMode) error {
9090
return p.Fs().MkdirAll(p.Path(), perm)
9191
}
9292

93-
// Open opens a file, returning it or an error, if any happens.
94-
func (p *Path) Open() (afero.File, error) {
95-
return p.Fs().Open(p.Path())
93+
// Open opens a file for read-only, returning it or an error, if any happens.
94+
func (p *Path) Open() (*File, error) {
95+
handle, err := p.Fs().Open(p.Path())
96+
return &File{
97+
File: handle,
98+
}, err
9699
}
97100

98101
// OpenFile opens a file using the given flags and the given mode.
99-
func (p *Path) OpenFile(flag int, perm os.FileMode) (afero.File, error) {
100-
return p.Fs().OpenFile(p.Path(), flag, perm)
102+
// See the list of flags at: https://golang.org/pkg/os/#pkg-constants
103+
func (p *Path) OpenFile(flag int, perm os.FileMode) (*File, error) {
104+
handle, err := p.Fs().OpenFile(p.Path(), flag, perm)
105+
return &File{
106+
File: handle,
107+
}, err
101108
}
102109

103110
// Remove removes a file, returning an error, if any
@@ -342,9 +349,16 @@ func (p *Path) IsFile() (bool, error) {
342349
}
343350

344351
// IsSymlink returns true if the given path is a symlink.
352+
// Fails if the filesystem doesn't implement afero.Lstater.
345353
func (p *Path) IsSymlink() (bool, error) {
346-
fileInfo, err := p.Fs().Stat(p.Path())
347-
if err != nil {
354+
lStater, ok := p.Fs().(afero.Lstater)
355+
if !ok {
356+
return false, p.doesNotImplementErr("afero.Lstater")
357+
}
358+
fileInfo, lstatCalled, err := lStater.LstatIfPossible(p.Path())
359+
if err != nil || !lstatCalled {
360+
// If lstat wasn't called then the filesystem doesn't implement it.
361+
// Thus, it isn't a symlink
348362
return false, err
349363
}
350364

path_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package pathlib
22

33
import (
4+
"errors"
45
"fmt"
6+
"io"
57
"io/ioutil"
68
"os"
79
"path/filepath"
@@ -21,6 +23,9 @@ type PathSuite struct {
2123
}
2224

2325
func (p *PathSuite) SetupTest() {
26+
// We actually can't use the MemMapFs because some of the tests
27+
// are testing symlink behavior. We might want to split these
28+
// tests out to use MemMapFs when possible.
2429
tmpdir, err := ioutil.TempDir("", "")
2530
require.NoError(p.T(), err)
2631
p.tmpdir = NewPath(tmpdir)
@@ -150,6 +155,81 @@ func (p *PathSuite) TestGetLatestEmpty() {
150155
assert.Nil(p.T(), latest)
151156
}
152157

158+
func (p *PathSuite) TestOpen() {
159+
msg := "cubs > cardinals"
160+
file := p.tmpdir.Join("file.txt")
161+
require.NoError(p.T(), file.WriteFile([]byte(msg), 0o644))
162+
fileHandle, err := file.Open()
163+
require.NoError(p.T(), err)
164+
165+
readBytes := make([]byte, len(msg)+5)
166+
n, err := fileHandle.Read(readBytes)
167+
p.Equal(len(msg), n)
168+
p.Equal(msg, string(readBytes[0:n]))
169+
}
170+
171+
func (p *PathSuite) TestOpenFile() {
172+
file := p.tmpdir.Join("file.txt")
173+
fileHandle, err := file.OpenFile(os.O_RDWR|os.O_CREATE, 0o644)
174+
require.NoError(p.T(), err)
175+
176+
msg := "do you play croquet?"
177+
n, err := fileHandle.WriteString(msg)
178+
p.Equal(len(msg), n)
179+
p.NoError(err)
180+
181+
bytes := make([]byte, len(msg)+5)
182+
n, err = fileHandle.ReadAt(bytes, 0)
183+
p.Equal(len(msg), n)
184+
p.True(errors.Is(err, io.EOF))
185+
p.Equal(msg, string(bytes[0:n]))
186+
}
187+
188+
func (p *PathSuite) TestDirExists() {
189+
dir1 := p.tmpdir.Join("subdir")
190+
exists, err := dir1.DirExists()
191+
require.NoError(p.T(), err)
192+
p.False(exists)
193+
194+
require.NoError(p.T(), dir1.Mkdir(0o755))
195+
exists, err = dir1.DirExists()
196+
require.NoError(p.T(), err)
197+
p.True(exists)
198+
}
199+
200+
func (p *PathSuite) TestIsFile() {
201+
file1 := p.tmpdir.Join("file.txt")
202+
203+
require.NoError(p.T(), file1.WriteFile([]byte(""), 0o644))
204+
exists, err := file1.IsFile()
205+
require.NoError(p.T(), err)
206+
p.True(exists)
207+
}
208+
209+
func (p *PathSuite) TestIsEmpty() {
210+
file1 := p.tmpdir.Join("file.txt")
211+
212+
require.NoError(p.T(), file1.WriteFile([]byte(""), 0o644))
213+
isEmpty, err := file1.IsEmpty()
214+
require.NoError(p.T(), err)
215+
p.True(isEmpty)
216+
}
217+
218+
func (p *PathSuite) TestIsSymlink() {
219+
file1 := p.tmpdir.Join("file.txt")
220+
require.NoError(p.T(), file1.WriteFile([]byte(""), 0o644))
221+
222+
symlink := p.tmpdir.Join("symlink")
223+
p.NoError(symlink.Symlink(file1))
224+
isSymlink, err := symlink.IsSymlink()
225+
require.NoError(p.T(), err)
226+
p.True(isSymlink)
227+
228+
stat, _ := symlink.Stat()
229+
p.T().Logf("%v", stat.Mode())
230+
p.T().Logf(symlink.Path())
231+
}
232+
153233
func TestPathSuite(t *testing.T) {
154234
suite.Run(t, new(PathSuite))
155235
}

0 commit comments

Comments
 (0)