Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional fields support to codegen/features #591

Merged
merged 1 commit into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions codegen/features/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@ import (
)

func main() {
if len(os.Args) < 6 {
if len(os.Args) < 7 {
printUsage("not enough parameters")
}

templateFilePath := os.Args[1]
conf := newConfiguration(os.Args[2], os.Args[3], os.Args[4], os.Args[5])
fileName := os.Args[2]
name := os.Args[3]
receiver := os.Args[4]
featuresStr := os.Args[5]
additionalFieldsStr := os.Args[6]

conf := newConfiguration(fileName, name, receiver, featuresStr, additionalFieldsStr)

funcs := template.FuncMap{
"firstLower": func(s string) string {
Expand All @@ -45,14 +51,14 @@ func main() {

formattedOutput := lo.PanicOnErr(format.Source(buffer.Bytes()))

panicOnError(os.WriteFile(conf.FileName, formattedOutput, 0600))
panicOnError(os.WriteFile(fileName, formattedOutput, 0600))
}

// printUsage prints the usage of the variadic code generator in case of an error.
func printUsage(errorMsg string) {
_, _ = fmt.Fprintf(os.Stderr, "Error:\t%s\n\n", errorMsg)
_, _ = fmt.Fprintf(os.Stderr, "Usage of gen/cmd:\n")
_, _ = fmt.Fprintf(os.Stderr, "\tcmd [templateFile] [outputFile] [typeName] [typeReceiver] [features separated by space]\n")
_, _ = fmt.Fprintf(os.Stderr, "\tcmd [templateFile] [outputFile] [typeName] [typeReceiver] [features separated by space] [additional fields separated by space (FieldName=FieldValue)]\n")

os.Exit(2)
}
Expand Down
70 changes: 54 additions & 16 deletions codegen/features/cmd/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,68 @@ package main

import (
"fmt"
"reflect"
"strings"
)

type configuration struct {
FileName string
Name string
Receiver string
Features map[string]bool
}

func newConfiguration(fileName, name, receiver, featuresStr string) *configuration {
func newConfiguration(fileName, name, receiver, featuresStr, additionalFieldsStr string) any {
// add all enabled features to a map
features := make(map[string]bool)
for _, feature := range strings.Split(featuresStr, " ") {
features[feature] = true
}

return &configuration{
FileName: fileName,
Name: name,
Receiver: strings.ToLower(receiver),
Features: features,
additionalFields := make(map[string]string)
for _, additionalField := range strings.Split(additionalFieldsStr, " ") {
if len(additionalField) == 0 {
continue
}

values := strings.Split(additionalField, "=")
if len(values) != 2 {
panic(fmt.Sprintf("failed to parse format of additional field, should be \"FieldName=FieldValue\", got \"%s\"", additionalField))
}

additionalFields[values[0]] = values[1]
}

// create a dynamic configuration struct
structData := map[string]any{
"FileName": fileName,
"Name": name,
"Receiver": strings.ToLower(receiver),
"Features": features,
}

// add the additional fields
for key, value := range additionalFields {
structData[key] = value
}

// gather all struct fields
structFields := make([]reflect.StructField, 0, len(structData))
for key, value := range structData {
structFields = append(structFields, reflect.StructField{
Name: key,
Type: reflect.TypeOf(value),
})
}

// create a struct type at runtime
structType := reflect.StructOf(structFields)

// create a new struct instance using reflection
newStruct := reflect.New(structType).Elem()

// set the values of the dynamic fields
for i := 0; i < newStruct.NumField(); i++ {
field := newStruct.Field(i)
fieldName := structType.Field(i).Name

if value, ok := structData[fieldName]; ok {
field.Set(reflect.ValueOf(value))
}
}
}

func (c *configuration) String() string {
return fmt.Sprintf("configuration{\n\tFileName:%s,\n\tName:%s,\n\tReceiver:%s,\n\tFeatures:%v,\n}\n", c.FileName, c.Name, c.Receiver, c.Features)
return newStruct.Interface()
}
Loading