@@ -24,15 +24,14 @@ type Preferences struct {
2424
2525type Config struct {
2626 Repository string `yaml:"repository"`
27- Preferences * Preferences `yaml:"preferences,omitempty"` // User preferences (new, optional)
27+ Preferences * Preferences `yaml:"preferences,omitempty"` // User preferences (optional)
2828 Groups []Group `yaml:"groups,omitempty"`
2929
3030 // Internal fields (not serialized)
31- configSource paths.ConfigSource `yaml:"-"` // Track where this config came from
32- configPath string `yaml:"-"` // Path to the config file
31+ configPath string `yaml:"-"` // Path to the config file
3332}
3433
35- // GetRefreshInterval returns the refresh interval, checking preferences first
34+ // GetRefreshInterval returns the refresh interval from preferences
3635func (c * Config ) GetRefreshInterval () int {
3736 if c .Preferences != nil {
3837 return c .Preferences .RefreshInterval
@@ -48,11 +47,6 @@ func (c *Config) SetRefreshInterval(interval int) {
4847 c .Preferences .RefreshInterval = interval
4948}
5049
51- // GetConfigSource returns the source of this config
52- func (c * Config ) GetConfigSource () paths.ConfigSource {
53- return c .configSource
54- }
55-
5650// GetConfigPath returns the path to this config file
5751func (c * Config ) GetConfigPath () string {
5852 return c .configPath
@@ -113,8 +107,8 @@ func Load(path string) (*Config, error) {
113107 return & config , nil
114108}
115109
116- // LoadFromPath loads a config from a specific path with source tracking
117- func LoadFromPath (path string , source paths. ConfigSource ) (* Config , error ) {
110+ // LoadFromPath loads a config from a specific path
111+ func LoadFromPath (path string ) (* Config , error ) {
118112 data , err := os .ReadFile (path )
119113 if err != nil {
120114 return nil , fmt .Errorf ("failed to read config file: %w" , err )
@@ -125,150 +119,11 @@ func LoadFromPath(path string, source paths.ConfigSource) (*Config, error) {
125119 return nil , fmt .Errorf ("failed to parse config: %w" , err )
126120 }
127121
128- config .configSource = source
129122 config .configPath = path
130123
131124 return & config , nil
132125}
133126
134- // LoadMultiTier loads config from multiple sources and merges them
135- // The order of precedence (lowest to highest):
136- // 1. Repository default (.github/.rivet.yaml)
137- // 2. User global config (~/.config/rivet/config.yaml)
138- // 3. Project user config (.git/.rivet/config.yaml)
139- // 4. Environment variables (RIVET_*)
140- // 5. Explicit path via CLI flag (if provided)
141- func LoadMultiTier (p * paths.Paths , explicitPath string ) (* Config , error ) {
142- var baseConfig * Config
143- var err error
144-
145- if explicitPath != "" {
146- // CLI flag has highest priority - load only this file
147- baseConfig , err = LoadFromPath (explicitPath , paths .SourceCLIFlag )
148- if err != nil {
149- return nil , fmt .Errorf ("failed to load config from %s: %w" , explicitPath , err )
150- }
151- } else {
152- // Load and merge from multiple sources
153- configPaths := p .GetConfigPaths ()
154-
155- if len (configPaths ) == 0 {
156- // No config files found, check for legacy config
157- if legacyPath , found := p .FindLegacyConfig (); found {
158- return LoadFromPath (legacyPath , paths .SourceRepoDefault )
159- }
160- return nil , fmt .Errorf ("no configuration file found" )
161- }
162-
163- // Start with the first (lowest priority) config
164- baseConfig , err = LoadFromPath (configPaths [0 ], p .GetConfigSource (configPaths [0 ]))
165- if err != nil {
166- return nil , fmt .Errorf ("failed to load base config from %s: %w" , configPaths [0 ], err )
167- }
168-
169- // Merge higher priority configs
170- for i := 1 ; i < len (configPaths ); i ++ {
171- overrideConfig , err := LoadFromPath (configPaths [i ], p .GetConfigSource (configPaths [i ]))
172- if err != nil {
173- // Log warning but continue with partial config
174- fmt .Fprintf (os .Stderr , "Warning: failed to load config from %s: %v\n " , configPaths [i ], err )
175- continue
176- }
177-
178- baseConfig = MergeConfigs (baseConfig , overrideConfig )
179- }
180- }
181-
182- // Apply environment variable overrides
183- applyEnvOverrides (baseConfig )
184-
185- return baseConfig , nil
186- }
187-
188- // MergeConfigs merges two configs, with override taking precedence
189- // Only non-empty values from override are applied to base
190- func MergeConfigs (base , override * Config ) * Config {
191- merged := & Config {
192- Repository : base .Repository ,
193- Preferences : base .Preferences ,
194- Groups : base .Groups ,
195- configSource : base .configSource ,
196- configPath : base .configPath ,
197- }
198-
199- // Override repository if specified
200- if override .Repository != "" {
201- merged .Repository = override .Repository
202- merged .configSource = override .configSource
203- merged .configPath = override .configPath
204- }
205-
206- // Merge preferences
207- if override .Preferences != nil {
208- if merged .Preferences == nil {
209- merged .Preferences = & Preferences {}
210- }
211-
212- if override .Preferences .RefreshInterval != 0 {
213- merged .Preferences .RefreshInterval = override .Preferences .RefreshInterval
214- }
215- if override .Preferences .Theme != "" {
216- merged .Preferences .Theme = override .Preferences .Theme
217- }
218- if override .Preferences .Keybindings != "" {
219- merged .Preferences .Keybindings = override .Preferences .Keybindings
220- }
221- if len (override .Preferences .CustomSettings ) > 0 {
222- if merged .Preferences .CustomSettings == nil {
223- merged .Preferences .CustomSettings = make (map [string ]string )
224- }
225- for k , v := range override .Preferences .CustomSettings {
226- merged .Preferences .CustomSettings [k ] = v
227- }
228- }
229- }
230-
231- // Override groups if specified (full replacement, not merge)
232- if len (override .Groups ) > 0 {
233- merged .Groups = override .Groups
234- }
235-
236- return merged
237- }
238-
239- // applyEnvOverrides applies environment variable overrides to the config
240- func applyEnvOverrides (config * Config ) {
241- // Check for RIVET_REPOSITORY
242- if repo := os .Getenv ("RIVET_REPOSITORY" ); repo != "" {
243- config .Repository = repo
244- config .configSource = paths .SourceEnvVar
245- }
246-
247- // Check for RIVET_REFRESH_INTERVAL
248- if interval := os .Getenv ("RIVET_REFRESH_INTERVAL" ); interval != "" {
249- var val int
250- if _ , err := fmt .Sscanf (interval , "%d" , & val ); err == nil {
251- config .SetRefreshInterval (val )
252- }
253- }
254-
255- // Check for RIVET_PREFERENCES_THEME
256- if theme := os .Getenv ("RIVET_PREFERENCES_THEME" ); theme != "" {
257- if config .Preferences == nil {
258- config .Preferences = & Preferences {}
259- }
260- config .Preferences .Theme = theme
261- }
262-
263- // Check for RIVET_PREFERENCES_KEYBINDINGS
264- if kb := os .Getenv ("RIVET_PREFERENCES_KEYBINDINGS" ); kb != "" {
265- if config .Preferences == nil {
266- config .Preferences = & Preferences {}
267- }
268- config .Preferences .Keybindings = kb
269- }
270- }
271-
272127func LoadWithViper (path string ) (* Config , * viper.Viper , error ) {
273128 v := viper .New ()
274129
0 commit comments