diff --git a/internal/lookup/executable.go b/internal/lookup/executable.go index e7ddf450..08316ed3 100644 --- a/internal/lookup/executable.go +++ b/internal/lookup/executable.go @@ -41,6 +41,7 @@ func newExecutableLocator(logger *log.Logger, root string, paths ...string) *exe WithRoot(root), WithSearchPaths(paths...), WithFilter(assertExecutable), + WithCount(1), ) l := executable{ diff --git a/internal/lookup/file.go b/internal/lookup/file.go index 94702174..0ddf0c08 100644 --- a/internal/lookup/file.go +++ b/internal/lookup/file.go @@ -31,6 +31,7 @@ type file struct { root string prefixes []string filter func(string) error + count int } // Option defines a function for passing options to the NewFileLocator() call @@ -65,6 +66,13 @@ func WithFilter(assert func(string) error) Option { } } +// WithCount sets the maximum number of candidates to discover +func WithCount(count int) Option { + return func(f *file) { + f.count = count + } +} + // NewFileLocator creates a Locator that can be used to find files with the specified options. func NewFileLocator(opts ...Option) Locator { return newFileLocator(opts...) @@ -126,6 +134,8 @@ var _ Locator = (*file)(nil) // All prefixes are searched and any matching candidates are returned. If no matches are found, an error is returned. func (p file) Locate(pattern string) ([]string, error) { var filenames []string + +visit: for _, prefix := range p.prefixes { pathPattern := filepath.Join(prefix, pattern) candidates, err := filepath.Glob(pathPattern) @@ -141,8 +151,13 @@ func (p file) Locate(pattern string) ([]string, error) { continue } filenames = append(filenames, candidate) + if p.count > 0 && len(filenames) == p.count { + p.logger.Debugf("Found %d candidates; ignoring further candidates", len(filenames)) + break visit + } } } + if len(filenames) == 0 { return nil, fmt.Errorf("pattern %v not found", pattern) }