remove viper

WIP
This commit is contained in:
Jesse Duffield
2020-10-03 14:54:55 +10:00
parent 9440dcf9de
commit 4912205adb
272 changed files with 10788 additions and 59939 deletions

View File

@@ -1,28 +1,27 @@
package config
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"github.com/shibukawa/configdir"
"github.com/spf13/viper"
yaml "gopkg.in/yaml.v2"
"github.com/OpenPeeDeeP/xdg"
yaml "github.com/jesseduffield/yaml"
)
// AppConfig contains the base configuration fields required for lazygit.
type AppConfig struct {
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
UserConfigDir string
AppState *AppState
IsNewRepo bool
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 *UserConfig
UserConfigDir string
UserConfigPath string
AppState *AppState
IsNewRepo bool
}
// AppConfigurer interface allows individual app config structs to inherit Fields
@@ -34,10 +33,11 @@ type AppConfigurer interface {
GetBuildDate() string
GetName() string
GetBuildSource() string
GetUserConfig() *viper.Viper
GetUserConfig() *UserConfig
GetUserConfigDir() string
GetUserConfigPath() string
GetAppState() *AppState
WriteToUserConfig(string, interface{}) error
WriteToUserConfig(func(*UserConfig) error) error
SaveAppState() error
LoadAppState() error
SetIsNewRepo(bool)
@@ -46,7 +46,12 @@ type AppConfigurer interface {
// NewAppConfig makes a new app config
func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool) (*AppConfig, error) {
userConfig, userConfigPath, err := LoadConfig("config", true)
configDir, err := findOrCreateConfigDir(name)
if err != nil {
return nil, err
}
userConfig, err := loadUserConfigWithDefaults(configDir)
if err != nil {
return nil, err
}
@@ -56,16 +61,17 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg
}
appConfig := &AppConfig{
Name: "lazygit",
Version: version,
Commit: commit,
BuildDate: date,
Debug: debuggingFlag,
BuildSource: buildSource,
UserConfig: userConfig,
UserConfigDir: filepath.Dir(userConfigPath),
AppState: &AppState{},
IsNewRepo: false,
Name: "lazygit",
Version: version,
Commit: commit,
BuildDate: date,
Debug: debuggingFlag,
BuildSource: buildSource,
UserConfig: userConfig,
UserConfigDir: configDir,
UserConfigPath: filepath.Join(configDir, "config.yml"),
AppState: &AppState{},
IsNewRepo: false,
}
if err := appConfig.LoadAppState(); err != nil {
@@ -75,6 +81,51 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg
return appConfig, nil
}
func findOrCreateConfigDir(projectName 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 := xdg.New("jesseduffield", projectName)
folder := configDirs.ConfigHome()
err := os.MkdirAll(folder, 0755)
if err != nil {
return "", err
}
return folder, nil
}
func loadUserConfigWithDefaults(configDir string) (*UserConfig, error) {
return loadUserConfig(configDir, GetDefaultConfig())
}
func loadUserConfig(configDir string, base *UserConfig) (*UserConfig, error) {
fileName := filepath.Join(configDir, "config.yml")
if _, err := os.Stat(fileName); err != nil {
if os.IsNotExist(err) {
file, err := os.Create(fileName)
if err != nil {
return nil, err
}
file.Close()
} else {
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
}
// GetIsNewRepo returns known repo boolean
func (c *AppConfig) GetIsNewRepo() bool {
return c.IsNewRepo
@@ -117,10 +168,15 @@ func (c *AppConfig) GetBuildSource() string {
}
// GetUserConfig returns the user config
func (c *AppConfig) GetUserConfig() *viper.Viper {
func (c *AppConfig) GetUserConfig() *UserConfig {
return c.UserConfig
}
// GetUserConfig returns the user config
func (c *AppConfig) GetUserConfigPath() string {
return c.UserConfigPath
}
// GetAppState returns the app state
func (c *AppConfig) GetAppState() *AppState {
return c.AppState
@@ -130,78 +186,40 @@ func (c *AppConfig) GetUserConfigDir() string {
return c.UserConfigDir
}
func newViper(filename string) (*viper.Viper, error) {
v := viper.New()
v.SetConfigType("yaml")
v.SetConfigName(filename)
return v, nil
}
// LoadConfig gets the user's config
func LoadConfig(filename string, withDefaults bool) (*viper.Viper, string, error) {
v, err := newViper(filename)
if err != nil {
return nil, "", err
}
if withDefaults {
if err = LoadDefaults(v, GetDefaultConfig()); err != nil {
return nil, "", err
}
if err = LoadDefaults(v, GetPlatformDefaultConfig()); err != nil {
return nil, "", err
}
}
configPath, err := LoadAndMergeFile(v, filename+".yml")
if err != nil {
return nil, "", err
}
return v, configPath, nil
}
// LoadDefaults loads in the defaults defined in this file
func LoadDefaults(v *viper.Viper, defaults []byte) error {
return v.MergeConfig(bytes.NewBuffer(defaults))
}
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")
folder := configDirs.QueryFolderContainsFile(filename)
if folder == nil {
// create the file as empty
folders := configDirs.QueryFolders(configdir.Global)
if err := folders[0].WriteFile(filename, []byte{}); err != nil {
return "", err
}
folder = configDirs.QueryFolderContainsFile(filename)
}
return filepath.Join(folder.Path, filename), nil
}
// LoadAndMergeFile Loads the config/state file, creating
// the file has an empty one if it does not exist
func LoadAndMergeFile(v *viper.Viper, filename string) (string, error) {
configPath, err := prepareConfigFile(filename)
func configFilePath(filename string) (string, error) {
folder, err := findOrCreateConfigDir("lazygit")
if err != nil {
return "", err
}
v.AddConfigPath(filepath.Dir(configPath))
return configPath, v.MergeInConfig()
return filepath.Join(folder, filename), nil
}
// WriteToUserConfig adds a key/value pair to the user's config and saves it
func (c *AppConfig) WriteToUserConfig(key string, value interface{}) error {
// reloading the user config directly (without defaults) so that we're not
// writing any defaults back to the user's config
v, _, err := LoadConfig("config", false)
// WriteToUserConfig allows you to set a value on the user config to be saved
// note that if you set a zero-value, it may be ignored e.g. a false or 0 or
// empty string this is because we are using the omitempty yaml directive so
// that we don't write a heap of zero values to the user's config.yml
func (c *AppConfig) WriteToUserConfig(updateConfig func(*UserConfig) error) error {
userConfig, err := loadUserConfig(c.UserConfigDir, &UserConfig{})
if err != nil {
return err
}
v.Set(key, value)
return v.WriteConfig()
if err := updateConfig(userConfig); err != nil {
return err
}
file, err := os.OpenFile(c.ConfigFilename(), os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return err
}
return yaml.NewEncoder(file).Encode(userConfig)
}
// ConfigFilename returns the filename of the current config file
func (c *AppConfig) ConfigFilename() string {
return filepath.Join(c.UserConfigDir, "config.yml")
}
// SaveAppState marshalls the AppState struct and writes it to the disk
@@ -211,7 +229,7 @@ func (c *AppConfig) SaveAppState() error {
return err
}
filepath, err := prepareConfigFile("state.yml")
filepath, err := configFilePath("state.yml")
if err != nil {
return err
}
@@ -221,7 +239,7 @@ func (c *AppConfig) SaveAppState() error {
// LoadAppState loads recorded AppState from file
func (c *AppConfig) LoadAppState() error {
filepath, err := prepareConfigFile("state.yml")
filepath, err := configFilePath("state.yml")
if err != nil {
return err
}
@@ -235,8 +253,20 @@ func (c *AppConfig) LoadAppState() error {
return yaml.Unmarshal(appStateBytes, c.AppState)
}
// GetDefaultConfig returns the application default configuration
func GetDefaultConfig() []byte {
func GetDefaultConfig() *UserConfig {
userConfig := &UserConfig{}
if err := yaml.Unmarshal(GetDefaultConfigBytes(), userConfig); err != nil {
panic(err)
}
userConfig.OS = GetPlatformDefaultConfig()
return userConfig
}
// GetDefaultConfigBytes returns the application default configuration
func GetDefaultConfigBytes() []byte {
return []byte(
`gui:
## stuff relating to the UI
@@ -414,12 +444,6 @@ func getDefaultAppState() []byte {
`)
}
func globalConfigDir() string {
configDirs := configdir.New("jesseduffield", "lazygit")
configDir := configDirs.QueryFolders(configdir.Global)[0]
return configDir.Path
}
func LogPath() string {
return filepath.Join(globalConfigDir(), "development.log")
func LogPath() (string, error) {
return configFilePath("development.log")
}

View File

@@ -3,9 +3,9 @@
package config
// GetPlatformDefaultConfig gets the defaults for the platform
func GetPlatformDefaultConfig() []byte {
return []byte(
`os:
openCommand: 'open {{filename}}'
openLinkCommand: 'open {{link}}'`)
func GetPlatformDefaultConfig() OSConfig {
return OSConfig{
OpenCommand: "open {{filename}}",
OpenLinkCommand: "open {{link}}",
}
}

View File

@@ -1,9 +1,9 @@
package config
// GetPlatformDefaultConfig gets the defaults for the platform
func GetPlatformDefaultConfig() []byte {
return []byte(
`os:
openCommand: 'sh -c "xdg-open {{filename}} >/dev/null"'
openLinkCommand: 'sh -c "xdg-open {{link}} >/dev/null"'`)
func GetPlatformDefaultConfig() OSConfig {
return OSConfig{
OpenCommand: `sh -c "xdg-open {{filename}} >/dev/null"`,
OpenLinkCommand: `sh -c "xdg-open {{link}} >/dev/null"`,
}
}

View File

@@ -1,9 +1,9 @@
package config
// GetPlatformDefaultConfig gets the defaults for the platform
func GetPlatformDefaultConfig() []byte {
return []byte(
`os:
openCommand: 'cmd /c "start "" {{filename}}"'
openLinkCommand: 'cmd /c "start "" {{link}}"'`)
func GetPlatformDefaultConfig() OSConfig {
return OSConfig{
OpenCommand: `cmd /c "start "" {{filename}}"`,
OpenLinkCommand: `cmd /c "start "" {{link}}"`,
}
}

View File

@@ -1,17 +1,11 @@
package config
import (
"github.com/spf13/viper"
yaml "gopkg.in/yaml.v2"
yaml "github.com/jesseduffield/yaml"
)
// NewDummyAppConfig creates a new dummy AppConfig for testing
func NewDummyAppConfig() *AppConfig {
userConfig := viper.New()
userConfig.SetConfigType("yaml")
if err := LoadDefaults(userConfig, GetDefaultConfig()); err != nil {
panic(err)
}
appConfig := &AppConfig{
Name: "lazygit",
Version: "unversioned",
@@ -19,7 +13,7 @@ func NewDummyAppConfig() *AppConfig {
BuildDate: "",
Debug: false,
BuildSource: "",
UserConfig: userConfig,
UserConfig: GetDefaultConfig(),
}
_ = yaml.Unmarshal([]byte{}, appConfig.AppState)
return appConfig

10
pkg/config/os_config.go Normal file
View File

@@ -0,0 +1,10 @@
package config
// OSConfig contains config on the level of the os
type OSConfig struct {
// OpenCommand is the command for opening a file
OpenCommand string `yaml:"openCommand,omitempty"`
// OpenCommand is the command for opening a link
OpenLinkCommand string `yaml:"openLinkCommand,omitempty"`
}

215
pkg/config/user_config.go Normal file
View File

@@ -0,0 +1,215 @@
package config
type CommitPrefixConfig struct {
Pattern string `yaml:"pattern"`
Replace string `yaml:"replace"`
}
type ThemeConfig struct {
LightTheme bool `yaml:"lightTheme"`
ActiveBorderColor []string `yaml:"activeBorderColor"`
InactiveBorderColor []string `yaml:"inactiveBorderColor"`
OptionsTextColor []string `yaml:"optionsTextColor"`
SelectedLineBgColor []string `yaml:"selectedLineBgColor"`
SelectedRangeBgColor []string `yaml:"selectedRangeBgColor"`
}
type CustomCommandMenuOption struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
Value string `yaml:"value"`
}
type CustomCommandPrompt struct {
Type string `yaml:"type"` // one of 'input' and 'menu'
Title string `yaml:"title"`
// this only apply to prompts
InitialValue string `yaml:"initialValue"`
// this only applies to menus
Options []CustomCommandMenuOption
}
type CustomCommand struct {
Key string `yaml:"key"`
Context string `yaml:"context"`
Command string `yaml:"command"`
Subprocess bool `yaml:"subprocess"`
Prompts []CustomCommandPrompt `yaml:"prompts"`
LoadingText string `yaml:"loadingText"`
Description string `yaml:"description"`
}
type UserConfig struct {
Gui struct {
ScrollHeight int `yaml:"scrollHeight"`
ScrollPastBottom bool `yaml:"scrollPastBottom"`
MouseEvents bool `yaml:"mouseEvents"`
SkipUnstageLineWarning bool `yaml:"skipUnstageLineWarning"`
SkipStashWarning bool `yaml:"skipStashWarning"`
SidePanelWidth float64 `yaml:"sidePanelWidth"`
ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`
MainPanelSplitMode string `yaml:"mainPanelSplitMode"`
Theme ThemeConfig `yaml:"theme"`
CommitLength struct {
Show bool `yaml:"show"`
} `yaml:"commitLength"`
} `yaml:"gui"`
Git struct {
Paging struct {
ColorArg string `yaml:"colorArg"`
Pager string `yaml:"pager"`
UseConfig bool `yaml:"useConfig"`
} `yaml:"paging"`
Merging struct {
ManualCommit bool `yaml:"manualCommit"`
Args string `yaml:"args"`
} `yaml:"merging"`
Pull struct {
Mode string `yaml:"mode"`
} `yaml:"pull"`
SkipHookPrefix string `yaml:"skipHookPrefix"`
AutoFetch bool `yaml:"autoFetch"`
BranchLogCmd string `yaml:"branchLogCmd"`
OverrideGpg bool `yaml:"overrideGpg"`
DisableForcePushing bool `yaml:"disableForcePushing"`
CommitPrefixes map[string]CommitPrefixConfig `yaml:"commitPrefixes"`
} `yaml:"git"`
Update struct {
Method string `yaml:"method"`
Days int64 `yaml:"days"`
} `yaml:"update"`
Reporting string `yaml:"reporting"`
SplashUpdatesIndex int `yaml:"splashUpdatesIndex"`
ConfirmOnQuit bool `yaml:"confirmOnQuit"`
QuitOnTopLevelReturn bool `yaml:"quitOnTopLevelReturn"`
Keybinding struct {
Universal struct {
Quit string `yaml:"quit"`
QuitAlt1 string `yaml:"quit-alt1"`
Return string `yaml:"return"`
QuitWithoutChangingDirectory string `yaml:"quitWithoutChangingDirectory"`
TogglePanel string `yaml:"togglePanel"`
PrevItem string `yaml:"prevItem"`
NextItem string `yaml:"nextItem"`
PrevItemAlt string `yaml:"prevItem-alt"`
NextItemAlt string `yaml:"nextItem-alt"`
PrevPage string `yaml:"prevPage"`
NextPage string `yaml:"nextPage"`
GotoTop string `yaml:"gotoTop"`
GotoBottom string `yaml:"gotoBottom"`
PrevBlock string `yaml:"prevBlock"`
NextBlock string `yaml:"nextBlock"`
PrevBlockAlt string `yaml:"prevBlock-alt"`
NextBlockAlt string `yaml:"nextBlock-alt"`
NextMatch string `yaml:"nextMatch"`
PrevMatch string `yaml:"prevMatch"`
StartSearch string `yaml:"startSearch"`
OptionMenu string `yaml:"optionMenu"`
OptionMenuAlt1 string `yaml:"optionMenu-alt1"`
Select string `yaml:"select"`
GoInto string `yaml:"goInto"`
Confirm string `yaml:"confirm"`
ConfirmAlt1 string `yaml:"confirm-alt1"`
Remove string `yaml:"remove"`
New string `yaml:"new"`
Edit string `yaml:"edit"`
OpenFile string `yaml:"openFile"`
ScrollUpMain string `yaml:"scrollUpMain"`
ScrollDownMain string `yaml:"scrollDownMain"`
ScrollUpMainAlt1 string `yaml:"scrollUpMain-alt1"`
ScrollDownMainAlt1 string `yaml:"scrollDownMain-alt1"`
ScrollUpMainAlt2 string `yaml:"scrollUpMain-alt2"`
ScrollDownMainAlt2 string `yaml:"scrollDownMain-alt2"`
ExecuteCustomCommand string `yaml:"executeCustomCommand"`
CreateRebaseOptionsMenu string `yaml:"createRebaseOptionsMenu"`
PushFiles string `yaml:"pushFiles"`
PullFiles string `yaml:"pullFiles"`
Refresh string `yaml:"refresh"`
CreatePatchOptionsMenu string `yaml:"createPatchOptionsMenu"`
NextTab string `yaml:"nextTab"`
PrevTab string `yaml:"prevTab"`
NextScreenMode string `yaml:"nextScreenMode"`
PrevScreenMode string `yaml:"prevScreenMode"`
Undo string `yaml:"undo"`
Redo string `yaml:"redo"`
FilteringMenu string `yaml:"filteringMenu"`
DiffingMenu string `yaml:"diffingMenu"`
DiffingMenuAlt string `yaml:"diffingMenu-alt"`
CopyToClipboard string `yaml:"copyToClipboard"`
} `yaml:"universal"`
Status struct {
CheckForUpdate string `yaml:"checkForUpdate"`
RecentRepos string `yaml:"recentRepos"`
} `yaml:"status"`
Files struct {
CommitChanges string `yaml:"commitChanges"`
CommitChangesWithoutHook string `yaml:"commitChangesWithoutHook"`
AmendLastCommit string `yaml:"amendLastCommit"`
CommitChangesWithEditor string `yaml:"commitChangesWithEditor"`
IgnoreFile string `yaml:"ignoreFile"`
RefreshFiles string `yaml:"refreshFiles"`
StashAllChanges string `yaml:"stashAllChanges"`
ViewStashOptions string `yaml:"viewStashOptions"`
ToggleStagedAll string `yaml:"toggleStagedAll"`
ViewResetOptions string `yaml:"viewResetOptions"`
Fetch string `yaml:"fetch"`
} `yaml:"files"`
Branches struct {
CreatePullRequest string `yaml:"createPullRequest"`
CheckoutBranchByName string `yaml:"checkoutBranchByName"`
ForceCheckoutBranch string `yaml:"forceCheckoutBranch"`
RebaseBranch string `yaml:"rebaseBranch"`
RenameBranch string `yaml:"renameBranch"`
MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"`
ViewGitFlowOptions string `yaml:"viewGitFlowOptions"`
FastForward string `yaml:"fastForward"`
PushTag string `yaml:"pushTag"`
SetUpstream string `yaml:"setUpstream"`
FetchRemote string `yaml:"fetchRemote"`
} `yaml:"branches"`
Commits struct {
SquashDown string `yaml:"squashDown"`
RenameCommit string `yaml:"renameCommit"`
RenameCommitWithEditor string `yaml:"renameCommitWithEditor"`
ViewResetOptions string `yaml:"viewResetOptions"`
MarkCommitAsFixup string `yaml:"markCommitAsFixup"`
CreateFixupCommit string `yaml:"createFixupCommit"`
SquashAboveCommits string `yaml:"squashAboveCommits"`
MoveDownCommit string `yaml:"moveDownCommit"`
MoveUpCommit string `yaml:"moveUpCommit"`
AmendToCommit string `yaml:"amendToCommit"`
PickCommit string `yaml:"pickCommit"`
RevertCommit string `yaml:"revertCommit"`
CherryPickCopy string `yaml:"cherryPickCopy"`
CherryPickCopyRange string `yaml:"cherryPickCopyRange"`
PasteCommits string `yaml:"pasteCommits"`
TagCommit string `yaml:"tagCommit"`
CheckoutCommit string `yaml:"checkoutCommit"`
ResetCherryPick string `yaml:"resetCherryPick"`
} `yaml:"commits"`
Stash struct {
PopStash string `yaml:"popStash"`
} `yaml:"stash"`
CommitFiles struct {
CheckoutCommitFile string `yaml:"checkoutCommitFile"`
} `yaml:"commitFiles"`
Main struct {
ToggleDragSelect string `yaml:"toggleDragSelect"`
ToggleDragSelectAlt string `yaml:"toggleDragSelect-alt"`
ToggleSelectHunk string `yaml:"toggleSelectHunk"`
PickBothHunks string `yaml:"pickBothHunks"`
} `yaml:"main"`
Submodules struct {
Init string `yaml:"init"`
Update string `yaml:"update"`
BulkMenu string `yaml:"bulkMenu"`
} `yaml:"submodules"`
} `yaml:"keybinding"`
// OS determines what defaults are set for opening files and links
OS OSConfig `yaml:"os,omitempty"`
StartupPopupVersion int `yaml:"startupPopupVersion"`
CustomCommands []CustomCommand `yaml:"customCommands"`
Services map[string]string `yaml:"services"`
}