Files
dirmd/internal/walker/walker.go
T

124 lines
2.2 KiB
Go

package walker
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"dirmd/internal/config"
"dirmd/internal/filter"
)
type Entry struct {
RelPath string
Size int64
}
type Result struct {
Entries []Entry
AbsRoot string
SingleFile bool
}
func Run(cfg *config.Config) (*Result, error) {
if cfg.SingleFile {
return processSingleFile(cfg)
}
return walkDirectory(cfg)
}
func processSingleFile(cfg *config.Config) (*Result, error) {
info, err := os.Stat(cfg.AbsRoot)
if err != nil {
return nil, fmt.Errorf("cannot access %s: %w", cfg.AbsRoot, err)
}
if info.IsDir() {
return walkDirectory(cfg)
}
flt := &filter.Filter{
MaxSize: cfg.MaxSize,
Extensions: cfg.Extensions,
Ignores: cfg.Ignores,
}
if flt.ShouldSkipFile(cfg.AbsRoot, filepath.Base(cfg.AbsRoot), info) {
return nil, fmt.Errorf("file %s filtered out", cfg.AbsRoot)
}
return &Result{
Entries: []Entry{{RelPath: filepath.Base(cfg.AbsRoot), Size: info.Size()}},
AbsRoot: filepath.Dir(cfg.AbsRoot),
SingleFile: true,
}, nil
}
func walkDirectory(cfg *config.Config) (*Result, error) {
flt := &filter.Filter{
MaxSize: cfg.MaxSize,
Extensions: cfg.Extensions,
Ignores: cfg.Ignores,
}
result := &Result{AbsRoot: cfg.AbsRoot}
err := filepath.WalkDir(cfg.AbsRoot, func(path string, d fs.DirEntry, err error) error {
if err != nil {
fmt.Fprintf(os.Stderr, "warning: %v\n", err)
return nil
}
rel, err := filepath.Rel(cfg.AbsRoot, path)
if err != nil {
return nil
}
depth := strings.Count(rel, string(filepath.Separator))
if rel != "." {
depth++
}
if depth > cfg.MaxDepth {
if d.IsDir() {
return filepath.SkipDir
}
return nil
}
if filter.IsSymlink(path) {
if d.IsDir() {
return filepath.SkipDir
}
return nil
}
base := filepath.Base(path)
if d.IsDir() {
if rel != "." && flt.ShouldSkipDir(base) {
return filepath.SkipDir
}
return nil
}
info, err := d.Info()
if err != nil {
fmt.Fprintf(os.Stderr, "warning: cannot stat %s: %v\n", rel, err)
return nil
}
if flt.ShouldSkipFile(path, base, info) {
return nil
}
result.Entries = append(result.Entries, Entry{RelPath: rel, Size: info.Size()})
return nil
})
return result, err
}