Files
renamer/internal/sequence/traversal.go

93 lines
1.9 KiB
Go

package sequence
import (
"context"
"errors"
"io/fs"
"path/filepath"
"strings"
"github.com/rogeecn/renamer/internal/traversal"
)
type traversalCandidate struct {
RelativePath string
AbsolutePath string
Stem string
Extension string
IsDir bool
Depth int
}
func collectTraversalCandidates(ctx context.Context, opts Options) ([]traversalCandidate, error) {
if opts.WorkingDir == "" {
return nil, errors.New("working directory must be provided")
}
absRoot, err := filepath.Abs(opts.WorkingDir)
if err != nil {
return nil, err
}
walker := traversal.NewWalker()
allowedExts := make(map[string]struct{}, len(opts.Extensions))
for _, ext := range opts.Extensions {
lower := strings.ToLower(ext)
allowedExts[lower] = struct{}{}
}
candidates := make([]traversalCandidate, 0)
emit := func(relPath string, entry fs.DirEntry, depth int) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
// Skip the root placeholder emitted by the walker when include dirs is true.
if relPath == "." {
return nil
}
relSlash := filepath.ToSlash(relPath)
absolute := filepath.Join(absRoot, relPath)
candidate := traversalCandidate{
RelativePath: relSlash,
AbsolutePath: absolute,
IsDir: entry.IsDir(),
Depth: depth,
}
if !entry.IsDir() {
rawExt := filepath.Ext(entry.Name())
lowerExt := strings.ToLower(rawExt)
if len(allowedExts) > 0 {
if _, ok := allowedExts[lowerExt]; !ok {
return nil
}
}
candidate.Extension = rawExt
stem := entry.Name()
if rawExt != "" {
stem = strings.TrimSuffix(stem, rawExt)
}
candidate.Stem = stem
} else {
candidate.Stem = entry.Name()
}
candidates = append(candidates, candidate)
return nil
}
err = walker.Walk(absRoot, opts.Recursive, opts.IncludeDirectories, opts.IncludeHidden, 0, emit)
if err != nil {
return nil, err
}
return candidates, nil
}