|
| 1 | +package getters |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "fmt" |
| 6 | + "github.com/devfile/api/generator/genutils" |
| 7 | + "github.com/elliotchance/orderedmap" |
| 8 | + "go/ast" |
| 9 | + "sigs.k8s.io/controller-tools/pkg/genall" |
| 10 | + "sigs.k8s.io/controller-tools/pkg/loader" |
| 11 | + "sigs.k8s.io/controller-tools/pkg/markers" |
| 12 | + "strconv" |
| 13 | +) |
| 14 | + |
| 15 | +//go:generate go run sigs.k8s.io/controller-tools/cmd/helpgen generate:headerFile=../header.go.txt,year=2021 paths=. |
| 16 | + |
| 17 | +var ( |
| 18 | + // GetterTypeMarker is associated with a type that's used as the pointer receiver of the getter method |
| 19 | + GetterTypeMarker = markers.Must(markers.MakeDefinition("devfile:getter:generate", markers.DescribesType, struct{}{})) |
| 20 | + // DefaultFieldMarker is associated with a boolean pointer field to indicate the default boolean value |
| 21 | + DefaultFieldMarker = markers.Must(markers.MakeDefinition("devfile:default:value", markers.DescribesField, "")) |
| 22 | +) |
| 23 | + |
| 24 | +// +controllertools:marker:generateHelp |
| 25 | + |
| 26 | +// Generator generates getter methods that are used to return values for the boolean pointer fields. |
| 27 | +// |
| 28 | +// The pointer receiver is determined from the `devfile:getter:generate` annotated type. The method will return the value of the |
| 29 | +// field if it's been set, otherwise it will return the default value specified by the devfile:default:value annotation. |
| 30 | +type Generator struct{} |
| 31 | + |
| 32 | +// RegisterMarkers registers the markers of the Generator |
| 33 | +func (Generator) RegisterMarkers(into *markers.Registry) error { |
| 34 | + if err := markers.RegisterAll(into, GetterTypeMarker, DefaultFieldMarker); err != nil { |
| 35 | + return err |
| 36 | + } |
| 37 | + into.AddHelp(GetterTypeMarker, |
| 38 | + markers.SimpleHelp("Devfile", "indicates the type that's used as the pointer receiver of the getter method")) |
| 39 | + into.AddHelp(DefaultFieldMarker, |
| 40 | + markers.SimpleHelp("Devfile", "indicates the default value of a boolean pointer field")) |
| 41 | + return genutils.RegisterUnionMarkers(into) |
| 42 | + |
| 43 | +} |
| 44 | + |
| 45 | +func (Generator) CheckFilter() loader.NodeFilter { |
| 46 | + return func(node ast.Node) bool { |
| 47 | + // ignore interfaces |
| 48 | + _, isIface := node.(*ast.InterfaceType) |
| 49 | + return !isIface |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +// getterInfo stores the info to generate the getter method |
| 54 | +type getterInfo struct { |
| 55 | + funcName string |
| 56 | + defaultVal string |
| 57 | +} |
| 58 | + |
| 59 | +// Generate generates the artifacts |
| 60 | +func (g Generator) Generate(ctx *genall.GenerationContext) error { |
| 61 | + for _, root := range ctx.Roots { |
| 62 | + ctx.Checker.Check(root) |
| 63 | + root.NeedTypesInfo() |
| 64 | + |
| 65 | + typesToProcess := orderedmap.NewOrderedMap() |
| 66 | + if err := markers.EachType(ctx.Collector, root, func(info *markers.TypeInfo) { |
| 67 | + if info.Markers.Get(GetterTypeMarker.Name) != nil { |
| 68 | + var getters []getterInfo |
| 69 | + for _, field := range info.Fields { |
| 70 | + defaultVal := field.Markers.Get(DefaultFieldMarker.Name) |
| 71 | + if defaultVal != nil { |
| 72 | + if _, err := strconv.ParseBool(defaultVal.(string)); err != nil { |
| 73 | + root.AddError(fmt.Errorf("devfile:default:value marker specified on %s/%s does not have a true or false value. Value is %s", info.Name, field.Name, defaultVal.(string))) |
| 74 | + } |
| 75 | + |
| 76 | + //look for boolean pointers |
| 77 | + if ptr, isPtr := field.RawField.Type.(*ast.StarExpr); isPtr { |
| 78 | + if ident, ok := ptr.X.(*ast.Ident); ok { |
| 79 | + if ident.Name == "bool" { |
| 80 | + getters = append(getters, getterInfo{ |
| 81 | + field.Name, |
| 82 | + defaultVal.(string), |
| 83 | + }) |
| 84 | + } else { |
| 85 | + root.AddError(fmt.Errorf("devfile:default:value marker is specified on %s/%s which is not a boolean pointer", info.Name, field.Name)) |
| 86 | + } |
| 87 | + } |
| 88 | + } else { |
| 89 | + root.AddError(fmt.Errorf("devfile:default:value marker is specified on %s/%s which is not a boolean pointer", info.Name, field.Name)) |
| 90 | + } |
| 91 | + |
| 92 | + } |
| 93 | + } |
| 94 | + if len(getters) > 0 { |
| 95 | + typesToProcess.Set(info, getters) |
| 96 | + } else { |
| 97 | + root.AddError(fmt.Errorf("type %s does not have the field marker, devfile:default:value specified on a boolean pointer field", info.Name)) |
| 98 | + } |
| 99 | + return |
| 100 | + } |
| 101 | + |
| 102 | + }); err != nil { |
| 103 | + root.AddError(err) |
| 104 | + return nil |
| 105 | + } |
| 106 | + |
| 107 | + genutils.WriteFormattedSourceFile("getters", ctx, root, func(buf *bytes.Buffer) { |
| 108 | + for elt := typesToProcess.Front(); elt != nil; elt = elt.Next() { |
| 109 | + cmd := elt.Key.(*markers.TypeInfo) |
| 110 | + fields := elt.Value.([]getterInfo) |
| 111 | + for _, getter := range fields { |
| 112 | + fName := getter.funcName |
| 113 | + defaultVal := getter.defaultVal |
| 114 | + getterMethod := fmt.Sprintf(` |
| 115 | +// Get%[1]s returns the value of the boolean property. If unset, it's the default value specified in the devfile:default:value marker |
| 116 | +func (in *%[2]s) Get%[1]s() bool { |
| 117 | +return getBoolOrDefault(in.%[1]s, %[3]s)}`, fName, cmd.Name, defaultVal) |
| 118 | + buf.WriteString(getterMethod) |
| 119 | + } |
| 120 | + } |
| 121 | + |
| 122 | + internalHelper := ` |
| 123 | +
|
| 124 | +func getBoolOrDefault(input *bool, defaultVal bool) bool { |
| 125 | + if input != nil { |
| 126 | + return *input |
| 127 | + } |
| 128 | + return defaultVal }` |
| 129 | + buf.WriteString(internalHelper) |
| 130 | + }) |
| 131 | + } |
| 132 | + |
| 133 | + return nil |
| 134 | +} |
0 commit comments