Skip to content

Commit 6f191bf

Browse files
committed
Template interface (phase 2) including insert code fragments logic
Signed-off-by: Adrian Orive <[email protected]>
1 parent e80f0a1 commit 6f191bf

File tree

24 files changed

+1457
-814
lines changed

24 files changed

+1457
-814
lines changed

pkg/model/file/interfaces.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package file
18+
19+
import (
20+
"sigs.k8s.io/kubebuilder/pkg/model/resource"
21+
)
22+
23+
// Builder defines the basic methods that any file builder must implement
24+
type Builder interface {
25+
// GetPath returns the path to the file location
26+
GetPath() string
27+
// GetIfExistsAction returns the behavior when creating a file that already exists
28+
GetIfExistsAction() IfExistsAction
29+
}
30+
31+
// RequiresValidation is a file builder that requires validation
32+
type RequiresValidation interface {
33+
Builder
34+
// Validate returns true if the template has valid values
35+
Validate() error
36+
}
37+
38+
// Template is file builder based on a file template
39+
type Template interface {
40+
Builder
41+
// GetBody returns the template body
42+
GetBody() string
43+
// SetTemplateDefaults returns the TemplateMixin for creating a scaffold file
44+
SetTemplateDefaults() error
45+
}
46+
47+
// Inserter is a file builder that inserts code fragments in marked positions
48+
type Inserter interface {
49+
Builder
50+
// GetMarkers returns the different markers where code fragments will be inserted
51+
GetMarkers() []Marker
52+
// GetCodeFragments returns a map that binds markers to code fragments
53+
GetCodeFragments() CodeFragmentsMap
54+
}
55+
56+
// HasDomain allows the domain to be used on a template
57+
type HasDomain interface {
58+
// InjectDomain sets the template domain
59+
InjectDomain(string)
60+
}
61+
62+
// HasRepository allows the repository to be used on a template
63+
type HasRepository interface {
64+
// InjectRepository sets the template repository
65+
InjectRepository(string)
66+
}
67+
68+
// HasMultiGroup allows the multi-group flag to be used on a template
69+
type HasMultiGroup interface {
70+
// InjectMultiGroup sets the template multi-group flag
71+
InjectMultiGroup(bool)
72+
}
73+
74+
// HasBoilerplate allows a boilerplate to be used on a template
75+
type HasBoilerplate interface {
76+
// InjectBoilerplate sets the template boilerplate
77+
InjectBoilerplate(string)
78+
}
79+
80+
// HasResource allows a resource to be used on a template
81+
type HasResource interface {
82+
// InjectResource sets the template resource
83+
InjectResource(*resource.Resource)
84+
}

pkg/model/file/marker.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package file
18+
19+
import (
20+
"fmt"
21+
"path/filepath"
22+
)
23+
24+
const prefix = "+kubebuilder:scaffold:"
25+
26+
var commentsByExt = map[string]string{
27+
// TODO(v3): machine-readable comments should not have spaces by Go convention. However,
28+
// this is a backwards incompatible change, and thus should be done for next project version.
29+
".go": "// ",
30+
".yaml": "# ",
31+
}
32+
33+
// Marker represents a comment LoC that will be used to insert code fragments by update operations
34+
type Marker struct {
35+
comment string
36+
value string
37+
}
38+
39+
// NewMarkerFor creates a new marker customized for the specific file
40+
func NewMarkerFor(path string, value string) Marker {
41+
ext := filepath.Ext(path)
42+
if comment, found := commentsByExt[ext]; found {
43+
return Marker{comment, value}
44+
}
45+
46+
panic(fmt.Errorf("unknown file extension: '%s', expected '.go' or '.yaml'", ext))
47+
}
48+
49+
// String implements Stringer
50+
func (m Marker) String() string {
51+
return m.comment + prefix + m.value
52+
}
53+
54+
type CodeFragments []string
55+
56+
type CodeFragmentsMap map[Marker]CodeFragments

pkg/model/file/template.go renamed to pkg/model/file/mixins.go

Lines changed: 29 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,46 +20,50 @@ import (
2020
"sigs.k8s.io/kubebuilder/pkg/model/resource"
2121
)
2222

