Limit number of candidates for executables

This change ensures that the first match of an executable in the path
is retured instead of a list of candidates. This prevents a CDI spec,
for example, from containing multiple entries for a single executable
(e.g. nvidia-smi).

Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
Evan Lezar 2023-01-20 15:08:47 +01:00
parent 6706024687
commit 6237477ba3
2 changed files with 16 additions and 0 deletions

View File

@ -41,6 +41,7 @@ func newExecutableLocator(logger *log.Logger, root string, paths ...string) *exe
WithRoot(root),
WithSearchPaths(paths...),
WithFilter(assertExecutable),
WithCount(1),
)
l := executable{

View File

@ -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)
}