Skip to content

Add Walk function. #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions walk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package vfs

import (
"os"
"path/filepath"
"sort"
"strings"
)

// Walk walks the file tree rooted at root, calling walkFunc 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(fs Filesystem, root string, walkFunc filepath.WalkFunc) error {
info, err := fs.Lstat(root)
if err != nil {
err = walkFunc(root, nil, err)
} else {
err = walk(fs, root, info, walkFunc)
}
if err == filepath.SkipDir {
return nil
}
return err
}

// readDirNames reads the directory named by dirname and returns
// a sorted list of directory entries.
func readDirNames(fs Filesystem, dirname string) ([]string, error) {
infos, err := fs.ReadDir(dirname)
if err != nil {
return nil, err
}
names := make([]string, 0, len(infos))
for _, info := range infos {
names = append(names, info.Name())
}
sort.Strings(names)
return names, nil
}

// walk recursively descends path, calling walkFunc.
func walk(fs Filesystem, path string, info os.FileInfo, walkFunc filepath.WalkFunc) error {
if !info.IsDir() {
return walkFunc(path, info, nil)
}

names, err := readDirNames(fs, path)
err1 := walkFunc(path, info, err)
// If err != nil, walk can't walk into this directory.
// err1 != nil means walkFn want walk to skip this directory or stop walking.
// Therefore, if one of err and err1 isn't nil, walk will return.
if err != nil || err1 != nil {
// The caller's behavior is controlled by the return value, which is decided
// by walkFn. walkFn may ignore err and return nil.
// If walkFn returns SkipDir, it will be handled by the caller.
// So walk should return whatever walkFn returns.
return err1
}

for _, name := range names {
filename := strings.Join([]string{path, name}, string(fs.PathSeparator()))
fileInfo, err := fs.Lstat(filename)
if err != nil {
if err := walkFunc(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
return err
}
} else {
err = walk(fs, filename, fileInfo, walkFunc)
if err != nil {
if !fileInfo.IsDir() || err != filepath.SkipDir {
return err
}
}
}
}
return nil
}
Loading