Generate all Crossplane method sets

This commit is contained in:
Nic Cope 2019-09-29 22:51:50 -07:00
parent b7badf61bf
commit 9d5fb56acf
7 changed files with 446 additions and 105 deletions

View File

@ -5,33 +5,195 @@ import (
"os"
"path/filepath"
"github.com/negz/angryjet/internal/comments"
"github.com/negz/angryjet/internal/generate"
"github.com/negz/angryjet/internal/match"
"github.com/negz/angryjet/internal/methods"
"github.com/pkg/errors"
"golang.org/x/tools/go/packages"
"gopkg.in/alecthomas/kingpin.v2"
)
"github.com/negz/angryjet/internal/generators/managed"
const (
// LoadMode used to load all packages.
LoadMode = packages.NeedName | packages.NeedImports | packages.NeedDeps | packages.NeedTypes | packages.NeedSyntax
// DisableMarker used to disable generation of managed resource methods for
// a type that otherwise appears to be a managed resource that is missing a
// subnet of its methods.
DisableMarker = "crossplane:generate:methods"
)
// Imports used in generated code.
const (
CoreAlias = "corev1"
CoreImport = "k8s.io/api/core/v1"
RuntimeAlias = "runtimev1alpha1"
RuntimeImport = "github.com/crossplaneio/crossplane-runtime/apis/core/v1alpha1"
ResourceImport = "github.com/crossplaneio/crossplane-runtime/pkg/resource"
)
func main() {
var (
app = kingpin.New(filepath.Base(os.Args[0]), "Generates Crossplane API type methods.").DefaultEnvars()
pattern = app.Arg("packages", "Package(s) for which to generate Crossplane methods, for example github.com/crossplaneio/crossplane/apis/...").String()
base = app.Flag("base-dir", "Generated files are written to their package paths relative to this directory.").Default(filepath.Join(os.Getenv("GOPATH"), "src")).ExistingDir()
prefix = app.Flag("prefix", "This string is prepended to the names of all generated files.").Default("zz_generated.").String()
header = app.Flag("header-file", "The contents of this file will be added to the top of all generated files.").ExistingFile()
app = kingpin.New(filepath.Base(os.Args[0]), "Generates Crossplane API type methods.").DefaultEnvars()
methodsets = app.Command("generate-methodsets", "Generate a Crossplane method sets.")
base = methodsets.Flag("base-dir", "Generated files are written to their package paths relative to this directory.").Default(filepath.Join(os.Getenv("GOPATH"), "src")).ExistingDir()
headerFile = methodsets.Flag("header-file", "The contents of this file will be added to the top of all generated files.").ExistingFile()
filenameManaged = methodsets.Flag("filename-managed", "The filename of generated managed resource files.").Default("zz_generated.managed.go").String()
filenameClaim = methodsets.Flag("filename-claim", "The filename of generated resource claim files.").Default("zz_generated.claim.go").String()
filenamePortableClass = methodsets.Flag("filename-portable-class", "The filename of generated portable class files.").Default("zz_generated.portableclass.go").String()
filenamePortableClassList = methodsets.Flag("filename-portable-class-list", "The filename of generated portable class list files.").Default("zz_generated.portableclasslist.go").String()
filenameNonPortableClass = methodsets.Flag("filename-non-portable-class", "The filename of generated non-portable class files.").Default("zz_generated.nonportableclass.go").String()
pattern = methodsets.Arg("packages", "Package(s) for which to generate methods, for example github.com/crossplaneio/crossplane/apis/...").String()
)
kingpin.MustParse(app.Parse(os.Args[1:]))
m := packages.NeedName | packages.NeedImports | packages.NeedDeps | packages.NeedTypes | packages.NeedSyntax
pkgs, err := packages.Load(&packages.Config{Mode: m}, *pattern)
pkgs, err := packages.Load(&packages.Config{Mode: LoadMode}, *pattern)
kingpin.FatalIfError(err, "cannot load packages %s", *pattern)
h, err := ioutil.ReadFile(*header)
kingpin.FatalIfError(err, "cannot read header file %s", *header)
header := ""
if *headerFile != "" {
h, err := ioutil.ReadFile(*headerFile)
kingpin.FatalIfError(err, "cannot read header file %s", *headerFile)
header = string(h)
}
for _, p := range pkgs {
for _, err := range p.Errors {
kingpin.FatalIfError(err, "error loading packages using pattern %s", *pattern)
}
kingpin.FatalIfError(managed.WriteMethods(*base, *prefix, string(h), p), "cannot write managed resource methods for package %s", p.PkgPath)
kingpin.FatalIfError(GenerateManaged(*base, *filenameManaged, header, p), "cannot write managed resource method set for package %s", p.PkgPath)
kingpin.FatalIfError(GenerateClaim(*base, *filenameClaim, header, p), "cannot write resource claim method set for package %s", p.PkgPath)
kingpin.FatalIfError(GeneratePortableClass(*base, *filenamePortableClass, header, p), "cannot write portable class method set for package %s", p.PkgPath)
kingpin.FatalIfError(GeneratePortableClassList(*base, *filenamePortableClassList, header, p), "cannot write portable class list method set for package %s", p.PkgPath)
kingpin.FatalIfError(GenerateNonPortableClass(*base, *filenameNonPortableClass, header, p), "cannot write non portable class method set for package %s", p.PkgPath)
}
}
// GenerateManaged generates the resource.Managed method set.
func GenerateManaged(base, filename, header string, p *packages.Package) error {
receiver := "mg"
methods := generate.MethodSet{
"SetConditions": methods.NewSetConditions(receiver, RuntimeImport),
"SetBindingPhase": methods.NewSetBindingPhase(receiver, RuntimeImport),
"GetBindingPhase": methods.NewGetBindingPhase(receiver, RuntimeImport),
"SetClaimReference": methods.NewSetClaimReference(receiver, CoreImport),
"GetClaimReference": methods.NewGetClaimReference(receiver, CoreImport),
"SetNonPortableClassReference": methods.NewSetNonPortableClassReference(receiver, CoreImport),
"GetNonPortableClassReference": methods.NewGetNonPortableClassReference(receiver, CoreImport),
"SetWriteConnectionSecretToReference": methods.NewSetWriteConnectionSecretToReference(receiver, CoreImport),
"GetWriteConnectionSecretToReference": methods.NewGetWriteConnectionSecretToReference(receiver, CoreImport),
"SetReclaimPolicy": methods.NewSetReclaimPolicy(receiver, RuntimeImport),
"GetReclaimPolicy": methods.NewGetReclaimPolicy(receiver, RuntimeImport),
}
err := generate.WriteMethods(p, methods, filepath.Join(base, p.PkgPath, filename),
generate.WithHeaders(header),
generate.WithImportAliases(map[string]string{
CoreImport: CoreAlias,
RuntimeImport: RuntimeAlias,
}),
generate.WithMatcher(match.AllOf(
match.Managed(),
match.DoesNotHaveMarker(comments.In(p), DisableMarker, "false")),
),
)
return errors.Wrap(err, "cannot write managed resource methods")
}
// GenerateClaim generates the resource.Claim method set.
func GenerateClaim(base, filename, header string, p *packages.Package) error {
receiver := "cm"
methods := generate.MethodSet{
"SetConditions": methods.NewSetConditions(receiver, RuntimeImport),
"SetBindingPhase": methods.NewSetBindingPhase(receiver, RuntimeImport),
"GetBindingPhase": methods.NewGetBindingPhase(receiver, RuntimeImport),
"SetResourceReference": methods.NewSetResourceReference(receiver, CoreImport),
"GetResourceReference": methods.NewGetResourceReference(receiver, CoreImport),
"SetPortableClassReference": methods.NewSetPortableClassReference(receiver, CoreImport),
"GetPortableClassReference": methods.NewGetPortableClassReference(receiver, CoreImport),
"SetWriteConnectionSecretToReference": methods.NewSetWriteConnectionSecretToReference(receiver, CoreImport),
"GetWriteConnectionSecretToReference": methods.NewGetWriteConnectionSecretToReference(receiver, CoreImport),
}
err := generate.WriteMethods(p, methods, filepath.Join(base, p.PkgPath, filename),
generate.WithHeaders(header),
generate.WithImportAliases(map[string]string{
CoreImport: CoreAlias,
RuntimeImport: RuntimeAlias,
}),
generate.WithMatcher(match.AllOf(
match.Claim(),
match.DoesNotHaveMarker(comments.In(p), DisableMarker, "false")),
),
)
return errors.Wrap(err, "cannot write resource claim methods")
}
// GeneratePortableClass generates the resource.PortableClass method set.
func GeneratePortableClass(base, filename, header string, p *packages.Package) error {
receiver := "cs"
methods := generate.MethodSet{
"SetNonPortableClassReference": methods.NewSetNonPortableClassReference(receiver, CoreImport),
"GetNonPortableClassReference": methods.NewGetNonPortableClassReference(receiver, CoreImport),
}
err := generate.WriteMethods(p, methods, filepath.Join(base, p.PkgPath, filename),
generate.WithHeaders(header),
generate.WithImportAliases(map[string]string{CoreImport: CoreAlias}),
generate.WithMatcher(match.AllOf(
match.PortableClass(),
match.DoesNotHaveMarker(comments.In(p), DisableMarker, "false")),
),
)
return errors.Wrap(err, "cannot write portable class methods")
}
// GeneratePortableClassList generates the resource.PortableClassList method set.
func GeneratePortableClassList(base, filename, header string, p *packages.Package) error {
receiver := "csl"
methods := generate.MethodSet{
"GetPortableClassItems": methods.NewGetPortableClassItems(receiver, ResourceImport),
}
err := generate.WriteMethods(p, methods, filepath.Join(base, p.PkgPath, filename),
generate.WithHeaders(header),
generate.WithMatcher(match.AllOf(
match.PortableClassList(),
match.DoesNotHaveMarker(comments.In(p), DisableMarker, "false")),
),
)
return errors.Wrap(err, "cannot write portable class methods")
}
// GenerateNonPortableClass generates the resource.NonPortableClass method set.
func GenerateNonPortableClass(base, filename, header string, p *packages.Package) error {
receiver := "cs"
methods := generate.MethodSet{
"SetReclaimPolicy": methods.NewSetReclaimPolicy(receiver, RuntimeImport),
"GetReclaimPolicy": methods.NewGetReclaimPolicy(receiver, RuntimeImport),
}
err := generate.WriteMethods(p, methods, filepath.Join(base, p.PkgPath, filename),
generate.WithHeaders(header),
generate.WithImportAliases(map[string]string{RuntimeImport: RuntimeAlias}),
generate.WithMatcher(match.AllOf(
match.NonPortableClass(),
match.DoesNotHaveMarker(comments.In(p), DisableMarker, "false")),
),
)
return errors.Wrap(err, "cannot write non-portable class methods")
}

