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), WithRoot(root),
WithSearchPaths(paths...), WithSearchPaths(paths...),
WithFilter(assertExecutable), WithFilter(assertExecutable),
WithCount(1),
) )
l := executable{ l := executable{

View File

@ -31,6 +31,7 @@ type file struct {
root string root string
prefixes []string prefixes []string
filter func(string) error filter func(string) error
count int
} }
// Option defines a function for passing options to the NewFileLocator() call // 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. // NewFileLocator creates a Locator that can be used to find files with the specified options.
func NewFileLocator(opts ...Option) Locator { func NewFileLocator(opts ...Option) Locator {
return newFileLocator(opts...) 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. // 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) { func (p file) Locate(pattern string) ([]string, error) {
var filenames []string var filenames []string
visit:
for _, prefix := range p.prefixes { for _, prefix := range p.prefixes {
pathPattern := filepath.Join(prefix, pattern) pathPattern := filepath.Join(prefix, pattern)
candidates, err := filepath.Glob(pathPattern) candidates, err := filepath.Glob(pathPattern)
@ -141,8 +151,13 @@ func (p file) Locate(pattern string) ([]string, error) {
continue continue
} }
filenames = append(filenames, candidate) 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 { if len(filenames) == 0 {
return nil, fmt.Errorf("pattern %v not found", pattern) return nil, fmt.Errorf("pattern %v not found", pattern)
} }