mirror of
https://github.com/anotherhadi/spilltea.git
synced 2026-07-06 12:42:32 +02:00
Per-project configuration overwrites
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
- [Installation](#installation)
|
||||
- [Project Management](#project-management)
|
||||
- [Configuration](#configuration)
|
||||
- [Per-project configuration](#per-project-configuration)
|
||||
- [CLI Flags](#cli-flags)
|
||||
- [Plugin System](#plugin-system)
|
||||
- [Vim / Neovim Integration](#vim--neovim-integration)
|
||||
@@ -118,6 +119,18 @@ Check the default configuration with all the options [here](./internal/config/de
|
||||
|
||||
Colors and styles can be customized using [ilovetui](https://github.com/anotherhadi/ilovetui), which applies theme changes across all compatible TUI applications at once.
|
||||
|
||||
### Per-project configuration
|
||||
|
||||
You can override any config value on a per-project basis by placing a `config.yaml` file inside the project directory (e.g. `~/.local/share/spilltea/projects/my-project/config.yaml`).
|
||||
|
||||
Only the keys present in that file are overridden; everything else falls back to the global config.
|
||||
|
||||
The priority order is:
|
||||
|
||||
1. Global config (`~/.config/spilltea/config.yaml`)
|
||||
2. Project config (`<project-dir>/config.yaml`)
|
||||
3. CLI flags (always win)
|
||||
|
||||
## CLI Flags
|
||||
|
||||
```
|
||||
|
||||
+24
-14
@@ -99,21 +99,26 @@ func main() {
|
||||
}
|
||||
config.Global.Version = version
|
||||
|
||||
if flagPluginsDir != "" {
|
||||
config.Global.App.PluginsDir = flagPluginsDir
|
||||
}
|
||||
if flagHost != "" {
|
||||
config.Global.App.Host = flagHost
|
||||
}
|
||||
if flagPort != 0 {
|
||||
config.Global.App.Port = flagPort
|
||||
}
|
||||
if flagUpstreamProxy != "" {
|
||||
config.Global.App.UpstreamProxy = flagUpstreamProxy
|
||||
}
|
||||
if cmd.Flags().Changed("ssl-insecure") {
|
||||
config.Global.App.SslInsecure = flagSslInsecure
|
||||
sslInsecureChanged := cmd.Flags().Changed("ssl-insecure")
|
||||
applyCLI := func(c *config.Config) {
|
||||
if flagPluginsDir != "" {
|
||||
c.App.PluginsDir = flagPluginsDir
|
||||
}
|
||||
if flagHost != "" {
|
||||
c.App.Host = flagHost
|
||||
}
|
||||
if flagPort != 0 {
|
||||
c.App.Port = flagPort
|
||||
}
|
||||
if flagUpstreamProxy != "" {
|
||||
c.App.UpstreamProxy = flagUpstreamProxy
|
||||
}
|
||||
if sslInsecureChanged {
|
||||
c.App.SslInsecure = flagSslInsecure
|
||||
}
|
||||
}
|
||||
applyCLI(config.Global)
|
||||
config.SetCLIOverrides(applyCLI)
|
||||
|
||||
style.Init()
|
||||
icons.Init(config.Global)
|
||||
@@ -126,6 +131,11 @@ func main() {
|
||||
if err != nil {
|
||||
return fmt.Errorf("project: %w", err)
|
||||
}
|
||||
if err := config.MergeProjectConfig(filepath.Dir(project.Path)); err != nil {
|
||||
return fmt.Errorf("project config: %w", err)
|
||||
}
|
||||
icons.Init(config.Global)
|
||||
keys.Init(config.Global)
|
||||
broker := intercept.NewBroker()
|
||||
m := appUI.New(broker, project.Name, project.Path)
|
||||
final, err := tea.NewProgram(m).Run()
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/anotherhadi/spilltea/internal/config"
|
||||
"github.com/anotherhadi/spilltea/internal/icons"
|
||||
"github.com/anotherhadi/spilltea/internal/intercept"
|
||||
"github.com/anotherhadi/spilltea/internal/keys"
|
||||
appUI "github.com/anotherhadi/spilltea/internal/ui/app"
|
||||
homeUI "github.com/anotherhadi/spilltea/internal/ui/home"
|
||||
)
|
||||
@@ -34,6 +40,11 @@ func (m rootModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
|
||||
if m.state == rootStateHome {
|
||||
if sel, ok := msg.(homeUI.ProjectSelectedMsg); ok {
|
||||
if err := config.MergeProjectConfig(filepath.Dir(sel.Project.Path)); err != nil {
|
||||
log.Printf("project config: %v", err)
|
||||
}
|
||||
icons.Init(config.Global)
|
||||
keys.Init(config.Global)
|
||||
broker := intercept.NewBroker()
|
||||
app := appUI.New(broker, sel.Project.Name, sel.Project.Path)
|
||||
m.app = app
|
||||
|
||||
@@ -15,6 +15,18 @@ Check the default configuration with all the options [here](./internal/config/de
|
||||
|
||||
Colors and styles can be customized using [ilovetui](https://github.com/anotherhadi/ilovetui), which applies theme changes across all compatible TUI applications at once.
|
||||
|
||||
### Per-project configuration
|
||||
|
||||
You can override any config value on a per-project basis by placing a `config.yaml` file inside the project directory (e.g. `~/.local/share/spilltea/projects/my-project/config.yaml`).
|
||||
|
||||
Only the keys present in that file are overridden; everything else falls back to the global config.
|
||||
|
||||
The priority order is:
|
||||
|
||||
1. Global config (`~/.config/spilltea/config.yaml`)
|
||||
2. Project config (`<project-dir>/config.yaml`)
|
||||
3. CLI flags (always win)
|
||||
|
||||
## CLI Flags
|
||||
|
||||
<!-- exec: echo '```' && go run ./cmd/spilltea -h && echo '```' -->
|
||||
|
||||
@@ -65,6 +65,43 @@ type GlobalPlugin struct {
|
||||
|
||||
var Global *Config
|
||||
|
||||
var projectCLIOverrides func(*Config)
|
||||
|
||||
// SetCLIOverrides stores a function that re-applies CLI flag overrides.
|
||||
// It is called automatically after MergeProjectConfig so that CLI flags
|
||||
// always win over both global and per-project config.
|
||||
func SetCLIOverrides(fn func(*Config)) {
|
||||
projectCLIOverrides = fn
|
||||
}
|
||||
|
||||
// MergeProjectConfig merges <projectDir>/config.yaml on top of the current
|
||||
// Global config, then re-applies any registered CLI overrides.
|
||||
// If no config.yaml exists in the project directory, this is a no-op.
|
||||
func MergeProjectConfig(projectDir string) error {
|
||||
projectConfigPath := filepath.Join(projectDir, "config.yaml")
|
||||
if _, err := os.Stat(projectConfigPath); errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
|
||||
pv := viper.New()
|
||||
pv.SetConfigFile(projectConfigPath)
|
||||
if err := pv.ReadInConfig(); err != nil {
|
||||
return fmt.Errorf("project config: %w", err)
|
||||
}
|
||||
if err := viper.MergeConfigMap(pv.AllSettings()); err != nil {
|
||||
return fmt.Errorf("merge project config: %w", err)
|
||||
}
|
||||
if err := viper.Unmarshal(Global); err != nil {
|
||||
return err
|
||||
}
|
||||
Global.App.ProxyAuth = expandEnvValue(Global.App.ProxyAuth)
|
||||
Global.App.UpstreamProxy = expandEnvValue(Global.App.UpstreamProxy)
|
||||
if projectCLIOverrides != nil {
|
||||
projectCLIOverrides(Global)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Load(path string) error {
|
||||
var defaults map[string]any
|
||||
if err := yaml.Unmarshal(defaultConfig, &defaults); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user