mirror of
https://github.com/grdl/git-get.git
synced 2026-02-06 16:52:57 +00:00
Refactor packages structure
- Isolate files into their own packages - Create new printer package and interface - Refactor Repo stuct to embed the go-git *Repository directly - Simplify cmd package
This commit is contained in:
112
cfg/config.go
Normal file
112
cfg/config.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
plumbing "github.com/go-git/go-git/v5/plumbing/format/config"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
GitgetPrefix = "gitget"
|
||||
KeyReposRoot = "reposRoot"
|
||||
DefReposRoot = "repositories"
|
||||
KeyDefaultHost = "defaultHost"
|
||||
DefDefaultHost = "github.com"
|
||||
KeyPrivateKey = "privateKey"
|
||||
DefPrivateKey = "id_rsa"
|
||||
)
|
||||
|
||||
// gitconfig provides methods for looking up configiration values inside .gitconfig file
|
||||
type gitconfig struct {
|
||||
*config.Config
|
||||
}
|
||||
|
||||
// InitConfig initializes viper config registry. Values are looked up in the following order: cli flag, env variable, gitconfig file, default value
|
||||
// Viper doesn't support gitconfig file format so it can't find missing values there automatically. They need to be specified in setMissingValues func.
|
||||
//
|
||||
// Because it reads the cli flags it needs to be called after the cmd.Execute().
|
||||
func InitConfig() {
|
||||
viper.SetEnvPrefix(strings.ToUpper(GitgetPrefix))
|
||||
viper.AutomaticEnv()
|
||||
|
||||
cfg := loadGitconfig()
|
||||
setMissingValues(cfg)
|
||||
}
|
||||
|
||||
// loadGitconfig loads configuration from a gitconfig file.
|
||||
// We ignore errors when gitconfig file can't be found, opened or parsed. In those cases viper will provide default config values.
|
||||
func loadGitconfig() *gitconfig {
|
||||
// TODO: load system scope
|
||||
cfg, _ := config.LoadConfig(config.GlobalScope)
|
||||
|
||||
return &gitconfig{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
// setMissingValues checks if config values are provided by flags or env vars. If not, it tries loading them from gitconfig file.
|
||||
// If that fails, the default values are used.
|
||||
func setMissingValues(cfg *gitconfig) {
|
||||
if isUnsetOrEmpty(KeyReposRoot) {
|
||||
viper.Set(KeyReposRoot, cfg.get(KeyReposRoot, path.Join(home(), DefReposRoot)))
|
||||
}
|
||||
|
||||
if isUnsetOrEmpty(KeyDefaultHost) {
|
||||
viper.Set(KeyDefaultHost, cfg.get(KeyDefaultHost, DefDefaultHost))
|
||||
}
|
||||
|
||||
if isUnsetOrEmpty(KeyPrivateKey) {
|
||||
viper.Set(KeyPrivateKey, cfg.get(KeyPrivateKey, path.Join(home(), ".ssh", DefPrivateKey)))
|
||||
}
|
||||
}
|
||||
|
||||
// get looks up the value for a given key in gitconfig file.
|
||||
// It returns the default value when gitconfig is missing, or it doesn't contain a gitget section,
|
||||
// or if the section is empty, or if it doesn't contain a valid value for the key.
|
||||
func (c *gitconfig) get(key string, def string) string {
|
||||
if c == nil || c.Config == nil {
|
||||
return def
|
||||
}
|
||||
|
||||
gitget := c.findGitconfigSection(GitgetPrefix)
|
||||
if gitget == nil {
|
||||
return def
|
||||
}
|
||||
|
||||
opt := gitget.Option(key)
|
||||
if strings.TrimSpace(opt) == "" {
|
||||
return def
|
||||
}
|
||||
|
||||
return opt
|
||||
}
|
||||
|
||||
func (c *gitconfig) findGitconfigSection(name string) *plumbing.Section {
|
||||
for _, s := range c.Raw.Sections {
|
||||
if strings.ToLower(s.Name) == strings.ToLower(name) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// home returns path to a home directory or empty string if can't be found.
|
||||
// Using empty string means that in the unlikely situation where home dir can't be found
|
||||
// and there's no reposRoot specified by any of the config methods, the current dir will be used as repos root.
|
||||
func home() string {
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return home
|
||||
}
|
||||
|
||||
func isUnsetOrEmpty(key string) bool {
|
||||
return !viper.IsSet(key) || strings.TrimSpace(viper.GetString(key)) == ""
|
||||
}
|
||||
164
cfg/config_test.go
Normal file
164
cfg/config_test.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
EnvDefaultHost = "GITGET_DEFAULTHOST"
|
||||
EnvReposRoot = "GITGET_REPOSROOT"
|
||||
)
|
||||
|
||||
func newConfigWithFullGitconfig() *gitconfig {
|
||||
cfg := config.NewConfig()
|
||||
|
||||
gitget := cfg.Raw.Section(GitgetPrefix)
|
||||
gitget.AddOption(KeyReposRoot, "file.root")
|
||||
gitget.AddOption(KeyDefaultHost, "file.host")
|
||||
|
||||
return &gitconfig{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigWithEmptyGitgetSection() *gitconfig {
|
||||
cfg := config.NewConfig()
|
||||
|
||||
_ = cfg.Raw.Section(GitgetPrefix)
|
||||
|
||||
return &gitconfig{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigWithEmptyValues() *gitconfig {
|
||||
cfg := config.NewConfig()
|
||||
|
||||
gitget := cfg.Raw.Section(GitgetPrefix)
|
||||
gitget.AddOption(KeyReposRoot, "")
|
||||
gitget.AddOption(KeyDefaultHost, " ")
|
||||
|
||||
return &gitconfig{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigWithoutGitgetSection() *gitconfig {
|
||||
cfg := config.NewConfig()
|
||||
|
||||
return &gitconfig{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigWithEmptyGitconfig() *gitconfig {
|
||||
return &gitconfig{
|
||||
Config: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigWithEnvVars() *gitconfig {
|
||||
_ = os.Setenv(EnvDefaultHost, "env.host")
|
||||
_ = os.Setenv(EnvReposRoot, "env.root")
|
||||
|
||||
return &gitconfig{
|
||||
Config: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigWithGitconfigAndEnvVars() *gitconfig {
|
||||
cfg := config.NewConfig()
|
||||
|
||||
gitget := cfg.Raw.Section(GitgetPrefix)
|
||||
gitget.AddOption(KeyReposRoot, "file.root")
|
||||
gitget.AddOption(KeyDefaultHost, "file.host")
|
||||
|
||||
_ = os.Setenv(EnvDefaultHost, "env.host")
|
||||
_ = os.Setenv(EnvReposRoot, "env.root")
|
||||
|
||||
return &gitconfig{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigWithEmptySectionAndEnvVars() *gitconfig {
|
||||
cfg := config.NewConfig()
|
||||
|
||||
_ = cfg.Raw.Section(GitgetPrefix)
|
||||
|
||||
_ = os.Setenv(EnvDefaultHost, "env.host")
|
||||
_ = os.Setenv(EnvReposRoot, "env.root")
|
||||
|
||||
return &gitconfig{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigWithMixed() *gitconfig {
|
||||
cfg := config.NewConfig()
|
||||
|
||||
gitget := cfg.Raw.Section(GitgetPrefix)
|
||||
gitget.AddOption(KeyReposRoot, "file.root")
|
||||
gitget.AddOption(KeyDefaultHost, "file.host")
|
||||
|
||||
_ = os.Setenv(EnvDefaultHost, "env.host")
|
||||
|
||||
return &gitconfig{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
defReposRoot := path.Join(home(), DefReposRoot)
|
||||
|
||||
var tests = []struct {
|
||||
makeConfig func() *gitconfig
|
||||
wantReposRoot string
|
||||
wantDefaultHost string
|
||||
}{
|
||||
{newConfigWithFullGitconfig, "file.root", "file.host"},
|
||||
{newConfigWithoutGitgetSection, defReposRoot, DefDefaultHost},
|
||||
{newConfigWithEmptyGitconfig, defReposRoot, DefDefaultHost},
|
||||
{newConfigWithEnvVars, "env.root", "env.host"},
|
||||
{newConfigWithGitconfigAndEnvVars, "env.root", "env.host"},
|
||||
{newConfigWithEmptySectionAndEnvVars, "env.root", "env.host"},
|
||||
{newConfigWithEmptyGitgetSection, defReposRoot, DefDefaultHost},
|
||||
{newConfigWithEmptyValues, defReposRoot, DefDefaultHost},
|
||||
{newConfigWithMixed, "file.root", "env.host"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
viper.SetEnvPrefix(strings.ToUpper(GitgetPrefix))
|
||||
viper.AutomaticEnv()
|
||||
|
||||
cfg := test.makeConfig()
|
||||
setMissingValues(cfg)
|
||||
|
||||
if viper.GetString(KeyDefaultHost) != test.wantDefaultHost {
|
||||
t.Errorf("Wrong %s value, got: %s; want: %s", KeyDefaultHost, viper.GetString(KeyDefaultHost), test.wantDefaultHost)
|
||||
}
|
||||
|
||||
if viper.GetString(KeyReposRoot) != test.wantReposRoot {
|
||||
t.Errorf("Wrong %s value, got: %s; want: %s", KeyReposRoot, viper.GetString(KeyReposRoot), test.wantReposRoot)
|
||||
}
|
||||
|
||||
// Unset env variables and reset viper registry after each test
|
||||
viper.Reset()
|
||||
err := os.Unsetenv(EnvDefaultHost)
|
||||
checkFatal(t, err)
|
||||
err = os.Unsetenv(EnvReposRoot)
|
||||
checkFatal(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func checkFatal(t *testing.T, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user