Skip to content

Commit

Permalink
Merge pull request #8 for v0.5.0 Release
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm committed Jun 21, 2018
2 parents 5e0e808 + 96e36cd commit 4a83ecc
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 73 deletions.
10 changes: 6 additions & 4 deletions .travis.yml
Expand Up @@ -7,17 +7,19 @@ branches:
# skip tags build, we are building branch and master that is enough for
# consistenty check and release. Let's use Travis CI resources optimally
# for aah framework.
- /^v[0-9]\.[0-9]/
- /^v[0-9.]+$/

go:
- 1.8
- 1.8.x
- 1.9.x
- 1.x
- tip

go_import_path: aahframework.org/config.v0

before_install:
- bash <(curl -s https://aahframework.org/base-before-install) "essentials vfs forge"

install:
- git config --global http.https://aahframework.org.followRedirects true
- go get -t -v ./...

script:
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2016-2017 Jeevanandam M., https://myjeeva.com <jeeva@myjeeva.com>
Copyright (c) 2016-2018 Jeevanandam M., https://myjeeva.com <jeeva@myjeeva.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
22 changes: 12 additions & 10 deletions README.md
@@ -1,19 +1,21 @@
# config - aah framework
<p align="center">
<img src="https://cdn.aahframework.org/assets/img/aah-logo-64x64.png" />
<h2 align="center">Config Library by aah framework</h2>
</p>
<p align="center">
<p align="center"><a href="https://travis-ci.org/go-aah/config"><img src="https://travis-ci.org/go-aah/config.svg?branch=master" alt="Build Status"></a> <a href="https://codecov.io/gh/go-aah/config/branch/master"><img src="https://codecov.io/gh/go-aah/config/branch/master/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/aahframework.org/config.v0"><img src="https://goreportcard.com/badge/aahframework.org/config.v0" alt="Go Report Card"></a> <a href="https://github.com/go-aah/config/releases/latest"><img src="https://img.shields.io/badge/version-0.5.0-blue.svg" alt="Release Version"></a> <a href="https://godoc.org/aahframework.org/config.v0"><img src="https://godoc.org/aahframework.org/config.v0?status.svg" alt="Godoc"></a> <a href="https://twitter.com/aahframework"><img src="https://img.shields.io/badge/twitter-@aahframework-55acee.svg" alt="Twitter @aahframework"></a></p>
</p>

[![Build Status](https://travis-ci.org/go-aah/config.svg?branch=master)](https://travis-ci.org/go-aah/config) [![codecov](https://codecov.io/gh/go-aah/config/branch/master/graph/badge.svg)](https://codecov.io/gh/go-aah/config/branch/master) [![Go Report Card](https://goreportcard.com/badge/aahframework.org/config.v0)](https://goreportcard.com/report/aahframework.org/config.v0)
[![Version](https://img.shields.io/badge/version-0.4.2-blue.svg)](https://github.com/go-aah/config/releases/latest) [![GoDoc](https://godoc.org/aahframework.org/config.v0?status.svg)](https://godoc.org/aahframework.org/config.v0) [![License](https://img.shields.io/github/license/go-aah/config.svg)](LICENSE) [![Twitter](https://img.shields.io/badge/twitter-@aahframework-55acee.svg)](https://twitter.com/aahframework)
`config` library is powerful and flexible to configuration file/structure. It internally uses `forge` library developed by [@brettlangdon](htpps://github.com/brettlangdon) and adds further functionality to it. Syntax is very similar to Typesafe HOCON :satisfied:. Config library is used across the aah framework.

***v0.4.2 [released](https://github.com/go-aah/config/releases/latest) and tagged on Jul 30, 2017***
### News

`config` library is powerful and flexible for configuration purpose. It's thin layer around `forge` config syntax which is very similar to Typesafe HOCON syntax :satisfied:. aah framework and it's modules is powered with `aah/config` library.
* `v0.5.0` [released](https://github.com/go-aah/config/releases/latest) and tagged on Jun 20, 2018.

*`config` developed for aah framework. However it's an independent library, can be used separately with any `Go` language project. Feel free to use it.*
## Installation

# Installation
#### Stable Version - Production Ready
```bash
# install the library
go get -u aahframework.org/config.v0
```

Visit official website https://aahframework.org to learn more.
Visit official website https://aahframework.org to learn more about `aah` framework.
101 changes: 59 additions & 42 deletions config.go
@@ -1,5 +1,5 @@
// Copyright (c) Jeevanandam M. (https://github.com/jeevatkm)
// go-aah/config source code and usage is governed by a MIT style
// aahframework.org/config source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

// Package config is nice and handy layer built around `forge` config syntax;
Expand All @@ -14,15 +14,26 @@ import (
"fmt"
"strings"

"aahframework.org/essentials.v0"
"aahframework.org/forge.v0"
"aahframework.org/vfs.v0"
)

// Version no. of aahframework.org/config library
var Version = "0.4.2"

var errKeyNotFound = errors.New("config: not found")

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Package methods
//______________________________________________________________________________

// NewEmpty method returns aah empty config instance.
func NewEmpty() *Config {
cfg, _ := ParseString("")
return cfg
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Config type and methods
//______________________________________________________________________________

// Config handles the configuration values and enables environment profile's,
// merge, etc. Also it provide nice and handly methods for accessing config values.
// Internally `aah config` uses `forge syntax` developed by `https://github.com/brettlangdon`.
Expand Down Expand Up @@ -60,6 +71,9 @@ func (c *Config) HasProfile(profile string) bool {

// IsProfileEnabled returns true of profile enabled otherwise false
func (c *Config) IsProfileEnabled() bool {
if c == nil {
return false
}
return len(c.profile) > 0
}

Expand Down Expand Up @@ -203,9 +217,9 @@ func (c *Config) Get(key string) (interface{}, bool) {
return c.get(key)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// List methods
//___________________________________
//______________________________________________________________________________

// StringList method returns the string slice value for the given key.
// Eaxmple:-
Expand Down Expand Up @@ -300,9 +314,9 @@ func (c *Config) Int64List(key string) ([]int64, bool) {
return values, true
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Setter methods
//___________________________________
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Config Setter methods
//______________________________________________________________________________

// SetString sets the given value string for config key
// First it tries to get value within enabled profile
Expand Down Expand Up @@ -377,36 +391,33 @@ func (c *Config) ToJSON() string {
return "{}"
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Configuration loading methods
//___________________________________
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Config load/parse methods
//______________________________________________________________________________

// LoadFile loads the configuration given config file
// LoadFile loads the configuration from given config file.
func LoadFile(file string) (*Config, error) {
if !ess.IsFileExists(file) {
return nil, fmt.Errorf("configuration does not exists: %v", file)
}

setting, err := forge.ParseFile(file)
if err != nil {
return nil, err
}
return VFSLoadFile(nil, file)
}

return &Config{
cfg: setting,
}, nil
// VFSLoadFile loads the configuration from given vfs and config file.
func VFSLoadFile(fs *vfs.VFS, file string) (*Config, error) {
setting, err := loadFile(fs, file)
return &Config{cfg: setting}, err
}

// LoadFiles loads the configuration given config files and
// does merging of configuration in the order they are given
// LoadFiles loads the configuration from given config files.
// It does merging of configuration in the order they are given.
func LoadFiles(files ...string) (*Config, error) {
return VFSLoadFiles(nil, files...)
}

// VFSLoadFiles loads the configuration from given config vfs and files.
// It does merging of configuration in the order they are given.
func VFSLoadFiles(fs *vfs.VFS, files ...string) (*Config, error) {
settings := forge.NewSection()
for _, file := range files {
if !ess.IsFileExists(file) {
return nil, fmt.Errorf("configuration does not exists: %v", file)
}

setting, err := forge.ParseFile(file)
setting, err := loadFile(fs, file)
if err != nil {
return nil, err
}
Expand All @@ -416,9 +427,7 @@ func LoadFiles(files ...string) (*Config, error) {
}
}

return &Config{
cfg: settings,
}, nil
return &Config{cfg: settings}, nil
}

// ParseString parses the configuration values from string
Expand All @@ -427,15 +436,19 @@ func ParseString(cfg string) (*Config, error) {
if err != nil {
return nil, err
}

return &Config{
cfg: setting,
}, nil
return &Config{cfg: setting}, nil
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Unexported methods
//___________________________________
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Config unexported methods
//______________________________________________________________________________

func loadFile(fs *vfs.VFS, file string) (*forge.Section, error) {
if _, err := vfs.Stat(fs, file); err != nil {
return nil, fmt.Errorf("configuration does not exists: %v", file)
}
return forge.VFSParseFile(fs, file)
}

func (c *Config) prepareKey(key string) string {
if c.IsProfileEnabled() {
Expand Down Expand Up @@ -472,6 +485,10 @@ func (c *Config) getListValue(key string) (*forge.List, bool) {
}

func (c *Config) getraw(key string) (forge.Value, bool) {
if c == nil || c.cfg == nil {
return nil, false
}

v, err := c.cfg.Resolve(key)
if err != nil {
return nil, false // not found
Expand Down
39 changes: 23 additions & 16 deletions config_test.go
Expand Up @@ -16,7 +16,7 @@ import (
)

func TestKeysAndKeysByPath(t *testing.T) {
cfg := initFile(t, join(getTestdataPath(), "test.cfg"))
cfg := initFile(t, join(testdataBaseDir(), "test.cfg"))
keys := cfg.Keys()
assert.True(t, ess.IsSliceContainsString(keys, "prod"))
assert.True(t, ess.IsSliceContainsString(keys, "dev"))
Expand All @@ -37,7 +37,7 @@ func TestKeysAndKeysByPath(t *testing.T) {
}

func TestGetSubConfig(t *testing.T) {
cfg := initFile(t, join(getTestdataPath(), "test.cfg"))
cfg := initFile(t, join(testdataBaseDir(), "test.cfg"))

prod, found1 := cfg.GetSubConfig("prod")
assert.NotNil(t, prod)
Expand All @@ -64,7 +64,7 @@ func TestGetSubConfig(t *testing.T) {
}

func TestIsExists(t *testing.T) {
cfg := initFile(t, join(getTestdataPath(), "test.cfg"))
cfg := initFile(t, join(testdataBaseDir(), "test.cfg"))
found := cfg.IsExists("prod.string")
assert.True(t, found)

Expand All @@ -77,7 +77,7 @@ func TestIsExists(t *testing.T) {
}

func TestStringValues(t *testing.T) {
cfg := initFile(t, join(getTestdataPath(), "test.cfg"))
cfg := initFile(t, join(testdataBaseDir(), "test.cfg"))

v1, _ := cfg.String("string")
assert.Equal(t, "a string", v1)
Expand All @@ -100,7 +100,7 @@ func TestStringValues(t *testing.T) {
}

func TestIntValues(t *testing.T) {
bytes, _ := ioutil.ReadFile(join(getTestdataPath(), "test.cfg"))
bytes, _ := ioutil.ReadFile(join(testdataBaseDir(), "test.cfg"))
cfg := initString(t, string(bytes))

v1, _ := cfg.Int("int")
Expand Down Expand Up @@ -136,7 +136,7 @@ func TestIntValues(t *testing.T) {
}

func TestFloatValues(t *testing.T) {
cfg := initFile(t, join(getTestdataPath(), "test.cfg"))
cfg := initFile(t, join(testdataBaseDir(), "test.cfg"))

v1, _ := cfg.Float32("float32")
assert.Equal(t, float32(32.2), v1)
Expand Down Expand Up @@ -180,7 +180,7 @@ func TestFloatValues(t *testing.T) {
}

func TestBoolValues(t *testing.T) {
bytes, _ := ioutil.ReadFile(join(getTestdataPath(), "test.cfg"))
bytes, _ := ioutil.ReadFile(join(testdataBaseDir(), "test.cfg"))
cfg := initString(t, string(bytes))

v1, _ := cfg.Bool("truevalue")
Expand Down Expand Up @@ -215,6 +215,12 @@ func TestStringList(t *testing.T) {
build {
# Valid exclude patterns refer: https://golang.org/pkg/path/filepath/#Match
excludes = ["*_test.go", ".*", "*.bak", "*.tmp", "vendor"]
keys = [
"X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg=",
"MHJYVThihUrJcxW6wcqyOISTXIsInsdj3xK8QrZbHec=",
"GGekerhihUrJcxW6wcqyOISTXIsInsdj3xK8QrZbHec=",
]
}`)

lst1, found1 := cfg.StringList("build.excludes")
Expand All @@ -225,6 +231,10 @@ build {
lst2, found2 := cfg.StringList("name")
assert.False(t, found2)
assert.True(t, len(lst2) == 0)

v, f := cfg.StringList("build.keys")
assert.True(t, f)
assert.True(t, len(v) == 3)
}

func TestIntAndInt64List(t *testing.T) {
Expand Down Expand Up @@ -253,7 +263,7 @@ func TestIntAndInt64List(t *testing.T) {
}

func TestProfile(t *testing.T) {
cfg := initFile(t, join(getTestdataPath(), "test.cfg"))
cfg := initFile(t, join(testdataBaseDir(), "test.cfg"))

t.Log(cfg.cfg.Keys())

Expand All @@ -266,9 +276,7 @@ func TestProfile(t *testing.T) {
}

func TestConfigLoadNotExists(t *testing.T) {
testdataPath := getTestdataPath()

_, err := LoadFile(join(testdataPath, "not_exists.cfg"))
_, err := LoadFile(join(testdataBaseDir(), "not_exists.cfg"))
assert.True(t, strings.HasPrefix(err.Error(), "configuration does not exists:"))

_, err = ParseString(`
Expand Down Expand Up @@ -326,7 +334,7 @@ prod {
}

func TestLoadFiles(t *testing.T) {
testdataPath := getTestdataPath()
testdataPath := testdataBaseDir()

cfg, err := LoadFiles(
join(testdataPath, "test-1.cfg"),
Expand Down Expand Up @@ -361,7 +369,7 @@ func TestLoadFiles(t *testing.T) {
}

func TestNestedKeyWithProfile(t *testing.T) {
testdataPath := getTestdataPath()
testdataPath := testdataBaseDir()

cfg, err := LoadFiles(join(testdataPath, "test-4.cfg"))
assert.FailNowOnError(t, err, "loading failed")
Expand Down Expand Up @@ -389,7 +397,7 @@ func TestNestedKeyWithProfile(t *testing.T) {
}

func TestConfigSetValues(t *testing.T) {
testdataPath := getTestdataPath()
testdataPath := testdataBaseDir()
cfg, err := LoadFiles(join(testdataPath, "test-4.cfg"))
assert.FailNowOnError(t, err, "loading failed")

Expand Down Expand Up @@ -419,7 +427,6 @@ func initString(t *testing.T, configStr string) *Config {
func initFile(t *testing.T, file string) *Config {
cfg, err := LoadFile(file)
assert.FailNowOnError(t, err, "")

return cfg
}

Expand All @@ -428,7 +435,7 @@ func setProfileForTest(t *testing.T, cfg *Config, profile string) {
assert.FailNowOnError(t, err, "")
}

func getTestdataPath() string {
func testdataBaseDir() string {
wd, _ := os.Getwd()
return filepath.Join(wd, "testdata")
}
Expand Down

0 comments on commit 4a83ecc

Please sign in to comment.