github.com/harryzcy/snuuze@v0.3.3-0.20240314015559-83a8fc5627a8/config/hosting.go (about)

     1  package config
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"strconv"
     9  	"unicode"
    10  
    11  	"github.com/harryzcy/snuuze/types"
    12  	"github.com/spf13/viper"
    13  )
    14  
    15  var (
    16  	ConfigFile = defaultValue(os.Getenv("SNUUZE_CONFIG_FILE"), "config.yaml")
    17  
    18  	hostingConfig types.HostingConfig
    19  )
    20  
    21  // LoadConfig loads the configuration for the application
    22  func LoadHostingConfig() error {
    23  	c := viper.New()
    24  	c.SetConfigFile(ConfigFile)
    25  	c.SetEnvPrefix("SNUUZE")
    26  	c.AddConfigPath(".")
    27  	c.AddConfigPath(".github")
    28  	err := c.ReadInConfig()
    29  	if err != nil {
    30  		return fmt.Errorf("fatal error config file: %w", err)
    31  	}
    32  
    33  	err = c.Unmarshal(&hostingConfig)
    34  	if err != nil {
    35  		return fmt.Errorf("unable to decode into struct, %w", err)
    36  	}
    37  
    38  	loadEnvs(c)
    39  
    40  	return nil
    41  }
    42  
    43  func loadEnvs(c *viper.Viper) {
    44  	v := reflect.ValueOf(&hostingConfig).Elem()
    45  	loadEnv(c, "", v)
    46  }
    47  
    48  func loadEnv(c *viper.Viper, parent string, v reflect.Value) {
    49  	t := v.Type()
    50  	for i := 0; i < t.NumField(); i++ {
    51  		field := v.Field(i)
    52  
    53  		name := t.Field(i).Tag.Get("yaml")
    54  		if parent != "" {
    55  			name = parent + "." + name
    56  		}
    57  
    58  		if field.Type().Kind() == reflect.Struct {
    59  			loadEnv(c, name, field)
    60  			continue
    61  		}
    62  
    63  		envName := "SNUUZE_" + toEnvName(name)
    64  		value := os.Getenv(envName)
    65  		if value == "" {
    66  			continue
    67  		}
    68  
    69  		if field.IsValid() && field.CanSet() {
    70  			fmt.Println(76, field.Kind())
    71  			switch field.Kind() {
    72  			case reflect.String:
    73  				field.SetString(value)
    74  			case reflect.Bool:
    75  				isTrue, err := strconv.ParseBool(value)
    76  				if err != nil {
    77  					panic(err)
    78  				}
    79  				field.SetBool(isTrue)
    80  			case reflect.Int, reflect.Int64:
    81  				if value != "" {
    82  					intValue, err := strconv.ParseInt(value, 10, 64)
    83  					if err != nil {
    84  						panic(err)
    85  					}
    86  					if !field.OverflowInt(intValue) {
    87  						field.SetInt(intValue)
    88  					}
    89  				}
    90  			default:
    91  				panic("unsupported type")
    92  			}
    93  		}
    94  	}
    95  }
    96  
    97  func toEnvName(name string) string {
    98  	if len(name) == 0 {
    99  		return ""
   100  	}
   101  
   102  	var buf bytes.Buffer
   103  	buf.WriteRune(unicode.ToUpper(rune(name[0])))
   104  
   105  	previousLower := name[0] >= 'a' && name[0] <= 'z'
   106  	for _, r := range name[1:] {
   107  		if r == '.' {
   108  			buf.WriteRune('_')
   109  			previousLower = false
   110  			continue
   111  		}
   112  
   113  		if r >= 'A' && r <= 'Z' {
   114  			if previousLower {
   115  				buf.WriteRune('_')
   116  			}
   117  		}
   118  
   119  		buf.WriteRune(unicode.ToUpper(r))
   120  		previousLower = r >= 'a' && r <= 'z'
   121  	}
   122  	return buf.String()
   123  }
   124  
   125  func GetHostingConfig() types.HostingConfig {
   126  	return hostingConfig
   127  }
   128  
   129  // TempDir returns the temporary directory to store the data
   130  func TempDir() string {
   131  	return defaultValue(hostingConfig.Data.TempDir, os.TempDir())
   132  }
   133  
   134  func GitHubToken() string {
   135  	return defaultValue(hostingConfig.GitHub.Token, os.Getenv("GITHUB_TOKEN"))
   136  }
   137  
   138  func GoPath() string {
   139  	return os.Getenv("GOPATH")
   140  }
   141  
   142  func GoProxy() string {
   143  	return defaultValue(os.Getenv("GOPROXY"), "https://proxy.golang.org,direct")
   144  }
   145  
   146  func defaultValue[T comparable](value, defaultValue T) T {
   147  	if value == *new(T) {
   148  		return defaultValue
   149  	}
   150  
   151  	return value
   152  }