2020-05-03 14:40:59 +02:00
|
|
|
package fs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type IgnoreLogFunc func(fileName string)
|
|
|
|
|
|
|
|
// IgnoreItem represents a file name pattern to be ignored.
|
|
|
|
type IgnoreItem struct {
|
|
|
|
Dir string
|
|
|
|
Pattern string
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewIgnoreItem returns a pointer to a new IgnoreItem instance.
|
|
|
|
func NewIgnoreItem(dir, pattern string, caseSensitive bool) IgnoreItem {
|
|
|
|
if caseSensitive {
|
2020-10-19 09:52:52 +02:00
|
|
|
return IgnoreItem{Dir: dir + PathSeparator, Pattern: pattern}
|
2020-05-03 14:40:59 +02:00
|
|
|
} else {
|
2020-10-19 09:52:52 +02:00
|
|
|
return IgnoreItem{Dir: strings.ToLower(dir) + PathSeparator, Pattern: strings.ToLower(pattern)}
|
2020-05-03 14:40:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore returns true if the file name "base" in the directory "dir" should be ignored.
|
2020-10-18 20:03:25 +02:00
|
|
|
func (i IgnoreItem) Ignore(dir, base string) bool {
|
2020-10-19 09:52:52 +02:00
|
|
|
if !strings.HasPrefix(dir+PathSeparator, i.Dir) {
|
2020-05-03 14:40:59 +02:00
|
|
|
// different directory prefix: don't look any further
|
|
|
|
return false
|
|
|
|
} else if i.Pattern == base {
|
|
|
|
// file name is the same as pattern (no wildcard)
|
2020-10-18 20:03:25 +02:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-10-19 09:23:09 +02:00
|
|
|
if strings.ContainsRune(i.Pattern, filepath.Separator) {
|
|
|
|
base = filepath.Join(RelName(dir, i.Dir), base)
|
2020-10-18 20:03:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ignore, err := filepath.Match(i.Pattern, base); ignore && err == nil {
|
|
|
|
return true
|
2020-05-03 14:40:59 +02:00
|
|
|
}
|
|
|
|
|
2020-10-18 20:03:25 +02:00
|
|
|
return false
|
2020-05-03 14:40:59 +02:00
|
|
|
}
|
|
|
|
|
2021-07-16 18:27:28 +02:00
|
|
|
// IgnoreList represents a list of name patterns to be ignored.
|
2020-05-03 14:40:59 +02:00
|
|
|
type IgnoreList struct {
|
|
|
|
Log IgnoreLogFunc
|
|
|
|
items []IgnoreItem
|
|
|
|
hiddenFiles []string
|
|
|
|
ignoredFiles []string
|
|
|
|
configFiles map[string][]string
|
|
|
|
configFile string
|
|
|
|
ignoreHidden bool
|
|
|
|
caseSensitive bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewIgnoreList returns a pointer to a new IgnoreList instance.
|
|
|
|
func NewIgnoreList(configFile string, ignoreHidden bool, caseSensitive bool) *IgnoreList {
|
|
|
|
return &IgnoreList{
|
|
|
|
configFile: configFile,
|
|
|
|
ignoreHidden: ignoreHidden,
|
|
|
|
caseSensitive: caseSensitive,
|
|
|
|
configFiles: make(map[string][]string),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hidden returns hidden files that were ignored.
|
|
|
|
func (l *IgnoreList) Hidden() []string {
|
|
|
|
return l.hiddenFiles
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignored returns files that were ignored in addition to hidden files.
|
|
|
|
func (l *IgnoreList) Ignored() []string {
|
|
|
|
return l.ignoredFiles
|
|
|
|
}
|
|
|
|
|
|
|
|
// AppendItems adds items to the list of ignored items.
|
|
|
|
func (l *IgnoreList) AppendItems(dir string, patterns []string) error {
|
|
|
|
if dir == "" {
|
|
|
|
return errors.New("empty directory name")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, pattern := range patterns {
|
2020-05-04 10:10:56 +02:00
|
|
|
if pattern != "" && !strings.HasPrefix(pattern, "#") {
|
2020-05-03 14:40:59 +02:00
|
|
|
l.items = append(l.items, NewIgnoreItem(dir, pattern, l.caseSensitive))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConfigFile adds items in fileName to the list of ignored items.
|
|
|
|
func (l *IgnoreList) ConfigFile(fileName string) error {
|
|
|
|
items, err := ReadLines(fileName)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
l.configFiles[fileName] = items
|
|
|
|
|
|
|
|
return l.AppendItems(filepath.Dir(fileName), items)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dir adds the ignore file in dirName to the list of ignored items.
|
|
|
|
func (l *IgnoreList) Dir(dir string) error {
|
|
|
|
if dir == "" {
|
|
|
|
return errors.New("empty directory name")
|
|
|
|
}
|
|
|
|
|
|
|
|
if l.configFile == "" {
|
2020-05-03 16:15:54 +02:00
|
|
|
return errors.New("empty ignore file name")
|
2020-05-03 14:40:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fileName := filepath.Join(dir, l.configFile)
|
|
|
|
|
|
|
|
if _, ok := l.configFiles[fileName]; ok {
|
2020-05-03 16:15:54 +02:00
|
|
|
return nil
|
2020-05-03 14:40:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !FileExists(fileName) {
|
2021-10-05 18:42:39 +02:00
|
|
|
return fmt.Errorf("found no %s file", l.configFile)
|
2020-05-03 14:40:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return l.ConfigFile(fileName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore returns true if the file name should be ignored.
|
|
|
|
func (l *IgnoreList) Ignore(fileName string) bool {
|
|
|
|
dir := filepath.Dir(fileName)
|
|
|
|
base := filepath.Base(fileName)
|
|
|
|
|
|
|
|
if l.caseSensitive == false {
|
|
|
|
dir = strings.ToLower(dir)
|
|
|
|
base = strings.ToLower(base)
|
|
|
|
}
|
|
|
|
|
|
|
|
if l.configFile != "" && base == l.configFile {
|
|
|
|
_ = l.ConfigFile(fileName)
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, item := range l.items {
|
|
|
|
if item.Ignore(dir, base) {
|
|
|
|
l.ignoredFiles = append(l.ignoredFiles, fileName)
|
|
|
|
|
|
|
|
if l.Log != nil {
|
|
|
|
l.Log(fileName)
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-24 01:24:36 +02:00
|
|
|
if l.ignoreHidden && FileNameHidden(fileName) {
|
2021-07-16 18:27:28 +02:00
|
|
|
l.hiddenFiles = append(l.hiddenFiles, fileName)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-05-03 14:40:59 +02:00
|
|
|
return false
|
|
|
|
}
|