View File

@ -10,6 +10,7 @@ import (
const (
NameTypeMeta = "TypeMeta"
NameObjectMeta = "ObjectMeta"
NameListMeta = "ListMeta"
NameSpec = "Spec"
NameSpecTemplate = "SpecTemplate"
NameStatus = "Status"
@ -18,12 +19,14 @@ const (
NameResourceClaimSpec = "ResourceClaimSpec"
NameNonPortableClassSpecTemplate = "NonPortableClassSpecTemplate"
NamePortableClass = "PortableClass"
NameItems = "Items"
)
// Field type suffixes.
const (
TypeSuffixTypeMeta = "k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta"
TypeSuffixObjectMeta = "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"
TypeSuffixListMeta = "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"
TypeSuffixSpec = NameSpec
TypeSuffixSpecTemplate = NameSpecTemplate
TypeSuffixStatus = NameStatus
@ -55,11 +58,11 @@ func (o Matcher) And(m Matcher) Matcher {
}
}
// Has returns true if the supplied Object's underlying type is struct, and it
// matches all of the supplied field Matchers.
// Has returns true if the supplied Object's underlying type is struct (or a
// slice or map of struct), and it matches all of the supplied field Matchers.
func Has(o types.Object, m ...Matcher) bool {
s, ok := o.Type().Underlying().(*types.Struct)
if !ok {
s := findStruct(o)
if s == nil {
return false
}
for _, matcher := range m {
@ -70,14 +73,39 @@ func Has(o types.Object, m ...Matcher) bool {
return true
}
func findStruct(o types.Object) *types.Struct {
switch t := o.Type().Underlying().(type) {
case *types.Struct:
return t
case *types.Slice:
s, ok := t.Elem().Underlying().(*types.Struct)
if !ok {
return nil
}
return s
case *types.Map:
s, ok := t.Elem().Underlying().(*types.Struct)
if !ok {
return nil
}
return s
}
return nil
}
// IsEmbedded returns a Matcher that returns true if the supplied field is
// embedded.
func IsEmbedded(m Matcher) Matcher {
func IsEmbedded() Matcher {
return func(f *types.Var) bool {
if !f.Embedded() {
return false
}
return m(f)
return f.Embedded()
}
}
// IsSlice returns a Matcher that returns true if the supplied field is a slice.
func IsSlice() Matcher {
return func(f *types.Var) bool {
_, ok := f.Type().Underlying().(*types.Slice)
return ok
}
}
@ -119,6 +147,10 @@ func IsTypeMeta() Matcher { return IsTypeNamed(TypeSuffixTypeMeta, NameTypeMeta)
// appears to be Kubernetes object metadata.
func IsObjectMeta() Matcher { return IsTypeNamed(TypeSuffixObjectMeta, NameObjectMeta) }
// IsListMeta returns a Matcher that returns true if the supplied field appears
// to be Kubernetes list metadata.
func IsListMeta() Matcher { return IsTypeNamed(TypeSuffixListMeta, NameListMeta) }
// IsSpec returns a Matcher that returns true if the supplied field appears to
// be a Kubernetes resource spec.
func IsSpec() Matcher { return IsTypeNamed(NameSpec, TypeSuffixSpec) }
@ -163,3 +195,9 @@ func IsNonPortableClassSpecTemplate() Matcher {
func IsPortableClass() Matcher {
return IsTypeNamed(TypeSuffixPortableClass, NamePortableClass)
}
// IsItems returns a Matcher that returns true if the supplied field appears to
// be the Items of a Kubernetes list.
func IsItems() Matcher {
return IsNamed(NameItems)
}

View File

@ -17,7 +17,7 @@ import (
// HeaderGenerated is added to all files generated by angryjet.
// See https://github.com/golang/go/issues/13560#issuecomment-288457920.
const HeaderGenerated = "Code generated https://github.com/negz/angryjet. DO NOT EDIT."
const HeaderGenerated = "Code generated by https://github.com/negz/angryjet. DO NOT EDIT."
type options struct {
Matches match.Object

View File

@ -1,71 +0,0 @@
// Package managed writes the method set required to satisfy
// crossplane-runtime's resource.Managed interface.
package managed
import (
"path/filepath"
"github.com/pkg/errors"
"golang.org/x/tools/go/packages"
"github.com/negz/angryjet/internal/comments"
"github.com/negz/angryjet/internal/generate"
"github.com/negz/angryjet/internal/generators/methods"
"github.com/negz/angryjet/internal/match"
)
// Imports used in generated code.
const (
CoreAlias = "corev1"
CoreImport = "k8s.io/api/core/v1"
RuntimeAlias = "runtimev1alpha1"
RuntimeImport = "github.com/crossplaneio/crossplane-runtime/apis/core/v1alpha1"
)
const (
// Receiver name for managed resource generated methods.
Receiver = "mg"
// FileName for managed resource generated methods.
FileName = "managed.go"
// DisableMarker used to disable generation of managed resource methods for
// a type that otherwise appears to be a managed resource that is missing a
// subnet of its methods.
DisableMarker = "crossplane:generate:methods"
)
// Methods to generate for managed resources that are missing them.
var Methods = generate.MethodSet{
"SetConditions": methods.NewSetConditions(Receiver, RuntimeImport),
"SetBindingPhase": methods.NewSetBindingPhase(Receiver, RuntimeImport),
"GetBindingPhase": methods.NewGetBindingPhase(Receiver, RuntimeImport),
"SetClaimReference": methods.NewSetClaimReference(Receiver, CoreImport),
"GetClaimReference": methods.NewGetClaimReference(Receiver, CoreImport),
"SetNonPortableClassReference": methods.NewSetNonPortableClassReference(Receiver, CoreImport),
"GetNonPortableClassReference": methods.NewGetNonPortableClassReference(Receiver, CoreImport),
"SetWriteConnectionSecretToReference": methods.NewSetWriteConnectionSecretToReference(Receiver, CoreImport),
"GetWriteConnectionSecretToReference": methods.NewGetWriteConnectionSecretToReference(Receiver, CoreImport),
"SetReclaimPolicy": methods.NewSetReclaimPolicy(Receiver, RuntimeImport),
"GetReclaimPolicy": methods.NewGetReclaimPolicy(Receiver, RuntimeImport),
}
// WriteMethods for all managed resources in the supplied package. Methods will
// be written to a file under the package's path relative to the supplied base
// path. The file will be named FileName, prefixed with the supplied prefix. The
// supplied header will be written as a comment to all generated files.
func WriteMethods(base, prefix, header string, p *packages.Package) error {
err := generate.WriteMethods(p, Methods, filepath.Join(base, p.PkgPath, prefix+FileName),
generate.WithHeaders(header),
generate.WithImportAliases(map[string]string{
CoreImport: CoreAlias,
RuntimeImport: RuntimeAlias,
}),
generate.WithMatcher(match.AllOf(
match.Managed(),
match.DoesNotHaveMarker(comments.In(p), DisableMarker, "false")),
),
)
return errors.Wrap(err, "cannot write managed resource methods")
}

View File

@ -17,10 +17,14 @@ type Object func(o types.Object) bool
func Managed() Object {
return func(o types.Object) bool {
return fields.Has(o,
fields.IsTypeMeta(),
fields.IsObjectMeta(),
fields.IsSpec().And(fields.HasFieldThat(fields.IsEmbedded(fields.IsResourceSpec()))),
fields.IsStatus().And(fields.HasFieldThat(fields.IsEmbedded(fields.IsResourceStatus()))),
fields.IsTypeMeta().And(fields.IsEmbedded()),
fields.IsObjectMeta().And(fields.IsEmbedded()),
fields.IsSpec().And(fields.HasFieldThat(
fields.IsResourceSpec().And(fields.IsEmbedded()),
)),
fields.IsStatus().And(fields.HasFieldThat(
fields.IsResourceStatus().And(fields.IsEmbedded()),
)),
)
}
}
@ -30,9 +34,11 @@ func Managed() Object {
func NonPortableClass() Object {
return func(o types.Object) bool {
return fields.Has(o,
fields.IsTypeMeta(),
fields.IsObjectMeta(),
fields.IsSpecTemplate().And(fields.HasFieldThat(fields.IsEmbedded(fields.IsNonPortableClassSpecTemplate()))),
fields.IsTypeMeta().And(fields.IsEmbedded()),
fields.IsObjectMeta().And(fields.IsEmbedded()),
fields.IsSpecTemplate().And(fields.HasFieldThat(
fields.IsNonPortableClassSpecTemplate().And(fields.IsEmbedded()),
)),
)
}
}
@ -42,9 +48,11 @@ func NonPortableClass() Object {
func Claim() Object {
return func(o types.Object) bool {
return fields.Has(o,
fields.IsTypeMeta(),
fields.IsObjectMeta(),
fields.IsSpec().And(fields.HasFieldThat(fields.IsEmbedded(fields.IsResourceClaimSpec()))),
fields.IsTypeMeta().And(fields.IsEmbedded()),
fields.IsObjectMeta().And(fields.IsEmbedded()),
fields.IsSpec().And(fields.HasFieldThat(
fields.IsResourceClaimSpec().And(fields.IsEmbedded()),
)),
fields.IsResourceClaimStatus(),
)
}
@ -55,9 +63,25 @@ func Claim() Object {
func PortableClass() Object {
return func(o types.Object) bool {
return fields.Has(o,
fields.IsTypeMeta(),
fields.IsObjectMeta(),
fields.IsEmbedded(fields.IsPortableClass()),
fields.IsTypeMeta().And(fields.IsEmbedded()),
fields.IsObjectMeta().And(fields.IsEmbedded()),
fields.IsPortableClass().And(fields.IsEmbedded()),
)
}
}
// PortableClassList returns an Object matcher that returns true if the supplied
// Object is a Crossplane portable resource class list.
func PortableClassList() Object {
return func(o types.Object) bool {
return fields.Has(o,
fields.IsTypeMeta().And(fields.IsEmbedded()),
fields.IsListMeta().And(fields.IsEmbedded()),
fields.IsItems().And(fields.IsSlice()).And(fields.HasFieldThat(
fields.IsTypeMeta().And(fields.IsEmbedded()),
fields.IsObjectMeta().And(fields.IsEmbedded()),
fields.IsPortableClass().And(fields.IsEmbedded()),
)),
)
}
}

View File

@ -3,6 +3,7 @@ package methods
import (
"go/types"
"strings"
"github.com/dave/jennifer/jen"
"github.com/negz/angryjet/internal/fields"
@ -64,6 +65,28 @@ func NewGetClaimReference(receiver, core string) generate.NewMethod {
}
}
// NewSetResourceReference returns a NewMethod that writes a
// SetResourceReference method for the supplied Object to the supplied file.
func NewSetResourceReference(receiver, core string) generate.NewMethod {
return func(f *jen.File, o types.Object) {
f.Commentf("SetResourceReference of this %s.", o.Name())
f.Func().Params(jen.Id(receiver).Op("*").Id(o.Name())).Id("SetResourceReference").Params(jen.Id("r").Op("*").Qual(core, "ObjectReference")).Block(
jen.Id(receiver).Dot(fields.NameSpec).Dot("ResourceReference").Op("=").Id("r"),
)
}
}
// NewGetResourceReference returns a NewMethod that writes a
// GetResourceReference method for the supplied Object to the supplied file.
func NewGetResourceReference(receiver, core string) generate.NewMethod {
return func(f *jen.File, o types.Object) {
f.Commentf("GetResourceReference of this %s.", o.Name())
f.Func().Params(jen.Id(receiver).Op("*").Id(o.Name())).Id("GetResourceReference").Params().Op("*").Qual(core, "ObjectReference").Block(
jen.Return(jen.Id(receiver).Dot(fields.NameSpec).Dot("ResourceReference")),
)
}
}
// NewSetNonPortableClassReference returns a NewMethod that writes a
// SetNonPortableClassReference method for the supplied Object to the supplied
// file.
@ -88,6 +111,30 @@ func NewGetNonPortableClassReference(receiver, core string) generate.NewMethod {
}
}
// NewSetPortableClassReference returns a NewMethod that writes a
// SetPortableClassReference method for the supplied Object to the supplied
// file.
func NewSetPortableClassReference(receiver, core string) generate.NewMethod {
return func(f *jen.File, o types.Object) {
f.Commentf("SetPortableClassReference of this %s.", o.Name())
f.Func().Params(jen.Id(receiver).Op("*").Id(o.Name())).Id("SetPortableClassReference").Params(jen.Id("r").Op("*").Qual(core, "LocalObjectReference")).Block(
jen.Id(receiver).Dot(fields.NameSpec).Dot("PortableClassReference").Op("=").Id("r"),
)
}
}
// NewGetPortableClassReference returns a NewMethod that writes a
// GetPortableClassReference method for the supplied Object to the supplied
// file.
func NewGetPortableClassReference(receiver, core string) generate.NewMethod {
return func(f *jen.File, o types.Object) {
f.Commentf("GetPortableClassReference of this %s.", o.Name())
f.Func().Params(jen.Id(receiver).Op("*").Id(o.Name())).Id("GetPortableClassReference").Params().Op("*").Qual(core, "LocalObjectReference").Block(
jen.Return(jen.Id(receiver).Dot(fields.NameSpec).Dot("PortableClassReference")),
)
}
}
// NewSetWriteConnectionSecretToReference returns a NewMethod that writes a
// SetWriteConnectionSecretToReference method for the supplied Object to the
// supplied file.
@ -133,3 +180,35 @@ func NewGetReclaimPolicy(receiver, runtime string) generate.NewMethod {
)
}
}
// NewSetPortableClassItems returns a NewMethod that writes a
// SetPortableClassItems method for the supplied Object to the supplied file.
func NewSetPortableClassItems(receiver, resource string) generate.NewMethod {
return func(f *jen.File, o types.Object) {
element := strings.TrimSuffix(o.Name(), "List")
f.Commentf("SetPortableClassItems of this %s.", o.Name())
f.Func().Params(jen.Id(receiver).Op("*").Id(o.Name())).Id("SetPortableClassItems").Params(jen.Id("i").Index().Qual(resource, "PortableClass")).Block(
jen.Id(receiver).Dot("Items").Op("=").Make(jen.Index().Id(element), jen.Id("0"), jen.Len(jen.Id("i"))),
jen.For(jen.Id("j").Op(":=").Range().Id("i")).Block(
jen.If(jen.List(jen.Id("actual"), jen.Id("ok")).Op(":=").Id("i").Index(jen.Id("j")).Assert(jen.Op("*").Id(element)), jen.Id("ok")).Block(
jen.Id(receiver).Dot("Items").Op("=").Append(jen.Id(receiver).Dot("Items"), jen.Op("*").Id("actual")),
),
),
)
}
}
// NewGetPortableClassItems returns a NewMethod that writes a
// GetPortableClassItems method for the supplied Object to the supplied file.
func NewGetPortableClassItems(receiver, resource string) generate.NewMethod {
return func(f *jen.File, o types.Object) {
f.Commentf("GetPortableClassItems of this %s.", o.Name())
f.Func().Params(jen.Id(receiver).Op("*").Id(o.Name())).Id("GetPortableClassItems").Params().Index().Qual(resource, "PortableClass").Block(
jen.Id("items").Op(":=").Make(jen.Index().Qual(resource, "PortableClass"), jen.Len(jen.Id(receiver).Dot("Items"))),
jen.For(jen.Id("i").Op(":=").Range().Id(receiver).Dot("Items")).Block(
jen.Id("items").Index(jen.Id("i")).Op("=").Qual(resource, "PortableClass").Call(jen.Op("&").Id(receiver).Dot("Items").Index(jen.Id("i"))),
),
jen.Return(jen.Id("items")),
)
}
}

View File

@ -103,6 +103,39 @@ func (t *Type) GetClaimReference() *core.ObjectReference {
t.Errorf("NewGetClaimReference(): -want, +got\n%s", diff)
}
}
func TestNewSetResourceReference(t *testing.T) {
want := `package pkg
import core "example.org/core"
// SetResourceReference of this Type.
func (t *Type) SetResourceReference(r *core.ObjectReference) {
t.Spec.ResourceReference = r
}
`
f := jen.NewFile("pkg")
NewSetResourceReference("t", "example.org/core")(f, MockObject{Named: "Type"})
if diff := cmp.Diff(want, fmt.Sprintf("%#v", f)); diff != "" {
t.Errorf("NewSetResourceReference(): -want, +got\n%s", diff)
}
}
func TestNewGetResourceReference(t *testing.T) {
want := `package pkg
import core "example.org/core"
// GetResourceReference of this Type.
func (t *Type) GetResourceReference() *core.ObjectReference {
return t.Spec.ResourceReference
}
`
f := jen.NewFile("pkg")
NewGetResourceReference("t", "example.org/core")(f, MockObject{Named: "Type"})
if diff := cmp.Diff(want, fmt.Sprintf("%#v", f)); diff != "" {
t.Errorf("NewGetResourceReference(): -want, +got\n%s", diff)
}
}
func TestNewSetNonPortableClassReference(t *testing.T) {
want := `package pkg
@ -137,6 +170,39 @@ func (t *Type) GetNonPortableClassReference() *core.ObjectReference {
t.Errorf("NewGetNonPortableClassReference(): -want, +got\n%s", diff)
}
}
func TestNewSetPortableClassReference(t *testing.T) {
want := `package pkg
import core "example.org/core"
// SetPortableClassReference of this Type.
func (t *Type) SetPortableClassReference(r *core.LocalObjectReference) {
t.Spec.PortableClassReference = r
}
`
f := jen.NewFile("pkg")
NewSetPortableClassReference("t", "example.org/core")(f, MockObject{Named: "Type"})
if diff := cmp.Diff(want, fmt.Sprintf("%#v", f)); diff != "" {
t.Errorf("NewSetPortableClassReference(): -want, +got\n%s", diff)
}
}
func TestNewGetPortableClassReference(t *testing.T) {
want := `package pkg
import core "example.org/core"
// GetPortableClassReference of this Type.
func (t *Type) GetPortableClassReference() *core.LocalObjectReference {
return t.Spec.PortableClassReference
}
`
f := jen.NewFile("pkg")
NewGetPortableClassReference("t", "example.org/core")(f, MockObject{Named: "Type"})
if diff := cmp.Diff(want, fmt.Sprintf("%#v", f)); diff != "" {
t.Errorf("NewGetPortableClassReference(): -want, +got\n%s", diff)
}
}
func TestNewSetWriteConnectionSecretToReference(t *testing.T) {
want := `package pkg
@ -205,3 +271,46 @@ func (t *Type) GetReclaimPolicy() runtime.ReclaimPolicy {
t.Errorf("NewGetReclaimPolicy(): -want, +got\n%s", diff)
}
}
func TestNewSetPortableClassItems(t *testing.T) {
want := `package pkg
import resource "example.org/resource"
// SetPortableClassItems of this TypeList.
func (tl *TypeList) SetPortableClassItems(i []resource.PortableClass) {
tl.Items = make([]Type, 0, len(i))
for j := range i {
if actual, ok := i[j].(*Type); ok {
tl.Items = append(tl.Items, *actual)
}
}
}
`
f := jen.NewFile("pkg")
NewSetPortableClassItems("tl", "example.org/resource")(f, MockObject{Named: "TypeList"})
if diff := cmp.Diff(want, fmt.Sprintf("%#v", f)); diff != "" {
t.Errorf("NewSetPortableClassItems(): -want, +got\n%s", diff)
}
}
func TestNewGetPortableClassItems(t *testing.T) {
want := `package pkg
import resource "example.org/resource"
// GetPortableClassItems of this Type.
func (t *Type) GetPortableClassItems() []resource.PortableClass {
items := make([]resource.PortableClass, len(t.Items))
for i := range t.Items {
items[i] = resource.PortableClass(&t.Items[i])
}
return items
}
`
f := jen.NewFile("pkg")
NewGetPortableClassItems("t", "example.org/resource")(f, MockObject{Named: "Type"})
if diff := cmp.Diff(want, fmt.Sprintf("%#v", f)); diff != "" {
t.Errorf("NewGetPortableClassItems(): -want, +got\n%s", diff)
}
}