databricks-cli/libs/git/ignore.go

112 lines
2.5 KiB
Go

package git
import (
"os"
"time"
ignore "github.com/sabhiram/go-gitignore"
)
// ignoreRules implements the interface for a gitignore-like file.
// It is backed by implementations for a file at a specific path (it may not exist)
// and an implementation for a set of in-memory ignore patterns.
type ignoreRules interface {
MatchesPath(path string) (bool, error)
// Taint forces checking if the underlying file needs to be reloaded.
// It checks the mtime of the file to see if has been modified after loading.
Taint()
}
// ignoreFile represents a gitignore file backed by a path.
// If the path doesn't exist (yet), it is treated as an empty file.
type ignoreFile struct {
absPath string
// Signal a reload of this file.
// Set this to call [os.Stat] and a potential reload
// of the file's contents next time it is used.
checkForReload bool
// Modified time for this file.
modTime time.Time
// Ignore patterns contained in this file.
patterns *ignore.GitIgnore
}
func newIgnoreFile(absPath string) ignoreRules {
return &ignoreFile{
absPath: absPath,
checkForReload: true,
}
}
func (f *ignoreFile) MatchesPath(path string) (bool, error) {
if f.checkForReload {
err := f.load()
if err != nil {
return false, err
}
// Don't check again in next call.
f.checkForReload = false
}
// A file that doesn't exist doesn't have ignore patterns.
if f.patterns == nil {
return false, nil
}
return f.patterns.MatchesPath(path), nil
}
func (f *ignoreFile) Taint() {
f.checkForReload = true
}
func (f *ignoreFile) load() error {
// The file must be stat-able.
// If it doesn't exist, treat it as an empty file.
stat, err := os.Stat(f.absPath)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
// If the underlying file has not been modified
// it does not need to be reloaded.
if stat.ModTime() == f.modTime {
return nil
}
f.modTime = stat.ModTime()
f.patterns, err = ignore.CompileIgnoreFile(f.absPath)
if err != nil {
return err
}
return nil
}
// stringIgnoreRules implements the [ignoreRules] interface
// for a set of in-memory ignore patterns.
type stringIgnoreRules struct {
patterns *ignore.GitIgnore
}
func newStringIgnoreRules(patterns []string) ignoreRules {
return &stringIgnoreRules{
patterns: ignore.CompileIgnoreLines(patterns...),
}
}
func (r *stringIgnoreRules) MatchesPath(path string) (bool, error) {
return r.patterns.MatchesPath(path), nil
}
func (r *stringIgnoreRules) Taint() {
// Tainting in-memory ignore patterns is a nop.
}