├── .gitignore ├── History.md ├── LICENSE ├── Readme.md ├── config.go ├── config_test.go ├── go.mod └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | .envrc 2 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | v1.4.0 / 2020-04-30 3 | =================== 4 | 5 | * add indentation 6 | 7 | v1.3.0 / 2019-11-08 8 | =================== 9 | 10 | * refactor Load() to return nil if the file does not exist 11 | 12 | v1.2.0 / 2019-09-27 13 | =================== 14 | 15 | * add directory creation to Save() 16 | 17 | v1.1.0 / 2019-09-27 18 | =================== 19 | 20 | * add LoadHome() and SaveHome() functions 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2019 TJ Holowaychuk tj@tjholowaychuk.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Config 2 | 3 | Utility for loading JSON configuration for command-line tools, nothing interesting, but copy/pasting is lame. 4 | 5 | --- 6 | 7 | [![GoDoc](https://godoc.org/github.com/tj/go-config?status.svg)](https://godoc.org/github.com/tj/go-config) 8 | ![](https://img.shields.io/badge/license-MIT-blue.svg) 9 | ![](https://img.shields.io/badge/status-stable-green.svg) 10 | 11 | 12 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | // Package config provides super simple JSON configuration for command-line programs. 2 | package config 3 | 4 | import ( 5 | "encoding/json" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | ) 10 | 11 | // Load configuration from path, into the struct pointer provided. No error is returned 12 | // if the file does not exist. 13 | func Load(path string, v interface{}) error { 14 | b, err := ioutil.ReadFile(path) 15 | 16 | if os.IsNotExist(err) { 17 | return nil 18 | } 19 | 20 | if err != nil { 21 | return err 22 | } 23 | 24 | return json.Unmarshal(b, v) 25 | } 26 | 27 | // Save saves configuration to path. If the directory does not exist, it is created. 28 | func Save(path string, v interface{}) error { 29 | err := os.MkdirAll(filepath.Dir(path), 0755) 30 | if err != nil { 31 | return err 32 | } 33 | 34 | b, err := json.MarshalIndent(v, "", " ") 35 | if err != nil { 36 | return err 37 | } 38 | 39 | return ioutil.WriteFile(path, b, 0600) 40 | } 41 | 42 | // LoadHome loads configuration from path relative to the user home directory. 43 | func LoadHome(path string, v interface{}) error { 44 | home, err := os.UserHomeDir() 45 | if err != nil { 46 | return err 47 | } 48 | 49 | return Load(filepath.Join(home, path), v) 50 | } 51 | 52 | // SaveHome saves configuration to path relative to the user home directory. 53 | func SaveHome(path string, v interface{}) error { 54 | home, err := os.UserHomeDir() 55 | if err != nil { 56 | return err 57 | } 58 | 59 | return Save(filepath.Join(home, path), v) 60 | } 61 | -------------------------------------------------------------------------------- /config_test.go: -------------------------------------------------------------------------------- 1 | package config_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/tj/assert" 7 | 8 | "github.com/tj/go-config" 9 | ) 10 | 11 | // Config struct. 12 | type Config struct { 13 | Name string `json:"name"` 14 | Email string `json:"email"` 15 | } 16 | 17 | // Test saving. 18 | func TestSave(t *testing.T) { 19 | err := config.Save("/tmp/whatever/some.json", Config{ 20 | Name: "tj", 21 | Email: "tj@apex.sh", 22 | }) 23 | assert.NoError(t, err) 24 | } 25 | 26 | // Test loading valid config. 27 | func TestLoad_valid(t *testing.T) { 28 | var c Config 29 | err := config.Load("/tmp/whatever/some.json", &c) 30 | assert.NoError(t, err) 31 | assert.Equal(t, "tj", c.Name) 32 | } 33 | 34 | // Test loading missing config. 35 | func TestLoad_missing(t *testing.T) { 36 | var c Config 37 | err := config.Load("/tmp/nope.json", &c) 38 | assert.NoError(t, err) 39 | } 40 | 41 | // Test saving in home. 42 | func TestSaveHome(t *testing.T) { 43 | err := config.SaveHome("some.json", Config{ 44 | Name: "tj", 45 | Email: "tj@apex.sh", 46 | }) 47 | assert.NoError(t, err) 48 | } 49 | 50 | // Test loading valid config in home. 51 | func TestLoadHome_valid(t *testing.T) { 52 | var c Config 53 | err := config.LoadHome("some.json", &c) 54 | assert.NoError(t, err) 55 | assert.Equal(t, "tj", c.Name) 56 | } 57 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tj/go-config 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/stretchr/testify v1.4.0 // indirect 7 | github.com/tj/assert v0.0.0-20171129193455-018094318fb0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 6 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 7 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 8 | github.com/tj/assert v0.0.0-20171129193455-018094318fb0 h1:Rw8kxzWo1mr6FSaYXjQELRe88y2KdfynXdnK72rdjtA= 9 | github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 12 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 13 | --------------------------------------------------------------------------------