Skip to content

Commit

Permalink
support file paths with braces (#94)
Browse files Browse the repository at this point in the history
Signed-off-by: Dmitry Shmulevich <[email protected]>
  • Loading branch information
dmitsh authored Aug 12, 2024
1 parent b973235 commit 7b315cd
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 8 deletions.
67 changes: 65 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,18 @@ func NewFromFile(path string) (*Workflow, error) {
}

func NewFromPaths(paths string) ([]*Workflow, error) {
cfgPaths := strings.Split(paths, ",")
if len(paths) == 0 {
return nil, fmt.Errorf("empty filepaths")
}

files, err := parsePaths(paths)
if err != nil {
return nil, err
}

configs := []*Workflow{}
var cfg *Workflow
for _, path := range cfgPaths {
for _, path := range files {
fileInfo, err := os.Stat(path)
if err != nil {
return nil, err
Expand Down Expand Up @@ -120,3 +128,58 @@ func (c *Workflow) validate() error {
}
return nil
}

func parsePaths(paths string) ([]string, error) {
start, n := 0, len(paths)
braces := false
ret := []string{}

for i := 1; i < n; i++ {
switch paths[i] {
case '{':
if braces {
return nil, fmt.Errorf("unbalanced braces in %q", paths)
}
braces = true
case '}':
if !braces {
return nil, fmt.Errorf("unbalanced braces in %q", paths)
}
braces = false
case ',':
if !braces {
ret = append(ret, expandBraces(strings.TrimSpace(paths[start:i]))...)
start = i + 1
}
}
}
if braces {
return nil, fmt.Errorf("unbalanced braces in %q", paths)
}
if start < n {
ret = append(ret, expandBraces(strings.TrimSpace(paths[start:n]))...)
}

return ret, nil
}

func expandBraces(pattern string) []string {
start := strings.Index(pattern, "{")
if start == -1 {
return []string{pattern}
}
end := strings.Index(pattern[start:], "}")
if end == -1 {
return []string{pattern}
}
end += start
prefix := pattern[:start]
suffix := pattern[end+1:]
parts := strings.Split(pattern[start+1:end], ",")

var res []string
for _, part := range parts {
res = append(res, expandBraces(prefix+part+suffix)...)
}
return res
}
73 changes: 67 additions & 6 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestWorkflowPaths(t *testing.T) {
}{
{
name: "Case 1: Empty string",
err: "stat : no such file or directory",
err: "empty filepaths",
},
{
name: "Case 2: Wrong path",
Expand All @@ -104,22 +104,83 @@ func TestWorkflowPaths(t *testing.T) {
},
{
name: "Case 3: Valid input",
paths: "../../resources/workflows/volcano,../../resources/workflows/test-custom-resource.yml",
count: 2,
paths: "../../resources/workflows/volcano,../../resources/workflows/k8s/{test-job.yml,test-jobset.yml}",
count: 3,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c, err := NewFromPaths(tc.paths)
if len(tc.err) != 0 {
require.Error(t, err)
require.Equal(t, err.Error(), tc.err)
require.EqualError(t, err, tc.err)
require.Nil(t, c)
} else {
require.Nil(t, err)
require.NoError(t, err)
require.NotNil(t, c)
require.Equal(t, tc.count, len(c))
}
})
}
}

func TestParsePaths(t *testing.T) {
testCases := []struct {
name string
input string
paths []string
err string
}{
{
name: "Case 1a: valid, multi string",
input: "a/b/c, dd/ee/{f,g,e},/x/y/zz",
paths: []string{"a/b/c", "dd/ee/f", "dd/ee/g", "dd/ee/e", "/x/y/zz"},
},
{
name: "Case 1b: valid, single string",
input: "a/b/c",
paths: []string{"a/b/c"},
},
{
name: "Case 1c: valid, multiple braces",
input: "dd/{ee}/{f,g,e}/xx/{yy,zz}",
paths: []string{"dd/ee/f/xx/yy", "dd/ee/f/xx/zz", "dd/ee/g/xx/yy", "dd/ee/g/xx/zz", "dd/ee/e/xx/yy", "dd/ee/e/xx/zz"},
},
{
name: "Case 2a: unbalanced braces",
input: "a/b/c{{",
err: `unbalanced braces in "a/b/c{{"`,
},
{
name: "Case 2b: unbalanced braces",
input: "a/b/c}",
err: `unbalanced braces in "a/b/c}"`,
},
{
name: "Case 2c: unbalanced braces",
input: "a/b/c{",
err: `unbalanced braces in "a/b/c{"`,
},
{
name: "Case 3: single character",
input: "a",
paths: []string{"a"},
},
{
name: "Case 4: empty string",
input: "",
paths: []string{},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
paths, err := parsePaths(tc.input)
if len(tc.err) != 0 {
require.EqualError(t, err, tc.err)
} else {
require.NoError(t, err)
require.Equal(t, tc.paths, paths)
}
})
}
}

0 comments on commit 7b315cd

Please sign in to comment.