github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/cmd/mattermost/commands/utils.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package commands 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "os" 11 "reflect" 12 "sort" 13 "strings" 14 15 "github.com/spf13/cobra" 16 17 "github.com/mattermost/mattermost-server/v5/mlog" 18 "github.com/mattermost/mattermost-server/v5/model" 19 ) 20 21 const CustomDefaultsEnvVar = "MM_CUSTOM_DEFAULTS_PATH" 22 23 // prettyPrintStruct will return a prettyPrint version of a given struct 24 func prettyPrintStruct(t interface{}) string { 25 return prettyPrintMap(structToMap(t)) 26 } 27 28 // structToMap converts a struct into a map 29 func structToMap(t interface{}) map[string]interface{} { 30 defer func() { 31 if r := recover(); r != nil { 32 mlog.Warn("Panicked in structToMap. This should never happen.", mlog.Any("recover", r)) 33 } 34 }() 35 36 val := reflect.ValueOf(t) 37 38 if val.Kind() != reflect.Struct { 39 return nil 40 } 41 42 out := map[string]interface{}{} 43 44 for i := 0; i < val.NumField(); i++ { 45 field := val.Field(i) 46 47 var value interface{} 48 49 switch field.Kind() { 50 case reflect.Struct: 51 value = structToMap(field.Interface()) 52 case reflect.Ptr: 53 indirectType := field.Elem() 54 55 if indirectType.Kind() == reflect.Struct { 56 value = structToMap(indirectType.Interface()) 57 } else if indirectType.Kind() != reflect.Invalid { 58 value = indirectType.Interface() 59 } 60 default: 61 value = field.Interface() 62 } 63 64 out[val.Type().Field(i).Name] = value 65 } 66 67 return out 68 } 69 70 // prettyPrintMap will return a prettyPrint version of a given map 71 func prettyPrintMap(configMap map[string]interface{}) string { 72 value := reflect.ValueOf(configMap) 73 return printStringMap(value, 0) 74 } 75 76 // printStringMap takes a reflect.Value and prints it out alphabetically based on key values, which must be strings. 77 // This is done recursively if it's a map, and uses the given tab settings. 78 func printStringMap(value reflect.Value, tabVal int) string { 79 out := &bytes.Buffer{} 80 81 var sortedKeys []string 82 stringToKeyMap := make(map[string]reflect.Value) 83 for _, k := range value.MapKeys() { 84 sortedKeys = append(sortedKeys, k.String()) 85 stringToKeyMap[k.String()] = k 86 } 87 88 sort.Strings(sortedKeys) 89 90 for _, keyString := range sortedKeys { 91 key := stringToKeyMap[keyString] 92 val := value.MapIndex(key) 93 if newVal, ok := val.Interface().(map[string]interface{}); !ok { 94 fmt.Fprintf(out, "%s", strings.Repeat("\t", tabVal)) 95 fmt.Fprintf(out, "%v: \"%v\"\n", key.Interface(), val.Interface()) 96 } else { 97 fmt.Fprintf(out, "%s", strings.Repeat("\t", tabVal)) 98 fmt.Fprintf(out, "%v:\n", key.Interface()) 99 // going one level in, increase the tab 100 tabVal++ 101 fmt.Fprintf(out, "%s", printStringMap(reflect.ValueOf(newVal), tabVal)) 102 // coming back one level, decrease the tab 103 tabVal-- 104 } 105 } 106 107 return out.String() 108 } 109 110 func getConfigDSN(command *cobra.Command, env map[string]string) string { 111 configDSN, _ := command.Flags().GetString("config") 112 113 // Config not supplied in flag, check env 114 if configDSN == "" { 115 configDSN = env["MM_CONFIG"] 116 } 117 118 // Config not supplied in env or flag use default 119 if configDSN == "" { 120 configDSN = "config.json" 121 } 122 123 return configDSN 124 } 125 126 func loadCustomDefaults() (*model.Config, error) { 127 customDefaultsPath := os.Getenv(CustomDefaultsEnvVar) 128 if customDefaultsPath == "" { 129 return nil, nil 130 } 131 132 file, err := os.Open(customDefaultsPath) 133 if err != nil { 134 return nil, fmt.Errorf("unable to open custom defaults file at %q: %w", customDefaultsPath, err) 135 } 136 defer file.Close() 137 138 var customDefaults *model.Config 139 err = json.NewDecoder(file).Decode(&customDefaults) 140 if err != nil { 141 return nil, fmt.Errorf("unable to decode custom defaults configuration: %w", err) 142 } 143 144 return customDefaults, nil 145 }