Skip to content

Commit f116710

Browse files
committed
add functionality for yaml to convert bytearray to base64
1 parent 9896dba commit f116710

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

internal/pkg/utils/utils.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"encoding/base64"
55
"fmt"
66
"net/url"
7+
"reflect"
78
"strings"
89
"time"
910

11+
"github.com/goccy/go-yaml"
1012
"github.com/google/uuid"
1113
"github.com/inhies/go-bytesize"
1214
"github.com/spf13/cobra"
@@ -153,3 +155,109 @@ func ConvertStringMapToInterfaceMap(m *map[string]string) *map[string]interface{
153155
}
154156
return &result
155157
}
158+
159+
// Base64Bytes implements yaml.Marshaler to convert []byte to base64 strings
160+
// ref: https://carlosbecker.com/posts/go-custom-marshaling
161+
type Base64Bytes []byte
162+
163+
// MarshalYAML implements yaml.Marshaler
164+
func (b Base64Bytes) MarshalYAML() (interface{}, error) {
165+
if len(b) == 0 {
166+
return "", nil
167+
}
168+
return base64.StdEncoding.EncodeToString(b), nil
169+
}
170+
171+
// MarshalToYAMLWithBase64Bytes converts any struct to YAML with []byte fields as base64 strings
172+
func MarshalToYAMLWithBase64Bytes(data interface{}) ([]byte, error) {
173+
// Convert the data to a map and replace []byte fields with Base64Bytes
174+
converted := convertToMapWithBase64Bytes(data)
175+
return yaml.MarshalWithOptions(converted, yaml.IndentSequence(true))
176+
}
177+
178+
// convertToMapWithBase64Bytes converts any data to a map, replacing []byte fields with Base64Bytes
179+
// using the custom type that implements yaml.Marshaler
180+
func convertToMapWithBase64Bytes(data interface{}) interface{} {
181+
if data == nil {
182+
return nil
183+
}
184+
185+
v := reflect.ValueOf(data)
186+
t := reflect.TypeOf(data)
187+
188+
// Handle pointers
189+
if v.Kind() == reflect.Ptr {
190+
if v.IsNil() {
191+
return nil
192+
}
193+
return convertToMapWithBase64Bytes(v.Elem().Interface())
194+
}
195+
196+
// Handle slices
197+
if v.Kind() == reflect.Slice {
198+
if v.IsNil() {
199+
return nil
200+
}
201+
result := make([]interface{}, v.Len())
202+
for i := 0; i < v.Len(); i++ {
203+
result[i] = convertToMapWithBase64Bytes(v.Index(i).Interface())
204+
}
205+
return result
206+
}
207+
208+
// Handle maps
209+
if v.Kind() == reflect.Map {
210+
if v.IsNil() {
211+
return nil
212+
}
213+
result := make(map[string]interface{})
214+
for _, key := range v.MapKeys() {
215+
result[fmt.Sprintf("%v", key)] = convertToMapWithBase64Bytes(v.MapIndex(key).Interface())
216+
}
217+
return result
218+
}
219+
220+
// Handle structs
221+
if v.Kind() == reflect.Struct {
222+
result := make(map[string]interface{})
223+
for i := 0; i < v.NumField(); i++ {
224+
field := v.Field(i)
225+
fieldType := t.Field(i)
226+
227+
if !field.CanInterface() {
228+
continue
229+
}
230+
231+
fieldName := fieldType.Name
232+
if jsonTag := fieldType.Tag.Get("json"); jsonTag != "" {
233+
if parts := strings.Split(jsonTag, ","); len(parts) > 0 && parts[0] != "" {
234+
fieldName = parts[0]
235+
}
236+
}
237+
238+
// Check if this is a *[]byte field and convert to Base64Bytes
239+
if field.Kind() == reflect.Ptr &&
240+
field.Type().Elem().Kind() == reflect.Slice &&
241+
field.Type().Elem().Elem().Kind() == reflect.Uint8 {
242+
if field.IsNil() {
243+
result[fieldName] = Base64Bytes(nil)
244+
} else {
245+
result[fieldName] = Base64Bytes(field.Elem().Bytes())
246+
}
247+
} else if field.Kind() == reflect.Slice && field.Type().Elem().Kind() == reflect.Uint8 {
248+
// Handle direct []byte fields
249+
if field.IsNil() {
250+
result[fieldName] = Base64Bytes(nil)
251+
} else {
252+
result[fieldName] = Base64Bytes(field.Bytes())
253+
}
254+
} else {
255+
result[fieldName] = convertToMapWithBase64Bytes(field.Interface())
256+
}
257+
}
258+
return result
259+
}
260+
261+
// For primitive types, return as-is
262+
return data
263+
}

0 commit comments

Comments
 (0)