Add support for specifying multiple prefixes

This change allows the file Locator to be instantiated with multiple
search prefixes.

Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
Evan Lezar 2022-11-25 13:37:50 +01:00
parent a7fc29d4bd
commit 55eb898186
2 changed files with 75 additions and 12 deletions

View File

@ -32,22 +32,56 @@ type file struct {
filter func(string) error filter func(string) error
} }
// NewFileLocator creates a Locator that can be used to find files at the specified root. A logger // NewFileLocator creates a Locator that can be used to find files at the specified root.
// can also be specified. // An optional list of prefixes can aslo be specified with each of these being searched in order.
func NewFileLocator(logger *log.Logger, root string) Locator { // The specified root is prefixed to each of the prefixes to determine the final search path.
l := newFileLocator(logger, root) func NewFileLocator(logger *log.Logger, root string, prefixes ...string) Locator {
l := newFileLocator(logger, root, prefixes...)
return &l return &l
} }
func newFileLocator(logger *log.Logger, root string) file { func newFileLocator(logger *log.Logger, root string, prefixes ...string) file {
return file{ return file{
logger: logger, logger: logger,
prefixes: []string{root}, prefixes: getSearchPrefixes(root, prefixes...),
filter: assertFile, filter: assertFile,
} }
} }
// getSearchPrefixes generates a list of unique paths to be searched by a file locator.
//
// For each of the unique prefixes <p> specified the path <root><p> is searched, where <root> is the
// specified root. If no prefixes are specified, <root> is returned as the only search prefix.
//
// Note that an empty root is equivalent to searching relative to the current working directory, and
// if the root filesystem should be searched instead, root should be specified as "/" explicitly.
//
// Also, a prefix of "" forces the root to be included in returned set of paths. This means that if
// the root in addition to another prefix must be searched the function should be called with:
//
// getSearchPrefixes("/root", "", "another/path")
//
// and will result in the search paths []{"/root", "/root/another/path"} being returned.
func getSearchPrefixes(root string, prefixes ...string) []string {
seen := make(map[string]bool)
var uniquePrefixes []string
for _, p := range prefixes {
if seen[p] {
continue
}
seen[p] = true
uniquePrefixes = append(uniquePrefixes, filepath.Join(root, p))
}
if len(uniquePrefixes) == 0 {
uniquePrefixes = append(uniquePrefixes, root)
}
return uniquePrefixes
}
var _ Locator = (*file)(nil) var _ Locator = (*file)(nil)
// Locate attempts to find files with names matching the specified pattern. // Locate attempts to find files with names matching the specified pattern.

View File

@ -20,18 +20,17 @@ import (
"fmt" "fmt"
"testing" "testing"
testlog "github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestFileLocator(t *testing.T) { func TestGetSearchPrefixes(t *testing.T) {
logger, _ := testlog.NewNullLogger()
testCases := []struct { testCases := []struct {
root string root string
prefixes []string
expectedPrefixes []string expectedPrefixes []string
}{ }{
{ {
root: "",
expectedPrefixes: []string{""}, expectedPrefixes: []string{""},
}, },
{ {
@ -42,12 +41,42 @@ func TestFileLocator(t *testing.T) {
root: "/some/root", root: "/some/root",
expectedPrefixes: []string{"/some/root"}, expectedPrefixes: []string{"/some/root"},
}, },
{
root: "",
prefixes: []string{"foo", "bar"},
expectedPrefixes: []string{"foo", "bar"},
},
{
root: "/",
prefixes: []string{"foo", "bar"},
expectedPrefixes: []string{"/foo", "/bar"},
},
{
root: "/",
prefixes: []string{"/foo", "/bar"},
expectedPrefixes: []string{"/foo", "/bar"},
},
{
root: "/some/root",
prefixes: []string{"foo", "bar"},
expectedPrefixes: []string{"/some/root/foo", "/some/root/bar"},
},
{
root: "",
prefixes: []string{"foo", "bar", "bar", "foo"},
expectedPrefixes: []string{"foo", "bar"},
},
{
root: "/some/root",
prefixes: []string{"foo", "bar", "foo", "bar"},
expectedPrefixes: []string{"/some/root/foo", "/some/root/bar"},
},
} }
for i, tc := range testCases { for i, tc := range testCases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
f := newFileLocator(logger, tc.root) prefixes := getSearchPrefixes(tc.root, tc.prefixes...)
require.EqualValues(t, tc.expectedPrefixes, f.prefixes) require.EqualValues(t, tc.expectedPrefixes, prefixes)
}) })
} }
} }