package resolver import ( "cliprepo/internal/tree" "os" "path/filepath" ) type Resolver struct { root string seen map[string]struct{} } func New(root string) *Resolver { return &Resolver{ root: root, seen: make(map[string]struct{}), } } // WalkAll 遍历所有文件,并自动跳过 .git 和 .gitignore 中的文件 func (r *Resolver) WalkAll() ([]string, error) { var result []string ig, _ := tree.Load(r.root) err := filepath.Walk(r.root, func(path string, info os.FileInfo, err error) error { if err != nil { return nil } // 显式跳过 .git 目录 if info.IsDir() && info.Name() == ".git" { return filepath.SkipDir } rel, _ := filepath.Rel(r.root, path) // 遵循 .gitignore 规则 if ig != nil && ig.MatchesPath(rel) { if info.IsDir() { return filepath.SkipDir } return nil } if info.IsDir() { return nil } r.add(rel, &result) return nil }) return result, err } func (r *Resolver) AddFile(path string, result *[]string) { r.add(path, result) } func (r *Resolver) add(path string, result *[]string) { if _, ok := r.seen[path]; ok { return } r.seen[path] = struct{}{} *result = append(*result, path) } // Unique 保留此方法供 run.go 调用 func (r *Resolver) Unique(in []string) []string { seen := make(map[string]struct{}) out := make([]string, 0, len(in)) for _, f := range in { if _, ok := seen[f]; ok { continue } seen[f] = struct{}{} out = append(out, f) } return out }