all repos

mugit @ b8bdd40

馃惍 git server that your cow will love
3 files changed, 93 insertions(+), 1 deletions(-)
config: $env: and $file: notations
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")

      
A internal/config/testdata/file_value
路路路
        
        1
        +qwerty123