23-
// Template is a scaffoldable file template
24-
type Template interface {
25-
// GetPath returns the path to the file location
26-
GetPath() string
27-
// GetBody returns the template body
28-
GetBody() string
29-
// GetIfExistsAction returns the behavior when creating a file that already exists
30-
GetIfExistsAction() IfExistsAction
31-
// SetTemplateDefaults returns the TemplateMixin for creating a scaffold file
32-
SetTemplateDefaults() error
33-
}
34-
35-
// TemplateMixin is the input for scaffolding a file
36-
type TemplateMixin struct {
37-
// Path is the file to write
23+
// PathMixin provides file builders with a path field
24+
type PathMixin struct {
25+
// Path is the of the file
3826
Path string
27+
}
3928

40-
// TemplateBody is the template body to execute
41-
TemplateBody string
29+
// GetPath implements Builder
30+
func (t *PathMixin) GetPath() string {
31+
return t.Path
32+
}
4233

34+
// IfExistsActionMixin provides file builders with a if-exists-action field
35+
type IfExistsActionMixin struct {
4336
// IfExistsAction determines what to do if the file exists
4437
IfExistsAction IfExistsAction
4538
}
4639

47-
func (t *TemplateMixin) GetPath() string {
48-
return t.Path
40+
// GetIfExistsAction implements Builder
41+
func (t *IfExistsActionMixin) GetIfExistsAction() IfExistsAction {
42+
return t.IfExistsAction
43+
}
44+
45+
// TemplateMixin is the mixin that should be embedded in Template builders
46+
type TemplateMixin struct {
47+
PathMixin
48+
IfExistsActionMixin
49+
50+
// TemplateBody is the template body to execute
51+
TemplateBody string
4952
}
5053

5154
func (t *TemplateMixin) GetBody() string {
5255
return t.TemplateBody
5356
}
5457

55-
func (t *TemplateMixin) GetIfExistsAction() IfExistsAction {
56-
return t.IfExistsAction
58+
// InserterMixin is the mixin that should be embedded in Inserter builders
59+
type InserterMixin struct {
60+
PathMixin
5761
}
5862

59-
// HasDomain allows the domain to be used on a template
60-
type HasDomain interface {
61-
// InjectDomain sets the template domain
62-
InjectDomain(string)
63+
// GetIfExistsAction implements Builder
64+
func (t *InserterMixin) GetIfExistsAction() IfExistsAction {
65+
// Inserter builders always need to overwrite previous files
66+
return Overwrite
6367
}
6468

6569
// DomainMixin provides templates with a injectable domain field
@@ -75,12 +79,6 @@ func (m *DomainMixin) InjectDomain(domain string) {
7579
}
7680
}
7781

78-
// HasRepository allows the repository to be used on a template
79-
type HasRepository interface {
80-
// InjectRepository sets the template repository
81-
InjectRepository(string)
82-
}
83-
8482
// RepositoryMixin provides templates with a injectable repository field
8583
type RepositoryMixin struct {
8684
// Repo is the go project package path
@@ -94,12 +92,6 @@ func (m *RepositoryMixin) InjectRepository(repository string) {
9492
}
9593
}
9694

97-
// HasMultiGroup allows the multi-group flag to be used on a template
98-
type HasMultiGroup interface {
99-
// InjectMultiGroup sets the template multi-group flag
100-
InjectMultiGroup(bool)
101-
}
102-
10395
// MultiGroupMixin provides templates with a injectable multi-group flag field
10496
type MultiGroupMixin struct {
10597
// MultiGroup is the multi-group flag
@@ -111,12 +103,6 @@ func (m *MultiGroupMixin) InjectMultiGroup(flag bool) {
111103
m.MultiGroup = flag
112104
}
113105

114-
// HasBoilerplate allows a boilerplate to be used on a template
115-
type HasBoilerplate interface {
116-
// InjectBoilerplate sets the template boilerplate
117-
InjectBoilerplate(string)
118-
}
119-
120106
// BoilerplateMixin provides templates with a injectable boilerplate field
121107
type BoilerplateMixin struct {
122108
// Boilerplate is the contents of a Boilerplate go header file
@@ -130,12 +116,6 @@ func (m *BoilerplateMixin) InjectBoilerplate(boilerplate string) {
130116
}
131117
}
132118

133-
// HasResource allows a resource to be used on a template
134-
type HasResource interface {
135-
// InjectResource sets the template resource
136-
InjectResource(*resource.Resource)
137-
}
138-
139119
// ResourceMixin provides templates with a injectable resource field
140120
type ResourceMixin struct {
141121
Resource *resource.Resource
@@ -147,10 +127,3 @@ func (m *ResourceMixin) InjectResource(res *resource.Resource) {
147127
m.Resource = res
148128
}
149129
}
150-
151-
// RequiresValidation is a file that requires validation
152-
type RequiresValidation interface {
153-
Template
154-
// Validate returns true if the template has valid values
155-
Validate() error
156-
}

pkg/model/universe.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ type Universe struct {
3434
Resource *resource.Resource `json:"resource,omitempty"`
3535

3636
// Files contains the model of the files that are being scaffolded
37-
Files []*file.File `json:"files,omitempty"`
37+
Files map[string]*file.File `json:"files,omitempty"`
3838
}
3939

4040
// NewUniverse creates a new Universe
@@ -78,7 +78,7 @@ func WithResource(resource *resource.Resource) UniverseOption {
7878
}
7979
}
8080

81-
func (u Universe) InjectInto(t file.Template) {
81+
func (u Universe) InjectInto(t file.Builder) {
8282
// Inject project configuration
8383
if u.Config != nil {
8484
if templateWithDomain, hasDomain := t.(file.HasDomain); hasDomain {

pkg/scaffold/api.go

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -162,19 +162,14 @@ func (s *apiScaffolder) scaffoldV2() error {
162162
return fmt.Errorf("error scaffolding APIs: %v", err)
163163
}
164164

165-
kustomizationFile := &crdv2.Kustomization{}
166165
if err := machinery.NewScaffold().Execute(
167166
s.newUniverse(),
168-
kustomizationFile,
167+
&crdv2.Kustomization{},
169168
&crdv2.KustomizeConfig{},
170169
); err != nil {
171170
return fmt.Errorf("error scaffolding kustomization: %v", err)
172171
}
173172

174-
if err := kustomizationFile.Update(); err != nil {
175-
return fmt.Errorf("error updating kustomization.yaml: %v", err)
176-
}
177-
178173
} else {
179174
// disable generation of example reconcile body if not scaffolding resource
180175
// because this could result in a fork-bomb of k8s resources where watching a
@@ -192,27 +187,18 @@ func (s *apiScaffolder) scaffoldV2() error {
192187
fmt.Sprintf("%s_controller.go", strings.ToLower(s.resource.Kind))))
193188
}
194189

195-
suiteTestFile := &controllerv2.SuiteTest{}
196190
if err := machinery.NewScaffold(s.plugins...).Execute(
197191
s.newUniverse(),
198-
suiteTestFile,
192+
&controllerv2.SuiteTest{},
199193
&controllerv2.Controller{},
200194
); err != nil {
201195
return fmt.Errorf("error scaffolding controller: %v", err)
202196
}
203-
204-
if err := suiteTestFile.Update(); err != nil {
205-
return fmt.Errorf("error updating suite_test.go under controllers pkg: %v", err)
206-
}
207197
}
208198

209-
if err := (&templatesv2.Main{}).Update(
210-
&templatesv2.MainUpdateOptions{
211-
Config: &s.config.Config,
212-
WireResource: s.doResource,
213-
WireController: s.doController,
214-
Resource: s.resource,
215-
},
199+
if err := machinery.NewScaffold(s.plugins...).Execute(
200+
s.newUniverse(),
201+
&templatesv2.MainUpdater{WireResource: s.doResource, WireController: s.doController},
216202
); err != nil {
217203
return fmt.Errorf("error updating main.go: %v", err)
218204
}

pkg/scaffold/init.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323

2424
"sigs.k8s.io/kubebuilder/internal/config"
2525
"sigs.k8s.io/kubebuilder/pkg/model"
26-
"sigs.k8s.io/kubebuilder/pkg/model/file"
2726
"sigs.k8s.io/kubebuilder/pkg/scaffold/internal/machinery"
2827
templatesv1 "sigs.k8s.io/kubebuilder/pkg/scaffold/internal/templates/v1"
2928
managerv1 "sigs.k8s.io/kubebuilder/pkg/scaffold/internal/templates/v1/manager"
@@ -86,13 +85,13 @@ func (s *initScaffolder) Scaffold() error {
8685
}
8786

8887
func (s *initScaffolder) scaffoldV1() error {
88+
bpFile := &templatesv1.Boilerplate{}
89+
bpFile.Path = s.boilerplatePath
90+
bpFile.License = s.license
91+
bpFile.Owner = s.owner
8992
if err := machinery.NewScaffold().Execute(
9093
s.newUniverse(""),
91-
&templatesv1.Boilerplate{
92-
TemplateMixin: file.TemplateMixin{Path: s.boilerplatePath},
93-
License: s.license,
94-
Owner: s.owner,
95-
},
94+
bpFile,
9695
); err != nil {
9796
return err
9897
}
@@ -126,13 +125,13 @@ func (s *initScaffolder) scaffoldV1() error {
126125
}
127126

128127
func (s *initScaffolder) scaffoldV2() error {
128+
bpFile := &templatesv2.Boilerplate{}
129+
bpFile.Path = s.boilerplatePath
130+
bpFile.License = s.license
131+
bpFile.Owner = s.owner
129132
if err := machinery.NewScaffold().Execute(
130133
s.newUniverse(""),
131-
&templatesv2.Boilerplate{
132-
TemplateMixin: file.TemplateMixin{Path: s.boilerplatePath},
133-
License: s.license,
134-
Owner: s.owner,
135-
},
134+
bpFile,
136135
); err != nil {
137136
return err
138137
}

0 commit comments

Comments
 (0)