github.com/lastbackend/toolkit@v0.0.0-20241020043710-cafa37b95aad/pkg/runtime/controller/config.go (about) 1 package controller 2 3 import ( 4 "context" 5 "fmt" 6 "github.com/caarlos0/env/v7" 7 "github.com/fatih/structs" 8 "github.com/jedib0t/go-pretty/v6/table" 9 "github.com/jedib0t/go-pretty/v6/text" 10 "github.com/lastbackend/toolkit/pkg/runtime" 11 "github.com/lastbackend/toolkit/pkg/runtime/meta" 12 "strings" 13 ) 14 15 const ConfigPrefixSeparator = "_" 16 17 type configController struct { 18 runtime.Config 19 20 runtime runtime.Runtime 21 configs []any 22 parsed map[string]interface{} 23 prefix string 24 } 25 26 func (c *configController) buildPrefix(prefix string) string { 27 28 pt := make([]string, 0) 29 if c.prefix != "" { 30 pt = append(pt, c.prefix) 31 } 32 33 if prefix != "" { 34 pt = append(pt, prefix) 35 } 36 37 if len(pt) > 0 { 38 pt = append(pt, "") 39 return strings.ToUpper(strings.Join(pt, ConfigPrefixSeparator)) 40 } 41 42 return "" 43 } 44 45 func (c *configController) Configs() []any { 46 return c.configs 47 } 48 49 func (c *configController) Provide(cfgs ...any) error { 50 51 if len(cfgs) == 0 { 52 return nil 53 } 54 55 for _, cfg := range cfgs { 56 if err := c.Parse(cfg, ""); err != nil { 57 c.runtime.Log().V(5).Errorf("can not parse config: %s", err.Error()) 58 return err 59 } 60 c.configs = append(c.configs, cfg) 61 } 62 63 return nil 64 } 65 66 func (c *configController) SetMeta(meta *meta.Meta) { 67 c.prefix = meta.GetEnvPrefix() 68 } 69 70 func (c *configController) Parse(v interface{}, prefix string, opts ...env.Options) error { 71 c.parsed[prefix] = v 72 opts = append(opts, env.Options{Prefix: c.buildPrefix(prefix)}) 73 return env.Parse(v, opts...) 74 } 75 76 func (c *configController) Print(v interface{}, prefix string) { 77 78 tw := table.NewWriter() 79 tw.AppendHeader(table.Row{"ENVIRONMENT", "DEFAULT VALUE", "REQUIRED", "DESCRIPTION"}) 80 tw.Style().Options.DrawBorder = true 81 tw.Style().Options.SeparateColumns = true 82 tw.Style().Options.SeparateFooter = false 83 tw.Style().Options.SeparateHeader = true 84 tw.Style().Options.SeparateRows = true 85 86 fields := structs.Fields(v) 87 for _, field := range fields { 88 89 tagE := field.Tag("env") 90 tagD := field.Tag("envDefault") 91 tagR := field.Tag("required") 92 tagC := field.Tag("comment") 93 94 if tagE != "" { 95 tw.AppendRows([]table.Row{ 96 {fmt.Sprintf("%s%s", c.buildPrefix(prefix), tagE), tagD, tagR, text.WrapText(tagC, 120)}, 97 }) 98 } 99 100 } 101 102 fmt.Println(tw.Render()) 103 } 104 105 func (c *configController) PrintTable(all, nocomments bool) string { 106 107 tw := table.NewWriter() 108 109 if nocomments { 110 tw.AppendHeader(table.Row{"ENVIRONMENT", "DEFAULT VALUE"}) 111 } else { 112 tw.AppendHeader(table.Row{"ENVIRONMENT", "DEFAULT VALUE", "REQUIRED", "DESCRIPTION"}) 113 } 114 115 tw.Style().Options.DrawBorder = true 116 tw.Style().Options.SeparateColumns = true 117 tw.Style().Options.SeparateFooter = false 118 tw.Style().Options.SeparateHeader = true 119 tw.Style().Options.SeparateRows = true 120 121 for prefix, v := range c.parsed { 122 fields := structs.Fields(v) 123 for _, field := range fields { 124 125 tagE := field.Tag("env") 126 tagD := field.Tag("envDefault") 127 tagR := field.Tag("required") 128 tagC := field.Tag("comment") 129 130 if tagE != "" { 131 132 if tagD == "" && tagR == "" && !all { 133 continue 134 } 135 136 if nocomments { 137 tw.AppendRows([]table.Row{ 138 {fmt.Sprintf("%s%s", c.buildPrefix(prefix), tagE), tagD}, 139 }) 140 } else { 141 tw.AppendRows([]table.Row{ 142 {fmt.Sprintf("%s%s", c.buildPrefix(prefix), tagE), tagD, tagR, text.WrapText(tagC, 120)}, 143 }) 144 } 145 146 } 147 148 } 149 } 150 151 return tw.Render() 152 } 153 154 func (c *configController) PrintYaml(all, nocomments bool) string { 155 156 yamlStr := "---" 157 158 for prefix, v := range c.parsed { 159 fields := structs.Fields(v) 160 for _, field := range fields { 161 162 tagE := field.Tag("env") 163 tagD := field.Tag("envDefault") 164 tagR := field.Tag("required") 165 tagC := field.Tag("comment") 166 167 if tagE != "" { 168 169 if tagD == "" && tagR == "" && !all { 170 continue 171 } 172 if tagC != "" && !nocomments { 173 yamlStr = fmt.Sprintf("%s\n// %s", yamlStr, tagC) 174 } 175 if tagD != "" { 176 yamlStr = fmt.Sprintf("%s\n%s: '%s'", yamlStr, fmt.Sprintf("%s%s", c.buildPrefix(prefix), tagE), tagD) 177 } else { 178 yamlStr = fmt.Sprintf("%s\n%s:", yamlStr, fmt.Sprintf("%s%s", c.buildPrefix(prefix), tagE)) 179 } 180 181 } 182 183 } 184 } 185 186 return yamlStr 187 } 188 189 func newConfigController(_ context.Context, runtime runtime.Runtime) runtime.Config { 190 cfg := new(configController) 191 cfg.runtime = runtime 192 193 cfg.configs = make([]interface{}, 0) 194 cfg.parsed = make(map[string]interface{}, 0) 195 196 return cfg 197 }