directory tree walk w/ visitor per rsc's suggestion

R=rsc,r
DELTA=193  (191 added, 0 deleted, 2 changed)
OCL=35849
CL=35877
This commit is contained in:
Robert Griesemer 2009-10-19 11:48:04 -07:00
parent e32883df01
commit 4adad657de
3 changed files with 193 additions and 2 deletions

View file

@ -6,7 +6,11 @@
// slash-separated filename paths.
package path
import "strings"
import (
"io";
"os";
"strings";
)
// Clean returns the shortest path name equivalent to path
// by purely lexical processing. It applies the following rules
@ -132,3 +136,51 @@ func Ext(path string) string {
}
return "";
}
// Visitor methods are invoked for corresponding file tree entries
// visited by Walk. The parameter path is the full path of d relative
// to root.
type Visitor interface {
VisitDir(path string, d *os.Dir) bool;
VisitFile(path string, d *os.Dir);
}
func walk(path string, d *os.Dir, v Visitor, errors chan<- os.Error) {
if !d.IsDirectory() {
v.VisitFile(path, d);
return;
}
if !v.VisitDir(path, d) {
return; // skip directory entries
}
list, err := io.ReadDir(path);
if err != nil {
if errors != nil {
errors <- err;
}
}
for _, e := range list {
walk(Join(path, e.Name), e, v, errors);
}
}
// Walk walks the file tree rooted at root, calling v.VisitDir or
// v.VisitFile for each directory or file in the tree, including root.
// If v.VisitDir returns false, Walk skips the directory's entries;
// otherwise it invokes itself for each directory entry in sorted order.
// An error reading a directory does not abort the Walk.
// If errors != nil, Walk sends each directory read error
// to the channel. Otherwise Walk discards the error.
func Walk(root string, v Visitor, errors chan<- os.Error) {
d, err := os.Lstat(root);
if err != nil {
if errors != nil {
errors <- err;
}
return; // can't progress
}
walk(root, d, v, errors);
}