Merge pull request #620 from github/gh_yaml

Refactor to `configService` to read & write `Config`
This commit is contained in:
Jingwen Owen Ou 2014-09-16 09:58:10 -07:00
Родитель 26255a0566 b3d5be4d93
Коммит 254bf7c7e7
12 изменённых файлов: 147 добавлений и 89 удалений

Просмотреть файл

@ -59,8 +59,8 @@ func transformCloneArgs(args *Args) {
name, owner := parseCloneNameAndOwner(a)
var host *github.Host
if owner == "" {
configs := github.CurrentConfigs()
h, err := configs.DefaultHost()
config := github.CurrentConfig()
h, err := config.DefaultHost()
if err != nil {
utils.Check(github.FormatError("cloning repository", err))
}

Просмотреть файл

@ -73,8 +73,8 @@ func create(command *Command, args *Args) {
newRepoName = args.FirstParam()
}
configs := github.CurrentConfigs()
host, err := configs.DefaultHost()
config := github.CurrentConfig()
host, err := config.DefaultHost()
if err != nil {
utils.Check(github.FormatError("creating repository", err))
}

Просмотреть файл

@ -2,9 +2,10 @@ package commands
import (
"fmt"
"os"
"github.com/github/hub/github"
"github.com/github/hub/utils"
"os"
)
var cmdFork = &Command{
@ -41,8 +42,8 @@ func fork(cmd *Command, args *Args) {
utils.Check(fmt.Errorf("Error: repository under 'origin' remote is not a GitHub project"))
}
configs := github.CurrentConfigs()
host, err := configs.PromptForHost(project.Host)
config := github.CurrentConfig()
host, err := config.PromptForHost(project.Host)
if err != nil {
utils.Check(github.FormatError("forking repository", err))
}

Просмотреть файл

@ -86,7 +86,7 @@ func pullRequest(cmd *Command, args *Args) {
baseProject, err := localRepo.MainProject()
utils.Check(err)
host, err := github.CurrentConfigs().PromptForHost(baseProject.Host)
host, err := github.CurrentConfig().PromptForHost(baseProject.Host)
if err != nil {
utils.Check(github.FormatError("creating pull request", err))
}

Просмотреть файл

@ -69,7 +69,7 @@ func transformRemoteArgs(args *Args) {
isPriavte := parseRemotePrivateFlag(args)
if len(words) == 2 && words[1] == "origin" {
// Origin special case triggers default user/repo
host, err := github.CurrentConfigs().DefaultHost()
host, err := github.CurrentConfig().DefaultHost()
if err != nil {
utils.Check(github.FormatError("adding remote", err))
}

Просмотреть файл

@ -443,7 +443,7 @@ func (client *Client) FindOrCreateToken(user, password, twoFactorCode string) (t
func (client *Client) api() (c *octokit.Client, err error) {
if client.Host.AccessToken == "" {
host, e := CurrentConfigs().PromptForHost(client.Host.Host)
host, e := CurrentConfig().PromptForHost(client.Host.Host)
if e != nil {
err = e
return

Просмотреть файл

@ -8,7 +8,6 @@ import (
"path/filepath"
"strconv"
"github.com/BurntSushi/toml"
"github.com/github/hub/utils"
"github.com/howeyc/gopass"
)
@ -24,11 +23,11 @@ type Host struct {
Protocol string `toml:"protocol"`
}
type Configs struct {
type Config struct {
Hosts []Host `toml:"hosts"`
}
func (c *Configs) PromptForHost(host string) (h *Host, err error) {
func (c *Config) PromptForHost(host string) (h *Host, err error) {
h = c.Find(host)
if h != nil {
return
@ -65,12 +64,12 @@ func (c *Configs) PromptForHost(host string) (h *Host, err error) {
Protocol: "https",
}
c.Hosts = append(c.Hosts, *h)
err = saveTo(configsFile(), c)
err = newConfigService().Save(configsFile(), c)
return
}
func (c *Configs) PromptForUser() (user string) {
func (c *Config) PromptForUser() (user string) {
user = os.Getenv("GITHUB_USER")
if user != "" {
return
@ -82,7 +81,7 @@ func (c *Configs) PromptForUser() (user string) {
return
}
func (c *Configs) PromptForPassword(host, user string) (pass string) {
func (c *Config) PromptForPassword(host, user string) (pass string) {
pass = os.Getenv("GITHUB_PASSWORD")
if pass != "" {
return
@ -98,12 +97,12 @@ func (c *Configs) PromptForPassword(host, user string) (pass string) {
return
}
func (c *Configs) PromptForOTP() string {
func (c *Config) PromptForOTP() string {
fmt.Print("two-factor authentication code: ")
return c.scanLine()
}
func (c *Configs) scanLine() string {
func (c *Config) scanLine() string {
var line string
scanner := bufio.NewScanner(os.Stdin)
if scanner.Scan() {
@ -114,7 +113,7 @@ func (c *Configs) scanLine() string {
return line
}
func (c *Configs) Find(host string) *Host {
func (c *Config) Find(host string) *Host {
for _, h := range c.Hosts {
if h.Host == host {
return &h
@ -124,61 +123,7 @@ func (c *Configs) Find(host string) *Host {
return nil
}
func saveTo(filename string, v interface{}) error {
err := os.MkdirAll(filepath.Dir(filename), 0771)
if err != nil {
return err
}
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
defer f.Close()
enc := toml.NewEncoder(f)
return enc.Encode(v)
}
func loadFrom(filename string, c *Configs) (err error) {
_, err = toml.DecodeFile(filename, c)
return
}
func configsFile() string {
configsFile := os.Getenv("GH_CONFIG")
if configsFile == "" {
configsFile = defaultConfigsFile
}
return configsFile
}
func CurrentConfigs() *Configs {
c := &Configs{}
configFile := configsFile()
err := loadFrom(configFile, c)
if err != nil {
// load from YAML
}
return c
}
func (c *Configs) DefaultHost() (host *Host, err error) {
if GitHubHostEnv != "" {
host, err = c.PromptForHost(GitHubHostEnv)
} else if len(c.Hosts) > 0 {
host = c.selectHost()
} else {
host, err = c.PromptForHost(DefaultGitHubHost())
}
return
}
func (c *Configs) selectHost() *Host {
func (c *Config) selectHost() *Host {
options := len(c.Hosts)
if options == 1 {
@ -201,12 +146,40 @@ func (c *Configs) selectHost() *Host {
return &c.Hosts[i-1]
}
func (c *Configs) Save() error {
return saveTo(configsFile(), c)
func configsFile() string {
configsFile := os.Getenv("GH_CONFIG")
if configsFile == "" {
configsFile = defaultConfigsFile
}
return configsFile
}
func CurrentConfig() *Config {
c := &Config{}
err := newConfigService().Load(configsFile(), c)
if err != nil {
// load from YAML
}
return c
}
func (c *Config) DefaultHost() (host *Host, err error) {
if GitHubHostEnv != "" {
host, err = c.PromptForHost(GitHubHostEnv)
} else if len(c.Hosts) > 0 {
host = c.selectHost()
} else {
host, err = c.PromptForHost(DefaultGitHubHost())
}
return
}
// Public for testing purpose
func CreateTestConfigs(user, token string) *Configs {
func CreateTestConfigs(user, token string) *Config {
f, _ := ioutil.TempFile("", "test-config")
defaultConfigsFile = f.Name()
@ -216,8 +189,11 @@ func CreateTestConfigs(user, token string) *Configs {
Host: GitHubHost,
}
c := &Configs{Hosts: []Host{host}}
saveTo(f.Name(), c)
c := &Config{Hosts: []Host{host}}
err := newConfigService().Save(f.Name(), c)
if err != nil {
panic(err)
}
return c
}

19
github/config_decoder.go Normal file
Просмотреть файл

@ -0,0 +1,19 @@
package github
import (
"io"
"github.com/BurntSushi/toml"
)
type configDecoder interface {
Decode(r io.Reader, v interface{}) error
}
type tomlConfigDecoder struct {
}
func (t *tomlConfigDecoder) Decode(r io.Reader, v interface{}) error {
_, err := toml.DecodeReader(r, v)
return err
}

19
github/config_encoder.go Normal file
Просмотреть файл

@ -0,0 +1,19 @@
package github
import (
"io"
"github.com/BurntSushi/toml"
)
type configEncoder interface {
Encode(w io.Writer, v interface{}) error
}
type tomlConfigEncoder struct {
}
func (t *tomlConfigEncoder) Encode(w io.Writer, v interface{}) error {
enc := toml.NewEncoder(w)
return enc.Encode(v)
}

43
github/config_service.go Normal file
Просмотреть файл

@ -0,0 +1,43 @@
package github
import (
"os"
"path/filepath"
)
func newConfigService() *configService {
return &configService{
Encoder: &tomlConfigEncoder{},
Decoder: &tomlConfigDecoder{},
}
}
type configService struct {
Encoder configEncoder
Decoder configDecoder
}
func (s *configService) Save(filename string, c *Config) error {
err := os.MkdirAll(filepath.Dir(filename), 0771)
if err != nil {
return err
}
w, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
defer w.Close()
return s.Encoder.Encode(w, c)
}
func (s *configService) Load(filename string, c *Config) error {
r, err := os.Open(filename)
if err != nil {
return err
}
defer r.Close()
return s.Decoder.Decode(r, c)
}

Просмотреть файл

@ -10,12 +10,12 @@ import (
"github.com/github/hub/fixtures"
)
func TestConfigs_loadFrom(t *testing.T) {
testConfigs := fixtures.SetupTestConfigs()
defer testConfigs.TearDown()
func TestConfigService_Load(t *testing.T) {
testConfig := fixtures.SetupTestConfigs()
defer testConfig.TearDown()
cc := &Configs{}
err := loadFrom(testConfigs.Path, cc)
cc := &Config{}
err := newConfigService().Load(testConfig.Path, cc)
assert.Equal(t, nil, err)
assert.Equal(t, 1, len(cc.Hosts))
@ -26,7 +26,7 @@ func TestConfigs_loadFrom(t *testing.T) {
assert.Equal(t, "http", host.Protocol)
}
func TestConfigs_saveTo(t *testing.T) {
func TestConfigService_Save(t *testing.T) {
file, _ := ioutil.TempFile("", "test-gh-config-")
defer os.RemoveAll(file.Name())
@ -36,9 +36,9 @@ func TestConfigs_saveTo(t *testing.T) {
AccessToken: "123",
Protocol: "https",
}
c := Configs{Hosts: []Host{host}}
c := Config{Hosts: []Host{host}}
err := saveTo(file.Name(), &c)
err := newConfigService().Save(file.Name(), &c)
assert.Equal(t, nil, err)
b, _ := ioutil.ReadFile(file.Name())

Просмотреть файл

@ -151,7 +151,7 @@ func newProject(owner, name, host, protocol string) *Project {
protocol = ""
}
if protocol == "" {
h := CurrentConfigs().Find(host)
h := CurrentConfig().Find(host)
if h != nil {
protocol = h.Protocol
}
@ -161,7 +161,7 @@ func newProject(owner, name, host, protocol string) *Project {
}
if owner == "" {
h := CurrentConfigs().Find(host)
h := CurrentConfig().Find(host)
if h != nil {
owner = h.User
}