132 lines
2.5 KiB
Go
132 lines
2.5 KiB
Go
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{}),
|
|
}
|
|
}
|
|
|
|
// ResolvePattern 智能解析各种 pattern 并过滤 ignore 文件
|
|
func (r *Resolver) ResolvePattern(pattern string) ([]string, error) {
|
|
if pattern == "*" {
|
|
return r.WalkAll()
|
|
}
|
|
|
|
var matches []string
|
|
// 处理类似 cmd/* 或 internal/tree/* 的情况
|
|
// 如果包含 * 且不是以 ** 开头,转换为通过 filepath.Walk 匹配或直接 Glob 过滤
|
|
rawMatches, err := filepath.Glob(pattern)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ig, _ := tree.Load(r.root)
|
|
|
|
for _, m := range rawMatches {
|
|
info, err := os.Stat(m)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
rel, _ := filepath.Rel(r.root, m)
|
|
// 统一检查 .gitignore
|
|
if ig != nil && ig.MatchesPath(rel) {
|
|
continue
|
|
}
|
|
|
|
if info.IsDir() {
|
|
// 如果匹配到的是目录(比如 internal/* 匹配到了 internal/config),则深层遍历该目录
|
|
err := filepath.Walk(m, func(path string, fInfo os.FileInfo, walkErr error) error {
|
|
if walkErr != nil || fInfo.IsDir() {
|
|
return nil
|
|
}
|
|
fRel, _ := filepath.Rel(r.root, path)
|
|
if ig != nil && ig.MatchesPath(fRel) {
|
|
return nil
|
|
}
|
|
r.add(fRel, &matches)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
r.add(rel, &matches)
|
|
}
|
|
}
|
|
|
|
return matches, nil
|
|
}
|
|
|
|
// WalkAll 遍历全库并过滤
|
|
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
|
|
}
|
|
|
|
if info.IsDir() && info.Name() == ".git" {
|
|
return filepath.SkipDir
|
|
}
|
|
|
|
rel, _ := filepath.Rel(r.root, path)
|
|
|
|
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)
|
|
}
|
|
|
|
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
|
|
} |