-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathripoff_file.go
124 lines (109 loc) · 3.01 KB
/
ripoff_file.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package ripoff
import (
"bytes"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"text/template"
"gopkg.in/yaml.v3"
)
type Row map[string]interface{}
type RipoffFile struct {
Rows map[string]Row `yaml:"rows"`
}
var funcMap = template.FuncMap{
// Convenient way to loop a set amount of times.
"intSlice": func(count int) ([]int, error) {
ret := make([]int, count)
for i := range ret {
ret[i] = i
}
return ret, nil
},
}
var templateFileRegex = regexp.MustCompile(`^template_(\S+)\.`)
// Adds newRows to existingRows, processing templated rows when needed.
func concatRows(templates *template.Template, existingRows map[string]Row, newRows map[string]Row, enums EnumValuesResult) error {
for rowId, row := range newRows {
_, rowExists := existingRows[rowId]
if rowExists {
return fmt.Errorf("row %s is defined more than once", rowId)
}
templateName, usesTemplate := row["template"].(string)
if usesTemplate {
// "rowId" allows dependencies between templated rows to be clear outside of the template.
// Templates can additionally use it to seed random generators.
templateVars := row
templateVars["rowId"] = rowId
templateVars["enums"] = enums
buf := &bytes.Buffer{}
err := templates.ExecuteTemplate(buf, templateName, templateVars)
if err != nil {
return err
}
ripoff := &RipoffFile{}
err = yaml.Unmarshal(buf.Bytes(), ripoff)
if err != nil {
return err
}
err = concatRows(templates, existingRows, ripoff.Rows, enums)
if err != nil {
return err
}
} else {
existingRows[rowId] = row
}
}
return nil
}
// Builds a single RipoffFile from a directory of yaml files.
func RipoffFromDirectory(dir string, enums EnumValuesResult) (RipoffFile, error) {
dir = filepath.Clean(dir)
// Treat files starting with template_ as go templates.
templates := template.New("").Option("missingkey=error").Funcs(funcMap)
_, err := templates.ParseGlob(filepath.Join(dir, "template_*"))
if err != nil && !strings.Contains(err.Error(), "template: pattern matches no files") {
return RipoffFile{}, err
}
// Find all ripoff files in dir recursively.
allRipoffs := []RipoffFile{}
err = filepath.WalkDir(dir, func(path string, entry os.DirEntry, err error) error {
if err != nil {
return err
}
if filepath.Ext(path) != ".yaml" && filepath.Ext(path) != ".yml" {
return nil
}
// Templates were already processed.
templateNameMatches := templateFileRegex.FindStringSubmatch(entry.Name())
if len(templateNameMatches) == 2 {
return nil
}
yamlFile, err := os.ReadFile(path)
if err != nil {
return err
}
ripoff := &RipoffFile{}
err = yaml.Unmarshal(yamlFile, ripoff)
if err != nil {
return err
}
allRipoffs = append(allRipoffs, *ripoff)
return nil
})
if err != nil {
return RipoffFile{}, err
}
totalRipoff := RipoffFile{
Rows: map[string]Row{},
}
for _, ripoff := range allRipoffs {
err = concatRows(templates, totalRipoff.Rows, ripoff.Rows, enums)
if err != nil {
return RipoffFile{}, err
}
}
return totalRipoff, nil
}