mirror of
https://github.com/DominicBreuker/pspy.git
synced 2025-12-21 11:44:51 +00:00
85 lines
1.3 KiB
Go
85 lines
1.3 KiB
Go
package walker
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
type Walker struct {
|
|
}
|
|
|
|
func NewWalker() *Walker {
|
|
return &Walker{}
|
|
}
|
|
|
|
type chans struct {
|
|
dirCh chan string
|
|
errCh chan error
|
|
doneCh chan struct{}
|
|
}
|
|
|
|
func newChans() *chans {
|
|
return &chans{
|
|
dirCh: make(chan string),
|
|
errCh: make(chan error),
|
|
doneCh: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
const maxInt = int(^uint(0) >> 1)
|
|
|
|
func (w *Walker) Walk(root string, depth int) (dirCh chan string, errCh chan error, doneCh chan struct{}) {
|
|
if depth < 0 {
|
|
depth = maxInt
|
|
}
|
|
c := newChans()
|
|
|
|
go func() {
|
|
defer close(dirCh)
|
|
descent(root, depth-1, c)
|
|
}()
|
|
return c.dirCh, c.errCh, c.doneCh
|
|
}
|
|
|
|
func descent(dir string, depth int, c *chans) {
|
|
if done := emitDir(dir, depth, c); done {
|
|
return
|
|
}
|
|
|
|
handleSubDirs(dir, depth, c)
|
|
}
|
|
|
|
func emitDir(dir string, depth int, c *chans) bool {
|
|
_, err := os.Stat(dir)
|
|
if err != nil {
|
|
c.errCh <- fmt.Errorf("visiting %s: %v", dir, err)
|
|
return true
|
|
}
|
|
select {
|
|
case c.dirCh <- dir:
|
|
case <-c.doneCh:
|
|
return true
|
|
}
|
|
if depth < 0 {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func handleSubDirs(dir string, depth int, c *chans) {
|
|
ls, err := ioutil.ReadDir(dir)
|
|
if err != nil {
|
|
c.errCh <- fmt.Errorf("opening dir %s: %v", dir, err)
|
|
}
|
|
|
|
for _, e := range ls {
|
|
if e.IsDir() {
|
|
newDir := filepath.Join(dir, e.Name())
|
|
descent(newDir, depth-1, c)
|
|
}
|
|
}
|
|
}
|