Skip to content

Commit

Permalink
Merge pull request sequelize#153 from exercism/refactor-config
Browse files Browse the repository at this point in the history
Refactor config
  • Loading branch information
kytrinyx committed Jan 19, 2015
2 parents 01214f3 + f801cd2 commit e8ad540
Show file tree
Hide file tree
Showing 16 changed files with 180 additions and 199 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Stop supporting legacy config files (~/.exercism.go)
* Deleted deprecated login/logout commands
* Deleted deprecated key names in config
* [#153](https://github.com/exercism/cli/pull/153): Refactored configuration package - [@kytrinyx](https://github.com/kytrinyx)
* Your contribution here

## v1.9.2 (Jan 11, 2015)
Expand Down
2 changes: 1 addition & 1 deletion cmd/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// If a setting is not passed as an argument, default
// values are used.
func Configure(ctx *cli.Context) {
c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func Debug(ctx *cli.Context) {
}
fmt.Printf("Home Dir: %s\n", dir)

c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/demo.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// Demo returns one problem for each active track.
func Demo(ctx *cli.Context) {
c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

// Download returns specified submissions and related problem.
func Download(ctx *cli.Context) {
c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// Fetch returns exercism problems.
func Fetch(ctx *cli.Context) {
c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// Restore returns a user's solved problems.
func Restore(ctx *cli.Context) {
c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func Submit(ctx *cli.Context) {
log.Fatal("Please enter a file name")
}

c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/tracks.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// Tracks lists available tracks.
func Tracks(ctx *cli.Context) {
c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/unsubmit.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// If no iteration is specified, the most recent iteration
// is deleted.
func Unsubmit(ctx *cli.Context) {
c, err := config.Read(ctx.GlobalString("config"))
c, err := config.New(ctx.GlobalString("config"))
if err != nil {
log.Fatal(err)
}
Expand Down
139 changes: 63 additions & 76 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package config
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -65,99 +64,116 @@ func Home() (string, error) {
return dir, nil
}

// Read loads the config from the stored JSON file.
func Read(file string) (*Config, error) {
func New(path string) (*Config, error) {
c := &Config{}
err := c.Read(file)
err := c.load(path, os.Getenv(fileEnvKey))
return c, err
}

// Update sets new values where given.
func (c *Config) Update(key, host, dir, xapi string) {
key = strings.TrimSpace(key)
if key != "" {
c.APIKey = key
}

host = strings.TrimSpace(host)
if host != "" {
c.API = host
}

dir = strings.TrimSpace(dir)
if dir != "" {
c.Dir = dir
}

xapi = strings.TrimSpace(xapi)
if xapi != "" {
c.XAPI = xapi
}

c.configure()
}

// Expand takes inputs for a config file location and builds an absolute path.
func Expand(path, env, home string) string {
if path == "" {
path = env
}

if path != "" && path[0] == '~' {
path = strings.Replace(path, "~/", fmt.Sprintf("%s/", home), 1)
}

if path == "" {
path = filepath.Join(home, File)
// Write saves the config as JSON.
func (c *Config) Write() error {
// truncates existing file if it exists
f, err := os.Create(c.File)
if err != nil {
return err
}
defer f.Close()

return path
e := json.NewEncoder(f)
return e.Encode(c)
}

// Read loads the config from the stored JSON file.
func (c *Config) Read(file string) error {
home, err := c.homeDir()
func (c *Config) load(argPath, envPath string) error {
path, err := c.resolvePath(argPath, envPath)
if err != nil {
return err
}
c.File = path

c.File = Expand(file, os.Getenv(fileEnvKey), home)
if err := c.read(); err != nil {
return err
}

// in case people manually update the config file
// with weird formatting
c.APIKey = strings.TrimSpace(c.APIKey)
c.Dir = strings.TrimSpace(c.Dir)
c.API = strings.TrimSpace(c.API)
c.XAPI = strings.TrimSpace(c.XAPI)

return c.setDefaults()
}

func (c *Config) read() error {
if _, err := os.Stat(c.File); err != nil {
if os.IsNotExist(err) {
c.configure()
return nil
}
return err
}

f, err := os.Open(c.File)
if err != nil {
return err
}
defer f.Close()

d := json.NewDecoder(f)
err = d.Decode(&c)
if err != nil {
return err
return d.Decode(&c)
}

// IsAuthenticated returns true if the config contains an API key.
// This does not check whether or not that key is valid.
func (c *Config) IsAuthenticated() bool {
return c.APIKey != ""
}

// homeDir caches the lookup of the user's home directory.
func (c *Config) homeDir() (string, error) {
if c.home != "" {
return c.home, nil
}
c.configure()
return nil
return Home()
}

// Write() saves the config as JSON.
func (c *Config) Write() error {
// truncates existing file if it exists
f, err := os.Create(c.File)
func (c *Config) resolvePath(argPath, envPath string) (string, error) {
path := argPath
if path == "" {
path = envPath
}
if path == "" {
path = filepath.Join("~", File)
}
h, err := c.homeDir()
if err != nil {
return err
return "", err
}
defer f.Close()

e := json.NewEncoder(f)
return e.Encode(c)
return strings.Replace(path, "~", h, 1), nil
}

func (c *Config) configure() (*Config, error) {
c.sanitize()

func (c *Config) setDefaults() error {
if c.API == "" {
c.API = hostAPI
}
Expand All @@ -166,44 +182,15 @@ func (c *Config) configure() (*Config, error) {
c.XAPI = hostXAPI
}

homeDir, err := c.homeDir()
h, err := c.homeDir()
if err != nil {
return c, err
return err
}

if c.Dir == "" {
// fall back to default value
c.Dir = filepath.Join(homeDir, DirExercises)
} else {
// replace '~' with user's home
c.Dir = strings.Replace(c.Dir, "~/", fmt.Sprintf("%s/", homeDir), 1)
}

if c.File == "" {
c.File = filepath.Join(homeDir, File)
}

return c, nil
}

// IsAuthenticated returns true if the config contains an API key.
// This does not check whether or not that key is valid.
func (c *Config) IsAuthenticated() bool {
return c.APIKey != ""
}

// See: http://stackoverflow.com/questions/7922270/obtain-users-home-directory
// we can't cross compile using cgo and use user.Current()
func (c *Config) homeDir() (string, error) {
if c.home != "" {
return c.home, nil
c.Dir = filepath.Join(h, DirExercises)
}
return Home()
}
c.Dir = strings.Replace(c.Dir, "~", h, 1)

func (c *Config) sanitize() {
c.APIKey = strings.TrimSpace(c.APIKey)
c.Dir = strings.TrimSpace(c.Dir)
c.API = strings.TrimSpace(c.API)
c.XAPI = strings.TrimSpace(c.XAPI)
return nil
}

0 comments on commit e8ad540

Please sign in to comment.