From a3a12846cb83d4f3b4586969faa0c4b980ca043e Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Sat, 12 Sep 2026 20:01:33 -0400 Subject: [PATCH 1/2] Add optional per-file limits for ignore files --- README.md | 11 ++++ gitignore.go | 130 ++++++++++++++++++++++++++++++++---------------- options.go | 60 ++++++++++++++++++++++ options_test.go | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 284 insertions(+), 42 deletions(-) create mode 100644 options.go create mode 100644 options_test.go diff --git a/README.md b/README.md index 44e8642..995bbca 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,15 @@ m.AddFromFile("/path/to/repo/src/.gitignore", "src") m.AddPatterns([]byte("*.log\nbuild/\n"), "") ``` +To limit the bytes read from each ignore file, use `NewWithOptions` or `NewFromDirectoryWithOptions`: + +```go +opts := gitignore.Options{MaxIgnoreFileSize: 1 << 20} +m := gitignore.NewFromDirectoryWithOptions("/path/to/repo", opts) +``` + +The limit applies to global excludes, `.git/info/exclude`, and `.gitignore` files, including later `AddFromFile` calls. Oversized files are skipped entirely and recorded in `Errors()` with their source path and line zero. Nonpositive limits are unlimited. `AddPatterns` is unaffected, and the limit does not cap total memory across files. + ## Matching `Match` uses the trailing-slash convention to distinguish files from directories. If you already know whether the path is a directory, `MatchPath` avoids that: @@ -85,6 +94,8 @@ gitignore.WalkFrom("/path/to/repo", "src/pkg", func(path string, d fs.DirEntry) }) ``` +`WalkWithOptions(root, opts, fn)` and `WalkFromWithOptions(root, start, opts, fn)` accept the same limits. They stop and return an `*IgnoreFileSizeError` when an oversized file is encountered. Its `Path` and `Limit` fields identify the file and configured byte limit; use `errors.As` to inspect it. Callbacks may already have run for earlier entries. + ## Error handling Invalid patterns (like unknown POSIX character classes) are silently skipped during matching. To inspect them: diff --git a/gitignore.go b/gitignore.go index 2b3588b..64a3dc3 100644 --- a/gitignore.go +++ b/gitignore.go @@ -41,19 +41,23 @@ type pattern struct { // AddPatterns/AddFromFile call). Do not call AddPatterns or AddFromFile // concurrently with Match. type Matcher struct { - patterns []pattern - errors []PatternError + maxIgnoreFileSize int64 + patterns []pattern + errors []PatternError } -// PatternError records a pattern that could not be compiled. +// PatternError records a pattern compilation error or a skipped oversized file. type PatternError struct { Pattern string // the original pattern text Source string // file path, empty for programmatic patterns - Line int // 1-based line number + Line int // 1-based line number; zero for a file-size error Message string } func (e PatternError) Error() string { + if e.Line == 0 && e.Source != "" { + return e.Source + ": " + e.Message + } if e.Source != "" { return e.Source + ":" + itoa(e.Line) + ": invalid pattern: " + e.Pattern + ": " + e.Message } @@ -74,9 +78,8 @@ func itoa(n int) string { return string(buf[i:]) } -// Errors returns any pattern compilation errors encountered while loading -// patterns. Invalid patterns are silently skipped during matching; this -// method lets callers detect and report them. +// Errors returns pattern compilation errors and skipped oversized files. +// File-size errors have a source path and a zero line number. func (m *Matcher) Errors() []PatternError { return m.errors } @@ -93,32 +96,37 @@ func (m *Matcher) Errors() []PatternError { // loaded and the returned Matcher is empty. Use AddPatterns or // AddFromFile to add patterns programmatically. func New(root string) *Matcher { - m := &Matcher{} + return NewWithOptions(root, Options{}) +} - if root == "" { - return m - } +// NewWithOptions loads the same files as New, using the supplied limits. +// Oversized files are skipped and recorded in Errors with Line set to zero. +func NewWithOptions(root string, options Options) *Matcher { + m, _ := newWithOptions(root, options) + return m +} - // Read global excludes (lowest priority) - if gef := globalExcludesFile(); gef != "" { - if data, err := os.ReadFile(gef); err == nil { - m.addPatterns(data, "", gef) - } - } +func newWithOptions(root string, options Options) (*Matcher, error) { + m := &Matcher{maxIgnoreFileSize: options.MaxIgnoreFileSize} - // Read .git/info/exclude - excludePath := filepath.Join(root, ".git", "info", "exclude") - if data, err := os.ReadFile(excludePath); err == nil { - m.addPatterns(data, "", excludePath) + if root == "" { + return m, nil } - // Read root .gitignore (highest priority) - ignorePath := filepath.Join(root, ".gitignore") - if data, err := os.ReadFile(ignorePath); err == nil { - m.addPatterns(data, "", ignorePath) + var firstErr error + for _, path := range []string{ + globalExcludesFile(), + filepath.Join(root, ".git", "info", "exclude"), + filepath.Join(root, ".gitignore"), + } { + if path == "" { + continue + } + if err := m.addFromFile(path, ""); firstErr == nil { + firstErr = err + } } - - return m + return m, firstErr } // globalExcludesFile returns the path to the user's global gitignore file. @@ -172,8 +180,14 @@ func expandTilde(path string) string { // .gitignore is scoped to its containing directory. The .git directory is // skipped. func NewFromDirectory(root string) *Matcher { - m := New(root) - _ = walkRecursive(root, "", m, nil) + return NewFromDirectoryWithOptions(root, Options{}) +} + +// NewFromDirectoryWithOptions loads nested ignore files using the supplied limits. +// Oversized files are skipped and recorded in Errors. +func NewFromDirectoryWithOptions(root string, options Options) *Matcher { + m := NewWithOptions(root, options) + _ = walkRecursive(root, "", m, nil, false) return m } @@ -185,8 +199,17 @@ func NewFromDirectory(root string) *Matcher { // Paths passed to fn are relative to root and use the OS path separator. // The root directory itself is not passed to fn. func Walk(root string, fn func(path string, d fs.DirEntry) error) error { - m := New(root) - return walkRecursive(root, "", m, fn) + return WalkWithOptions(root, Options{}, fn) +} + +// WalkWithOptions walks like Walk using the supplied file limits. +// An oversized ignore file stops the walk with an IgnoreFileSizeError. +func WalkWithOptions(root string, options Options, fn func(path string, d fs.DirEntry) error) error { + m, err := newWithOptions(root, options) + if err != nil { + return err + } + return walkRecursive(root, "", m, fn, true) } // WalkFrom walks the directory tree starting at a subdirectory of root, @@ -201,16 +224,25 @@ func Walk(root string, fn func(path string, d fs.DirEntry) error) error { // to fn are relative to root (not to start) and use the OS path // separator. The start directory itself is passed to fn. func WalkFrom(root, start string, fn func(path string, d fs.DirEntry) error) error { + return WalkFromWithOptions(root, start, Options{}, fn) +} + +// WalkFromWithOptions walks like WalkFrom using the supplied file limits. +// An oversized ignore file stops the walk with an IgnoreFileSizeError. +func WalkFromWithOptions(root, start string, options Options, fn func(path string, d fs.DirEntry) error) error { if start == "" || start == "." { - return Walk(root, fn) + return WalkWithOptions(root, options, fn) } start = filepath.Clean(start) if start == "." { - return Walk(root, fn) + return WalkWithOptions(root, options, fn) } - m := New(root) + m, err := newWithOptions(root, options) + if err != nil { + return err + } // Load .gitignore from each ancestor directory between root and start // (exclusive of start itself, which walkRecursive loads). @@ -222,7 +254,9 @@ func WalkFrom(root, start string, fn func(path string, d fs.DirEntry) error) err break } prefix := slashed[:off+i] - m.AddFromFile(filepath.Join(root, prefix, ".gitignore"), prefix) + if err := m.addFromFile(filepath.Join(root, prefix, ".gitignore"), prefix); err != nil { + return err + } off += i + 1 } } @@ -239,10 +273,10 @@ func WalkFrom(root, start string, fn func(path string, d fs.DirEntry) error) err } } - return walkRecursive(root, start, m, fn) + return walkRecursive(root, start, m, fn, true) } -func walkRecursive(root, rel string, m *Matcher, fn func(string, fs.DirEntry) error) error { +func walkRecursive(root, rel string, m *Matcher, fn func(string, fs.DirEntry) error, stopOnSizeError bool) error { dir := root if rel != "" { dir = filepath.Join(root, rel) @@ -250,7 +284,9 @@ func walkRecursive(root, rel string, m *Matcher, fn func(string, fs.DirEntry) er // Load .gitignore for this directory before processing entries. if rel != "" { - m.AddFromFile(filepath.Join(dir, ".gitignore"), filepath.ToSlash(rel)) + if err := m.addFromFile(filepath.Join(dir, ".gitignore"), filepath.ToSlash(rel)); err != nil && stopOnSizeError { + return err + } } entries, err := os.ReadDir(dir) @@ -282,7 +318,7 @@ func walkRecursive(root, rel string, m *Matcher, fn func(string, fs.DirEntry) er } if entry.IsDir() { - if err := walkRecursive(root, entryRel, m, fn); err != nil { + if err := walkRecursive(root, entryRel, m, fn, stopOnSizeError); err != nil { return err } } @@ -298,13 +334,23 @@ func (m *Matcher) AddPatterns(data []byte, dir string) { } // AddFromFile reads a .gitignore file at the given absolute path and scopes -// its patterns to the given relative directory. +// its patterns to the given relative directory. It uses the matcher's file-size +// limit, if set, and records oversized files in Errors without applying any rules. func (m *Matcher) AddFromFile(absPath, relDir string) { - data, err := os.ReadFile(absPath) + _ = m.addFromFile(absPath, relDir) +} + +func (m *Matcher) addFromFile(absPath, relDir string) error { + data, err := readIgnoreFile(absPath, m.maxIgnoreFileSize) if err != nil { - return + if sizeErr, ok := err.(*IgnoreFileSizeError); ok { + m.errors = append(m.errors, PatternError{Source: absPath, Message: sizeErr.message()}) + return err + } + return nil } m.addPatterns(data, relDir, absPath) + return nil } // Match returns true if the given path should be ignored. diff --git a/options.go b/options.go new file mode 100644 index 0000000..160f19f --- /dev/null +++ b/options.go @@ -0,0 +1,60 @@ +package gitignore + +import ( + "fmt" + "io" + "os" +) + +// Options controls loading ignore files from disk. +type Options struct { + // MaxIgnoreFileSize limits each file in bytes. Nonpositive values are unlimited. + // AddPatterns is unaffected because its data is already in memory. + MaxIgnoreFileSize int64 +} + +// IgnoreFileSizeError reports an ignore file that exceeded its byte limit. +type IgnoreFileSizeError struct { + Path string + Limit int64 +} + +func (e *IgnoreFileSizeError) Error() string { + return e.Path + ": " + e.message() +} + +func (e *IgnoreFileSizeError) message() string { + return fmt.Sprintf("ignore file exceeds size limit of %d bytes", e.Limit) +} + +func readIgnoreFile(path string, limit int64) ([]byte, error) { + if limit <= 0 { + return os.ReadFile(path) + } + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer func() { _ = f.Close() }() + info, err := f.Stat() + if err != nil { + return nil, err + } + if info.Size() > limit { + return nil, &IgnoreFileSizeError{Path: path, Limit: limit} + } + data, err := io.ReadAll(io.LimitReader(f, limit)) + if err != nil { + return nil, err + } + if int64(len(data)) < limit { + return data, nil + } + // The file can grow after Stat. Probe without overflowing limit+1. + if n, err := io.CopyN(io.Discard, f, 1); n != 0 { + return nil, &IgnoreFileSizeError{Path: path, Limit: limit} + } else if err != io.EOF { + return nil, err + } + return data, nil +} diff --git a/options_test.go b/options_test.go new file mode 100644 index 0000000..49a2e48 --- /dev/null +++ b/options_test.go @@ -0,0 +1,125 @@ +package gitignore_test + +import ( + "errors" + "math" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/git-pkgs/gitignore" +) + +func writeIgnoreFile(t *testing.T, path, data string) { + t.Helper() + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(path, []byte(data), 0o644); err != nil { + t.Fatal(err) + } +} + +func TestIgnoreFileSizeBoundary(t *testing.T) { + isolateGitEnv(t) + root := t.TempDir() + path := filepath.Join(root, ".gitignore") + writeIgnoreFile(t, path, "*.log") + for _, limit := range []int64{-1, 0, 4, 5, 6, math.MaxInt64} { + m := gitignore.NewWithOptions(root, gitignore.Options{MaxIgnoreFileSize: limit}) + if got := m.Match("app.log"); got != (limit != 4) { + t.Errorf("limit %d: Match = %v", limit, got) + } + if limit == 4 { + checkSizeDiagnostic(t, m, path) + } else if len(m.Errors()) != 0 { + t.Errorf("limit %d: Errors = %v", limit, m.Errors()) + } + } + m := gitignore.NewWithOptions("", gitignore.Options{MaxIgnoreFileSize: 4}) + m.AddFromFile(path, "src") + checkSizeDiagnostic(t, m, path) + if m.Match("src/app.log") { + t.Fatal("oversized file was partially applied") + } + m.AddPatterns([]byte("*.log"), "src") + if !m.Match("src/app.log") { + t.Fatal("file limit applied to AddPatterns") + } + if !gitignore.New(root).Match("app.log") { + t.Fatal("default constructor changed") + } +} + +func checkSizeDiagnostic(t *testing.T, m *gitignore.Matcher, path string) { + t.Helper() + errs := m.Errors() + if len(errs) != 1 { + t.Fatalf("Errors = %v", errs) + } + if errs[0].Source != path || errs[0].Line != 0 || errs[0].Pattern != "" { + t.Errorf("diagnostic = %+v", errs[0]) + } + if !strings.Contains(errs[0].Error(), "size limit") || strings.Contains(errs[0].Error(), "invalid pattern") { + t.Errorf("diagnostic text = %s", errs[0].Error()) + } +} + +func TestIgnoreFileSizeSources(t *testing.T) { + isolateGitEnv(t) + for _, source := range []string{".gitignore", ".git/info/exclude", ".global/git/ignore", "src/.gitignore"} { + t.Run(source, func(t *testing.T) { checkSizeLimitedSource(t, source) }) + } +} + +func checkSizeLimitedSource(t *testing.T, source string) { + t.Helper() + root := t.TempDir() + t.Setenv("XDG_CONFIG_HOME", filepath.Join(root, ".global")) + path := filepath.Join(root, source) + writeIgnoreFile(t, path, "*.log\n") + writeIgnoreFile(t, filepath.Join(root, "src/deep/file.log"), "") + opts := gitignore.Options{MaxIgnoreFileSize: 5} + m := gitignore.NewFromDirectoryWithOptions(root, opts) + checkSizeDiagnostic(t, m, path) + if m.Match("src/deep/file.log") { + t.Fatal("skipped rules were applied") + } + for _, start := range []string{"", ".", "src", "src/deep"} { + err := gitignore.WalkFromWithOptions(root, start, opts, func(path string, _ os.DirEntry) error { + if filepath.ToSlash(path) == "src/deep/file.log" { + t.Error("walk continued past oversized ignore file") + } + return nil + }) + checkSizeError(t, err, path, opts.MaxIgnoreFileSize) + } + checkSizeError(t, gitignore.WalkWithOptions(root, opts, nil), path, opts.MaxIgnoreFileSize) + if err := gitignore.Walk(root, nil); err != nil { + t.Fatal(err) + } +} + +func checkSizeError(t *testing.T, err error, path string, limit int64) { + t.Helper() + var sizeErr *gitignore.IgnoreFileSizeError + if !errors.As(err, &sizeErr) { + t.Fatalf("error = %v, want IgnoreFileSizeError", err) + } + if sizeErr.Path != path || sizeErr.Limit != limit { + t.Errorf("error = %+v", sizeErr) + } +} + +func TestSizeLimitedDiscoveryContinues(t *testing.T) { + isolateGitEnv(t) + root := t.TempDir() + writeIgnoreFile(t, filepath.Join(root, "a/.gitignore"), "*.log\n") + writeIgnoreFile(t, filepath.Join(root, "b/.gitignore"), "*.go") + m := gitignore.NewFromDirectoryWithOptions(root, gitignore.Options{MaxIgnoreFileSize: 5}) + if !m.Match("b/main.go") { + t.Fatal("discovery stopped after oversized file") + } + checkSizeDiagnostic(t, m, filepath.Join(root, "a/.gitignore")) +} From 366f0512c72f5ebc22885348eadad900bc0c5962 Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Sat, 12 Sep 2026 20:28:07 -0400 Subject: [PATCH 2/2] Use variadic Option on existing entry points and drop fmt dependency --- README.md | 7 +++--- gitignore.go | 64 +++++++++++++++++++++---------------------------- options.go | 17 +++++++------ options_test.go | 18 +++++++------- 4 files changed, 49 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 995bbca..9502504 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,10 @@ m.AddFromFile("/path/to/repo/src/.gitignore", "src") m.AddPatterns([]byte("*.log\nbuild/\n"), "") ``` -To limit the bytes read from each ignore file, use `NewWithOptions` or `NewFromDirectoryWithOptions`: +To limit the bytes read from each ignore file, pass `MaxIgnoreFileSize` to any constructor or walk function: ```go -opts := gitignore.Options{MaxIgnoreFileSize: 1 << 20} -m := gitignore.NewFromDirectoryWithOptions("/path/to/repo", opts) +m := gitignore.NewFromDirectory("/path/to/repo", gitignore.MaxIgnoreFileSize(1<<20)) ``` The limit applies to global excludes, `.git/info/exclude`, and `.gitignore` files, including later `AddFromFile` calls. Oversized files are skipped entirely and recorded in `Errors()` with their source path and line zero. Nonpositive limits are unlimited. `AddPatterns` is unaffected, and the limit does not cap total memory across files. @@ -94,7 +93,7 @@ gitignore.WalkFrom("/path/to/repo", "src/pkg", func(path string, d fs.DirEntry) }) ``` -`WalkWithOptions(root, opts, fn)` and `WalkFromWithOptions(root, start, opts, fn)` accept the same limits. They stop and return an `*IgnoreFileSizeError` when an oversized file is encountered. Its `Path` and `Limit` fields identify the file and configured byte limit; use `errors.As` to inspect it. Callbacks may already have run for earlier entries. +`Walk` and `WalkFrom` accept the same options as trailing arguments. With `MaxIgnoreFileSize` set they stop and return an `*IgnoreFileSizeError` when an oversized file is encountered. Its `Path` and `Limit` fields identify the file and configured byte limit; use `errors.As` to inspect it. Callbacks may already have run for earlier entries. ## Error handling diff --git a/gitignore.go b/gitignore.go index 64a3dc3..7c30608 100644 --- a/gitignore.go +++ b/gitignore.go @@ -95,19 +95,20 @@ func (m *Matcher) Errors() []PatternError { // (containing .git/). If root is empty, no filesystem patterns are // loaded and the returned Matcher is empty. Use AddPatterns or // AddFromFile to add patterns programmatically. -func New(root string) *Matcher { - return NewWithOptions(root, Options{}) -} - -// NewWithOptions loads the same files as New, using the supplied limits. -// Oversized files are skipped and recorded in Errors with Line set to zero. -func NewWithOptions(root string, options Options) *Matcher { - m, _ := newWithOptions(root, options) +// +// Options such as MaxIgnoreFileSize apply to files loaded here and to +// later AddFromFile calls; oversized files are skipped and recorded in +// Errors with Line set to zero. +func New(root string, opts ...Option) *Matcher { + m, _ := newMatcher(root, opts) return m } -func newWithOptions(root string, options Options) (*Matcher, error) { - m := &Matcher{maxIgnoreFileSize: options.MaxIgnoreFileSize} +func newMatcher(root string, opts []Option) (*Matcher, error) { + m := &Matcher{} + for _, opt := range opts { + opt(m) + } if root == "" { return m, nil @@ -178,15 +179,10 @@ func expandTilde(path string) string { // NewFromDirectory creates a Matcher by walking the directory tree rooted // at root, loading every .gitignore file found along the way. Each nested // .gitignore is scoped to its containing directory. The .git directory is -// skipped. -func NewFromDirectory(root string) *Matcher { - return NewFromDirectoryWithOptions(root, Options{}) -} - -// NewFromDirectoryWithOptions loads nested ignore files using the supplied limits. -// Oversized files are skipped and recorded in Errors. -func NewFromDirectoryWithOptions(root string, options Options) *Matcher { - m := NewWithOptions(root, options) +// skipped. Oversized files under MaxIgnoreFileSize are skipped and recorded +// in Errors. +func NewFromDirectory(root string, opts ...Option) *Matcher { + m := New(root, opts...) _ = walkRecursive(root, "", m, nil, false) return m } @@ -198,14 +194,11 @@ func NewFromDirectoryWithOptions(root string, options Options) *Matcher { // // Paths passed to fn are relative to root and use the OS path separator. // The root directory itself is not passed to fn. -func Walk(root string, fn func(path string, d fs.DirEntry) error) error { - return WalkWithOptions(root, Options{}, fn) -} - -// WalkWithOptions walks like Walk using the supplied file limits. -// An oversized ignore file stops the walk with an IgnoreFileSizeError. -func WalkWithOptions(root string, options Options, fn func(path string, d fs.DirEntry) error) error { - m, err := newWithOptions(root, options) +// +// With MaxIgnoreFileSize set, an oversized ignore file stops the walk and +// is returned as an *IgnoreFileSizeError. +func Walk(root string, fn func(path string, d fs.DirEntry) error, opts ...Option) error { + m, err := newMatcher(root, opts) if err != nil { return err } @@ -223,23 +216,20 @@ func WalkWithOptions(root string, options Options, fn func(path string, d fs.Dir // using either forward slashes or the OS path separator. Paths passed // to fn are relative to root (not to start) and use the OS path // separator. The start directory itself is passed to fn. -func WalkFrom(root, start string, fn func(path string, d fs.DirEntry) error) error { - return WalkFromWithOptions(root, start, Options{}, fn) -} - -// WalkFromWithOptions walks like WalkFrom using the supplied file limits. -// An oversized ignore file stops the walk with an IgnoreFileSizeError. -func WalkFromWithOptions(root, start string, options Options, fn func(path string, d fs.DirEntry) error) error { +// +// With MaxIgnoreFileSize set, an oversized ignore file stops the walk and +// is returned as an *IgnoreFileSizeError. +func WalkFrom(root, start string, fn func(path string, d fs.DirEntry) error, opts ...Option) error { if start == "" || start == "." { - return WalkWithOptions(root, options, fn) + return Walk(root, fn, opts...) } start = filepath.Clean(start) if start == "." { - return WalkWithOptions(root, options, fn) + return Walk(root, fn, opts...) } - m, err := newWithOptions(root, options) + m, err := newMatcher(root, opts) if err != nil { return err } diff --git a/options.go b/options.go index 160f19f..0d36beb 100644 --- a/options.go +++ b/options.go @@ -1,16 +1,19 @@ package gitignore import ( - "fmt" "io" "os" + "strconv" ) -// Options controls loading ignore files from disk. -type Options struct { - // MaxIgnoreFileSize limits each file in bytes. Nonpositive values are unlimited. - // AddPatterns is unaffected because its data is already in memory. - MaxIgnoreFileSize int64 +// Option configures a Matcher at construction time. +type Option func(*Matcher) + +// MaxIgnoreFileSize limits the bytes read from each ignore file. Nonpositive +// values are unlimited. AddPatterns is unaffected because its data is already +// in memory. +func MaxIgnoreFileSize(n int64) Option { + return func(m *Matcher) { m.maxIgnoreFileSize = n } } // IgnoreFileSizeError reports an ignore file that exceeded its byte limit. @@ -24,7 +27,7 @@ func (e *IgnoreFileSizeError) Error() string { } func (e *IgnoreFileSizeError) message() string { - return fmt.Sprintf("ignore file exceeds size limit of %d bytes", e.Limit) + return "ignore file exceeds size limit of " + strconv.FormatInt(e.Limit, 10) + " bytes" } func readIgnoreFile(path string, limit int64) ([]byte, error) { diff --git a/options_test.go b/options_test.go index 49a2e48..42df7b2 100644 --- a/options_test.go +++ b/options_test.go @@ -27,7 +27,7 @@ func TestIgnoreFileSizeBoundary(t *testing.T) { path := filepath.Join(root, ".gitignore") writeIgnoreFile(t, path, "*.log") for _, limit := range []int64{-1, 0, 4, 5, 6, math.MaxInt64} { - m := gitignore.NewWithOptions(root, gitignore.Options{MaxIgnoreFileSize: limit}) + m := gitignore.New(root, gitignore.MaxIgnoreFileSize(limit)) if got := m.Match("app.log"); got != (limit != 4) { t.Errorf("limit %d: Match = %v", limit, got) } @@ -37,7 +37,7 @@ func TestIgnoreFileSizeBoundary(t *testing.T) { t.Errorf("limit %d: Errors = %v", limit, m.Errors()) } } - m := gitignore.NewWithOptions("", gitignore.Options{MaxIgnoreFileSize: 4}) + m := gitignore.New("", gitignore.MaxIgnoreFileSize(4)) m.AddFromFile(path, "src") checkSizeDiagnostic(t, m, path) if m.Match("src/app.log") { @@ -80,22 +80,22 @@ func checkSizeLimitedSource(t *testing.T, source string) { path := filepath.Join(root, source) writeIgnoreFile(t, path, "*.log\n") writeIgnoreFile(t, filepath.Join(root, "src/deep/file.log"), "") - opts := gitignore.Options{MaxIgnoreFileSize: 5} - m := gitignore.NewFromDirectoryWithOptions(root, opts) + opt := gitignore.MaxIgnoreFileSize(5) + m := gitignore.NewFromDirectory(root, opt) checkSizeDiagnostic(t, m, path) if m.Match("src/deep/file.log") { t.Fatal("skipped rules were applied") } for _, start := range []string{"", ".", "src", "src/deep"} { - err := gitignore.WalkFromWithOptions(root, start, opts, func(path string, _ os.DirEntry) error { + err := gitignore.WalkFrom(root, start, func(path string, _ os.DirEntry) error { if filepath.ToSlash(path) == "src/deep/file.log" { t.Error("walk continued past oversized ignore file") } return nil - }) - checkSizeError(t, err, path, opts.MaxIgnoreFileSize) + }, opt) + checkSizeError(t, err, path, 5) } - checkSizeError(t, gitignore.WalkWithOptions(root, opts, nil), path, opts.MaxIgnoreFileSize) + checkSizeError(t, gitignore.Walk(root, nil, opt), path, 5) if err := gitignore.Walk(root, nil); err != nil { t.Fatal(err) } @@ -117,7 +117,7 @@ func TestSizeLimitedDiscoveryContinues(t *testing.T) { root := t.TempDir() writeIgnoreFile(t, filepath.Join(root, "a/.gitignore"), "*.log\n") writeIgnoreFile(t, filepath.Join(root, "b/.gitignore"), "*.go") - m := gitignore.NewFromDirectoryWithOptions(root, gitignore.Options{MaxIgnoreFileSize: 5}) + m := gitignore.NewFromDirectory(root, gitignore.MaxIgnoreFileSize(5)) if !m.Match("b/main.go") { t.Fatal("discovery stopped after oversized file") }