1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-12 11:15:00 +02:00
lazygit/pkg/config/app_config.go

283 lines
6.9 KiB
Go
Raw Normal View History

package config
2018-08-15 13:34:25 +02:00
import (
"bytes"
2018-08-25 07:55:49 +02:00
"io/ioutil"
2019-02-18 12:29:43 +02:00
"os"
2018-08-25 07:55:49 +02:00
"path/filepath"
2018-08-15 13:34:25 +02:00
"github.com/shibukawa/configdir"
2018-08-15 13:34:25 +02:00
"github.com/spf13/viper"
2018-08-25 07:55:49 +02:00
yaml "gopkg.in/yaml.v2"
2018-08-15 13:34:25 +02:00
)
// AppConfig contains the base configuration fields required for lazygit.
type AppConfig struct {
2018-08-25 07:55:49 +02:00
Debug bool `long:"debug" env:"DEBUG" default:"false"`
Version string `long:"version" env:"VERSION" default:"unversioned"`
Commit string `long:"commit" env:"COMMIT"`
BuildDate string `long:"build-date" env:"BUILD_DATE"`
Name string `long:"name" env:"NAME" default:"lazygit"`
BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
UserConfig *viper.Viper
AppState *AppState
2018-12-10 14:45:03 +02:00
IsNewRepo bool
}
// AppConfigurer interface allows individual app config structs to inherit Fields
// from AppConfig and still be used by lazygit.
type AppConfigurer interface {
GetDebug() bool
GetVersion() string
GetCommit() string
GetBuildDate() string
GetName() string
2018-08-25 07:55:49 +02:00
GetBuildSource() string
2018-08-15 13:34:25 +02:00
GetUserConfig() *viper.Viper
2018-08-25 07:55:49 +02:00
GetAppState() *AppState
WriteToUserConfig(string, string) error
SaveAppState() error
LoadAppState() error
2018-12-10 14:45:03 +02:00
SetIsNewRepo(bool)
GetIsNewRepo() bool
2018-08-15 13:34:25 +02:00
}
// NewAppConfig makes a new app config
2019-02-18 12:29:43 +02:00
func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool) (*AppConfig, error) {
2018-09-01 06:33:01 +02:00
userConfig, err := LoadConfig("config", true)
2018-08-15 13:34:25 +02:00
if err != nil {
2018-08-25 07:55:49 +02:00
return nil, err
2018-08-15 13:34:25 +02:00
}
2019-02-18 12:29:43 +02:00
if os.Getenv("DEBUG") == "TRUE" {
debuggingFlag = true
}
2018-08-15 13:34:25 +02:00
appConfig := &AppConfig{
2018-08-25 07:55:49 +02:00
Name: "lazygit",
Version: version,
Commit: commit,
BuildDate: date,
2019-02-18 12:29:43 +02:00
Debug: debuggingFlag,
2018-08-25 07:55:49 +02:00
BuildSource: buildSource,
UserConfig: userConfig,
AppState: &AppState{},
2018-12-10 14:45:03 +02:00
IsNewRepo: false,
2018-08-25 07:55:49 +02:00
}
if err := appConfig.LoadAppState(); err != nil {
return nil, err
2018-08-15 13:34:25 +02:00
}
2018-08-25 07:55:49 +02:00
2018-08-15 13:34:25 +02:00
return appConfig, nil
}
2018-12-10 14:45:03 +02:00
// GetIsNewRepo returns known repo boolean
func (c *AppConfig) GetIsNewRepo() bool {
return c.IsNewRepo
}
// SetIsNewRepo set if the current repo is known
func (c *AppConfig) SetIsNewRepo(toSet bool) {
c.IsNewRepo = toSet
}
// GetDebug returns debug flag
func (c *AppConfig) GetDebug() bool {
return c.Debug
}
// GetVersion returns debug flag
func (c *AppConfig) GetVersion() string {
return c.Version
}
// GetCommit returns debug flag
func (c *AppConfig) GetCommit() string {
return c.Commit
}
// GetBuildDate returns debug flag
func (c *AppConfig) GetBuildDate() string {
return c.BuildDate
}
// GetName returns debug flag
func (c *AppConfig) GetName() string {
return c.Name
}
2018-08-15 13:34:25 +02:00
2018-08-25 07:55:49 +02:00
// GetBuildSource returns the source of the build. For builds from goreleaser
// this will be binaryBuild
func (c *AppConfig) GetBuildSource() string {
return c.BuildSource
}
2018-08-15 13:34:25 +02:00
// GetUserConfig returns the user config
func (c *AppConfig) GetUserConfig() *viper.Viper {
return c.UserConfig
}
2018-08-25 07:55:49 +02:00
// GetAppState returns the app state
func (c *AppConfig) GetAppState() *AppState {
return c.AppState
}
func newViper(filename string) (*viper.Viper, error) {
2018-08-15 13:34:25 +02:00
v := viper.New()
v.SetConfigType("yaml")
2018-08-25 07:55:49 +02:00
v.SetConfigName(filename)
2018-08-18 05:22:05 +02:00
return v, nil
}
2018-08-25 07:55:49 +02:00
// LoadConfig gets the user's config
2018-09-01 06:33:01 +02:00
func LoadConfig(filename string, withDefaults bool) (*viper.Viper, error) {
2018-08-25 07:55:49 +02:00
v, err := newViper(filename)
2018-08-15 13:34:25 +02:00
if err != nil {
return nil, err
}
2018-09-01 06:33:01 +02:00
if withDefaults {
if err = LoadDefaults(v, GetDefaultConfig()); err != nil {
return nil, err
}
if err = LoadDefaults(v, GetPlatformDefaultConfig()); err != nil {
2018-08-25 07:55:49 +02:00
return nil, err
}
}
if err = LoadAndMergeFile(v, filename+".yml"); err != nil {
2018-08-18 05:22:05 +02:00
return nil, err
}
return v, nil
}
2018-08-25 07:55:49 +02:00
// LoadDefaults loads in the defaults defined in this file
func LoadDefaults(v *viper.Viper, defaults []byte) error {
2018-09-01 06:33:01 +02:00
return v.MergeConfig(bytes.NewBuffer(defaults))
2018-08-18 05:22:05 +02:00
}
2018-08-25 07:55:49 +02:00
func prepareConfigFile(filename string) (string, error) {
// chucking my name there is not for vanity purposes, the xdg spec (and that
// function) requires a vendor name. May as well line up with github
configDirs := configdir.New("jesseduffield", "lazygit")
2018-08-25 07:55:49 +02:00
folder := configDirs.QueryFolderContainsFile(filename)
2018-08-18 05:22:05 +02:00
if folder == nil {
2018-08-25 07:55:49 +02:00
// create the file as empty
2018-08-18 05:22:05 +02:00
folders := configDirs.QueryFolders(configdir.Global)
2018-08-25 07:55:49 +02:00
if err := folders[0].WriteFile(filename, []byte{}); err != nil {
return "", err
2018-08-18 05:54:39 +02:00
}
2018-08-25 07:55:49 +02:00
folder = configDirs.QueryFolderContainsFile(filename)
2018-08-15 13:34:25 +02:00
}
2018-08-25 07:55:49 +02:00
return filepath.Join(folder.Path, filename), nil
2018-08-18 05:22:05 +02:00
}
2018-08-25 07:55:49 +02:00
// LoadAndMergeFile Loads the config/state file, creating
2018-12-10 14:45:03 +02:00
// the file has an empty one if it does not exist
2018-08-25 07:55:49 +02:00
func LoadAndMergeFile(v *viper.Viper, filename string) error {
configPath, err := prepareConfigFile(filename)
2018-08-18 05:22:05 +02:00
if err != nil {
return err
}
2018-08-25 07:55:49 +02:00
v.AddConfigPath(filepath.Dir(configPath))
return v.MergeInConfig()
}
// WriteToUserConfig adds a key/value pair to the user's config and saves it
func (c *AppConfig) WriteToUserConfig(key, value string) error {
// reloading the user config directly (without defaults) so that we're not
// writing any defaults back to the user's config
2018-09-01 06:33:01 +02:00
v, err := LoadConfig("config", false)
2018-08-25 07:55:49 +02:00
if err != nil {
2018-08-18 05:22:05 +02:00
return err
}
2018-08-25 07:55:49 +02:00
2018-08-18 05:22:05 +02:00
v.Set(key, value)
2018-08-21 08:41:31 +02:00
return v.WriteConfig()
2018-08-15 13:34:25 +02:00
}
2019-05-22 15:34:29 +02:00
// SaveAppState marshalls the AppState struct and writes it to the disk
2018-08-25 07:55:49 +02:00
func (c *AppConfig) SaveAppState() error {
marshalledAppState, err := yaml.Marshal(c.AppState)
if err != nil {
return err
}
filepath, err := prepareConfigFile("state.yml")
if err != nil {
return err
}
return ioutil.WriteFile(filepath, marshalledAppState, 0644)
}
2018-08-29 13:32:34 +02:00
// LoadAppState loads recorded AppState from file
2018-08-25 07:55:49 +02:00
func (c *AppConfig) LoadAppState() error {
filepath, err := prepareConfigFile("state.yml")
if err != nil {
return err
}
appStateBytes, err := ioutil.ReadFile(filepath)
if err != nil {
return err
}
if len(appStateBytes) == 0 {
return yaml.Unmarshal(getDefaultAppState(), c.AppState)
}
return yaml.Unmarshal(appStateBytes, c.AppState)
}
2018-08-29 13:45:52 +02:00
// GetDefaultConfig returns the application default configuration
2018-08-26 10:42:25 +02:00
func GetDefaultConfig() []byte {
return []byte(
2018-08-27 10:01:05 +02:00
`gui:
## stuff relating to the UI
2018-08-26 10:42:25 +02:00
scrollHeight: 2
scrollPastBottom: true
mouseEvents: false # will default to true when the feature is complete
2018-08-26 10:42:25 +02:00
theme:
activeBorderColor:
- white
- bold
inactiveBorderColor:
- white
optionsTextColor:
- blue
commitLength:
show: true
git:
merging:
manualCommit: false
skipHookPrefix: 'WIP'
autoFetch: true
update:
method: prompt # can be: prompt | background | never
days: 14 # how often a update is checked for
2018-08-26 07:46:18 +02:00
reporting: 'undetermined' # one of: 'on' | 'off' | 'undetermined'
2018-09-05 19:56:11 +02:00
confirmOnQuit: false
2018-08-25 07:55:49 +02:00
`)
}
2018-08-25 07:55:49 +02:00
// AppState stores data between runs of the app like when the last update check
// was performed and which other repos have been checked out
type AppState struct {
2018-12-10 14:45:03 +02:00
LastUpdateCheck int64
RecentRepos []string
2018-08-25 07:55:49 +02:00
}
func getDefaultAppState() []byte {
2018-12-08 17:54:00 +02:00
return []byte(`
2018-12-07 16:46:49 +02:00
lastUpdateCheck: 0
recentRepos: []
`)
2018-08-15 13:34:25 +02:00
}
2018-08-18 05:54:39 +02:00
// // commenting this out until we use it again
// func homeDirectory() string {
// usr, err := user.Current()
// if err != nil {
// log.Fatal(err)
// }
// return usr.HomeDir
// }