common: remove config.go
The code in config.go is unused. The main reason for removing it is to get rid github.com/rakyll/goini in Godeps (it has no license).
This commit is contained in:
		
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,2 +0,0 @@ | ||||
| language: go | ||||
| go: 1.2 | ||||
							
								
								
									
										144
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										144
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,144 +0,0 @@ | ||||
| # globalconf | ||||
|  | ||||
| [](https://travis-ci.org/rakyll/globalconf) | ||||
|  | ||||
| Effortlessly persist/retrieve flags of your Golang programs. If you need global configuration instead of requiring user always to set command line flags, you are looking at the right package. `globalconf` allows your users to not only provide flags, but config files and environment variables as well. | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| ~~~ go | ||||
| import "github.com/rakyll/globalconf" | ||||
| ~~~ | ||||
|  | ||||
| ### Loading a config file | ||||
|  | ||||
| By default, globalconf provides you a config file under `~/.config/<yourappname>/config.ini`. | ||||
|  | ||||
| ~~~ go | ||||
| globalconf.New("appname") // loads from ~/.config/<appname>/config.ini | ||||
| ~~~ | ||||
|  | ||||
| If you don't prefer the default location you can load from a specified path as well. | ||||
|  | ||||
| ~~~ go | ||||
| globalconf.NewWithOptions(&globalconf.Options{ | ||||
| 	Filename: "/path/to/config/file", | ||||
| }) | ||||
| ~~~ | ||||
|  | ||||
| You may like to override configuration with env variables. See "Environment variables" header to see how to it works. | ||||
|  | ||||
| ~~~ go | ||||
| globalconf.NewWithOptions(&globalconf.Options{ | ||||
| 	Filename:  "/path/to/config/file", | ||||
| 	EnvPrefix: "APPCONF_", | ||||
| }) | ||||
| ~~~ | ||||
|  | ||||
| ### Parsing flag values | ||||
|  | ||||
| `globalconf` populates flags with data in the config file if they are not already set. | ||||
|  | ||||
| ~~~ go | ||||
| var ( | ||||
| 	flagName    = flag.String("name", "", "Name of the person.") | ||||
| 	flagAddress = flag.String("addr", "", "Address of the person.") | ||||
| ) | ||||
| ~~~ | ||||
| 	 | ||||
| Assume the configuration file to be loaded contains the following lines. | ||||
|  | ||||
| 	name = Burcu | ||||
| 	addr = Brandschenkestrasse 110, 8002 | ||||
|  | ||||
| And your program is being started, `$ myapp -name=Jane` | ||||
| ~~~ go | ||||
| conf, err := globalconf.New("myapp") | ||||
| conf.ParseAll() | ||||
| ~~~ | ||||
|  | ||||
| `*flagName` is going to be equal to `Jane`, whereas `*flagAddress` is `Brandschenkestrasse 110, 8002`, what is provided in the configuration file. | ||||
|  | ||||
| ### Custom flag sets | ||||
|  | ||||
| Custom flagsets are supported, but required registration before parse is done. The default flagset `flag.CommandLine` is automatically registered. | ||||
|  | ||||
| ~~~ go | ||||
| globalconf.Register("termopts", termOptsFlagSet) | ||||
| conf.ParseAll() // parses command line and all registered flag sets | ||||
| ~~~ | ||||
|  | ||||
| Custom flagset values should be provided in their own segment. Getting back to the sample ini config file, termopts values will have their own segment. | ||||
|  | ||||
| 	name = Burcu | ||||
| 	addr = Brandschenkestrasse 110, 8002 | ||||
| 	 | ||||
| 	[termopts] | ||||
| 	color = true | ||||
| 	background = ff0000 | ||||
|  | ||||
| ### Environment variables | ||||
|  | ||||
| If an EnvPrefix is provided, environment variables will take precedence over values in the configuration file. | ||||
| Set the `EnvPrefix` option when calling `globalconf.NewWithOptions`. | ||||
| An `EnvPrefix` will only be used if it is a non-empty string. | ||||
| Command line flags will override the environment variables. | ||||
|  | ||||
| ~~~ go | ||||
| opts := globalconf.Options{ | ||||
| 	EnvPrefix: "MYAPP_", | ||||
| 	Filename:  "/path/to/config", | ||||
| } | ||||
| conf, err := globalconf.NewWithOptions(&opts) | ||||
| conf.ParseAll() | ||||
| ~~~ | ||||
|  | ||||
| With environment variables: | ||||
|  | ||||
| 	APPCONF_NAME = Burcu | ||||
|  | ||||
| and configuration: | ||||
|  | ||||
| 	name = Jane | ||||
| 	addr = Brandschenkestrasse 110, 8002 | ||||
|  | ||||
| `name` will be set to "burcu" and `addr` will be set to "Brandschenkestrasse 110, 8002". | ||||
|  | ||||
| ### Modifying stored flags | ||||
|  | ||||
| Modifications are persisted as long as you set a new flag and your GlobalConf | ||||
| object was configured with a filename. | ||||
|  | ||||
| ~~~ go | ||||
| f := &flag.Flag{Name: "name", Value: val} | ||||
| conf.Set("", f) // if you are modifying a command line flag | ||||
|  | ||||
| f := &flag.Flag{Name: "color", Value: val} | ||||
| conf.Set("termopts", color) // if you are modifying a custom flag set flag | ||||
| ~~~ | ||||
|  | ||||
| ### Deleting stored flags | ||||
|  | ||||
| Like Set, Deletions are persisted as long as you delete a flag's value and your | ||||
| GlobalConf object was configured with a filename. | ||||
|  | ||||
| ~~~ go | ||||
| conf.Delete("", "name") // removes command line flag "name"s value from config | ||||
| conf.Delete("termopts", "color") // removes "color"s value from the custom flag set | ||||
| ~~~ | ||||
|  | ||||
| ## License | ||||
|  | ||||
| Copyright 2014 Google Inc. All Rights Reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License.  | ||||
							
								
								
									
										179
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/globalconf.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										179
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/globalconf.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,179 +0,0 @@ | ||||
| package globalconf | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"os/user" | ||||
| 	"path" | ||||
| 	"strings" | ||||
|  | ||||
| 	ini "github.com/rakyll/goini" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	defaultConfigFileName = "config.ini" | ||||
| ) | ||||
|  | ||||
| var flags map[string]*flag.FlagSet = make(map[string]*flag.FlagSet) | ||||
|  | ||||
| // Represents a GlobalConf context. | ||||
| type GlobalConf struct { | ||||
| 	Filename  string | ||||
| 	EnvPrefix string | ||||
| 	dict      *ini.Dict | ||||
| } | ||||
|  | ||||
| type Options struct { | ||||
| 	Filename  string | ||||
| 	EnvPrefix string | ||||
| } | ||||
|  | ||||
| // NewWithOptions creates a GlobalConf from the provided | ||||
| // Options. The caller is responsible for creating any | ||||
| // referenced config files. | ||||
| func NewWithOptions(opts *Options) (g *GlobalConf, err error) { | ||||
| 	Register("", flag.CommandLine) | ||||
|  | ||||
| 	var dict ini.Dict | ||||
| 	if opts.Filename != "" { | ||||
| 		dict, err = ini.Load(opts.Filename) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} else { | ||||
| 		dict = make(ini.Dict, 0) | ||||
| 	} | ||||
|  | ||||
| 	return &GlobalConf{ | ||||
| 		Filename:  opts.Filename, | ||||
| 		EnvPrefix: opts.EnvPrefix, | ||||
| 		dict:      &dict, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // Opens/creates a config file for the specified appName. | ||||
| // The path to config file is ~/.config/appName/config.ini. | ||||
| func New(appName string) (g *GlobalConf, err error) { | ||||
| 	var u *user.User | ||||
| 	if u, err = user.Current(); u == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	// Create config file's directory. | ||||
| 	dirPath := path.Join(u.HomeDir, ".config", appName) | ||||
| 	if err = os.MkdirAll(dirPath, 0755); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	// Touch a config file if it doesn't exit. | ||||
| 	filePath := path.Join(dirPath, defaultConfigFileName) | ||||
| 	if _, err = os.Stat(filePath); err != nil { | ||||
| 		if !os.IsNotExist(err) { | ||||
| 			return | ||||
| 		} | ||||
| 		// create file | ||||
| 		if err = ioutil.WriteFile(filePath, []byte{}, 0644); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	opts := Options{Filename: filePath} | ||||
| 	return NewWithOptions(&opts) | ||||
| } | ||||
|  | ||||
| // Sets a flag's value and persists the changes to the disk. | ||||
| func (g *GlobalConf) Set(flagSetName string, f *flag.Flag) error { | ||||
| 	g.dict.SetString(flagSetName, f.Name, f.Value.String()) | ||||
| 	if g.Filename != "" { | ||||
| 		return ini.Write(g.Filename, g.dict) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Deletes a flag from config file and persists the changes | ||||
| // to the disk. | ||||
| func (g *GlobalConf) Delete(flagSetName, flagName string) error { | ||||
| 	g.dict.Delete(flagSetName, flagName) | ||||
| 	if g.Filename != "" { | ||||
| 		return ini.Write(g.Filename, g.dict) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Parses the config file for the provided flag set. | ||||
| // If the flags are already set, values are overwritten | ||||
| // by the values in the config file. Defaults are not set | ||||
| // if the flag is not in the file. | ||||
| func (g *GlobalConf) ParseSet(flagSetName string, set *flag.FlagSet) { | ||||
| 	set.VisitAll(func(f *flag.Flag) { | ||||
| 		val := getEnv(g.EnvPrefix, flagSetName, f.Name) | ||||
| 		if val != "" { | ||||
| 			set.Set(f.Name, val) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		val, found := g.dict.GetString(flagSetName, f.Name) | ||||
| 		if found { | ||||
| 			set.Set(f.Name, val) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Parses all the registered flag sets, including the command | ||||
| // line set and sets values from the config file if they are | ||||
| // not already set. | ||||
| func (g *GlobalConf) Parse() { | ||||
| 	for name, set := range flags { | ||||
| 		alreadySet := make(map[string]bool) | ||||
| 		set.Visit(func(f *flag.Flag) { | ||||
| 			alreadySet[f.Name] = true | ||||
| 		}) | ||||
| 		set.VisitAll(func(f *flag.Flag) { | ||||
| 			// if not already set, set it from dict if exists | ||||
| 			if alreadySet[f.Name] { | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			val := getEnv(g.EnvPrefix, name, f.Name) | ||||
| 			if val != "" { | ||||
| 				set.Set(f.Name, val) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			val, found := g.dict.GetString(name, f.Name) | ||||
| 			if found { | ||||
| 				set.Set(f.Name, val) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Parses command line flags and then, all of the registered | ||||
| // flag sets with the values provided in the config file. | ||||
| func (g *GlobalConf) ParseAll() { | ||||
| 	if !flag.Parsed() { | ||||
| 		flag.Parse() | ||||
| 	} | ||||
| 	g.Parse() | ||||
| } | ||||
|  | ||||
| // Looks up variable in environment | ||||
| func getEnv(envPrefix, flagSetName, flagName string) string { | ||||
| 	// If we haven't set an EnvPrefix, don't lookup vals in the ENV | ||||
| 	if envPrefix == "" { | ||||
| 		return "" | ||||
| 	} | ||||
| 	// Append a _ to flagSetName if it exists. | ||||
| 	if flagSetName != "" { | ||||
| 		flagSetName += "_" | ||||
| 	} | ||||
| 	flagName = strings.Replace(flagName, ".", "_", -1) | ||||
| 	flagName = strings.Replace(flagName, "-", "_", -1) | ||||
| 	envKey := strings.ToUpper(envPrefix + flagSetName + flagName) | ||||
| 	return os.Getenv(envKey) | ||||
| } | ||||
|  | ||||
| // Registers a flag set to be parsed. Register all flag sets | ||||
| // before calling this function. flag.CommandLine is automatically | ||||
| // registered. | ||||
| func Register(flagSetName string, set *flag.FlagSet) { | ||||
| 	flags[flagSetName] = set | ||||
| } | ||||
							
								
								
									
										267
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/globalconf_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										267
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/globalconf_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,267 +0,0 @@ | ||||
| package globalconf | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| const envTestPrefix = "CONFTEST_" | ||||
|  | ||||
| func TestNewWithOptionsNoFilename(t *testing.T) { | ||||
| 	opts := Options{EnvPrefix: envTestPrefix} | ||||
|  | ||||
| 	os.Setenv(envTestPrefix+"D", "EnvD") | ||||
|  | ||||
| 	flagD := flag.String("d", "default", "") | ||||
| 	flagE := flag.Bool("e", true, "") | ||||
|  | ||||
| 	conf, err := NewWithOptions(&opts) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	conf.ParseAll() | ||||
|  | ||||
| 	if *flagD != "EnvD" { | ||||
| 		t.Errorf("flagD found %v, expected 'EnvD'", *flagD) | ||||
| 	} | ||||
| 	if !*flagE { | ||||
| 		t.Errorf("flagE found %v, expected true", *flagE) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParse_Global(t *testing.T) { | ||||
| 	resetForTesting("") | ||||
|  | ||||
| 	os.Setenv(envTestPrefix+"D", "EnvD") | ||||
| 	os.Setenv(envTestPrefix+"E", "true") | ||||
| 	os.Setenv(envTestPrefix+"F", "5.5") | ||||
|  | ||||
| 	flagA := flag.Bool("a", false, "") | ||||
| 	flagB := flag.Float64("b", 0.0, "") | ||||
| 	flagC := flag.String("c", "", "") | ||||
|  | ||||
| 	flagD := flag.String("d", "", "") | ||||
| 	flagE := flag.Bool("e", false, "") | ||||
| 	flagF := flag.Float64("f", 0.0, "") | ||||
|  | ||||
| 	parse(t, "./testdata/global.ini", envTestPrefix) | ||||
| 	if !*flagA { | ||||
| 		t.Errorf("flagA found %v, expected true", *flagA) | ||||
| 	} | ||||
| 	if *flagB != 5.6 { | ||||
| 		t.Errorf("flagB found %v, expected 5.6", *flagB) | ||||
| 	} | ||||
| 	if *flagC != "Hello world" { | ||||
| 		t.Errorf("flagC found %v, expected 'Hello world'", *flagC) | ||||
| 	} | ||||
| 	if *flagD != "EnvD" { | ||||
| 		t.Errorf("flagD found %v, expected 'EnvD'", *flagD) | ||||
| 	} | ||||
| 	if !*flagE { | ||||
| 		t.Errorf("flagE found %v, expected true", *flagE) | ||||
| 	} | ||||
| 	if *flagF != 5.5 { | ||||
| 		t.Errorf("flagF found %v, expected 5.5", *flagF) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParse_DashConversion(t *testing.T) { | ||||
| 	resetForTesting("") | ||||
|  | ||||
| 	flagFooBar := flag.String("foo-bar", "", "") | ||||
| 	os.Setenv("PREFIX_FOO_BAR", "baz") | ||||
|  | ||||
| 	opts := Options{EnvPrefix: "PREFIX_"} | ||||
| 	conf, err := NewWithOptions(&opts) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	conf.ParseAll() | ||||
|  | ||||
| 	if *flagFooBar != "baz" { | ||||
| 		t.Errorf("flagFooBar found %v, expected 5.5", *flagFooBar) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParse_GlobalWithDottedFlagname(t *testing.T) { | ||||
| 	resetForTesting("") | ||||
| 	os.Setenv(envTestPrefix+"SOME_VALUE", "some-value") | ||||
| 	flagSomeValue := flag.String("some.value", "", "") | ||||
|  | ||||
| 	parse(t, "./testdata/global.ini", envTestPrefix) | ||||
| 	if *flagSomeValue != "some-value" { | ||||
| 		t.Errorf("flagSomeValue found %v, some-value expected", *flagSomeValue) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParse_GlobalOverwrite(t *testing.T) { | ||||
| 	resetForTesting("-b=7.6") | ||||
| 	flagB := flag.Float64("b", 0.0, "") | ||||
|  | ||||
| 	parse(t, "./testdata/global.ini", "") | ||||
| 	if *flagB != 7.6 { | ||||
| 		t.Errorf("flagB found %v, expected 7.6", *flagB) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParse_Custom(t *testing.T) { | ||||
| 	resetForTesting("") | ||||
|  | ||||
| 	os.Setenv(envTestPrefix+"CUSTOM_E", "Hello Env") | ||||
|  | ||||
| 	flagB := flag.Float64("b", 5.0, "") | ||||
|  | ||||
| 	name := "custom" | ||||
| 	custom := flag.NewFlagSet(name, flag.ExitOnError) | ||||
| 	flagD := custom.String("d", "dd", "") | ||||
| 	flagE := custom.String("e", "ee", "") | ||||
|  | ||||
| 	Register(name, custom) | ||||
| 	parse(t, "./testdata/custom.ini", envTestPrefix) | ||||
| 	if *flagB != 5.0 { | ||||
| 		t.Errorf("flagB found %v, expected 5.0", *flagB) | ||||
| 	} | ||||
| 	if *flagD != "Hello d" { | ||||
| 		t.Errorf("flagD found %v, expected 'Hello d'", *flagD) | ||||
| 	} | ||||
| 	if *flagE != "Hello Env" { | ||||
| 		t.Errorf("flagE found %v, expected 'Hello Env'", *flagE) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParse_CustomOverwrite(t *testing.T) { | ||||
| 	resetForTesting("-b=6") | ||||
| 	flagB := flag.Float64("b", 5.0, "") | ||||
|  | ||||
| 	name := "custom" | ||||
| 	custom := flag.NewFlagSet(name, flag.ExitOnError) | ||||
| 	flagD := custom.String("d", "dd", "") | ||||
|  | ||||
| 	Register(name, custom) | ||||
| 	parse(t, "./testdata/custom.ini", "") | ||||
| 	if *flagB != 6.0 { | ||||
| 		t.Errorf("flagB found %v, expected 6.0", *flagB) | ||||
| 	} | ||||
| 	if *flagD != "Hello d" { | ||||
| 		t.Errorf("flagD found %v, expected 'Hello d'", *flagD) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParse_GlobalAndCustom(t *testing.T) { | ||||
| 	resetForTesting("") | ||||
| 	flagA := flag.Bool("a", false, "") | ||||
| 	flagB := flag.Float64("b", 0.0, "") | ||||
| 	flagC := flag.String("c", "", "") | ||||
|  | ||||
| 	name := "custom" | ||||
| 	custom := flag.NewFlagSet(name, flag.ExitOnError) | ||||
| 	flagD := custom.String("d", "", "") | ||||
|  | ||||
| 	Register(name, custom) | ||||
| 	parse(t, "./testdata/globalandcustom.ini", "") | ||||
| 	if !*flagA { | ||||
| 		t.Errorf("flagA found %v, expected true", *flagA) | ||||
| 	} | ||||
| 	if *flagB != 5.6 { | ||||
| 		t.Errorf("flagB found %v, expected 5.6", *flagB) | ||||
| 	} | ||||
| 	if *flagC != "Hello world" { | ||||
| 		t.Errorf("flagC found %v, expected 'Hello world'", *flagC) | ||||
| 	} | ||||
| 	if *flagD != "Hello d" { | ||||
| 		t.Errorf("flagD found %v, expected 'Hello d'", *flagD) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParse_GlobalAndCustomOverwrite(t *testing.T) { | ||||
| 	resetForTesting("-a=true", "-b=5", "-c=Hello") | ||||
| 	flagA := flag.Bool("a", false, "") | ||||
| 	flagB := flag.Float64("b", 0.0, "") | ||||
| 	flagC := flag.String("c", "", "") | ||||
|  | ||||
| 	name := "custom" | ||||
| 	custom := flag.NewFlagSet(name, flag.ExitOnError) | ||||
| 	flagD := custom.String("d", "", "") | ||||
|  | ||||
| 	Register(name, custom) | ||||
| 	parse(t, "./testdata/globalandcustom.ini", "") | ||||
| 	if !*flagA { | ||||
| 		t.Errorf("flagA found %v, expected true", *flagA) | ||||
| 	} | ||||
| 	if *flagB != 5.0 { | ||||
| 		t.Errorf("flagB found %v, expected 5.0", *flagB) | ||||
| 	} | ||||
| 	if *flagC != "Hello" { | ||||
| 		t.Errorf("flagC found %v, expected 'Hello'", *flagC) | ||||
| 	} | ||||
| 	if *flagD != "Hello d" { | ||||
| 		t.Errorf("flagD found %v, expected 'Hello d'", *flagD) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSet(t *testing.T) { | ||||
| 	resetForTesting() | ||||
| 	file, _ := ioutil.TempFile("", "") | ||||
| 	conf := parse(t, file.Name(), "") | ||||
| 	conf.Set("", &flag.Flag{Name: "a", Value: newFlagValue("test")}) | ||||
|  | ||||
| 	flagA := flag.String("a", "", "") | ||||
| 	parse(t, file.Name(), "") | ||||
| 	if *flagA != "test" { | ||||
| 		t.Errorf("flagA found %v, expected 'test'", *flagA) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestDelete(t *testing.T) { | ||||
| 	resetForTesting() | ||||
| 	file, _ := ioutil.TempFile("", "") | ||||
| 	conf := parse(t, file.Name(), "") | ||||
| 	conf.Set("", &flag.Flag{Name: "a", Value: newFlagValue("test")}) | ||||
| 	conf.Delete("", "a") | ||||
|  | ||||
| 	flagA := flag.String("a", "", "") | ||||
| 	parse(t, file.Name(), "") | ||||
| 	if *flagA != "" { | ||||
| 		t.Errorf("flagNewA found %v, expected ''", *flagA) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func parse(t *testing.T, filename, envPrefix string) *GlobalConf { | ||||
| 	opts := Options{ | ||||
| 		Filename:  filename, | ||||
| 		EnvPrefix: envPrefix, | ||||
| 	} | ||||
| 	conf, err := NewWithOptions(&opts) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	conf.ParseAll() | ||||
| 	return conf | ||||
| } | ||||
|  | ||||
| // Resets os.Args and the default flag set. | ||||
| func resetForTesting(args ...string) { | ||||
| 	os.Clearenv() | ||||
|  | ||||
| 	os.Args = append([]string{"cmd"}, args...) | ||||
| 	flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) | ||||
| } | ||||
|  | ||||
| type flagValue struct { | ||||
| 	str string | ||||
| } | ||||
|  | ||||
| func (f *flagValue) String() string { | ||||
| 	return f.str | ||||
| } | ||||
|  | ||||
| func (f *flagValue) Set(value string) error { | ||||
| 	f.str = value | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func newFlagValue(val string) *flagValue { | ||||
| 	return &flagValue{str: val} | ||||
| } | ||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/custom.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/custom.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,2 +0,0 @@ | ||||
| [custom] | ||||
| d = Hello d | ||||
							
								
								
									
										3
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/global.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/global.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,3 +0,0 @@ | ||||
| a = true | ||||
| b = 5.6 | ||||
| c = Hello world | ||||
							
								
								
									
										6
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/globalandcustom.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								Godeps/_workspace/src/github.com/rakyll/globalconf/testdata/globalandcustom.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +0,0 @@ | ||||
| a = true | ||||
| b = 5.6 | ||||
| c = Hello world | ||||
|  | ||||
| [custom] | ||||
| d = Hello d | ||||
							
								
								
									
										8
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,8 +0,0 @@ | ||||
| .*.swp | ||||
|  | ||||
| *.[689] | ||||
| [689].out | ||||
|  | ||||
| _obj | ||||
| _test | ||||
| _testmain.go | ||||
							
								
								
									
										7
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,7 +0,0 @@ | ||||
| test: | ||||
| 	go test | ||||
|  | ||||
| format: | ||||
| 	gofmt -w *.go | ||||
|  | ||||
| .PHONY: format test | ||||
							
								
								
									
										0
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/empty.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/empty.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
									
										18
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/example.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/example.ini
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,18 +0,0 @@ | ||||
| # | ||||
| # This is an example of ini file | ||||
| # | ||||
|  | ||||
| [Pizza] | ||||
|  | ||||
| Ham         = yes; | ||||
| Mushrooms   = TRUE; | ||||
| Capres      = 0; | ||||
| Cheese      = Non; | ||||
|  | ||||
|  | ||||
| [Wine] | ||||
|  | ||||
| Grape   = Cabernet Sauvignon; | ||||
| Year    = 1989; | ||||
| Country = Spain; | ||||
| Alcohol = 12.5; | ||||
							
								
								
									
										241
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/ini.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										241
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/ini.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,241 +0,0 @@ | ||||
| package ini | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| ) | ||||
|  | ||||
| type Dict map[string]map[string]string | ||||
|  | ||||
| type Error string | ||||
|  | ||||
| var ( | ||||
| 	regDoubleQuote = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*\"([^\"]*)\"$") | ||||
| 	regSingleQuote = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*'([^']*)'$") | ||||
| 	regNoQuote     = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*([^#;]+)") | ||||
| 	regNoValue     = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*([#;].*)?") | ||||
| ) | ||||
|  | ||||
| func Load(filename string) (dict Dict, err error) { | ||||
| 	file, err := os.Open(filename) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer file.Close() | ||||
|  | ||||
| 	dict = make(map[string]map[string]string) | ||||
| 	reader := bufio.NewReader(file) | ||||
| 	lineno := 0 | ||||
| 	section := "" | ||||
| 	dict[section] = make(map[string]string) | ||||
|  | ||||
| 	for err == nil { | ||||
| 		l, _, err := reader.ReadLine() | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		lineno++ | ||||
| 		if len(l) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		line := strings.TrimFunc(string(l), unicode.IsSpace) | ||||
|  | ||||
| 		for line[len(line)-1] == '\\' { | ||||
| 			line = line[:len(line)-1] | ||||
| 			l, _, err := reader.ReadLine() | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			line += strings.TrimFunc(string(l), unicode.IsSpace) | ||||
| 		} | ||||
|  | ||||
| 		section, err = dict.parseLine(section, line) | ||||
| 		if err != nil { | ||||
| 			return nil, newError( | ||||
| 				err.Error() + fmt.Sprintf("'%s:%d'.", filename, lineno)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Write(filename string, dict *Dict) error { | ||||
| 	buffer := dict.format() | ||||
| 	return ioutil.WriteFile(filename, buffer.Bytes(), 0644) | ||||
| } | ||||
|  | ||||
| func (e Error) Error() string { | ||||
| 	return string(e) | ||||
| } | ||||
| func (dict Dict) parseLine(section, line string) (string, error) { | ||||
| 	// commets | ||||
| 	if line[0] == '#' || line[0] == ';' { | ||||
| 		return section, nil | ||||
| 	} | ||||
|  | ||||
| 	// section name | ||||
| 	if line[0] == '[' && line[len(line)-1] == ']' { | ||||
| 		section := strings.TrimFunc(line[1:len(line)-1], unicode.IsSpace) | ||||
| 		section = strings.ToLower(section) | ||||
| 		dict[section] = make(map[string]string) | ||||
| 		return section, nil | ||||
| 	} | ||||
|  | ||||
| 	// key = value | ||||
| 	if m := regDoubleQuote.FindAllStringSubmatch(line, 1); m != nil { | ||||
| 		dict.add(section, m[0][1], m[0][2]) | ||||
| 		return section, nil | ||||
| 	} else if m = regSingleQuote.FindAllStringSubmatch(line, 1); m != nil { | ||||
| 		dict.add(section, m[0][1], m[0][2]) | ||||
| 		return section, nil | ||||
| 	} else if m = regNoQuote.FindAllStringSubmatch(line, 1); m != nil { | ||||
| 		dict.add(section, m[0][1], strings.TrimFunc(m[0][2], unicode.IsSpace)) | ||||
| 		return section, nil | ||||
| 	} else if m = regNoValue.FindAllStringSubmatch(line, 1); m != nil { | ||||
| 		dict.add(section, m[0][1], "") | ||||
| 		return section, nil | ||||
| 	} | ||||
|  | ||||
| 	return section, newError("iniparser: syntax error at ") | ||||
| } | ||||
|  | ||||
| func (dict Dict) add(section, key, value string) { | ||||
| 	key = strings.ToLower(key) | ||||
| 	dict[section][key] = value | ||||
| } | ||||
|  | ||||
| func (dict Dict) GetBool(section, key string) (bool, bool) { | ||||
| 	sec, ok := dict[section] | ||||
| 	if !ok { | ||||
| 		return false, false | ||||
| 	} | ||||
| 	value, ok := sec[key] | ||||
| 	if !ok { | ||||
| 		return false, false | ||||
| 	} | ||||
| 	v := value[0] | ||||
| 	if v == 'y' || v == 'Y' || v == '1' || v == 't' || v == 'T' { | ||||
| 		return true, true | ||||
| 	} | ||||
| 	if v == 'n' || v == 'N' || v == '0' || v == 'f' || v == 'F' { | ||||
| 		return false, true | ||||
| 	} | ||||
| 	return false, false | ||||
| } | ||||
|  | ||||
| func (dict Dict) SetBool(section, key string, value bool) { | ||||
| 	dict.SetString(section, key, strconv.FormatBool(value)) | ||||
| } | ||||
|  | ||||
| func (dict Dict) GetString(section, key string) (string, bool) { | ||||
| 	sec, ok := dict[section] | ||||
| 	if !ok { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	value, ok := sec[key] | ||||
| 	if !ok { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	return value, true | ||||
| } | ||||
|  | ||||
| func (dict Dict) SetString(section, key, value string) { | ||||
| 	_, ok := dict[section] | ||||
| 	if !ok { | ||||
| 		dict[section] = make(map[string]string) | ||||
| 	} | ||||
| 	dict[section][key] = value | ||||
| } | ||||
|  | ||||
| func (dict Dict) GetInt(section, key string) (int, bool) { | ||||
| 	sec, ok := dict[section] | ||||
| 	if !ok { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	value, ok := sec[key] | ||||
| 	if !ok { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	i, err := strconv.Atoi(value) | ||||
| 	if err != nil { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return i, true | ||||
| } | ||||
|  | ||||
| func (dict Dict) SetInt(section, key string, value int) { | ||||
| 	dict.SetString(section, key, strconv.FormatInt(int64(value), 10)) | ||||
| } | ||||
|  | ||||
| func (dict Dict) GetDouble(section, key string) (float64, bool) { | ||||
| 	sec, ok := dict[section] | ||||
| 	if !ok { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	value, ok := sec[key] | ||||
| 	if !ok { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	d, err := strconv.ParseFloat(value, 64) | ||||
| 	if err != nil { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return d, true | ||||
| } | ||||
|  | ||||
| func (dict Dict) SetDouble(section, key string, value float64) { | ||||
| 	dict.SetString(section, key, strconv.FormatFloat(value, 'f', -1, 64)) | ||||
| } | ||||
|  | ||||
| func (dict Dict) Delete(section, key string) { | ||||
| 	_, ok := dict[section] | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	delete(dict[section], key) | ||||
| 	// If there are no items left in the section, | ||||
| 	// delete the section. | ||||
| 	if len(dict[section]) == 0 { | ||||
| 		delete(dict, section) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (dict Dict) GetSections() []string { | ||||
| 	size := len(dict) | ||||
| 	sections := make([]string, size) | ||||
| 	i := 0 | ||||
| 	for section, _ := range dict { | ||||
| 		sections[i] = section | ||||
| 		i++ | ||||
| 	} | ||||
| 	return sections | ||||
| } | ||||
|  | ||||
| func (dict Dict) String() string { | ||||
| 	return (*dict.format()).String() | ||||
| } | ||||
|  | ||||
| func (dict Dict) format() *bytes.Buffer { | ||||
| 	var buffer bytes.Buffer | ||||
| 	for section, vals := range dict { | ||||
| 		if section != "" { | ||||
| 			buffer.WriteString(fmt.Sprintf("[%s]\n", section)) | ||||
| 		} | ||||
| 		for key, val := range vals { | ||||
| 			buffer.WriteString(fmt.Sprintf("%s = %s\n", key, val)) | ||||
| 		} | ||||
| 		buffer.WriteString("\n") | ||||
| 	} | ||||
| 	return &buffer | ||||
| } | ||||
|  | ||||
| func newError(message string) (e error) { | ||||
| 	return Error(message) | ||||
| } | ||||
							
								
								
									
										169
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/ini_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										169
									
								
								Godeps/_workspace/src/github.com/rakyll/goini/ini_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,169 +0,0 @@ | ||||
| package ini | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	exampleStr = `key1 = true | ||||
|  | ||||
| [section1] | ||||
| key1 = value2 | ||||
| key2 = 5 | ||||
| key3 = 1.3 | ||||
|  | ||||
| [section2] | ||||
| key1 = 5 | ||||
|  | ||||
| ` | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	dict Dict | ||||
| 	err  error | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	dict, err = Load("example.ini") | ||||
| } | ||||
|  | ||||
| func TestLoad(t *testing.T) { | ||||
| 	if err != nil { | ||||
| 		t.Error("Example: load error:", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestWrite(t *testing.T) { | ||||
| 	d, err := Load("empty.ini") | ||||
| 	if err != nil { | ||||
| 		t.Error("Example: load error:", err) | ||||
| 	} | ||||
| 	d.SetString("", "key", "value") | ||||
| 	tempFile, err := ioutil.TempFile("", "") | ||||
| 	if err != nil { | ||||
| 		t.Error("Write: Couldn't create temp file.", err) | ||||
| 	} | ||||
| 	err = Write(tempFile.Name(), &d) | ||||
| 	if err != nil { | ||||
| 		t.Error("Write: Couldn't write to temp config file.", err) | ||||
| 	} | ||||
| 	contents, err := ioutil.ReadFile(tempFile.Name()) | ||||
| 	if err != nil { | ||||
| 		t.Error("Write: Couldn't read from the temp config file.", err) | ||||
| 	} | ||||
| 	if string(contents) != "key = value\n\n" { | ||||
| 		t.Error("Write: Contents of the config file doesn't match the expected.") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetBool(t *testing.T) { | ||||
| 	b, found := dict.GetBool("pizza", "ham") | ||||
| 	if !found || !b { | ||||
| 		t.Error("Example: parse error for key ham of section pizza.") | ||||
| 	} | ||||
| 	b, found = dict.GetBool("pizza", "mushrooms") | ||||
| 	if !found || !b { | ||||
| 		t.Error("Example: parse error for key mushrooms of section pizza.") | ||||
| 	} | ||||
| 	b, found = dict.GetBool("pizza", "capres") | ||||
| 	if !found || b { | ||||
| 		t.Error("Example: parse error for key capres of section pizza.") | ||||
| 	} | ||||
| 	b, found = dict.GetBool("pizza", "cheese") | ||||
| 	if !found || b { | ||||
| 		t.Error("Example: parse error for key cheese of section pizza.") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetStringIntAndDouble(t *testing.T) { | ||||
| 	str, found := dict.GetString("wine", "grape") | ||||
| 	if !found || str != "Cabernet Sauvignon" { | ||||
| 		t.Error("Example: parse error for key grape of section wine.") | ||||
| 	} | ||||
| 	i, found := dict.GetInt("wine", "year") | ||||
| 	if !found || i != 1989 { | ||||
| 		t.Error("Example: parse error for key year of section wine.") | ||||
| 	} | ||||
| 	str, found = dict.GetString("wine", "country") | ||||
| 	if !found || str != "Spain" { | ||||
| 		t.Error("Example: parse error for key grape of section wine.") | ||||
| 	} | ||||
| 	d, found := dict.GetDouble("wine", "alcohol") | ||||
| 	if !found || d != 12.5 { | ||||
| 		t.Error("Example: parse error for key grape of section wine.") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSetBoolAndStringAndIntAndDouble(t *testing.T) { | ||||
| 	dict.SetBool("pizza", "ham", false) | ||||
| 	b, found := dict.GetBool("pizza", "ham") | ||||
| 	if !found || b { | ||||
| 		t.Error("Example: bool set error for key ham of section pizza.") | ||||
| 	} | ||||
| 	dict.SetString("pizza", "ham", "no") | ||||
| 	n, found := dict.GetString("pizza", "ham") | ||||
| 	if !found || n != "no" { | ||||
| 		t.Error("Example: string set error for key ham of section pizza.") | ||||
| 	} | ||||
| 	dict.SetInt("wine", "year", 1978) | ||||
| 	i, found := dict.GetInt("wine", "year") | ||||
| 	if !found || i != 1978 { | ||||
| 		t.Error("Example: int set error for key year of section wine.") | ||||
| 	} | ||||
| 	dict.SetDouble("wine", "not-exists", 5.6) | ||||
| 	d, found := dict.GetDouble("wine", "not-exists") | ||||
| 	if !found || d != 5.6 { | ||||
| 		t.Error("Example: float set error for not existing key for wine.") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestDelete(t *testing.T) { | ||||
| 	d, err := Load("empty.ini") | ||||
| 	if err != nil { | ||||
| 		t.Error("Example: load error:", err) | ||||
| 	} | ||||
| 	d.SetString("pizza", "ham", "yes") | ||||
| 	d.Delete("pizza", "ham") | ||||
| 	_, found := d.GetString("pizza", "ham") | ||||
| 	if found { | ||||
| 		t.Error("Example: delete error for key ham of section pizza.") | ||||
| 	} | ||||
| 	if len(d.GetSections()) > 1 { | ||||
| 		t.Error("Only a single section should exist after deletion.") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetNotExist(t *testing.T) { | ||||
| 	_, found := dict.GetString("not", "exist") | ||||
| 	if found { | ||||
| 		t.Error("There is no key exist of section not.") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetSections(t *testing.T) { | ||||
| 	sections := dict.GetSections() | ||||
| 	if len(sections) != 3 { | ||||
| 		t.Error("The number of sections is wrong:", len(sections)) | ||||
| 	} | ||||
| 	for _, section := range sections { | ||||
| 		if section != "" && section != "pizza" && section != "wine" { | ||||
| 			t.Errorf("Section '%s' should not be exist.", section) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestString(t *testing.T) { | ||||
| 	d, err := Load("empty.ini") | ||||
| 	if err != nil { | ||||
| 		t.Error("Example: load error:", err) | ||||
| 	} | ||||
| 	d.SetBool("", "key1", true) | ||||
| 	d.SetString("section1", "key1", "value2") | ||||
| 	d.SetInt("section1", "key2", 5) | ||||
| 	d.SetDouble("section1", "key3", 1.3) | ||||
| 	d.SetDouble("section2", "key1", 5.0) | ||||
| 	if d.String() != exampleStr { | ||||
| 		t.Errorf("Dict cannot be stringified as expected.") | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user