diff --git a/vars.go b/vars.go index f850febe..81b23cea 100644 --- a/vars.go +++ b/vars.go @@ -3,14 +3,19 @@ package runn import ( "bytes" "fmt" + "os" "path/filepath" + "sort" "strings" "text/template" + "github.com/bmatcuk/doublestar/v4" "github.com/goccy/go-json" "github.com/goccy/go-yaml" ) +const multiple = "*" + type evaluator struct { scheme string exts []string @@ -30,45 +35,51 @@ var ( func evaluateSchema(value any, operationRoot string, store map[string]any) (any, error) { switch v := value.(type) { case string: - var targetEvaluator *evaluator + var e *evaluator for _, evaluator := range evaluators { if strings.HasPrefix(v, evaluator.scheme) { - targetEvaluator = evaluator + e = evaluator } } - - if targetEvaluator == nil { + if e == nil { return value, nil } - p := v[len(targetEvaluator.scheme):] - if !hasExts(p, targetEvaluator.exts) && !hasTemplateSuffix(p, targetEvaluator.exts) { + p := v[len(e.scheme):] + if strings.Contains(p, "://") { + return value, fmt.Errorf("invalid path: %s", v) + } + if !hasExts(p, e.exts) && !hasTemplateSuffix(p, e.exts) { return value, fmt.Errorf("unsupported file extension: %s", p) } if operationRoot != "" { p = filepath.Join(operationRoot, p) } - byteArray, err := readFile(p) - if err != nil { - return value, fmt.Errorf("read external files error: %w", err) - } - if store != nil && hasTemplateSuffix(p, targetEvaluator.exts) { - tmpl, err := template.New(p).Parse(string(byteArray)) + + if strings.Contains(p, multiple) { + base, pattern := doublestar.SplitPattern(p) + fsys := os.DirFS(base) + matches, err := doublestar.Glob(fsys, pattern) if err != nil { - return value, fmt.Errorf("template parse error: %w", err) + return value, fmt.Errorf("glob error: %w", err) } - buf := new(bytes.Buffer) - if err := tmpl.Execute(buf, store); err != nil { - return value, fmt.Errorf("template excute error: %w", err) + sort.Slice(matches, func(i, j int) bool { return matches[i] < matches[j] }) + outs := []any{} + for _, m := range matches { + out, err := evalutateFile(filepath.Join(base, m), store, e) + if err != nil { + return value, fmt.Errorf("evaluate file error: %w", err) + } + outs = append(outs, out) } - byteArray = buf.Bytes() - } - var evaluatedObj any - if err := targetEvaluator.unmarshal(byteArray, &evaluatedObj); err != nil { - return value, fmt.Errorf("unmarshal error: %w", err) + return outs, nil + } else { + out, err := evalutateFile(p, store, e) + if err != nil { + return value, fmt.Errorf("evaluate file error: %w", err) + } + return out, nil } - - return evaluatedObj, nil } return value, nil @@ -91,3 +102,26 @@ func hasTemplateSuffix(p string, exts []string) bool { } return false } + +func evalutateFile(p string, store map[string]any, e *evaluator) (any, error) { + b, err := readFile(p) + if err != nil { + return nil, fmt.Errorf("read external files error: %w", err) + } + if store != nil && hasTemplateSuffix(p, e.exts) { + tmpl, err := template.New(p).Parse(string(b)) + if err != nil { + return nil, fmt.Errorf("template parse error: %w", err) + } + buf := new(bytes.Buffer) + if err := tmpl.Execute(buf, store); err != nil { + return nil, fmt.Errorf("template excute error: %w", err) + } + b = buf.Bytes() + } + var out any + if err := e.unmarshal(b, &out); err != nil { + return nil, fmt.Errorf("unmarshal error: %w", err) + } + return out, nil +} diff --git a/vars_test.go b/vars_test.go index 54d20ba0..f4c4e080 100644 --- a/vars_test.go +++ b/vars_test.go @@ -63,6 +63,13 @@ func TestEvaluateSchema(t *testing.T) { "", true, }, + {"json://testdata/vars*.json", nil, []any{ + map[string]any{"foo": "test", "bar": float64(1)}, + []any{ + map[string]any{"foo": "test1", "bar": float64(1)}, + map[string]any{"foo": "test2", "bar": float64(2)}, + }, + }, false}, } for i, tt := range tests { tt := tt