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 }