81 lines
2.0 KiB
Go
81 lines
2.0 KiB
Go
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
|
|
|
package fs
|
|
|
|
import (
|
|
"io/fs"
|
|
"log/slog"
|
|
"path/filepath"
|
|
"fmt"
|
|
)
|
|
|
|
type DirEntry fs.DirEntry
|
|
type FS fs.FS
|
|
type Selector[Item comparable] func(r Item) bool
|
|
|
|
type WalkFunc func(fsys FS, path string, file DirEntry) (err error)
|
|
|
|
type WalkDir struct {
|
|
root *WorkingDir
|
|
subDirsStack []*WorkingDir `yaml:"-" json:"-"`
|
|
fn WalkFunc
|
|
}
|
|
|
|
type WorkingDir struct {
|
|
path string
|
|
fsys FS
|
|
}
|
|
|
|
func NewWalkDir(fsys FS, path string, fn WalkFunc) *WalkDir {
|
|
w := &WalkDir{
|
|
subDirsStack: make([]*WorkingDir, 0, 100),
|
|
fn: fn,
|
|
}
|
|
|
|
w.root = &WorkingDir{ path: path, fsys: fsys }
|
|
w.subDirsStack = append(w.subDirsStack, w.root)
|
|
return w
|
|
}
|
|
|
|
func (w *WalkDir) WalkDirectory(fsys FS, path string, filter Selector[DirEntry]) (err error) {
|
|
var files []fs.DirEntry
|
|
|
|
if files, err = fs.ReadDir(fsys, "."); err == nil {
|
|
for _,file := range files {
|
|
if filter != nil && filter(file) {
|
|
continue
|
|
}
|
|
slog.Info("fs.WalkDir.WalkDirectory()", "file", file, "path", path, "file", file.Name())
|
|
entryPath := filepath.Join(path, file.Name())
|
|
if err = w.fn(fsys, entryPath, file); err != nil {
|
|
slog.Info("fs.WalkDir.WalkDirectory() ERROR", "file", entryPath, "error", err)
|
|
return
|
|
}
|
|
if file.IsDir() {
|
|
var dir FS
|
|
if dir, err = fs.Sub(fsys, file.Name()); err != nil {
|
|
slog.Info("fs.WalkDir.WalkDirectory() SubDir ERROR", "dir", dir, "error", err)
|
|
return
|
|
} else {
|
|
w.subDirsStack = append(w.subDirsStack, &WorkingDir{ path: entryPath, fsys: dir })
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
err = fmt.Errorf("fs.ReadDir failed on path %s: %w", path, err)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w *WalkDir) Walk(filter Selector[DirEntry]) (err error) {
|
|
for len(w.subDirsStack) != 0 {
|
|
var dirPath *WorkingDir
|
|
dirPath, w.subDirsStack = w.subDirsStack[len(w.subDirsStack) - 1], w.subDirsStack[:len(w.subDirsStack) - 1]
|
|
if err = w.WalkDirectory(dirPath.fsys, dirPath.path, filter); err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|