103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
package ezconf
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// ParseConfigStruct extracts environment variable metadata from a config
|
|
// struct's ezconf struct tags using reflection.
|
|
//
|
|
// The configPtr parameter must be a pointer to a struct. Each field with an
|
|
// ezconf tag will be parsed to extract environment variable information.
|
|
//
|
|
// Tag format: `ezconf:"VAR_NAME,description:Description text,default:value,required"`
|
|
//
|
|
// Components:
|
|
// - First value: environment variable name (required)
|
|
// - description:...: Description of the variable
|
|
// - default:...: Default value
|
|
// - required: Marks the variable as required (optionally required:condition)
|
|
func ParseConfigStruct(configPtr any) ([]EnvVar, error) {
|
|
if configPtr == nil {
|
|
return nil, errors.New("config pointer cannot be nil")
|
|
}
|
|
|
|
v := reflect.ValueOf(configPtr)
|
|
if v.Kind() != reflect.Ptr {
|
|
return nil, errors.New("config must be a pointer to a struct")
|
|
}
|
|
|
|
v = v.Elem()
|
|
if v.Kind() != reflect.Struct {
|
|
return nil, errors.New("config must be a pointer to a struct")
|
|
}
|
|
|
|
t := v.Type()
|
|
envVars := make([]EnvVar, 0)
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
tag := field.Tag.Get("ezconf")
|
|
if tag == "" {
|
|
continue
|
|
}
|
|
|
|
envVar, err := parseEzconfTag(tag)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to parse ezconf tag on field %s", field.Name)
|
|
}
|
|
|
|
envVars = append(envVars, *envVar)
|
|
}
|
|
|
|
return envVars, nil
|
|
}
|
|
|
|
// parseEzconfTag parses an ezconf struct tag value to extract environment
|
|
// variable information.
|
|
//
|
|
// Expected format: "VAR_NAME,description:Description text,default:value,required"
|
|
func parseEzconfTag(tag string) (*EnvVar, error) {
|
|
if tag == "" {
|
|
return nil, errors.New("tag cannot be empty")
|
|
}
|
|
|
|
parts := strings.Split(tag, ",")
|
|
if len(parts) == 0 {
|
|
return nil, errors.New("tag cannot be empty")
|
|
}
|
|
|
|
envVar := &EnvVar{
|
|
Name: strings.TrimSpace(parts[0]),
|
|
}
|
|
|
|
if envVar.Name == "" {
|
|
return nil, errors.New("environment variable name cannot be empty")
|
|
}
|
|
|
|
for _, part := range parts[1:] {
|
|
part = strings.TrimSpace(part)
|
|
|
|
switch {
|
|
case strings.HasPrefix(part, "description:"):
|
|
envVar.Description = strings.TrimSpace(strings.TrimPrefix(part, "description:"))
|
|
case strings.HasPrefix(part, "default:"):
|
|
envVar.Default = strings.TrimSpace(strings.TrimPrefix(part, "default:"))
|
|
case part == "required":
|
|
envVar.Required = true
|
|
case strings.HasPrefix(part, "required:"):
|
|
envVar.Required = true
|
|
// Store the condition in the description if it adds context
|
|
condition := strings.TrimSpace(strings.TrimPrefix(part, "required:"))
|
|
if condition != "" && envVar.Description != "" {
|
|
envVar.Description = envVar.Description + " (required " + condition + ")"
|
|
}
|
|
}
|
|
}
|
|
|
|
return envVar, nil
|
|
}
|