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  }