3 files changed,
93 insertions(+),
1 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-02-13 00:07:29 +0200
Authored at:
2026-02-12 23:23:18 +0200
Change ID:
kuwtpkzyrplzpzynozotqmukxwwpkzol
Parent:
8703591
M
internal/config/config.go
路路路 5 5 "fmt" 6 6 "os" 7 7 "path/filepath" 8 + "strings" 8 9 9 10 "gopkg.in/yaml.v2" 10 11 ) 11 12 12 -var ErrConfigNotFound = errors.New("no config file found") 13 +var ( 14 + ErrConfigNotFound = errors.New("no config file found") 15 + ErrUnsetEnv = errors.New("environment variable is not set") 16 + ErrFileNotFound = errors.New("provided file path is invalid") 17 +) 13 18 14 19 type ServerConfig struct { 15 20 Host string `yaml:"host"` 路路路 66 71 67 72 config.ensureDefaults() 68 73 74 + if perr := config.parseValues(); perr != nil { 75 + return nil, perr 76 + } 77 + 69 78 if verr := config.validate(); verr != nil { 70 79 return nil, verr 71 80 } 路路路 131 140 // mirroring 132 141 if c.Mirror.Interval == "" { 133 142 c.Mirror.Interval = "8h" 143 + } 144 +} 145 + 146 +func (c *Config) parseValues() error { 147 + if c.Mirror.Enable { 148 + ghToken, err := parseValue(c.Mirror.GithubToken) 149 + if err != nil { 150 + return err 151 + } 152 + c.Mirror.GithubToken = ghToken 153 + } 154 + return nil 155 +} 156 + 157 +func parseValue(value string) (string, error) { 158 + envPrefix := "$env:" 159 + filePrefix := "$file:" 160 + 161 + switch { 162 + case strings.HasPrefix(value, envPrefix): 163 + env := os.Getenv(os.ExpandEnv(value[len(envPrefix):])) 164 + if env == "" { 165 + return "", ErrUnsetEnv 166 + } 167 + return env, nil 168 + 169 + case strings.HasPrefix(value, filePrefix): 170 + // supports only absolute paths 171 + 172 + fpath := value[len(filePrefix):] 173 + if !isFileExists(fpath) { 174 + return "", ErrFileNotFound 175 + } 176 + 177 + data, err := os.ReadFile(fpath) 178 + if err != nil { 179 + return "", err 180 + } 181 + 182 + return strings.TrimSpace(string(data)), nil 183 + 184 + default: 185 + return value, nil 134 186 } 135 187 } 136 188
M
internal/config/config_test.go
路路路 8 8 "olexsmir.xyz/x/is" 9 9 ) 10 10 11 +func TestConfig_parseValue(t *testing.T) { 12 + def := "qwerty123" 13 + 14 + t.Run("string", func(t *testing.T) { 15 + r, err := parseValue(def) 16 + is.Err(t, err, nil) 17 + is.Equal(t, r, def) 18 + }) 19 + 20 + t.Run("env var", func(t *testing.T) { 21 + t.Setenv("secret_value", "123") 22 + r, err := parseValue("$env:secret_value") 23 + is.Err(t, err, nil) 24 + is.Equal(t, r, "123") 25 + }) 26 + 27 + t.Run("unset env var", func(t *testing.T) { 28 + _, err := parseValue("$env:secret_password") 29 + is.Err(t, err, ErrUnsetEnv) 30 + }) 31 + 32 + t.Run("file", func(t *testing.T) { 33 + fpath, _ := filepath.Abs("./testdata/file_value") 34 + r, err := parseValue("$file:" + fpath) 35 + is.Err(t, err, nil) 36 + is.Equal(t, r, def) 37 + }) 38 + 39 + t.Run("non existing file", func(t *testing.T) { 40 + _, err := parseValue("$file:/not/exists") 41 + is.Err(t, err, ErrFileNotFound) 42 + }) 43 + 44 + t.Run("file, not set path", func(t *testing.T) { 45 + _, err := parseValue("$file:") 46 + is.Err(t, err, ErrFileNotFound) 47 + }) 48 +} 49 + 11 50 func TestPathOrDefaultWithCandidates(t *testing.T) { 12 51 first := candidateFile(t, "first.yaml") 13 52 second := candidateFile(t, "second.yaml")