3 files changed,
55 insertions(+),
98 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-02-13 00:07:29 +0200
Authored at:
2026-02-12 22:15:35 +0200
Change ID:
lwxymwsrprsnylporrqztkzquyxktwpv
Parent:
c9e6e1a
M
internal/cli/cli.go
路路路 35 35 }, 36 36 }, 37 37 Before: func(ctx context.Context, cmd *cli.Command) (context.Context, error) { 38 - loadedCfg, err := config.Load(cmd.String("config")) 38 + loadedCfg, err := config.Load( 39 + config.PathOrDefault(cmd.String("config"))) 39 40 if err != nil { 40 41 return ctx, err 41 42 }
M
internal/config/config.go
路路路 49 49 Mirror MirrorConfig `yaml:"mirror"` 50 50 } 51 51 52 -// Load loads configuration with the following priority: 53 -// 1. User provided fpath (if provided and exists) 54 -// 2. /var/lib/mugit/config.yaml 55 -// 3. $XDG_CONFIG_HOME/mugit/config.yaml or $HOME/.config/mugit/config.yaml 56 52 func Load(fpath string) (*Config, error) { 57 - // 4. /etc/mugit/config.yaml 58 - configPath, err := findConfigFile(fpath) 59 - if err != nil { 60 - return nil, err 61 - } 62 - 63 - configBytes, err := os.ReadFile(configPath) 53 + configBytes, err := os.ReadFile(fpath) 64 54 if err != nil { 65 55 return nil, err 66 56 } 路路路 83 73 return &config, nil 84 74 } 85 75 76 +// PathOrDefault uses userPath, if it's "", or invalid path, will default to one of those(in priority order) 77 +// 1. ./config.yaml 78 +// 2. /etc/mugit.yaml 79 +// 3. /var/lib/mugit/config.yaml 80 +func PathOrDefault(userPath string) string { 81 + return pathOrDefaultWithCandidates(userPath, []string{ 82 + "./config.yaml", 83 + "/etc/mugit.yaml", 84 + "/var/lib/mugit/config.yaml", 85 + }) 86 +} 87 + 88 +func pathOrDefaultWithCandidates(path string, candidates []string) string { 89 + if isFileExists(path) { 90 + return path 91 + } 92 + 93 + for _, fpath := range candidates { 94 + if isFileExists(fpath) { 95 + return fpath 96 + } 97 + } 98 + 99 + return "" 100 +} 101 + 86 102 func (c *Config) ensureDefaults() { 87 103 // ports 88 104 if c.Server.Port == 0 { 路路路 116 132 if c.Mirror.Interval == "" { 117 133 c.Mirror.Interval = "8h" 118 134 } 119 -} 120 - 121 -func findConfigFile(userPath string) (string, error) { 122 - if userPath != "" { 123 - if _, err := os.Stat(userPath); err == nil { 124 - return userPath, nil 125 - } 126 - } 127 - 128 - path := "/var/lib/mugit/config.yaml" 129 - if _, err := os.Stat(path); err == nil { 130 - return path, nil 131 - } 132 - 133 - if configDir, err := os.UserConfigDir(); err == nil { 134 - p := filepath.Join(configDir, "mugit", "config.yaml") 135 - if _, err := os.Stat(p); err == nil { 136 - return p, nil 137 - } 138 - } 139 - 140 - path = "/etc/mugit/config.yaml" 141 - if _, err := os.Stat(path); err == nil { 142 - return path, nil 143 - } 144 - 145 - return "", ErrConfigNotFound 146 135 } 147 136 148 137 func isFileExists(path string) bool {
M
internal/config/config_test.go
路路路 8 8 "olexsmir.xyz/x/is" 9 9 ) 10 10 11 -func TestFindConfigFile(t *testing.T) { 12 - t.Run("returns user provided path when it exists", func(t *testing.T) { 13 - path, err := findConfigFile("testdata/hostkey") 14 - is.Err(t, err, nil) 15 - is.Equal(t, path, "testdata/hostkey") 16 - }) 11 +func TestPathOrDefaultWithCandidates(t *testing.T) { 12 + first := candidateFile(t, "first.yaml") 13 + second := candidateFile(t, "second.yaml") 14 + third := candidateFile(t, "third.yaml") 17 15 18 - t.Run("falls back when user path doesn't exist", func(t *testing.T) { 19 - path, err := findConfigFile("/nonexistent/user/config.yaml") 20 - if err != nil { 21 - is.Err(t, err, ErrConfigNotFound) 22 - } else { 23 - _, statErr := os.Stat(path) 24 - is.Err(t, statErr, nil) 16 + t.Run("returns user path when exists", func(t *testing.T) { 17 + userPath := candidateFile(t, "user.yaml") 18 + candidates := []string{first, second, third} 19 + got := pathOrDefaultWithCandidates(userPath, candidates) 20 + if got != userPath { 21 + t.Errorf("got %q, want %q", got, userPath) 25 22 } 26 23 }) 27 24 28 - t.Run("finds config in user config directory", func(t *testing.T) { 29 - tmpDir := t.TempDir() 30 - configDir := filepath.Join(tmpDir, "mugit") 31 - if err := os.MkdirAll(configDir, 0o755); err != nil { 32 - t.Fatal(err) 33 - } 34 - configFile := filepath.Join(configDir, "config.yaml") 35 - if err := os.WriteFile(configFile, []byte("test"), 0o644); err != nil { 36 - t.Fatal(err) 37 - } 38 - 39 - t.Setenv("XDG_CONFIG_HOME", tmpDir) 40 - 41 - path, err := findConfigFile("") 42 - is.Err(t, err, nil) 43 - is.Equal(t, path, configFile) 25 + t.Run("returns first existing candidate", func(t *testing.T) { 26 + candidates := []string{first, second, third} 27 + got := pathOrDefaultWithCandidates("", candidates) 28 + is.Equal(t, got, first) 44 29 }) 45 30 46 - t.Run("returns error when no config found anywhere", func(t *testing.T) { 47 - t.Setenv("XDG_CONFIG_HOME", "/nonexistent") 48 - t.Setenv("HOME", "/nonexistent") 49 - 50 - path, err := findConfigFile("/nonexistent/config.yaml") 51 - is.Err(t, err, ErrConfigNotFound) 52 - is.Equal(t, path, "") 53 - }) 54 - 55 - t.Run("prefers data directory over user config", func(t *testing.T) { 56 - tmpDir := t.TempDir() 57 - configDir := filepath.Join(tmpDir, "mugit") 58 - if err := os.MkdirAll(configDir, 0o755); err != nil { 59 - t.Fatal(err) 60 - } 61 - userConfigFile := filepath.Join(configDir, "config.yaml") 62 - if err := os.WriteFile(userConfigFile, []byte("user config"), 0o644); err != nil { 63 - t.Fatal(err) 64 - } 65 - 66 - t.Setenv("XDG_CONFIG_HOME", tmpDir) 67 - 68 - path, err := findConfigFile("") 69 - is.Err(t, err, nil) 70 - 71 - if path == "/var/lib/mugit/config.yaml" { 72 - _, statErr := os.Stat(path) 73 - is.Err(t, statErr, nil) 74 - } else { 75 - is.Equal(t, path, userConfigFile) 31 + t.Run("returns empty when nothing exists", func(t *testing.T) { 32 + candidates := []string{} 33 + got := pathOrDefaultWithCandidates("", candidates) 34 + if got != "" { 35 + t.Errorf("got %q, want empty", got) 76 36 } 77 37 }) 78 38 } 39 + 40 +func candidateFile(t *testing.T, name string) string { 41 + t.Helper() 42 + out := filepath.Join(t.TempDir(), name) 43 + os.WriteFile(out, []byte("test"), 0o644) 44 + return out 45 +}