-
Notifications
You must be signed in to change notification settings - Fork 8
/
funcs.go
225 lines (200 loc) · 7.18 KB
/
funcs.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
package funcs
import (
"path/filepath"
"sort"
"strings"
"text/template"
"github.com/rotisserie/eris"
"github.com/solo-io/skv2/codegen/model"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type importedGroup struct {
model.Group
GoModule string // the module where the group is defined, if it differs from the group module itself. e.g. for external type imports such as k8s.io/api
}
// make funcs for "Top Level" templates, i.e.: templates which
// combine resources from multiple (including externally defined) codegen Groups.
//
// selectFromGroups = a map of Go modules to (a superset of) the imported codegen Groups. only required if the codegen group is defined in a different go module than the types (i.e. it is using a CustomTypesImportPath)
// resourcesToSelect = the GVKs of the resources which we want to select from the provided groups
func MakeHomogenousSnapshotFuncs(
snapshotName, outputFile string,
selectFromGroups map[string][]model.Group,
resourcesToSelect map[schema.GroupVersion][]string,
) template.FuncMap {
groups, groupImports, err := getImportedGroups(selectFromGroups, resourcesToSelect)
return template.FuncMap{
"snapshot_name": func() string { return snapshotName },
"package": func() string {
dirs := strings.Split(filepath.Dir(outputFile), string(filepath.Separator))
return dirs[len(dirs)-1] // last path element = package name
},
"imported_groups": func() ([]model.Group, error) { return groups, err },
"client_import_path": func(group model.Group) string {
grp, ok := groupImports[group.GroupVersion]
if !ok {
panic("group not found " + grp.String())
}
return clientImportPath(grp)
},
"set_import_path": func(group model.Group) string {
grp, ok := groupImports[group.GroupVersion]
if !ok {
panic("group not found " + grp.String())
}
return clientImportPath(grp) + "/sets"
},
"controller_import_path": func(group model.Group) string {
grp, ok := groupImports[group.GroupVersion]
if !ok {
panic("group not found " + grp.String())
}
return clientImportPath(grp) + "/controller"
},
}
}
func getImportedGroups(selectFromGroups map[string][]model.Group, resourcesToSelect map[schema.GroupVersion][]string) ([]model.Group, map[schema.GroupVersion]importedGroup, error) {
importedGroups, err := selectResources(selectFromGroups, resourcesToSelect)
if err != nil {
return nil, nil, err
}
var groups []model.Group
groupImports := map[schema.GroupVersion]importedGroup{}
for _, grp := range importedGroups {
grp := grp // pike
grp.Init()
groups = append(groups, grp.Group)
groupImports[grp.GroupVersion] = grp
}
return groups, groupImports, nil
}
// make funcs for "Top Level" templates, i.e.: templates which
// combine resources from multiple (including externally defined) codegen Groups.
//
// selectFromGroups = a map of Go modules to (a superset of) the imported codegen Groups. only required if the codegen group is defined in a different go module than the types (i.e. it is using a CustomTypesImportPath)
// resourcesToSelect = the GVKs of the resources which we want to select from the provided groups
func MakeHybridSnapshotFuncs(
snapshotName, outputFile string,
selectFromGroups map[string][]model.Group,
localResourcesToSelect, remoteResourcesToSelect map[schema.GroupVersion][]string,
) template.FuncMap {
localGroups, localGroupImports, localGroupsErr := getImportedGroups(selectFromGroups, localResourcesToSelect)
remoteGroups, remoteGroupImports, remoteGroupsErr := getImportedGroups(selectFromGroups, remoteResourcesToSelect)
groups := append([]model.Group{}, localGroups...)
groups = append([]model.Group{}, remoteGroups...)
groupImports := map[schema.GroupVersion]importedGroup{}
for groupVersion, group := range localGroupImports {
groupImports[groupVersion] = group
}
for groupVersion, group := range remoteGroupImports {
groupImports[groupVersion] = group
}
return template.FuncMap{
"snapshot_name": func() string { return snapshotName },
"package": func() string {
dirs := strings.Split(filepath.Dir(outputFile), string(filepath.Separator))
return dirs[len(dirs)-1] // last path element = package name
},
"imported_groups": func() ([]model.Group, error) {
return groups, eris.Errorf("invalid groups: local: %v, remote: %v", localGroupsErr, remoteGroupsErr)
},
"local_imported_groups": func() ([]model.Group, error) { return localGroups, localGroupsErr },
"remote_imported_groups": func() ([]model.Group, error) { return remoteGroups, remoteGroupsErr },
"client_import_path": func(group model.Group) string {
grp, ok := groupImports[group.GroupVersion]
if !ok {
panic("group not found " + grp.String())
}
return clientImportPath(grp)
},
"set_import_path": func(group model.Group) string {
grp, ok := groupImports[group.GroupVersion]
if !ok {
panic("group not found " + grp.String())
}
return clientImportPath(grp) + "/sets"
},
"controller_import_path": func(group model.Group) string {
grp, ok := groupImports[group.GroupVersion]
if !ok {
panic("group not found " + grp.String())
}
return clientImportPath(grp) + "/controller"
},
}
}
// gets the go package for an imported group's clients
func clientImportPath(grp importedGroup) string {
grp.ApiRoot = strings.Trim(grp.ApiRoot, "/")
module := grp.GoModule
if module == "" {
// import should be our local module, which comes from the imported group
module = grp.Group.Module
}
s := strings.ReplaceAll(
strings.Join([]string{
module,
grp.ApiRoot,
grp.Group.Group,
grp.Version,
}, "/"),
"//", "/",
)
return s
}
// pass empty string if clients live in the same go module as the type definitions
func selectResources(groups map[string][]model.Group, resourcesToSelect map[schema.GroupVersion][]string) ([]importedGroup, error) {
var selectedResources []importedGroup
for clientModule, groups := range groups {
for _, group := range groups {
resources := resourcesToSelect[group.GroupVersion]
if len(resources) == 0 {
continue
}
filteredGroup := group
filteredGroup.Resources = nil
isResourceSelected := func(kind string) bool {
for _, resource := range resources {
if resource == kind {
return true
}
}
return false
}
for _, resource := range group.Resources {
if !isResourceSelected(resource.Kind) {
continue
}
filteredGroup.Resources = append(filteredGroup.Resources, resource)
}
selectedResources = append(selectedResources, importedGroup{
Group: filteredGroup,
GoModule: clientModule,
})
}
}
// ensure nothing was missed
for groupVersion, kinds := range resourcesToSelect {
for _, kind := range kinds {
var kindFound bool
for _, selectedGroup := range selectedResources {
if selectedGroup.GroupVersion != groupVersion {
continue
}
for _, resource := range selectedGroup.Resources {
if resource.Kind == kind {
kindFound = true
break
}
}
}
if !kindFound {
return nil, eris.Errorf("resource %v/%v selected, but not found in %v", groupVersion, kind, groups)
}
}
}
sort.SliceStable(selectedResources, func(i, j int) bool {
return selectedResources[i].GoModule < selectedResources[j].GoModule
})
return selectedResources, nil
}