Skip to content

Commit

Permalink
Merge pull request #73 from k1LoW/default-config-file
Browse files Browse the repository at this point in the history
Support default config file `.tbls.yml`
  • Loading branch information
k1LoW committed Nov 28, 2018
2 parents c2a0789 + 9b0812c commit 06a39a6
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 19 deletions.
6 changes: 6 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
coverage:
status:
project:
default:
target: 70%
patch: off
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ test_env:
test_config:
./tbls doc -c testdata/mysql_testdb_config.yml -f
./tbls diff -c testdata/mysql_testdb_config.yml
cp testdata/mysql_testdb_config.yml .tbls.yml
./tbls diff
rm .tbls.yml

build:
packr
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@ testdoc: ## Test database schema document
$ tbls doc my://root:mypass@localhost:33306/testdb sample/mysql
```

### 2. `--config` option
### 2. Use `.tbls.yml` or set `--config` option

Specify the YAML file with the `--config` option as follows
Put `.tbls.yml` on execute directory or specify with the `--config` option.

YAML format is follows

``` yaml
---
Expand Down
10 changes: 5 additions & 5 deletions cmd/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ var diffCmd = &cobra.Command{
os.Exit(1)
}

if configPath != "" {
err = c.LoadConfigFile(configPath)
if configPath == "" && additionalDataPath != "" {
fmt.Println("Warning: `--add` option is deprecated. Use `--config`")
err = c.LoadConfigFile(additionalDataPath)
if err != nil {
printError(err)
os.Exit(1)
}
} else if additionalDataPath != "" {
fmt.Println("Warning: `--add` option is deprecated. Use `--config`")
err = c.LoadConfigFile(additionalDataPath)
} else {
err = c.LoadConfigFile(configPath)
if err != nil {
printError(err)
os.Exit(1)
Expand Down
10 changes: 5 additions & 5 deletions cmd/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ var docCmd = &cobra.Command{
os.Exit(1)
}

if configPath != "" {
err = c.LoadConfigFile(configPath)
if configPath == "" && additionalDataPath != "" {
fmt.Println("Warning: `--add` option is deprecated. Use `--config`")
err = c.LoadConfigFile(additionalDataPath)
if err != nil {
printError(err)
os.Exit(1)
}
} else if additionalDataPath != "" {
fmt.Println("Warning: `--add` option is deprecated. Use `--config`")
err = c.LoadConfigFile(additionalDataPath)
} else {
err = c.LoadConfigFile(configPath)
if err != nil {
printError(err)
os.Exit(1)
Expand Down
10 changes: 5 additions & 5 deletions cmd/out.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ var outCmd = &cobra.Command{
os.Exit(1)
}

if configPath != "" {
err = c.LoadConfigFile(configPath)
if configPath == "" && additionalDataPath != "" {
fmt.Println("Warning: `--add` option is deprecated. Use `--config`")
err = c.LoadConfigFile(additionalDataPath)
if err != nil {
printError(err)
os.Exit(1)
}
} else if additionalDataPath != "" {
fmt.Println("Warning: `--add` option is deprecated. Use `--config`")
err = c.LoadConfigFile(additionalDataPath)
} else {
err = c.LoadConfigFile(configPath)
if err != nil {
printError(err)
os.Exit(1)
Expand Down
61 changes: 59 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package config

import (
"bytes"
"html/template"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/pkg/errors"
"gopkg.in/yaml.v2"
)

var configDefaultPath = ".tbls.yml"

// Config is tbls config
type Config struct {
DSN string `yaml:"dsn"`
Expand Down Expand Up @@ -54,7 +60,7 @@ func (c *Config) LoadArgs(args []string) error {
c.DocPath = args[1]
}
if len(args) > 2 {
return errors.WithStack(errors.New("requires two args"))
return errors.WithStack(errors.New("too many arguments"))
}
if len(args) == 1 {
if c.DSN == "" {
Expand All @@ -68,6 +74,13 @@ func (c *Config) LoadArgs(args []string) error {

// LoadConfigFile load config file
func (c *Config) LoadConfigFile(path string) error {
if path == "" {
path = configDefaultPath
if _, err := os.Lstat(path); err != nil {
return nil
}
}

fullPath, err := filepath.Abs(path)
if err != nil {
return errors.Wrap(errors.WithStack(err), "failed to load config file")
Expand All @@ -80,7 +93,51 @@ func (c *Config) LoadConfigFile(path string) error {

err = yaml.Unmarshal(buf, c)
if err != nil {
return errors.WithStack(err)
return errors.Wrap(errors.WithStack(err), "failed to load config file")
}

c.DSN, err = parseWithEnviron(c.DSN)
if err != nil {
return errors.Wrap(errors.WithStack(err), "failed to load config file")
}
c.DocPath, err = parseWithEnviron(c.DocPath)
if err != nil {
return errors.Wrap(errors.WithStack(err), "failed to load config file")
}
return nil
}

func parseWithEnviron(v string) (string, error) {
r := regexp.MustCompile(`\${\s*([^{}]+)\s*}`)
r2 := regexp.MustCompile(`{{([^\.])`)
r3 := regexp.MustCompile(`__TBLS__(.)`)
replaced := r.ReplaceAllString(v, "{{.$1}}")
replaced2 := r2.ReplaceAllString(replaced, "__TBLS__$1")
tmpl, err := template.New("config").Parse(replaced2)
if err != nil {
return "", err
}
buf := &bytes.Buffer{}
err = tmpl.Execute(buf, envMap())
if err != nil {
return "", err
}
return r3.ReplaceAllString(buf.String(), "{{$1"), nil
}

func envMap() map[string]string {
m := map[string]string{}
for _, kv := range os.Environ() {
if strings.Index(kv, "=") == -1 {
continue
}
parts := strings.SplitN(kv, "=", 2)
k := parts[0]
if len(parts) < 2 {
m[k] = ""
continue
}
m[k] = parts[1]
}
return m
}
59 changes: 59 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package config

import (
"os"
"path/filepath"
"testing"
)

func TestLoadConfigFile(t *testing.T) {
_ = os.Setenv("TBLS_TEST_PG_PASS", "pgpass")
_ = os.Setenv("TBLS_TEST_PG_DOC_PATH", "sample/pg")
configFilepath := filepath.Join(testdataDir(), "env_testdb_config.yml")
config, err := NewConfig()
if err != nil {
t.Fatal(err)
}
err = config.LoadConfigFile(configFilepath)
if err != nil {
t.Fatal(err)
}
expected := "pg://root:pgpass@localhost:55432/testdb?sslmode=disable"
if config.DSN != expected {
t.Errorf("actual %v\nwant %v", config.DSN, expected)
}
expected2 := "sample/pg"
if config.DocPath != expected2 {
t.Errorf("actual %v\nwant %v", config.DocPath, expected2)
}
}

var tests = []struct {
value string
expected string
}{
{"${TBLS_ONE}/${TBLS_TWO}", "one/two"},
{"${TBLS_ONE}/${TBLS_TWO}/${TBLS_NONE}", "one/two/"},
{"${{TBLS_ONE}}", "${{TBLS_ONE}}"},
{"{{.TBLS_ONE}}/{{.TBLS_TWO}}", "one/two"},
}

func TestParseWithEnvirion(t *testing.T) {
_ = os.Setenv("TBLS_ONE", "one")
_ = os.Setenv("TBLS_TWO", "two")
for _, tt := range tests {
actual, err := parseWithEnviron(tt.value)
if err != nil {
t.Fatal(err)
}
if actual != tt.expected {
t.Errorf("actual %v\nwant %v", actual, tt.expected)
}
}
}

func testdataDir() string {
wd, _ := os.Getwd()
dir, _ := filepath.Abs(filepath.Join(filepath.Dir(wd), "testdata"))
return dir
}
3 changes: 3 additions & 0 deletions testdata/env_testdb_config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
dsn: pg://root:${TBLS_TEST_PG_PASS}@localhost:55432/testdb?sslmode=disable
dataPath: ${TBLS_TEST_PG_DOC_PATH}

0 comments on commit 06a39a6

Please sign in to comment.