github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/os/fsi/common/walk.go (about) 1 // Package common - contains convenience functions, 2 // built on top of fsi interfaces; 3 // thus independent of implementations. 4 // Sadly we cannot attach methods to interfaces. 5 // Generic filesystem utils should be implemented here. 6 // find, compact, export ... 7 package common 8 9 import ( 10 "errors" 11 "os" 12 pth "path" 13 14 "github.com/pbberlin/tools/os/fsi" 15 ) 16 17 // SkipDir is an "error", which a walk-function can 18 // return, in order to signal, that walk should not traverse into this dir. 19 var SkipDir = errors.New("skip this directory") 20 21 type WalkFunc func(path string, info os.FileInfo, err error) error 22 23 var cntr = 0 24 25 // walk recursively descends path, calling walkFn. 26 func walk(fs fsi.FileSystem, path string, info os.FileInfo, walkFn WalkFunc) error { 27 28 // cntr++ 29 // if cntr > 20 { 30 // return fmt.Errorf("too many recursions") 31 // } 32 33 err := walkFn(path, info, nil) 34 if err != nil { 35 if info.IsDir() && err == SkipDir { 36 return nil 37 } 38 return err 39 } 40 41 if !info.IsDir() { 42 return nil 43 } 44 45 fis, err := fs.ReadDir(path) 46 // fnd := "" 47 // for i := 0; i < len(fis); i++ { 48 // fnd += fis[i].Name() + ", " 49 // } 50 // log.Printf("readdir of %-26v => %v, %v", path, len(fis), fnd) 51 if err != nil && err != fsi.EmptyQueryResult { 52 return walkFn(path, info, err) 53 } 54 55 // 56 for _, fi := range fis { 57 filename := pth.Join(path, pth.Base(fi.Name())) 58 59 fileInfo, err := fs.Lstat(filename) 60 if err != nil { 61 if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir { 62 return err 63 } 64 } else { 65 err = walk(fs, filename, fileInfo, walkFn) 66 if err != nil { 67 if !fileInfo.IsDir() || err != SkipDir { 68 return err 69 } 70 } 71 } 72 } 73 return nil 74 } 75 76 // Walk walks the file tree rooted at root, calling walkFn for each file or 77 // directory in the tree, including root. 78 // 79 // It requires only the fsi.FileSystem interface, and is therefore implementation independent. 80 // 81 // It is similar to filepath.Walk(root string, walkFunc) 82 // 83 // Directories are crawled in order of fs.ReadDir() 84 // Walk crawls directories first, files second. 85 // 86 // Errors that arise visiting directories can be filtered by walkFn. 87 // 88 // Walk does not follow symbolic links. 89 func Walk(fs fsi.FileSystem, root string, walkFn WalkFunc) error { 90 info, err := fs.Lstat(root) 91 if err != nil { 92 // log.Printf("walk start error %10v %v", root, err) 93 return walkFn(root, nil, err) 94 } 95 // log.Printf("walk start fnd %v", info.Name()) 96 return walk(fs, root, info, walkFn) 97 }