feat: apply ignores from .gitignore/.ignore files
1 file changed, 122 insertions(+), 0 deletions(-)
changed files
A ignore/ignore.go
@@ -0,0 +1,122 @@ +package ignore + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + "slices" + "strings" + + ignore "github.com/sabhiram/go-gitignore" + + "alin.ovh/erl/repository" +) + +var DefaultIgnoreFilename = ".ignore" + +type Filter struct { + repo *repository.Repo + projectRoot string + wd string + + givenPaths []string + paths []string + ignores []*Ignore +} + +type Ignore struct { + *ignore.GitIgnore + + filename string +} + +func New(wd string, path ...string) *Filter { + return &Filter{ + wd: wd, + givenPaths: path, + } +} + +func (f *Filter) ReadIgnoreFiles(ctx context.Context) error { + if f.projectRoot == "" { + repo, err := repository.GetRepo(ctx, f.wd) + if err != nil { + return err + } + + f.repo = repo + f.projectRoot = repo.GetRoot() + } + + err := f.getPaths() + if err != nil { + return err + } + + f.ignores = []*Ignore{} + for _, path := range f.paths { + ig, err := ignore.CompileIgnoreFile(path) + if err != nil { + return err + } + + f.ignores = append(f.ignores, &Ignore{ + GitIgnore: ig, + filename: path, + }) + } + + return nil +} + +func (f *Filter) Ignored(path string) bool { + return slices.ContainsFunc(f.ignores, func(ig *Ignore) bool { + return ig.MatchesPath(path) + }) +} + +func (f *Filter) getPaths() error { + f.paths = f.givenPaths + + rel, err := filepath.Rel(f.projectRoot, f.wd) + if err != nil { + return err + } + + ignoreFileNames := []string{DefaultIgnoreFilename} + ignoreFileNames = append(ignoreFileNames, f.repo.GetIgnoreFileNames()...) + dirs := strings.Split(rel, string(filepath.Separator)) + for i := range dirs { + var dir string + if i == 0 { + dir = "." + } else { + dir = filepath.Join(dirs[:i+1]...) + } + + for _, basename := range ignoreFileNames { + filename := filepath.Join(f.projectRoot, dir, basename) + stat, err := os.Stat(filename) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + continue + } + + return err + } + if stat.IsDir() { + return fmt.Errorf( + "%s path is a directory: %s", + basename, + filepath.Join(f.projectRoot, dir, filename), + ) + } + + f.paths = append(f.paths, filename) + } + } + + return nil +}