add pkg to handle walking a directory structure
This commit is contained in:
parent
432a9472fe
commit
eab06e2f6c
80
internal/fs/fs.go
Normal file
80
internal/fs/fs.go
Normal file
@ -0,0 +1,80 @@
|
||||
// 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
|
||||
}
|
||||
|
46
internal/fs/fs_test.go
Normal file
46
internal/fs/fs_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"os"
|
||||
"log/slog"
|
||||
"decl/tests/tempdir"
|
||||
_ "path/filepath"
|
||||
)
|
||||
|
||||
var TempDir tempdir.Path = "testfswalkdir"
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
err := TempDir.Create()
|
||||
if err != nil || TempDir == "" {
|
||||
slog.Error("Failed creating temp dir", "error", err)
|
||||
}
|
||||
|
||||
rc := m.Run()
|
||||
|
||||
TempDir.Remove()
|
||||
os.Exit(rc)
|
||||
}
|
||||
|
||||
func TestNewWalkDir(t *testing.T) {
|
||||
expected := []string { "bar", "foo.txt" }
|
||||
assert.Nil(t, TempDir.CreateFile("foo.txt", "testdata"))
|
||||
assert.Nil(t, TempDir.Mkdir("bar", 0700))
|
||||
|
||||
fileSystem := TempDir.DirFS()
|
||||
i := 0
|
||||
d := NewWalkDir(fileSystem, string(TempDir), func(fsys FS, path string, entry DirEntry) (err error) {
|
||||
slog.Info("TestWalkDir()", "path", path, "entry", entry)
|
||||
assert.Equal(t, expected[i], entry.Name())
|
||||
i++
|
||||
return nil
|
||||
})
|
||||
assert.NotNil(t, d)
|
||||
assert.Nil(t, d.Walk(nil))
|
||||
}
|
||||
|
||||
func TestWalk(t *testing.T) {
|
||||
}
|
Loading…
Reference in New Issue
Block a user