Files
go-task/internal/fingerprint/gitignore.go
Valentin Maerten 13ef1b2dda wip
2026-06-07 15:02:55 +02:00

93 lines
1.8 KiB
Go

package fingerprint
import (
"bufio"
"os"
"path/filepath"
"strings"
ignore "github.com/sabhiram/go-gitignore"
)
type gitignoreRule struct {
dir string
matcher *ignore.GitIgnore
}
// loadGitignoreRules walks up from dir collecting .gitignore files.
// Stops at the first .git (file or directory) found.
// Returns nil if no .git is found (not in a git repo).
func loadGitignoreRules(dir string) []gitignoreRule {
dir, _ = filepath.Abs(dir)
var rules []gitignoreRule
foundGit := false
current := dir
for {
lines := readGitignoreLines(filepath.Join(current, ".gitignore"))
if len(lines) > 0 {
rules = append(rules, gitignoreRule{
dir: current,
matcher: ignore.CompileIgnoreLines(lines...),
})
}
if _, err := os.Stat(filepath.Join(current, ".git")); err == nil {
foundGit = true
break
}
parent := filepath.Dir(current)
if parent == current {
break
}
current = parent
}
if !foundGit {
return nil
}
return rules
}
func readGitignoreLines(path string) []string {
f, err := os.Open(path)
if err != nil {
return nil
}
defer f.Close()
var lines []string
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if line != "" && !strings.HasPrefix(line, "#") {
lines = append(lines, line)
}
}
return lines
}
// filterGitignored removes entries from the file map that match gitignore rules.
func filterGitignored(files map[string]bool, dir string) map[string]bool {
rules := loadGitignoreRules(dir)
if len(rules) == 0 {
return files
}
for path := range files {
for _, rule := range rules {
relPath, err := filepath.Rel(rule.dir, path)
if err != nil || strings.HasPrefix(relPath, "..") {
continue
}
if rule.matcher.MatchesPath(filepath.ToSlash(relPath)) {
files[path] = false
break
}
}
}
return files
}