Skip to content

Commit 1298929

Browse files
committed
Add Walk function and tests for it.
1 parent 2c3e227 commit 1298929

File tree

2 files changed

+401
-0
lines changed

2 files changed

+401
-0
lines changed

walk.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package vfs
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"sort"
7+
"strings"
8+
)
9+
10+
// Walk walks the file tree rooted at root, calling walkFunc for each file or
11+
// directory in the tree, including root. All errors that arise visiting files
12+
// and directories are filtered by walkFn. The files are walked in lexical
13+
// order, which makes the output deterministic but means that for very
14+
// large directories Walk can be inefficient.
15+
// Walk does not follow symbolic links.
16+
func Walk(fs Filesystem, root string, walkFunc filepath.WalkFunc) error {
17+
info, err := fs.Lstat(root)
18+
if err != nil {
19+
err = walkFunc(root, nil, err)
20+
} else {
21+
err = walk(fs, root, info, walkFunc)
22+
}
23+
if err == filepath.SkipDir {
24+
return nil
25+
}
26+
return err
27+
}
28+
29+
// readDirNames reads the directory named by dirname and returns
30+
// a sorted list of directory entries.
31+
func readDirNames(fs Filesystem, dirname string) ([]string, error) {
32+
infos, err := fs.ReadDir(dirname)
33+
if err != nil {
34+
return nil, err
35+
}
36+
names := make([]string, 0, len(infos))
37+
for _, info := range infos {
38+
names = append(names, info.Name())
39+
}
40+
sort.Strings(names)
41+
return names, nil
42+
}
43+
44+
// walk recursively descends path, calling walkFunc.
45+
func walk(fs Filesystem, path string, info os.FileInfo, walkFunc filepath.WalkFunc) error {
46+
if !info.IsDir() {
47+
return walkFunc(path, info, nil)
48+
}
49+
50+
names, err := readDirNames(fs, path)
51+
err1 := walkFunc(path, info, err)
52+
// If err != nil, walk can't walk into this directory.
53+
// err1 != nil means walkFn want walk to skip this directory or stop walking.
54+
// Therefore, if one of err and err1 isn't nil, walk will return.
55+
if err != nil || err1 != nil {
56+
// The caller's behavior is controlled by the return value, which is decided
57+
// by walkFn. walkFn may ignore err and return nil.
58+
// If walkFn returns SkipDir, it will be handled by the caller.
59+
// So walk should return whatever walkFn returns.
60+
return err1
61+
}
62+
63+
for _, name := range names {
64+
filename := strings.Join([]string{path, name}, string(fs.PathSeparator()))
65+
fileInfo, err := fs.Lstat(filename)
66+
if err != nil {
67+
if err := walkFunc(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
68+
return err
69+
}
70+
} else {
71+
err = walk(fs, filename, fileInfo, walkFunc)
72+
if err != nil {
73+
if !fileInfo.IsDir() || err != filepath.SkipDir {
74+
return err
75+
}
76+
}
77+
}
78+
}
79+
return nil
80+
}

0 commit comments

Comments
 (0)