1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-27 22:01:46 +02:00

Allow having multiple config files

This commit is contained in:
mjarkk 2021-07-27 22:03:37 +02:00 committed by Jesse Duffield
parent db736896bc
commit 913a2fd065
7 changed files with 137 additions and 65 deletions

View File

@ -265,6 +265,11 @@ os:
`{{editor}}` in `editCommandTemplate` is replaced with the value of `editCommand`. `{{editor}}` in `editCommandTemplate` is replaced with the value of `editCommand`.
### Change config file used
- Use `--config-file=~/.base_lg_conf,~/.light_theme_lg_conf` or `$LG_CONFIG_FILE="~/.base_lg_conf,~/.light_theme_lg_conf"`
- Change the default config directory `$CONFIG_DIR="~/.config/lazygit"`
### Recommended Config Values ### Recommended Config Values
for users of VSCode for users of VSCode

View File

@ -61,6 +61,9 @@ func main() {
gitDir := "" gitDir := ""
flaggy.String(&gitDir, "g", "git-dir", "equivalent of the --git-dir git argument") flaggy.String(&gitDir, "g", "git-dir", "equivalent of the --git-dir git argument")
customConfig := ""
flaggy.String(&customConfig, "cf", "config-file", "Comma seperated list to custom config file(s)")
flaggy.Parse() flaggy.Parse()
if repoPath != "" { if repoPath != "" {
@ -72,6 +75,10 @@ func main() {
gitDir = filepath.Join(repoPath, ".git") gitDir = filepath.Join(repoPath, ".git")
} }
if customConfig != "" {
os.Setenv("LG_CONFIG_FILE", customConfig)
}
if useConfigDir != "" { if useConfigDir != "" {
os.Setenv("CONFIG_DIR", useConfigDir) os.Setenv("CONFIG_DIR", useConfigDir)
} }

View File

@ -12,18 +12,20 @@ import (
// AppConfig contains the base configuration fields required for lazygit. // AppConfig contains the base configuration fields required for lazygit.
type AppConfig struct { type AppConfig struct {
Debug bool `long:"debug" env:"DEBUG" default:"false"` Debug bool `long:"debug" env:"DEBUG" default:"false"`
Version string `long:"version" env:"VERSION" default:"unversioned"` Version string `long:"version" env:"VERSION" default:"unversioned"`
Commit string `long:"commit" env:"COMMIT"` Commit string `long:"commit" env:"COMMIT"`
BuildDate string `long:"build-date" env:"BUILD_DATE"` BuildDate string `long:"build-date" env:"BUILD_DATE"`
Name string `long:"name" env:"NAME" default:"lazygit"` Name string `long:"name" env:"NAME" default:"lazygit"`
BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""` BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
UserConfig *UserConfig UserConfig *UserConfig
UserConfigDir string UserConfigFiles []string
UserConfigPath string DeafultConfFiles bool
TempDir string UserConfigPath string
AppState *AppState UserConfigDir string
IsNewRepo bool TempDir string
AppState *AppState
IsNewRepo bool
} }
// AppConfigurer interface allows individual app config structs to inherit Fields // AppConfigurer interface allows individual app config structs to inherit Fields
@ -36,6 +38,7 @@ type AppConfigurer interface {
GetName() string GetName() string
GetBuildSource() string GetBuildSource() string
GetUserConfig() *UserConfig GetUserConfig() *UserConfig
GetUserConfigFiles() []string
GetUserConfigDir() string GetUserConfigDir() string
GetUserConfigPath() string GetUserConfigPath() string
GetTempDir() string GetTempDir() string
@ -49,11 +52,24 @@ type AppConfigurer interface {
// NewAppConfig makes a new app config // NewAppConfig makes a new app config
func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool) (*AppConfig, error) { func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool) (*AppConfig, error) {
configDir, err := findOrCreateConfigDir() configDir, err := findOrCreateConfigDir()
if err != nil { if err != nil && !os.IsPermission(err) {
return nil, err return nil, err
} }
userConfig, err := loadUserConfigWithDefaults(configDir) var userConfigFiles []string
userConfigFilesOverwrite := os.Getenv("LG_CONFIG_FILE")
deafultConfFiles := true
if userConfigFilesOverwrite != "" {
// Load user defined config files
userConfigFiles = strings.Split(userConfigFilesOverwrite, ",")
deafultConfFiles = false
} else {
// Load default config files
userConfigFiles = []string{filepath.Join(configDir, ConfigFilename)}
}
userConfig, err := loadUserConfigWithDefaults(userConfigFiles, deafultConfFiles)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -70,18 +86,20 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg
} }
appConfig := &AppConfig{ appConfig := &AppConfig{
Name: "lazygit", Name: "lazygit",
Version: version, Version: version,
Commit: commit, Commit: commit,
BuildDate: date, BuildDate: date,
Debug: debuggingFlag, Debug: debuggingFlag,
BuildSource: buildSource, BuildSource: buildSource,
UserConfig: userConfig, UserConfig: userConfig,
UserConfigDir: configDir, UserConfigFiles: userConfigFiles,
UserConfigPath: filepath.Join(configDir, "config.yml"), UserConfigDir: configDir,
TempDir: tempDir, DeafultConfFiles: deafultConfFiles,
AppState: appState, UserConfigPath: filepath.Join(configDir, "config.yml"),
IsNewRepo: false, TempDir: tempDir,
AppState: appState,
IsNewRepo: false,
} }
return appConfig, nil return appConfig, nil
@ -107,45 +125,45 @@ func configDirForVendor(vendor string) string {
func findOrCreateConfigDir() (string, error) { func findOrCreateConfigDir() (string, error) {
folder := ConfigDir() folder := ConfigDir()
err := os.MkdirAll(folder, 0755) return folder, os.MkdirAll(folder, 0755)
if err != nil {
return "", err
}
return folder, nil
} }
func loadUserConfigWithDefaults(configDir string) (*UserConfig, error) { func loadUserConfigWithDefaults(configFiles []string, deafultConfFiles bool) (*UserConfig, error) {
return loadUserConfig(configDir, GetDefaultConfig()) return loadUserConfig(configFiles, GetDefaultConfig(), deafultConfFiles)
} }
func loadUserConfig(configDir string, base *UserConfig) (*UserConfig, error) { func loadUserConfig(configFiles []string, base *UserConfig, deafultConfFiles bool) (*UserConfig, error) {
fileName := filepath.Join(configDir, "config.yml") for _, fileName := range configFiles {
content, readConfFileErr := ioutil.ReadFile(fileName)
if readConfFileErr != nil {
if !deafultConfFiles {
return nil, readConfFileErr
}
_, err := os.Stat(fileName)
if err == nil {
return nil, readConfFileErr
}
if !os.IsNotExist(err) {
return nil, readConfFileErr
}
if _, err := os.Stat(fileName); err != nil {
if os.IsNotExist(err) {
file, err := os.Create(fileName) file, err := os.Create(fileName)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "read-only file system") { if os.IsPermission(err) {
return base, nil continue
} else {
return nil, readConfFileErr
} }
return nil, err
} }
file.Close() file.Close()
} else { }
if err := yaml.Unmarshal(content, base); err != nil {
return nil, err return nil, err
} }
} }
content, err := ioutil.ReadFile(fileName)
if err != nil {
return nil, err
}
if err := yaml.Unmarshal(content, base); err != nil {
return nil, err
}
return base, nil return base, nil
} }
@ -195,16 +213,15 @@ func (c *AppConfig) GetUserConfig() *UserConfig {
return c.UserConfig return c.UserConfig
} }
// GetUserConfig returns the user config
func (c *AppConfig) GetUserConfigPath() string {
return c.UserConfigPath
}
// GetAppState returns the app state // GetAppState returns the app state
func (c *AppConfig) GetAppState() *AppState { func (c *AppConfig) GetAppState() *AppState {
return c.AppState return c.AppState
} }
func (c *AppConfig) GetUserConfigFiles() []string {
return c.UserConfigFiles
}
func (c *AppConfig) GetUserConfigDir() string { func (c *AppConfig) GetUserConfigDir() string {
return c.UserConfigDir return c.UserConfigDir
} }
@ -214,7 +231,7 @@ func (c *AppConfig) GetTempDir() string {
} }
func (c *AppConfig) ReloadUserConfig() error { func (c *AppConfig) ReloadUserConfig() error {
userConfig, err := loadUserConfigWithDefaults(c.UserConfigDir) userConfig, err := loadUserConfigWithDefaults(c.UserConfigFiles, c.DeafultConfFiles)
if err != nil { if err != nil {
return err return err
} }
@ -232,9 +249,11 @@ func configFilePath(filename string) (string, error) {
return filepath.Join(folder, filename), nil return filepath.Join(folder, filename), nil
} }
// ConfigFilename returns the filename of the current config file var ConfigFilename = "config.yml"
// ConfigFilename returns the filename of the deafult config file
func (c *AppConfig) ConfigFilename() string { func (c *AppConfig) ConfigFilename() string {
return filepath.Join(c.UserConfigDir, "config.yml") return filepath.Join(c.UserConfigDir, ConfigFilename)
} }
// SaveAppState marshalls the AppState struct and writes it to the disk // SaveAppState marshalls the AppState struct and writes it to the disk
@ -256,6 +275,9 @@ func (c *AppConfig) SaveAppState() error {
func loadAppState() (*AppState, error) { func loadAppState() (*AppState, error) {
filepath, err := configFilePath("state.yml") filepath, err := configFilePath("state.yml")
if err != nil { if err != nil {
if os.IsPermission(err) {
return getDefaultAppState(), nil
}
return nil, err return nil, err
} }

View File

@ -656,7 +656,11 @@ func (gui *Gui) showIntroPopupMessage(done chan struct{}) error {
onConfirm := func() error { onConfirm := func() error {
done <- struct{}{} done <- struct{}{}
gui.Config.GetAppState().StartupPopupVersion = StartupPopupVersion gui.Config.GetAppState().StartupPopupVersion = StartupPopupVersion
return gui.Config.SaveAppState() err := gui.Config.SaveAppState()
if err != nil && os.IsPermission(err) {
return nil
}
return err
} }
return gui.ask(askOpts{ return gui.ask(askOpts{

View File

@ -114,7 +114,11 @@ func (gui *Gui) updateRecentRepoList() error {
known, recentRepos := newRecentReposList(recentRepos, currentRepo) known, recentRepos := newRecentReposList(recentRepos, currentRepo)
gui.Config.SetIsNewRepo(known) gui.Config.SetIsNewRepo(known)
gui.Config.GetAppState().RecentRepos = recentRepos gui.Config.GetAppState().RecentRepos = recentRepos
return gui.Config.SaveAppState() err = gui.Config.SaveAppState()
if err != nil && os.IsPermission(err) {
return nil
}
return err
} }
// newRecentReposList returns a new repo list with a new entry but only when it doesn't exist yet // newRecentReposList returns a new repo list with a new entry but only when it doesn't exist yet

View File

@ -1,6 +1,7 @@
package gui package gui
import ( import (
"errors"
"fmt" "fmt"
"strings" "strings"
@ -114,13 +115,38 @@ func (gui *Gui) handleStatusSelect() error {
}) })
} }
func (gui *Gui) askForConfigFile(action func(file string) error) error {
confFiles := gui.Config.GetUserConfigFiles()
switch len(confFiles) {
case 0:
return errors.New("no config file found")
case 1:
return action(confFiles[0])
default:
menuItems := make([]*menuItem, len(confFiles))
for i, file := range confFiles {
i := i
menuItems[i] = &menuItem{
displayString: file,
onPress: func() error {
return action(confFiles[i])
},
}
}
return gui.createMenu("select config file", menuItems, createMenuOptions{})
}
}
func (gui *Gui) handleOpenConfig() error { func (gui *Gui) handleOpenConfig() error {
return gui.openFile(gui.Config.GetUserConfigPath()) return gui.askForConfigFile(func(file string) error {
return gui.openFile(file)
})
} }
func (gui *Gui) handleEditConfig() error { func (gui *Gui) handleEditConfig() error {
filename := gui.Config.GetUserConfigPath() return gui.askForConfigFile(func(file string) error {
return gui.editFile(filename) return gui.editFile(file)
})
} }
func lazygitTitle() string { func lazygitTitle() string {

View File

@ -76,7 +76,11 @@ func (u *Updater) getLatestVersionNumber() (string, error) {
// RecordLastUpdateCheck records last time an update check was performed // RecordLastUpdateCheck records last time an update check was performed
func (u *Updater) RecordLastUpdateCheck() error { func (u *Updater) RecordLastUpdateCheck() error {
u.Config.GetAppState().LastUpdateCheck = time.Now().Unix() u.Config.GetAppState().LastUpdateCheck = time.Now().Unix()
return u.Config.SaveAppState() err := u.Config.SaveAppState()
if err != nil && os.IsPermission(err) {
return nil
}
return err
} }
// expecting version to be of the form `v12.34.56` // expecting version to be of the form `v12.34.56`