forked from mirror/afero
add Walk function similar to filepath.Walk, add test for Walk
This commit is contained in:
parent
582dcbe54c
commit
56c149609a
82
fs.go
82
fs.go
|
@ -26,6 +26,7 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
@ -119,6 +120,87 @@ func ReadDir(dirname string, fs Fs) ([]os.FileInfo, error) {
|
|||
return list, nil
|
||||
}
|
||||
|
||||
// readDirNames reads the directory named by dirname and returns
|
||||
// a sorted list of directory entries.
|
||||
// adapted from https://golang.org/src/path/filepath/path.go
|
||||
func readDirNames(dirname string, fs Fs) ([]string, error) {
|
||||
f, err := fs.Open(dirname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names, err := f.Readdirnames(-1)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// walk recursively descends path, calling walkFn
|
||||
// adapted from https://golang.org/src/path/filepath/path.go
|
||||
func walk(path string, info os.FileInfo, walkFn filepath.WalkFunc, fs Fs) error {
|
||||
err := walkFn(path, info, nil)
|
||||
if err != nil {
|
||||
if info.IsDir() && err == filepath.SkipDir {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
names, err := readDirNames(path, fs)
|
||||
if err != nil {
|
||||
return walkFn(path, info, err)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
filename := filepath.Join(path, name)
|
||||
fileInfo, err := lstatIfOs(filename, fs)
|
||||
if err != nil {
|
||||
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = walk(filename, fileInfo, walkFn, fs)
|
||||
if err != nil {
|
||||
if !fileInfo.IsDir() || err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the filesystem is OsFs use Lstat, else use fs.Stat
|
||||
func lstatIfOs(path string, fs Fs) (info os.FileInfo, err error) {
|
||||
_, ok := fs.(*OsFs)
|
||||
if ok {
|
||||
info, err = os.Lstat(path)
|
||||
} else {
|
||||
info, err = fs.Stat(path)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Walk walks the file tree rooted at root, calling walkFn for each file or
|
||||
// directory in the tree, including root. All errors that arise visiting files
|
||||
// and directories are filtered by walkFn. The files are walked in lexical
|
||||
// order, which makes the output deterministic but means that for very
|
||||
// large directories Walk can be inefficient.
|
||||
// Walk does not follow symbolic links.
|
||||
func Walk(root string, walkFn filepath.WalkFunc, fs Fs) error {
|
||||
info, err := lstatIfOs(root, fs)
|
||||
if err != nil {
|
||||
return walkFn(root, nil, err)
|
||||
}
|
||||
return walk(root, info, walkFn, fs)
|
||||
}
|
||||
|
||||
// byName implements sort.Interface.
|
||||
type byName []os.FileInfo
|
||||
|
||||
|
|
44
fs_test.go
44
fs_test.go
|
@ -28,14 +28,6 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
var dot = []string{
|
||||
"fs.go",
|
||||
"fs_test.go",
|
||||
"httpFs.go",
|
||||
"memfile.go",
|
||||
"memmap.go",
|
||||
}
|
||||
|
||||
var testDir = "/tmp/afero"
|
||||
var testSubDir = "/tmp/afero/we/have/to/go/deeper"
|
||||
var testName = "test.txt"
|
||||
|
@ -450,6 +442,42 @@ func (m myFileInfo) String() string {
|
|||
return out
|
||||
}
|
||||
|
||||
func TestWalk(t *testing.T) {
|
||||
outputs := make([]string, len(Fss))
|
||||
for i, fs := range Fss {
|
||||
walkFn := func(path string, info os.FileInfo, err error) error {
|
||||
var size int64
|
||||
if !info.IsDir() {
|
||||
size = info.Size()
|
||||
}
|
||||
outputs[i] += fmt.Sprintln(path, info.Name(), size, info.IsDir(), err)
|
||||
return nil
|
||||
}
|
||||
err := Walk(testDir, walkFn, fs)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
fail := false
|
||||
for i, o := range outputs {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
if o != outputs[i-1] {
|
||||
fail = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if fail {
|
||||
t.Log("Walk outputs not equal!")
|
||||
for i, o := range outputs {
|
||||
t.Log(Fss[i].Name())
|
||||
t.Log(o)
|
||||
}
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestReaddirAll(t *testing.T) {
|
||||
defer removeTestDir(t)
|
||||
for _, fs := range Fss {
|
||||
|
|
Loading…
Reference in New Issue