@@ -5,14 +5,16 @@ import (
5
5
"fmt"
6
6
"io"
7
7
"net/url"
8
+ "os"
8
9
"reflect"
9
- "strings "
10
+ "strconv "
10
11
"time"
11
12
12
13
// Packages
13
- "github.com/mutablelogic/go-server"
14
+ server "github.com/mutablelogic/go-server"
14
15
httpresponse "github.com/mutablelogic/go-server/pkg/httpresponse"
15
16
ast "github.com/mutablelogic/go-server/pkg/parser/ast"
17
+ types "github.com/mutablelogic/go-server/pkg/types"
16
18
)
17
19
18
20
////////////////////////////////////////////////////////////////////////////////
@@ -21,7 +23,9 @@ import (
21
23
type Meta struct {
22
24
Name string
23
25
Description string
26
+ Default string
24
27
Type reflect.Type
28
+ Index []int
25
29
Fields []* Meta
26
30
}
27
31
@@ -93,6 +97,9 @@ func (m *Meta) Write(w io.Writer) error {
93
97
buf .WriteString (" // " )
94
98
buf .WriteString (field .Description )
95
99
}
100
+ if field .Default != "" {
101
+ buf .WriteString (" (default: " + types .Quote (field .Default ) + ")" )
102
+ }
96
103
97
104
buf .WriteString ("\n " )
98
105
}
@@ -114,16 +121,20 @@ func (m *Meta) Validate(values any) error {
114
121
}
115
122
116
123
func (m * Meta ) New () server.Plugin {
117
- return reflect .New (m .Type ).Interface ().(server.Plugin )
124
+ obj := reflect .New (m .Type )
125
+ for _ , field := range m .Fields {
126
+ // Expand field for env
127
+ setValue (obj .Elem ().FieldByIndex (field .Index ), os .ExpandEnv (field .Default ))
128
+ }
129
+ return obj .Interface ().(server.Plugin )
118
130
}
119
131
120
132
////////////////////////////////////////////////////////////////////////////////
121
133
// PRIVATE METHODS
122
134
123
135
func newMetaField (rf reflect.StructField ) (* Meta , error ) {
124
136
meta := new (Meta )
125
-
126
- //fmt.Println("newMetaField", rf.Name, rf.Type)
137
+ meta .Index = rf .Index
127
138
128
139
// Name
129
140
if name := nameForField (rf , "json" , "yaml" , "name" ); name == "" {
@@ -134,7 +145,16 @@ func newMetaField(rf reflect.StructField) (*Meta, error) {
134
145
}
135
146
136
147
// Description
137
- meta .Description = rf .Tag .Get ("help" )
148
+ if description , _ := valueForField (rf , "description" , "help" ); description != "" {
149
+ meta .Description = description
150
+ }
151
+
152
+ // Env - needs to be an identififer
153
+ if env , _ := valueForField (rf , "env" ); types .IsIdentifier (env ) {
154
+ meta .Default = "${" + env + "}"
155
+ } else if def , _ := valueForField (rf , "default" ); def != "" {
156
+ meta .Default = def
157
+ }
138
158
139
159
// Type
140
160
if t := typeName (rf .Type ); t == "" {
@@ -152,6 +172,67 @@ var (
152
172
durationType = reflect .TypeOf (time .Duration (0 ))
153
173
)
154
174
175
+ func setValue (rv reflect.Value , str string ) error {
176
+ switch rv .Kind () {
177
+ case reflect .Bool :
178
+ // Zero value
179
+ if str == "" {
180
+ rv .SetZero ()
181
+ }
182
+ // Bool
183
+ if v , err := strconv .ParseBool (str ); err != nil {
184
+ return httpresponse .ErrBadRequest .Withf ("invalid value for %s: %q" , rv .Type (), str )
185
+ } else {
186
+ rv .SetBool (v )
187
+ }
188
+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
189
+ // Zero value
190
+ if str == "" {
191
+ rv .SetZero ()
192
+ }
193
+ // Duration
194
+ if rv .Type () == durationType {
195
+ if v , err := time .ParseDuration (str ); err != nil {
196
+ return httpresponse .ErrBadRequest .Withf ("invalid value for %s: %q" , rv .Type (), str )
197
+ } else {
198
+ rv .Set (reflect .ValueOf (v ))
199
+ }
200
+ }
201
+ // Int
202
+ if v , err := strconv .ParseInt (str , 10 , 64 ); err != nil {
203
+ return httpresponse .ErrBadRequest .Withf ("invalid value for %s: %q" , rv .Type (), str )
204
+ } else {
205
+ rv .SetInt (v )
206
+ }
207
+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 :
208
+ // Zero value
209
+ if str == "" {
210
+ rv .SetZero ()
211
+ }
212
+ // Uint
213
+ if v , err := strconv .ParseUint (str , 10 , 64 ); err != nil {
214
+ return httpresponse .ErrBadRequest .Withf ("invalid value for %s: %q" , rv .Type (), str )
215
+ } else {
216
+ rv .SetUint (v )
217
+ }
218
+ case reflect .Float32 , reflect .Float64 :
219
+ // Zero value
220
+ if str == "" {
221
+ rv .SetZero ()
222
+ }
223
+ // Float
224
+ if v , err := strconv .ParseFloat (str , 64 ); err != nil {
225
+ return httpresponse .ErrBadRequest .Withf ("invalid value for %s: %q" , rv .Type (), str )
226
+ } else {
227
+ rv .SetFloat (v )
228
+ }
229
+ case reflect .String :
230
+ // String
231
+ rv .SetString (str )
232
+ }
233
+ return httpresponse .ErrBadRequest .Withf ("invalid value for %s: %q" , rv .Type (), str )
234
+ }
235
+
155
236
func typeName (rt reflect.Type ) string {
156
237
if rt .Kind () == reflect .Ptr {
157
238
rt = rt .Elem ()
@@ -189,20 +270,26 @@ func typeName(rt reflect.Type) string {
189
270
return "ref"
190
271
}
191
272
192
- func nameForField ( rt reflect.StructField , tags ... string ) string {
273
+ func valueForField ( rf reflect.StructField , tags ... string ) ( string , bool ) {
193
274
for _ , tag := range tags {
194
- tag , ok := rt .Tag .Lookup (tag )
275
+ tag , ok := rf .Tag .Lookup (tag )
195
276
if ! ok {
196
277
continue
197
278
}
198
- if tag == "-" || tag == "" {
279
+ if tag == "-" {
199
280
// Ignore
200
- return ""
201
- }
202
- name := strings .Split (tag , "," )
203
- if len (name ) > 0 && name [0 ] != "" {
204
- return name [0 ]
281
+ return "" , true
282
+ } else {
283
+ return tag , true
205
284
}
206
285
}
286
+ return "" , false
287
+ }
288
+
289
+ func nameForField (rt reflect.StructField , tags ... string ) string {
290
+ value , exists := valueForField (rt , tags ... )
291
+ if exists {
292
+ return value
293
+ }
207
294
return rt .Name
208
295
}
0 commit comments