Skip to content
This repository was archived by the owner on Sep 21, 2022. It is now read-only.

Commit 07cf2e1

Browse files
authored
Merge pull request #66 from patdhlk/hcl-support
HCL support incl. tests Closes #65
2 parents fcd6fbb + 6a3b0cd commit 07cf2e1

File tree

8 files changed

+76
-36
lines changed

8 files changed

+76
-36
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* [x] Middleware support. All [alice](https://github.com/justinas/alice) compatible Middleware works out of the box
1212
* [x] Gopher spirit (write golang, use all the golang libraries you like)
1313
* [x] Lightweight. Only MVC
14-
* [x] Multiple configuration files support (currently json, yaml and toml)
14+
* [x] Multiple configuration files support (currently json, yaml, toml and hcl)
1515

1616

1717

@@ -88,7 +88,7 @@ I have included three configuration files to show how they work, but you are bet
8888
## Configurations
8989
utron support yaml, json and toml configurations files. In our todo app, we put the configuration files in the config directory. I have included all three formats for clarity, you can be just fine with either one of them.
9090

91-
`utron` searches for a file named `app.json`, or `app.yml` or `app.toml` in the config directory. The first to be found is the one to be used.
91+
`utron` searches for a file named `app.json`, or `app.yml`, `app.toml`, `app.hcl` in the config directory. The first to be found is the one to be used.
9292

9393
This is the content of `config/app.json` file:
9494

config.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,21 @@ import (
1414

1515
"github.com/BurntSushi/toml"
1616
"github.com/fatih/camelcase"
17+
"github.com/hashicorp/hcl"
1718
"gopkg.in/yaml.v2"
1819
)
1920

2021
// Config stores configurations values
2122
type Config struct {
22-
AppName string `json:"app_name" yaml:"app_name" toml:"app_name"`
23-
BaseURL string `json:"base_url" yaml:"base_url" toml:"base_url"`
24-
Port int `json:"port" yaml:"port" toml:"port"`
25-
Verbose bool `json:"verbose" yaml:"verbose" toml:"verbose"`
26-
StaticDir string `json:"static_dir" yaml:"static_dir" toml:"static_dir"`
27-
ViewsDir string `json:"view_dir" yaml:"view_dir" toml:"view_dir"`
28-
Database string `json:"database" yaml:"database" toml:"database"`
29-
DatabaseConn string `json:"database_conn" yaml:"database_conn" toml:"database_conn"`
30-
Automigrate bool `json:"automigrate" yaml:"automigrate" toml:"automigrate"`
23+
AppName string `json:"app_name" yaml:"app_name" toml:"app_name" hcl:"app_name"`
24+
BaseURL string `json:"base_url" yaml:"base_url" toml:"base_url" hcl:"base_url"`
25+
Port int `json:"port" yaml:"port" toml:"port" hcl:"port"`
26+
Verbose bool `json:"verbose" yaml:"verbose" toml:"verbose" hcl:"verbose"`
27+
StaticDir string `json:"static_dir" yaml:"static_dir" toml:"static_dir" hcl:"static_dir"`
28+
ViewsDir string `json:"view_dir" yaml:"view_dir" toml:"view_dir" hcl:"view_dir"`
29+
Database string `json:"database" yaml:"database" toml:"database" hcl:"database"`
30+
DatabaseConn string `json:"database_conn" yaml:"database_conn" toml:"database_conn" hcl:"database_conn"`
31+
Automigrate bool `json:"automigrate" yaml:"automigrate" toml:"automigrate" hcl:"automigrate"`
3132
}
3233

3334
// DefaultConfig returns the default configuration settings.
@@ -47,6 +48,7 @@ func DefaultConfig() *Config {
4748
// * .json - is decoded as json
4849
// * .yml - is decoded as yaml
4950
// * .toml - is decoded as toml
51+
// * .hcl - is decoded as hcl
5052
func NewConfig(path string) (*Config, error) {
5153
_, err := os.Stat(path)
5254
if err != nil {
@@ -75,7 +77,14 @@ func NewConfig(path string) (*Config, error) {
7577
if yerr != nil {
7678
return nil, yerr
7779
}
78-
80+
case ".hcl":
81+
obj, herr := hcl.Parse(string(data))
82+
if herr != nil {
83+
return nil, herr
84+
}
85+
if herr = hcl.DecodeObject(&cfg, obj); herr != nil {
86+
return nil, herr
87+
}
7988
default:
8089
return nil, errors.New("utron: config file format not supported")
8190
}
@@ -110,7 +119,6 @@ func (c *Config) saveToFile(path string) error {
110119
return err
111120
}
112121
data = b.Bytes()
113-
114122
}
115123
return ioutil.WriteFile(path, data, 0600)
116124
}

config_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ func TestConfig(t *testing.T) {
1010
"fixtures/config/app.json",
1111
"fixtures/config/app.yml",
1212
"fixtures/config/app.toml",
13+
"fixtures/config/app.hcl",
1314
}
1415

1516
cfg := DefaultConfig()

fixtures/config/app.hcl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
app_name = "utron web app"
2+
base_url = "http://localhost:8090"
3+
port = 8090
4+
verbose = false
5+
static_dir = "fixtures/static"
6+
view_dir = "fixtures/view"
7+
database = ""
8+
database_conn = ""
9+
automigrate = true

fixtures/config/routes.hcl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
routes = [
2+
"get,post;/hello;Sample.Hello",
3+
"get,post;/about;Hello.About"
4+
]

routes.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/BurntSushi/toml"
1515
"github.com/gernest/ita"
1616
"github.com/gorilla/mux"
17+
"github.com/hashicorp/hcl"
1718
"github.com/justinas/alice"
1819
"gopkg.in/yaml.v2"
1920
)
@@ -415,7 +416,7 @@ type routeFile struct {
415416
// ]
416417
// }
417418
//
418-
// supported formats are json,toml and yaml with extension .json, .toml and .yml respectively.
419+
// supported formats are json, toml, yaml and hcl with extension .json, .toml, .yml and .hcl respectively.
419420
//
420421
//TODO refactor the decoding part to a separate function? This part shares the same logic as the
421422
// one found in NewConfig()
@@ -441,6 +442,14 @@ func (r *Router) LoadRoutesFile(file string) error {
441442
if err != nil {
442443
return err
443444
}
445+
case ".hcl":
446+
obj, err := hcl.Parse(string(data))
447+
if err != nil {
448+
return err
449+
}
450+
if err = hcl.DecodeObject(&rFile, obj); err != nil {
451+
return err
452+
}
444453
default:
445454
return errors.New("utron: unsupported file format")
446455
}
@@ -461,8 +470,9 @@ func (r *Router) LoadRoutesFile(file string) error {
461470
// * routes.json
462471
// * routes.toml
463472
// * routes.yml
473+
// * routes.hcl
464474
func (r *Router) loadRoutes(cfgPath string) {
465-
exts := []string{".json", ".toml", ".yml"}
475+
exts := []string{".json", ".toml", ".yml", ".hcl"}
466476
rFile := "routes"
467477
for _, ext := range exts {
468478
file := filepath.Join(cfgPath, rFile+ext)

routes_test.go

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -92,31 +92,39 @@ func TestRouteField(t *testing.T) {
9292
}
9393

9494
func TestRoutesFile(t *testing.T) {
95-
file := "fixtures/config/routes.json"
96-
r := NewRouter()
9795

98-
err := r.LoadRoutesFile(file)
99-
if err != nil {
100-
t.Error(err)
96+
routeFiles := []string{
97+
"fixtures/config/routes.json",
98+
"fixtures/config/routes.hcl",
10199
}
102-
if len(r.routes) != 2 {
103-
t.Errorf("expcted 2 got %d", len(r.routes))
104-
}
105-
_ = r.Add(NewSample())
106100

107-
req, err := http.NewRequest("GET", "/hello", nil)
108-
if err != nil {
109-
t.Error(err)
110-
}
111-
w := httptest.NewRecorder()
112-
r.ServeHTTP(w, req)
101+
for _, file := range routeFiles {
102+
r := NewRouter()
113103

114-
if w.Code != http.StatusOK {
115-
t.Errorf("expected %d got %d", http.StatusOK, w.Code)
116-
}
117-
if w.Body.String() != msg {
118-
t.Errorf("expected %s got %s", msg, w.Body.String())
104+
err := r.LoadRoutesFile(file)
105+
if err != nil {
106+
t.Error(err)
107+
}
108+
if len(r.routes) != 2 {
109+
t.Errorf("expcted 2 got %d", len(r.routes))
110+
}
111+
_ = r.Add(NewSample())
112+
113+
req, err := http.NewRequest("GET", "/hello", nil)
114+
if err != nil {
115+
t.Error(err)
116+
}
117+
w := httptest.NewRecorder()
118+
r.ServeHTTP(w, req)
119+
120+
if w.Code != http.StatusOK {
121+
t.Errorf("expected %d got %d", http.StatusOK, w.Code)
122+
}
123+
if w.Body.String() != msg {
124+
t.Errorf("expected %s got %s", msg, w.Body.String())
125+
}
119126
}
127+
120128
}
121129

122130
func TestSplitRoutes(t *testing.T) {

utron.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func loadConfig(cfg ...string) (*Config, error) {
155155

156156
// findConfigFile finds the configuration file name in the directory dir.
157157
func findConfigFile(dir string, name string) (file string, err error) {
158-
extensions := []string{".json", ".toml", ".yml"}
158+
extensions := []string{".json", ".toml", ".yml", ".hcl"}
159159

160160
for _, ext := range extensions {
161161
file = filepath.Join(dir, name)

0 commit comments

Comments
 (0)