diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 34e86c4..99c12cb 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -15,10 +15,5 @@ "Comment": "v1.0-71-g2152b45", "Rev": "2152b45fa28a361beba9aab0885972323a444e28" } - { - "ImportPath": "github.com/magiconair/properties", - "Comment": "v1.7.3", - "Rev": "152b45fa28a361beba9aab0885972323a444e28" - } ] } diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/CHANGELOG.md b/Godeps/_workspace/src/github.com/magiconair/properties/CHANGELOG.md deleted file mode 100644 index b0d98d8..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/CHANGELOG.md +++ /dev/null @@ -1,104 +0,0 @@ -## Changelog - -### [1.7.4](https://github.com/magiconair/properties/tree/v1.7.4) - 31 Oct 2017 - - * [Issue #23](https://github.com/magiconair/properties/issues/23): Ignore blank lines with whitespaces - * [PR #24](https://github.com/magiconair/properties/pull/24): Update keys when DisableExpansion is enabled - Thanks to @mgurov for the fix. - -### [1.7.3](https://github.com/magiconair/properties/tree/v1.7.3) - 10 Jul 2017 - - * [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically - * [Issue #22](https://github.com/magiconair/properties/issues/22): Add [LoadMap()](http://godoc.org/github.com/magiconair/properties#LoadMap) function to load properties from a string map - -### [1.7.2](https://github.com/magiconair/properties/tree/v1.7.2) - 20 Mar 2017 - - * [Issue #15](https://github.com/magiconair/properties/issues/15): Drop gocheck dependency - * [PR #21](https://github.com/magiconair/properties/pull/21): Add [Map()](http://godoc.org/github.com/magiconair/properties#Properties.Map) and [FilterFunc()](http://godoc.org/github.com/magiconair/properties#Properties.FilterFunc) - -### [1.7.1](https://github.com/magiconair/properties/tree/v1.7.1) - 13 Jan 2017 - - * [Issue #14](https://github.com/magiconair/properties/issues/14): Decouple TestLoadExpandedFile from `$USER` - * [PR #12](https://github.com/magiconair/properties/pull/12): Load from files and URLs - * [PR #16](https://github.com/magiconair/properties/pull/16): Keep gofmt happy - * [PR #18](https://github.com/magiconair/properties/pull/18): Fix Delete() function - -### [1.7.0](https://github.com/magiconair/properties/tree/v1.7.0) - 20 Mar 2016 - - * [Issue #10](https://github.com/magiconair/properties/issues/10): Add [LoadURL,LoadURLs,MustLoadURL,MustLoadURLs](http://godoc.org/github.com/magiconair/properties#LoadURL) method to load properties from a URL. - * [Issue #11](https://github.com/magiconair/properties/issues/11): Add [LoadString,MustLoadString](http://godoc.org/github.com/magiconair/properties#LoadString) method to load properties from an UTF8 string. - * [PR #8](https://github.com/magiconair/properties/pull/8): Add [MustFlag](http://godoc.org/github.com/magiconair/properties#Properties.MustFlag) method to provide overrides via command line flags. (@pascaldekloe) - -### [1.6.0](https://github.com/magiconair/properties/tree/v1.6.0) - 11 Dec 2015 - - * Add [Decode](http://godoc.org/github.com/magiconair/properties#Properties.Decode) method to populate struct from properties via tags. - -### [1.5.6](https://github.com/magiconair/properties/tree/v1.5.6) - 18 Oct 2015 - - * Vendored in gopkg.in/check.v1 - -### [1.5.5](https://github.com/magiconair/properties/tree/v1.5.5) - 31 Jul 2015 - - * [PR #6](https://github.com/magiconair/properties/pull/6): Add [Delete](http://godoc.org/github.com/magiconair/properties#Properties.Delete) method to remove keys including comments. (@gerbenjacobs) - -### [1.5.4](https://github.com/magiconair/properties/tree/v1.5.4) - 23 Jun 2015 - - * [Issue #5](https://github.com/magiconair/properties/issues/5): Allow disabling of property expansion [DisableExpansion](http://godoc.org/github.com/magiconair/properties#Properties.DisableExpansion). When property expansion is disabled Properties become a simple key/value store and don't check for circular references. - -### [1.5.3](https://github.com/magiconair/properties/tree/v1.5.3) - 02 Jun 2015 - - * [Issue #4](https://github.com/magiconair/properties/issues/4): Maintain key order in [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) and [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) - -### [1.5.2](https://github.com/magiconair/properties/tree/v1.5.2) - 10 Apr 2015 - - * [Issue #3](https://github.com/magiconair/properties/issues/3): Don't print comments in [WriteComment()](http://godoc.org/github.com/magiconair/properties#Properties.WriteComment) if they are all empty - * Add clickable links to README - -### [1.5.1](https://github.com/magiconair/properties/tree/v1.5.1) - 08 Dec 2014 - - * Added [GetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.GetParsedDuration) and [MustGetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.MustGetParsedDuration) for values specified compatible with - [time.ParseDuration()](http://golang.org/pkg/time/#ParseDuration). - -### [1.5.0](https://github.com/magiconair/properties/tree/v1.5.0) - 18 Nov 2014 - - * Added support for single and multi-line comments (reading, writing and updating) - * The order of keys is now preserved - * Calling [Set()](http://godoc.org/github.com/magiconair/properties#Properties.Set) with an empty key now silently ignores the call and does not create a new entry - * Added a [MustSet()](http://godoc.org/github.com/magiconair/properties#Properties.MustSet) method - * Migrated test library from launchpad.net/gocheck to [gopkg.in/check.v1](http://gopkg.in/check.v1) - -### [1.4.2](https://github.com/magiconair/properties/tree/v1.4.2) - 15 Nov 2014 - - * [Issue #2](https://github.com/magiconair/properties/issues/2): Fixed goroutine leak in parser which created two lexers but cleaned up only one - -### [1.4.1](https://github.com/magiconair/properties/tree/v1.4.1) - 13 Nov 2014 - - * [Issue #1](https://github.com/magiconair/properties/issues/1): Fixed bug in Keys() method which returned an empty string - -### [1.4.0](https://github.com/magiconair/properties/tree/v1.4.0) - 23 Sep 2014 - - * Added [Keys()](http://godoc.org/github.com/magiconair/properties#Properties.Keys) to get the keys - * Added [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) and [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) to get a subset of the properties - -### [1.3.0](https://github.com/magiconair/properties/tree/v1.3.0) - 18 Mar 2014 - -* Added support for time.Duration -* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tree/vior configurable (log.Fatal, panic) - custom) -* Changed default of MustXXX() failure from panic to log.Fatal - -### [1.2.0](https://github.com/magiconair/properties/tree/v1.2.0) - 05 Mar 2014 - -* Added MustGet... functions -* Added support for int and uint with range checks on 32 bit platforms - -### [1.1.0](https://github.com/magiconair/properties/tree/v1.1.0) - 20 Jan 2014 - -* Renamed from goproperties to properties -* Added support for expansion of environment vars in - filenames and value expressions -* Fixed bug where value expressions were not at the - start of the string - -### [1.0.0](https://github.com/magiconair/properties/tree/v1.0.0) - 7 Jan 2014 - -* Initial release diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/LICENSE b/Godeps/_workspace/src/github.com/magiconair/properties/LICENSE deleted file mode 100644 index 7eab43b..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -goproperties - properties file decoder for Go - -Copyright (c) 2013-2014 - Frank Schroeder - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/README.md b/Godeps/_workspace/src/github.com/magiconair/properties/README.md deleted file mode 100644 index 258fbb2..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/README.md +++ /dev/null @@ -1,100 +0,0 @@ -Overview [![Build Status](https://travis-ci.org/magiconair/properties.svg?branch=master)](https://travis-ci.org/magiconair/properties) -======== - -#### Current version: 1.7.4 - -properties is a Go library for reading and writing properties files. - -It supports reading from multiple files or URLs and Spring style recursive -property expansion of expressions like `${key}` to their corresponding value. -Value expressions can refer to other keys like in `${key}` or to environment -variables like in `${USER}`. Filenames can also contain environment variables -like in `/home/${USER}/myapp.properties`. - -Properties can be decoded into structs, maps, arrays and values through -struct tags. - -Comments and the order of keys are preserved. Comments can be modified -and can be written to the output. - -The properties library supports both ISO-8859-1 and UTF-8 encoded data. - -Starting from version 1.3.0 the behavior of the MustXXX() functions is -configurable by providing a custom `ErrorHandler` function. The default has -changed from `panic` to `log.Fatal` but this is configurable and custom -error handling functions can be provided. See the package documentation for -details. - -Read the full documentation on [GoDoc](https://godoc.org/github.com/magiconair/properties) [![GoDoc](https://godoc.org/github.com/magiconair/properties?status.png)](https://godoc.org/github.com/magiconair/properties) - -Getting Started ---------------- - -```go -import ( - "flag" - "github.com/magiconair/properties" -) - -func main() { - // init from a file - p := properties.MustLoadFile("${HOME}/config.properties", properties.UTF8) - - // or multiple files - p = properties.MustLoadFiles([]string{ - "${HOME}/config.properties", - "${HOME}/config-${USER}.properties", - }, properties.UTF8, true) - - // or from a map - p = properties.LoadMap(map[string]string{"key": "value", "abc": "def"}) - - // or from a string - p = properties.MustLoadString("key=value\nabc=def") - - // or from a URL - p = properties.MustLoadURL("http://host/path") - - // or from multiple URLs - p = properties.MustLoadURL([]string{ - "http://host/config", - "http://host/config-${USER}", - }, true) - - // or from flags - p.MustFlag(flag.CommandLine) - - // get values through getters - host := p.MustGetString("host") - port := p.GetInt("port", 8080) - - // or through Decode - type Config struct { - Host string `properties:"host"` - Port int `properties:"port,default=9000"` - Accept []string `properties:"accept,default=image/png;image;gif"` - Timeout time.Duration `properties:"timeout,default=5s"` - } - var cfg Config - if err := p.Decode(&cfg); err != nil { - log.Fatal(err) - } -} - -``` - -Installation and Upgrade ------------------------- - -``` -$ go get -u github.com/magiconair/properties -``` - -License -------- - -2 clause BSD license. See [LICENSE](https://github.com/magiconair/properties/blob/master/LICENSE) file for details. - -ToDo ----- -* Dump contents with passwords and secrets obscured diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/assert/assert.go b/Godeps/_workspace/src/github.com/magiconair/properties/assert/assert.go deleted file mode 100644 index cb1097b..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/assert/assert.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package assert provides helper functions for testing. -package assert - -import ( - "fmt" - "path/filepath" - "reflect" - "regexp" - "runtime" - "strings" - "testing" -) - -// skip defines the default call depth -const skip = 2 - -// Equal asserts that got and want are equal as defined by -// reflect.DeepEqual. The test fails with msg if they are not equal. -func Equal(t *testing.T, got, want interface{}, msg ...string) { - if x := equal(2, got, want, msg...); x != "" { - fmt.Println(x) - t.Fail() - } -} - -func equal(skip int, got, want interface{}, msg ...string) string { - if !reflect.DeepEqual(got, want) { - return fail(skip, "got %v want %v %s", got, want, strings.Join(msg, " ")) - } - return "" -} - -// Panic asserts that function fn() panics. -// It assumes that recover() either returns a string or -// an error and fails if the message does not match -// the regular expression in 'matches'. -func Panic(t *testing.T, fn func(), matches string) { - if x := doesPanic(2, fn, matches); x != "" { - fmt.Println(x) - t.Fail() - } -} - -func doesPanic(skip int, fn func(), expr string) (err string) { - defer func() { - r := recover() - if r == nil { - err = fail(skip, "did not panic") - return - } - var v string - switch r.(type) { - case error: - v = r.(error).Error() - case string: - v = r.(string) - } - err = matches(skip, v, expr) - }() - fn() - return "" -} - -// Matches asserts that a value matches a given regular expression. -func Matches(t *testing.T, value, expr string) { - if x := matches(2, value, expr); x != "" { - fmt.Println(x) - t.Fail() - } -} - -func matches(skip int, value, expr string) string { - ok, err := regexp.MatchString(expr, value) - if err != nil { - return fail(skip, "invalid pattern %q. %s", expr, err) - } - if !ok { - return fail(skip, "got %s which does not match %s", value, expr) - } - return "" -} - -func fail(skip int, format string, args ...interface{}) string { - _, file, line, _ := runtime.Caller(skip) - return fmt.Sprintf("\t%s:%d: %s\n", filepath.Base(file), line, fmt.Sprintf(format, args...)) -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/assert/assert_test.go b/Godeps/_workspace/src/github.com/magiconair/properties/assert/assert_test.go deleted file mode 100644 index dcef73d..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/assert/assert_test.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package assert - -import "testing" - -func TestEqualEquals(t *testing.T) { - if got, want := equal(2, "a", "a"), ""; got != want { - t.Fatalf("got %q want %q", got, want) - } -} - -func TestEqualFails(t *testing.T) { - if got, want := equal(2, "a", "b"), "\tassert_test.go:16: got a want b \n"; got != want { - t.Fatalf("got %q want %q", got, want) - } -} - -func TestPanicPanics(t *testing.T) { - if got, want := doesPanic(2, func() { panic("foo") }, ""), ""; got != want { - t.Fatalf("got %q want %q", got, want) - } -} - -func TestPanicPanicsAndMatches(t *testing.T) { - if got, want := doesPanic(2, func() { panic("foo") }, "foo"), ""; got != want { - t.Fatalf("got %q want %q", got, want) - } -} - -func TestPanicPanicsAndDoesNotMatch(t *testing.T) { - if got, want := doesPanic(2, func() { panic("foo") }, "bar"), "\tassert.go:62: got foo which does not match bar\n"; got != want { - t.Fatalf("got %q want %q", got, want) - } -} - -func TestPanicPanicsAndDoesNotPanic(t *testing.T) { - if got, want := doesPanic(2, func() {}, "bar"), "\tassert.go:65: did not panic\n"; got != want { - t.Fatalf("got %q want %q", got, want) - } -} - -func TestMatchesMatches(t *testing.T) { - if got, want := matches(2, "aaa", "a"), ""; got != want { - t.Fatalf("got %q want %q", got, want) - } -} - -func TestMatchesDoesNotMatch(t *testing.T) { - if got, want := matches(2, "aaa", "b"), "\tassert_test.go:52: got aaa which does not match b\n"; got != want { - t.Fatalf("got %q want %q", got, want) - } -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/benchmark_test.go b/Godeps/_workspace/src/github.com/magiconair/properties/benchmark_test.go deleted file mode 100644 index 62c7cc5..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/benchmark_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2013-2014 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "testing" -) - -// Benchmarks the decoder by creating a property file with 1000 key/value pairs. -func BenchmarkLoad(b *testing.B) { - input := "" - for i := 0; i < 1000; i++ { - input += fmt.Sprintf("key%d=value%d\n", i, i) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - if _, err := Load([]byte(input), ISO_8859_1); err != nil { - b.Fatal(err) - } - } -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/decode.go b/Godeps/_workspace/src/github.com/magiconair/properties/decode.go deleted file mode 100644 index 0a961bb..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/decode.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "reflect" - "strconv" - "strings" - "time" -) - -// Decode assigns property values to exported fields of a struct. -// -// Decode traverses v recursively and returns an error if a value cannot be -// converted to the field type or a required value is missing for a field. -// -// The following type dependent decodings are used: -// -// String, boolean, numeric fields have the value of the property key assigned. -// The property key name is the name of the field. A different key and a default -// value can be set in the field's tag. Fields without default value are -// required. If the value cannot be converted to the field type an error is -// returned. -// -// time.Duration fields have the result of time.ParseDuration() assigned. -// -// time.Time fields have the vaule of time.Parse() assigned. The default layout -// is time.RFC3339 but can be set in the field's tag. -// -// Arrays and slices of string, boolean, numeric, time.Duration and time.Time -// fields have the value interpreted as a comma separated list of values. The -// individual values are trimmed of whitespace and empty values are ignored. A -// default value can be provided as a semicolon separated list in the field's -// tag. -// -// Struct fields are decoded recursively using the field name plus "." as -// prefix. The prefix (without dot) can be overridden in the field's tag. -// Default values are not supported in the field's tag. Specify them on the -// fields of the inner struct instead. -// -// Map fields must have a key of type string and are decoded recursively by -// using the field's name plus ".' as prefix and the next element of the key -// name as map key. The prefix (without dot) can be overridden in the field's -// tag. Default values are not supported. -// -// Examples: -// -// // Field is ignored. -// Field int `properties:"-"` -// -// // Field is assigned value of 'Field'. -// Field int -// -// // Field is assigned value of 'myName'. -// Field int `properties:"myName"` -// -// // Field is assigned value of key 'myName' and has a default -// // value 15 if the key does not exist. -// Field int `properties:"myName,default=15"` -// -// // Field is assigned value of key 'Field' and has a default -// // value 15 if the key does not exist. -// Field int `properties:",default=15"` -// -// // Field is assigned value of key 'date' and the date -// // is in format 2006-01-02 -// Field time.Time `properties:"date,layout=2006-01-02"` -// -// // Field is assigned the non-empty and whitespace trimmed -// // values of key 'Field' split by commas. -// Field []string -// -// // Field is assigned the non-empty and whitespace trimmed -// // values of key 'Field' split by commas and has a default -// // value ["a", "b", "c"] if the key does not exist. -// Field []string `properties:",default=a;b;c"` -// -// // Field is decoded recursively with "Field." as key prefix. -// Field SomeStruct -// -// // Field is decoded recursively with "myName." as key prefix. -// Field SomeStruct `properties:"myName"` -// -// // Field is decoded recursively with "Field." as key prefix -// // and the next dotted element of the key as map key. -// Field map[string]string -// -// // Field is decoded recursively with "myName." as key prefix -// // and the next dotted element of the key as map key. -// Field map[string]string `properties:"myName"` -func (p *Properties) Decode(x interface{}) error { - t, v := reflect.TypeOf(x), reflect.ValueOf(x) - if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct { - return fmt.Errorf("not a pointer to struct: %s", t) - } - if err := dec(p, "", nil, nil, v); err != nil { - return err - } - return nil -} - -func dec(p *Properties, key string, def *string, opts map[string]string, v reflect.Value) error { - t := v.Type() - - // value returns the property value for key or the default if provided. - value := func() (string, error) { - if val, ok := p.Get(key); ok { - return val, nil - } - if def != nil { - return *def, nil - } - return "", fmt.Errorf("missing required key %s", key) - } - - // conv converts a string to a value of the given type. - conv := func(s string, t reflect.Type) (val reflect.Value, err error) { - var v interface{} - - switch { - case isDuration(t): - v, err = time.ParseDuration(s) - - case isTime(t): - layout := opts["layout"] - if layout == "" { - layout = time.RFC3339 - } - v, err = time.Parse(layout, s) - - case isBool(t): - v, err = boolVal(s), nil - - case isString(t): - v, err = s, nil - - case isFloat(t): - v, err = strconv.ParseFloat(s, 64) - - case isInt(t): - v, err = strconv.ParseInt(s, 10, 64) - - case isUint(t): - v, err = strconv.ParseUint(s, 10, 64) - - default: - return reflect.Zero(t), fmt.Errorf("unsupported type %s", t) - } - if err != nil { - return reflect.Zero(t), err - } - return reflect.ValueOf(v).Convert(t), nil - } - - // keydef returns the property key and the default value based on the - // name of the struct field and the options in the tag. - keydef := func(f reflect.StructField) (string, *string, map[string]string) { - _key, _opts := parseTag(f.Tag.Get("properties")) - - var _def *string - if d, ok := _opts["default"]; ok { - _def = &d - } - if _key != "" { - return _key, _def, _opts - } - return f.Name, _def, _opts - } - - switch { - case isDuration(t) || isTime(t) || isBool(t) || isString(t) || isFloat(t) || isInt(t) || isUint(t): - s, err := value() - if err != nil { - return err - } - val, err := conv(s, t) - if err != nil { - return err - } - v.Set(val) - - case isPtr(t): - return dec(p, key, def, opts, v.Elem()) - - case isStruct(t): - for i := 0; i < v.NumField(); i++ { - fv := v.Field(i) - fk, def, opts := keydef(t.Field(i)) - if !fv.CanSet() { - return fmt.Errorf("cannot set %s", t.Field(i).Name) - } - if fk == "-" { - continue - } - if key != "" { - fk = key + "." + fk - } - if err := dec(p, fk, def, opts, fv); err != nil { - return err - } - } - return nil - - case isArray(t): - val, err := value() - if err != nil { - return err - } - vals := split(val, ";") - a := reflect.MakeSlice(t, 0, len(vals)) - for _, s := range vals { - val, err := conv(s, t.Elem()) - if err != nil { - return err - } - a = reflect.Append(a, val) - } - v.Set(a) - - case isMap(t): - valT := t.Elem() - m := reflect.MakeMap(t) - for postfix := range p.FilterStripPrefix(key + ".").m { - pp := strings.SplitN(postfix, ".", 2) - mk, mv := pp[0], reflect.New(valT) - if err := dec(p, key+"."+mk, nil, nil, mv); err != nil { - return err - } - m.SetMapIndex(reflect.ValueOf(mk), mv.Elem()) - } - v.Set(m) - - default: - return fmt.Errorf("unsupported type %s", t) - } - return nil -} - -// split splits a string on sep, trims whitespace of elements -// and omits empty elements -func split(s string, sep string) []string { - var a []string - for _, v := range strings.Split(s, sep) { - if v = strings.TrimSpace(v); v != "" { - a = append(a, v) - } - } - return a -} - -// parseTag parses a "key,k=v,k=v,..." -func parseTag(tag string) (key string, opts map[string]string) { - opts = map[string]string{} - for i, s := range strings.Split(tag, ",") { - if i == 0 { - key = s - continue - } - - pp := strings.SplitN(s, "=", 2) - if len(pp) == 1 { - opts[pp[0]] = "" - } else { - opts[pp[0]] = pp[1] - } - } - return key, opts -} - -func isArray(t reflect.Type) bool { return t.Kind() == reflect.Array || t.Kind() == reflect.Slice } -func isBool(t reflect.Type) bool { return t.Kind() == reflect.Bool } -func isDuration(t reflect.Type) bool { return t == reflect.TypeOf(time.Second) } -func isMap(t reflect.Type) bool { return t.Kind() == reflect.Map } -func isPtr(t reflect.Type) bool { return t.Kind() == reflect.Ptr } -func isString(t reflect.Type) bool { return t.Kind() == reflect.String } -func isStruct(t reflect.Type) bool { return t.Kind() == reflect.Struct } -func isTime(t reflect.Type) bool { return t == reflect.TypeOf(time.Time{}) } -func isFloat(t reflect.Type) bool { - return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64 -} -func isInt(t reflect.Type) bool { - return t.Kind() == reflect.Int || t.Kind() == reflect.Int8 || t.Kind() == reflect.Int16 || t.Kind() == reflect.Int32 || t.Kind() == reflect.Int64 -} -func isUint(t reflect.Type) bool { - return t.Kind() == reflect.Uint || t.Kind() == reflect.Uint8 || t.Kind() == reflect.Uint16 || t.Kind() == reflect.Uint32 || t.Kind() == reflect.Uint64 -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/decode_test.go b/Godeps/_workspace/src/github.com/magiconair/properties/decode_test.go deleted file mode 100644 index c829314..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/decode_test.go +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "reflect" - "testing" - "time" -) - -func TestDecodeValues(t *testing.T) { - type S struct { - S string - BT bool - BF bool - I int - I8 int8 - I16 int16 - I32 int32 - I64 int64 - U uint - U8 uint8 - U16 uint16 - U32 uint32 - U64 uint64 - F32 float32 - F64 float64 - D time.Duration - TM time.Time - } - in := ` - S=abc - BT=true - BF=false - I=-1 - I8=-8 - I16=-16 - I32=-32 - I64=-64 - U=1 - U8=8 - U16=16 - U32=32 - U64=64 - F32=3.2 - F64=6.4 - D=5s - TM=2015-01-02T12:34:56Z - ` - out := &S{ - S: "abc", - BT: true, - BF: false, - I: -1, - I8: -8, - I16: -16, - I32: -32, - I64: -64, - U: 1, - U8: 8, - U16: 16, - U32: 32, - U64: 64, - F32: 3.2, - F64: 6.4, - D: 5 * time.Second, - TM: tm(t, time.RFC3339, "2015-01-02T12:34:56Z"), - } - testDecode(t, in, &S{}, out) -} - -func TestDecodeValueDefaults(t *testing.T) { - type S struct { - S string `properties:",default=abc"` - BT bool `properties:",default=true"` - BF bool `properties:",default=false"` - I int `properties:",default=-1"` - I8 int8 `properties:",default=-8"` - I16 int16 `properties:",default=-16"` - I32 int32 `properties:",default=-32"` - I64 int64 `properties:",default=-64"` - U uint `properties:",default=1"` - U8 uint8 `properties:",default=8"` - U16 uint16 `properties:",default=16"` - U32 uint32 `properties:",default=32"` - U64 uint64 `properties:",default=64"` - F32 float32 `properties:",default=3.2"` - F64 float64 `properties:",default=6.4"` - D time.Duration `properties:",default=5s"` - TM time.Time `properties:",default=2015-01-02T12:34:56Z"` - } - out := &S{ - S: "abc", - BT: true, - BF: false, - I: -1, - I8: -8, - I16: -16, - I32: -32, - I64: -64, - U: 1, - U8: 8, - U16: 16, - U32: 32, - U64: 64, - F32: 3.2, - F64: 6.4, - D: 5 * time.Second, - TM: tm(t, time.RFC3339, "2015-01-02T12:34:56Z"), - } - testDecode(t, "", &S{}, out) -} - -func TestDecodeArrays(t *testing.T) { - type S struct { - S []string - B []bool - I []int - I8 []int8 - I16 []int16 - I32 []int32 - I64 []int64 - U []uint - U8 []uint8 - U16 []uint16 - U32 []uint32 - U64 []uint64 - F32 []float32 - F64 []float64 - D []time.Duration - TM []time.Time - } - in := ` - S=a;b - B=true;false - I=-1;-2 - I8=-8;-9 - I16=-16;-17 - I32=-32;-33 - I64=-64;-65 - U=1;2 - U8=8;9 - U16=16;17 - U32=32;33 - U64=64;65 - F32=3.2;3.3 - F64=6.4;6.5 - D=4s;5s - TM=2015-01-01T00:00:00Z;2016-01-01T00:00:00Z - ` - out := &S{ - S: []string{"a", "b"}, - B: []bool{true, false}, - I: []int{-1, -2}, - I8: []int8{-8, -9}, - I16: []int16{-16, -17}, - I32: []int32{-32, -33}, - I64: []int64{-64, -65}, - U: []uint{1, 2}, - U8: []uint8{8, 9}, - U16: []uint16{16, 17}, - U32: []uint32{32, 33}, - U64: []uint64{64, 65}, - F32: []float32{3.2, 3.3}, - F64: []float64{6.4, 6.5}, - D: []time.Duration{4 * time.Second, 5 * time.Second}, - TM: []time.Time{tm(t, time.RFC3339, "2015-01-01T00:00:00Z"), tm(t, time.RFC3339, "2016-01-01T00:00:00Z")}, - } - testDecode(t, in, &S{}, out) -} - -func TestDecodeArrayDefaults(t *testing.T) { - type S struct { - S []string `properties:",default=a;b"` - B []bool `properties:",default=true;false"` - I []int `properties:",default=-1;-2"` - I8 []int8 `properties:",default=-8;-9"` - I16 []int16 `properties:",default=-16;-17"` - I32 []int32 `properties:",default=-32;-33"` - I64 []int64 `properties:",default=-64;-65"` - U []uint `properties:",default=1;2"` - U8 []uint8 `properties:",default=8;9"` - U16 []uint16 `properties:",default=16;17"` - U32 []uint32 `properties:",default=32;33"` - U64 []uint64 `properties:",default=64;65"` - F32 []float32 `properties:",default=3.2;3.3"` - F64 []float64 `properties:",default=6.4;6.5"` - D []time.Duration `properties:",default=4s;5s"` - TM []time.Time `properties:",default=2015-01-01T00:00:00Z;2016-01-01T00:00:00Z"` - } - out := &S{ - S: []string{"a", "b"}, - B: []bool{true, false}, - I: []int{-1, -2}, - I8: []int8{-8, -9}, - I16: []int16{-16, -17}, - I32: []int32{-32, -33}, - I64: []int64{-64, -65}, - U: []uint{1, 2}, - U8: []uint8{8, 9}, - U16: []uint16{16, 17}, - U32: []uint32{32, 33}, - U64: []uint64{64, 65}, - F32: []float32{3.2, 3.3}, - F64: []float64{6.4, 6.5}, - D: []time.Duration{4 * time.Second, 5 * time.Second}, - TM: []time.Time{tm(t, time.RFC3339, "2015-01-01T00:00:00Z"), tm(t, time.RFC3339, "2016-01-01T00:00:00Z")}, - } - testDecode(t, "", &S{}, out) -} - -func TestDecodeSkipUndef(t *testing.T) { - type S struct { - X string `properties:"-"` - Undef string `properties:",default=some value"` - } - in := `X=ignore` - out := &S{"", "some value"} - testDecode(t, in, &S{}, out) -} - -func TestDecodeStruct(t *testing.T) { - type A struct { - S string - T string `properties:"t"` - U string `properties:"u,default=uuu"` - } - type S struct { - A A - B A `properties:"b"` - } - in := ` - A.S=sss - A.t=ttt - b.S=SSS - b.t=TTT - ` - out := &S{ - A{S: "sss", T: "ttt", U: "uuu"}, - A{S: "SSS", T: "TTT", U: "uuu"}, - } - testDecode(t, in, &S{}, out) -} - -func TestDecodeMap(t *testing.T) { - type S struct { - A string `properties:"a"` - } - type X struct { - A map[string]string - B map[string][]string - C map[string]map[string]string - D map[string]S - E map[string]int - F map[string]int `properties:"-"` - } - in := ` - A.foo=bar - A.bar=bang - B.foo=a;b;c - B.bar=1;2;3 - C.foo.one=1 - C.foo.two=2 - C.bar.three=3 - C.bar.four=4 - D.foo.a=bar - ` - out := &X{ - A: map[string]string{"foo": "bar", "bar": "bang"}, - B: map[string][]string{"foo": []string{"a", "b", "c"}, "bar": []string{"1", "2", "3"}}, - C: map[string]map[string]string{"foo": map[string]string{"one": "1", "two": "2"}, "bar": map[string]string{"three": "3", "four": "4"}}, - D: map[string]S{"foo": S{"bar"}}, - E: map[string]int{}, - } - testDecode(t, in, &X{}, out) -} - -func testDecode(t *testing.T, in string, v, out interface{}) { - p, err := parse(in) - if err != nil { - t.Fatalf("got %v want nil", err) - } - if err := p.Decode(v); err != nil { - t.Fatalf("got %v want nil", err) - } - if got, want := v, out; !reflect.DeepEqual(got, want) { - t.Fatalf("\ngot %+v\nwant %+v", got, want) - } -} - -func tm(t *testing.T, layout, s string) time.Time { - tm, err := time.Parse(layout, s) - if err != nil { - t.Fatalf("got %v want nil", err) - } - return tm -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/doc.go b/Godeps/_workspace/src/github.com/magiconair/properties/doc.go deleted file mode 100644 index 36c8368..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/doc.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package properties provides functions for reading and writing -// ISO-8859-1 and UTF-8 encoded .properties files and has -// support for recursive property expansion. -// -// Java properties files are ISO-8859-1 encoded and use Unicode -// literals for characters outside the ISO character set. Unicode -// literals can be used in UTF-8 encoded properties files but -// aren't necessary. -// -// To load a single properties file use MustLoadFile(): -// -// p := properties.MustLoadFile(filename, properties.UTF8) -// -// To load multiple properties files use MustLoadFiles() -// which loads the files in the given order and merges the -// result. Missing properties files can be ignored if the -// 'ignoreMissing' flag is set to true. -// -// Filenames can contain environment variables which are expanded -// before loading. -// -// f1 := "/etc/myapp/myapp.conf" -// f2 := "/home/${USER}/myapp.conf" -// p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true) -// -// All of the different key/value delimiters ' ', ':' and '=' are -// supported as well as the comment characters '!' and '#' and -// multi-line values. -// -// ! this is a comment -// # and so is this -// -// # the following expressions are equal -// key value -// key=value -// key:value -// key = value -// key : value -// key = val\ -// ue -// -// Properties stores all comments preceding a key and provides -// GetComments() and SetComments() methods to retrieve and -// update them. The convenience functions GetComment() and -// SetComment() allow access to the last comment. The -// WriteComment() method writes properties files including -// the comments and with the keys in the original order. -// This can be used for sanitizing properties files. -// -// Property expansion is recursive and circular references -// and malformed expressions are not allowed and cause an -// error. Expansion of environment variables is supported. -// -// # standard property -// key = value -// -// # property expansion: key2 = value -// key2 = ${key} -// -// # recursive expansion: key3 = value -// key3 = ${key2} -// -// # circular reference (error) -// key = ${key} -// -// # malformed expression (error) -// key = ${ke -// -// # refers to the users' home dir -// home = ${HOME} -// -// # local key takes precendence over env var: u = foo -// USER = foo -// u = ${USER} -// -// The default property expansion format is ${key} but can be -// changed by setting different pre- and postfix values on the -// Properties object. -// -// p := properties.NewProperties() -// p.Prefix = "#[" -// p.Postfix = "]#" -// -// Properties provides convenience functions for getting typed -// values with default values if the key does not exist or the -// type conversion failed. -// -// # Returns true if the value is either "1", "on", "yes" or "true" -// # Returns false for every other value and the default value if -// # the key does not exist. -// v = p.GetBool("key", false) -// -// # Returns the value if the key exists and the format conversion -// # was successful. Otherwise, the default value is returned. -// v = p.GetInt64("key", 999) -// v = p.GetUint64("key", 999) -// v = p.GetFloat64("key", 123.0) -// v = p.GetString("key", "def") -// v = p.GetDuration("key", 999) -// -// As an alterantive properties may be applied with the standard -// library's flag implementation at any time. -// -// # Standard configuration -// v = flag.Int("key", 999, "help message") -// flag.Parse() -// -// # Merge p into the flag set -// p.MustFlag(flag.CommandLine) -// -// Properties provides several MustXXX() convenience functions -// which will terminate the app if an error occurs. The behavior -// of the failure is configurable and the default is to call -// log.Fatal(err). To have the MustXXX() functions panic instead -// of logging the error set a different ErrorHandler before -// you use the Properties package. -// -// properties.ErrorHandler = properties.PanicHandler -// -// # Will panic instead of logging an error -// p := properties.MustLoadFile("config.properties") -// -// You can also provide your own ErrorHandler function. The only requirement -// is that the error handler function must exit after handling the error. -// -// properties.ErrorHandler = func(err error) { -// fmt.Println(err) -// os.Exit(1) -// } -// -// # Will write to stdout and then exit -// p := properties.MustLoadFile("config.properties") -// -// Properties can also be loaded into a struct via the `Decode` -// method, e.g. -// -// type S struct { -// A string `properties:"a,default=foo"` -// D time.Duration `properties:"timeout,default=5s"` -// E time.Time `properties:"expires,layout=2006-01-02,default=2015-01-01"` -// } -// -// See `Decode()` method for the full documentation. -// -// The following documents provide a description of the properties -// file format. -// -// http://en.wikipedia.org/wiki/.properties -// -// http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29 -// -package properties diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/example_test.go b/Godeps/_workspace/src/github.com/magiconair/properties/example_test.go deleted file mode 100644 index 6f21dfb..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/example_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "log" -) - -func ExampleLoad_iso88591() { - buf := []byte("key = ISO-8859-1 value with unicode literal \\u2318 and umlaut \xE4") // 0xE4 == ä - p, _ := Load(buf, ISO_8859_1) - v, ok := p.Get("key") - fmt.Println(ok) - fmt.Println(v) - // Output: - // true - // ISO-8859-1 value with unicode literal ⌘ and umlaut ä -} - -func ExampleLoad_utf8() { - p, _ := Load([]byte("key = UTF-8 value with unicode character ⌘ and umlaut ä"), UTF8) - v, ok := p.Get("key") - fmt.Println(ok) - fmt.Println(v) - // Output: - // true - // UTF-8 value with unicode character ⌘ and umlaut ä -} - -func ExampleProperties_GetBool() { - var input = ` - key=1 - key2=On - key3=YES - key4=true` - p, _ := Load([]byte(input), ISO_8859_1) - fmt.Println(p.GetBool("key", false)) - fmt.Println(p.GetBool("key2", false)) - fmt.Println(p.GetBool("key3", false)) - fmt.Println(p.GetBool("key4", false)) - fmt.Println(p.GetBool("keyX", false)) - // Output: - // true - // true - // true - // true - // false -} - -func ExampleProperties_GetString() { - p, _ := Load([]byte("key=value"), ISO_8859_1) - v := p.GetString("another key", "default value") - fmt.Println(v) - // Output: - // default value -} - -func Example() { - // Decode some key/value pairs with expressions - p, err := Load([]byte("key=value\nkey2=${key}"), ISO_8859_1) - if err != nil { - log.Fatal(err) - } - - // Get a valid key - if v, ok := p.Get("key"); ok { - fmt.Println(v) - } - - // Get an invalid key - if _, ok := p.Get("does not exist"); !ok { - fmt.Println("invalid key") - } - - // Get a key with a default value - v := p.GetString("does not exist", "some value") - fmt.Println(v) - - // Dump the expanded key/value pairs of the Properties - fmt.Println("Expanded key/value pairs") - fmt.Println(p) - - // Output: - // value - // invalid key - // some value - // Expanded key/value pairs - // key = value - // key2 = value -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/integrate.go b/Godeps/_workspace/src/github.com/magiconair/properties/integrate.go deleted file mode 100644 index 0d775e0..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/integrate.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import "flag" - -// MustFlag sets flags that are skipped by dst.Parse when p contains -// the respective key for flag.Flag.Name. -// -// It's use is recommended with command line arguments as in: -// flag.Parse() -// p.MustFlag(flag.CommandLine) -func (p *Properties) MustFlag(dst *flag.FlagSet) { - m := make(map[string]*flag.Flag) - dst.VisitAll(func(f *flag.Flag) { - m[f.Name] = f - }) - dst.Visit(func(f *flag.Flag) { - delete(m, f.Name) // overridden - }) - - for name, f := range m { - v, ok := p.Get(name) - if !ok { - continue - } - - if err := f.Value.Set(v); err != nil { - ErrorHandler(err) - } - } -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/integrate_test.go b/Godeps/_workspace/src/github.com/magiconair/properties/integrate_test.go deleted file mode 100644 index cbee181..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/integrate_test.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "flag" - "fmt" - "testing" -) - -// TestFlag verifies Properties.MustFlag without flag.FlagSet.Parse -func TestFlag(t *testing.T) { - f := flag.NewFlagSet("src", flag.PanicOnError) - gotS := f.String("s", "?", "string flag") - gotI := f.Int("i", -1, "int flag") - - p := NewProperties() - p.MustSet("s", "t") - p.MustSet("i", "9") - p.MustFlag(f) - - if want := "t"; *gotS != want { - t.Errorf("Got string s=%q, want %q", *gotS, want) - } - if want := 9; *gotI != want { - t.Errorf("Got int i=%d, want %d", *gotI, want) - } -} - -// TestFlagOverride verifies Properties.MustFlag with flag.FlagSet.Parse. -func TestFlagOverride(t *testing.T) { - f := flag.NewFlagSet("src", flag.PanicOnError) - gotA := f.Int("a", 1, "remain default") - gotB := f.Int("b", 2, "customized") - gotC := f.Int("c", 3, "overridden") - - if err := f.Parse([]string{"-c", "4"}); err != nil { - t.Fatal(err) - } - - p := NewProperties() - p.MustSet("b", "5") - p.MustSet("c", "6") - p.MustFlag(f) - - if want := 1; *gotA != want { - t.Errorf("Got remain default a=%d, want %d", *gotA, want) - } - if want := 5; *gotB != want { - t.Errorf("Got customized b=%d, want %d", *gotB, want) - } - if want := 4; *gotC != want { - t.Errorf("Got overriden c=%d, want %d", *gotC, want) - } -} - -func ExampleProperties_MustFlag() { - x := flag.Int("x", 0, "demo customize") - y := flag.Int("y", 0, "demo override") - - // Demo alternative for flag.Parse(): - flag.CommandLine.Parse([]string{"-y", "10"}) - fmt.Printf("flagged as x=%d, y=%d\n", *x, *y) - - p := NewProperties() - p.MustSet("x", "7") - p.MustSet("y", "42") // note discard - p.MustFlag(flag.CommandLine) - fmt.Printf("configured to x=%d, y=%d\n", *x, *y) - - // Output: - // flagged as x=0, y=10 - // configured to x=7, y=10 -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/lex.go b/Godeps/_workspace/src/github.com/magiconair/properties/lex.go deleted file mode 100644 index c63fcc6..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/lex.go +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -// Parts of the lexer are from the template/text/parser package -// For these parts the following applies: -// -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file of the go 1.2 -// distribution. - -package properties - -import ( - "fmt" - "strconv" - "strings" - "unicode/utf8" -) - -// item represents a token or text string returned from the scanner. -type item struct { - typ itemType // The type of this item. - pos int // The starting position, in bytes, of this item in the input string. - val string // The value of this item. -} - -func (i item) String() string { - switch { - case i.typ == itemEOF: - return "EOF" - case i.typ == itemError: - return i.val - case len(i.val) > 10: - return fmt.Sprintf("%.10q...", i.val) - } - return fmt.Sprintf("%q", i.val) -} - -// itemType identifies the type of lex items. -type itemType int - -const ( - itemError itemType = iota // error occurred; value is text of error - itemEOF - itemKey // a key - itemValue // a value - itemComment // a comment -) - -// defines a constant for EOF -const eof = -1 - -// permitted whitespace characters space, FF and TAB -const whitespace = " \f\t" - -// stateFn represents the state of the scanner as a function that returns the next state. -type stateFn func(*lexer) stateFn - -// lexer holds the state of the scanner. -type lexer struct { - input string // the string being scanned - state stateFn // the next lexing function to enter - pos int // current position in the input - start int // start position of this item - width int // width of last rune read from input - lastPos int // position of most recent item returned by nextItem - runes []rune // scanned runes for this item - items chan item // channel of scanned items -} - -// next returns the next rune in the input. -func (l *lexer) next() rune { - if l.pos >= len(l.input) { - l.width = 0 - return eof - } - r, w := utf8.DecodeRuneInString(l.input[l.pos:]) - l.width = w - l.pos += l.width - return r -} - -// peek returns but does not consume the next rune in the input. -func (l *lexer) peek() rune { - r := l.next() - l.backup() - return r -} - -// backup steps back one rune. Can only be called once per call of next. -func (l *lexer) backup() { - l.pos -= l.width -} - -// emit passes an item back to the client. -func (l *lexer) emit(t itemType) { - i := item{t, l.start, string(l.runes)} - l.items <- i - l.start = l.pos - l.runes = l.runes[:0] -} - -// ignore skips over the pending input before this point. -func (l *lexer) ignore() { - l.start = l.pos -} - -// appends the rune to the current value -func (l *lexer) appendRune(r rune) { - l.runes = append(l.runes, r) -} - -// accept consumes the next rune if it's from the valid set. -func (l *lexer) accept(valid string) bool { - if strings.ContainsRune(valid, l.next()) { - return true - } - l.backup() - return false -} - -// acceptRun consumes a run of runes from the valid set. -func (l *lexer) acceptRun(valid string) { - for strings.ContainsRune(valid, l.next()) { - } - l.backup() -} - -// acceptRunUntil consumes a run of runes up to a terminator. -func (l *lexer) acceptRunUntil(term rune) { - for term != l.next() { - } - l.backup() -} - -// hasText returns true if the current parsed text is not empty. -func (l *lexer) isNotEmpty() bool { - return l.pos > l.start -} - -// lineNumber reports which line we're on, based on the position of -// the previous item returned by nextItem. Doing it this way -// means we don't have to worry about peek double counting. -func (l *lexer) lineNumber() int { - return 1 + strings.Count(l.input[:l.lastPos], "\n") -} - -// errorf returns an error token and terminates the scan by passing -// back a nil pointer that will be the next state, terminating l.nextItem. -func (l *lexer) errorf(format string, args ...interface{}) stateFn { - l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)} - return nil -} - -// nextItem returns the next item from the input. -func (l *lexer) nextItem() item { - i := <-l.items - l.lastPos = i.pos - return i -} - -// lex creates a new scanner for the input string. -func lex(input string) *lexer { - l := &lexer{ - input: input, - items: make(chan item), - runes: make([]rune, 0, 32), - } - go l.run() - return l -} - -// run runs the state machine for the lexer. -func (l *lexer) run() { - for l.state = lexBeforeKey(l); l.state != nil; { - l.state = l.state(l) - } -} - -// state functions - -// lexBeforeKey scans until a key begins. -func lexBeforeKey(l *lexer) stateFn { - switch r := l.next(); { - case isEOF(r): - l.emit(itemEOF) - return nil - - case isEOL(r): - l.ignore() - return lexBeforeKey - - case isComment(r): - return lexComment - - case isWhitespace(r): - l.ignore() - return lexBeforeKey - - default: - l.backup() - return lexKey - } -} - -// lexComment scans a comment line. The comment character has already been scanned. -func lexComment(l *lexer) stateFn { - l.acceptRun(whitespace) - l.ignore() - for { - switch r := l.next(); { - case isEOF(r): - l.ignore() - l.emit(itemEOF) - return nil - case isEOL(r): - l.emit(itemComment) - return lexBeforeKey - default: - l.appendRune(r) - } - } -} - -// lexKey scans the key up to a delimiter -func lexKey(l *lexer) stateFn { - var r rune - -Loop: - for { - switch r = l.next(); { - - case isEscape(r): - err := l.scanEscapeSequence() - if err != nil { - return l.errorf(err.Error()) - } - - case isEndOfKey(r): - l.backup() - break Loop - - case isEOF(r): - break Loop - - default: - l.appendRune(r) - } - } - - if len(l.runes) > 0 { - l.emit(itemKey) - } - - if isEOF(r) { - l.emit(itemEOF) - return nil - } - - return lexBeforeValue -} - -// lexBeforeValue scans the delimiter between key and value. -// Leading and trailing whitespace is ignored. -// We expect to be just after the key. -func lexBeforeValue(l *lexer) stateFn { - l.acceptRun(whitespace) - l.accept(":=") - l.acceptRun(whitespace) - l.ignore() - return lexValue -} - -// lexValue scans text until the end of the line. We expect to be just after the delimiter. -func lexValue(l *lexer) stateFn { - for { - switch r := l.next(); { - case isEscape(r): - if isEOL(l.peek()) { - l.next() - l.acceptRun(whitespace) - } else { - err := l.scanEscapeSequence() - if err != nil { - return l.errorf(err.Error()) - } - } - - case isEOL(r): - l.emit(itemValue) - l.ignore() - return lexBeforeKey - - case isEOF(r): - l.emit(itemValue) - l.emit(itemEOF) - return nil - - default: - l.appendRune(r) - } - } -} - -// scanEscapeSequence scans either one of the escaped characters -// or a unicode literal. We expect to be after the escape character. -func (l *lexer) scanEscapeSequence() error { - switch r := l.next(); { - - case isEscapedCharacter(r): - l.appendRune(decodeEscapedCharacter(r)) - return nil - - case atUnicodeLiteral(r): - return l.scanUnicodeLiteral() - - case isEOF(r): - return fmt.Errorf("premature EOF") - - // silently drop the escape character and append the rune as is - default: - l.appendRune(r) - return nil - } -} - -// scans a unicode literal in the form \uXXXX. We expect to be after the \u. -func (l *lexer) scanUnicodeLiteral() error { - // scan the digits - d := make([]rune, 4) - for i := 0; i < 4; i++ { - d[i] = l.next() - if d[i] == eof || !strings.ContainsRune("0123456789abcdefABCDEF", d[i]) { - return fmt.Errorf("invalid unicode literal") - } - } - - // decode the digits into a rune - r, err := strconv.ParseInt(string(d), 16, 0) - if err != nil { - return err - } - - l.appendRune(rune(r)) - return nil -} - -// decodeEscapedCharacter returns the unescaped rune. We expect to be after the escape character. -func decodeEscapedCharacter(r rune) rune { - switch r { - case 'f': - return '\f' - case 'n': - return '\n' - case 'r': - return '\r' - case 't': - return '\t' - default: - return r - } -} - -// atUnicodeLiteral reports whether we are at a unicode literal. -// The escape character has already been consumed. -func atUnicodeLiteral(r rune) bool { - return r == 'u' -} - -// isComment reports whether we are at the start of a comment. -func isComment(r rune) bool { - return r == '#' || r == '!' -} - -// isEndOfKey reports whether the rune terminates the current key. -func isEndOfKey(r rune) bool { - return strings.ContainsRune(" \f\t\r\n:=", r) -} - -// isEOF reports whether we are at EOF. -func isEOF(r rune) bool { - return r == eof -} - -// isEOL reports whether we are at a new line character. -func isEOL(r rune) bool { - return r == '\n' || r == '\r' -} - -// isEscape reports whether the rune is the escape character which -// prefixes unicode literals and other escaped characters. -func isEscape(r rune) bool { - return r == '\\' -} - -// isEscapedCharacter reports whether we are at one of the characters that need escaping. -// The escape character has already been consumed. -func isEscapedCharacter(r rune) bool { - return strings.ContainsRune(" :=fnrt", r) -} - -// isWhitespace reports whether the rune is a whitespace character. -func isWhitespace(r rune) bool { - return strings.ContainsRune(whitespace, r) -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/load.go b/Godeps/_workspace/src/github.com/magiconair/properties/load.go deleted file mode 100644 index 278cc2e..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/load.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "io/ioutil" - "net/http" - "os" - "strings" -) - -// Encoding specifies encoding of the input data. -type Encoding uint - -const ( - // UTF8 interprets the input data as UTF-8. - UTF8 Encoding = 1 << iota - - // ISO_8859_1 interprets the input data as ISO-8859-1. - ISO_8859_1 -) - -// Load reads a buffer into a Properties struct. -func Load(buf []byte, enc Encoding) (*Properties, error) { - return loadBuf(buf, enc) -} - -// LoadString reads an UTF8 string into a properties struct. -func LoadString(s string) (*Properties, error) { - return loadBuf([]byte(s), UTF8) -} - -// LoadMap creates a new Properties struct from a string map. -func LoadMap(m map[string]string) *Properties { - p := NewProperties() - for k, v := range m { - p.Set(k, v) - } - return p -} - -// LoadFile reads a file into a Properties struct. -func LoadFile(filename string, enc Encoding) (*Properties, error) { - return loadAll([]string{filename}, enc, false) -} - -// LoadFiles reads multiple files in the given order into -// a Properties struct. If 'ignoreMissing' is true then -// non-existent files will not be reported as error. -func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - return loadAll(filenames, enc, ignoreMissing) -} - -// LoadURL reads the content of the URL into a Properties struct. -// -// The encoding is determined via the Content-Type header which -// should be set to 'text/plain'. If the 'charset' parameter is -// missing, 'iso-8859-1' or 'latin1' the encoding is set to -// ISO-8859-1. If the 'charset' parameter is set to 'utf-8' the -// encoding is set to UTF-8. A missing content type header is -// interpreted as 'text/plain; charset=utf-8'. -func LoadURL(url string) (*Properties, error) { - return loadAll([]string{url}, UTF8, false) -} - -// LoadURLs reads the content of multiple URLs in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code will -// not be reported as error. See LoadURL for the Content-Type header -// and the encoding. -func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) { - return loadAll(urls, UTF8, ignoreMissing) -} - -// LoadAll reads the content of multiple URLs or files in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will -// not be reported as error. Encoding sets the encoding for files. For the URLs please see -// LoadURL for the Content-Type header and the encoding. -func LoadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - return loadAll(names, enc, ignoreMissing) -} - -// MustLoadString reads an UTF8 string into a Properties struct and -// panics on error. -func MustLoadString(s string) *Properties { - return must(LoadString(s)) -} - -// MustLoadFile reads a file into a Properties struct and -// panics on error. -func MustLoadFile(filename string, enc Encoding) *Properties { - return must(LoadFile(filename, enc)) -} - -// MustLoadFiles reads multiple files in the given order into -// a Properties struct and panics on error. If 'ignoreMissing' -// is true then non-existent files will not be reported as error. -func MustLoadFiles(filenames []string, enc Encoding, ignoreMissing bool) *Properties { - return must(LoadFiles(filenames, enc, ignoreMissing)) -} - -// MustLoadURL reads the content of a URL into a Properties struct and -// panics on error. -func MustLoadURL(url string) *Properties { - return must(LoadURL(url)) -} - -// MustLoadURLs reads the content of multiple URLs in the given order into a -// Properties struct and panics on error. If 'ignoreMissing' is true then a 404 -// status code will not be reported as error. -func MustLoadURLs(urls []string, ignoreMissing bool) *Properties { - return must(LoadURLs(urls, ignoreMissing)) -} - -// MustLoadAll reads the content of multiple URLs or files in the given order into a -// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will -// not be reported as error. Encoding sets the encoding for files. For the URLs please see -// LoadURL for the Content-Type header and the encoding. It panics on error. -func MustLoadAll(names []string, enc Encoding, ignoreMissing bool) *Properties { - return must(LoadAll(names, enc, ignoreMissing)) -} - -func loadBuf(buf []byte, enc Encoding) (*Properties, error) { - p, err := parse(convert(buf, enc)) - if err != nil { - return nil, err - } - return p, p.check() -} - -func loadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) { - result := NewProperties() - for _, name := range names { - n, err := expandName(name) - if err != nil { - return nil, err - } - var p *Properties - if strings.HasPrefix(n, "http://") || strings.HasPrefix(n, "https://") { - p, err = loadURL(n, ignoreMissing) - } else { - p, err = loadFile(n, enc, ignoreMissing) - } - if err != nil { - return nil, err - } - result.Merge(p) - - } - return result, result.check() -} - -func loadFile(filename string, enc Encoding, ignoreMissing bool) (*Properties, error) { - data, err := ioutil.ReadFile(filename) - if err != nil { - if ignoreMissing && os.IsNotExist(err) { - LogPrintf("properties: %s not found. skipping", filename) - return NewProperties(), nil - } - return nil, err - } - p, err := parse(convert(data, enc)) - if err != nil { - return nil, err - } - return p, nil -} - -func loadURL(url string, ignoreMissing bool) (*Properties, error) { - resp, err := http.Get(url) - if err != nil { - return nil, fmt.Errorf("properties: error fetching %q. %s", url, err) - } - if resp.StatusCode == 404 && ignoreMissing { - LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode) - return NewProperties(), nil - } - if resp.StatusCode != 200 { - return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode) - } - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) - } - if err = resp.Body.Close(); err != nil { - return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) - } - - ct := resp.Header.Get("Content-Type") - var enc Encoding - switch strings.ToLower(ct) { - case "text/plain", "text/plain; charset=iso-8859-1", "text/plain; charset=latin1": - enc = ISO_8859_1 - case "", "text/plain; charset=utf-8": - enc = UTF8 - default: - return nil, fmt.Errorf("properties: invalid content type %s", ct) - } - - p, err := parse(convert(body, enc)) - if err != nil { - return nil, err - } - return p, nil -} - -func must(p *Properties, err error) *Properties { - if err != nil { - ErrorHandler(err) - } - return p -} - -// expandName expands ${ENV_VAR} expressions in a name. -// If the environment variable does not exist then it will be replaced -// with an empty string. Malformed expressions like "${ENV_VAR" will -// be reported as error. -func expandName(name string) (string, error) { - return expand(name, make(map[string]bool), "${", "}", make(map[string]string)) -} - -// Interprets a byte buffer either as an ISO-8859-1 or UTF-8 encoded string. -// For ISO-8859-1 we can convert each byte straight into a rune since the -// first 256 unicode code points cover ISO-8859-1. -func convert(buf []byte, enc Encoding) string { - switch enc { - case UTF8: - return string(buf) - case ISO_8859_1: - runes := make([]rune, len(buf)) - for i, b := range buf { - runes[i] = rune(b) - } - return string(runes) - default: - ErrorHandler(fmt.Errorf("unsupported encoding %v", enc)) - } - panic("ErrorHandler should exit") -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/load_test.go b/Godeps/_workspace/src/github.com/magiconair/properties/load_test.go deleted file mode 100644 index d8770c8..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/load_test.go +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "strings" - "testing" - - "github.com/magiconair/properties/assert" -) - -func TestLoadFailsWithNotExistingFile(t *testing.T) { - _, err := LoadFile("doesnotexist.properties", ISO_8859_1) - assert.Equal(t, err != nil, true, "") - assert.Matches(t, err.Error(), "open.*no such file or directory") -} - -func TestLoadFilesFailsOnNotExistingFile(t *testing.T) { - _, err := LoadFile("doesnotexist.properties", ISO_8859_1) - assert.Equal(t, err != nil, true, "") - assert.Matches(t, err.Error(), "open.*no such file or directory") -} - -func TestLoadFilesDoesNotFailOnNotExistingFileAndIgnoreMissing(t *testing.T) { - p, err := LoadFiles([]string{"doesnotexist.properties"}, ISO_8859_1, true) - assert.Equal(t, err, nil) - assert.Equal(t, p.Len(), 0) -} - -func TestLoadString(t *testing.T) { - x := "key=äüö" - p1 := MustLoadString(x) - p2 := must(Load([]byte(x), UTF8)) - assert.Equal(t, p1, p2) -} - -func TestLoadMap(t *testing.T) { - // LoadMap does not guarantee the same import order - // of keys every time since map access is randomized. - // Therefore, we need to compare the generated maps. - m := map[string]string{"key": "value", "abc": "def"} - assert.Equal(t, LoadMap(m).Map(), m) -} - -func TestLoadFile(t *testing.T) { - tf := make(tempFiles, 0) - defer tf.removeAll() - - filename := tf.makeFile("key=value") - p := MustLoadFile(filename, ISO_8859_1) - - assert.Equal(t, p.Len(), 1) - assertKeyValues(t, "", p, "key", "value") -} - -func TestLoadFiles(t *testing.T) { - tf := make(tempFiles, 0) - defer tf.removeAll() - - filename := tf.makeFile("key=value") - filename2 := tf.makeFile("key2=value2") - p := MustLoadFiles([]string{filename, filename2}, ISO_8859_1, false) - assertKeyValues(t, "", p, "key", "value", "key2", "value2") -} - -func TestLoadExpandedFile(t *testing.T) { - tf := make(tempFiles, 0) - defer tf.removeAll() - - if err := os.Setenv("_VARX", "some-value"); err != nil { - t.Fatal(err) - } - filename := tf.makeFilePrefix(os.Getenv("_VARX"), "key=value") - filename = strings.Replace(filename, os.Getenv("_VARX"), "${_VARX}", -1) - p := MustLoadFile(filename, ISO_8859_1) - assertKeyValues(t, "", p, "key", "value") -} - -func TestLoadFilesAndIgnoreMissing(t *testing.T) { - tf := make(tempFiles, 0) - defer tf.removeAll() - - filename := tf.makeFile("key=value") - filename2 := tf.makeFile("key2=value2") - p := MustLoadFiles([]string{filename, filename + "foo", filename2, filename2 + "foo"}, ISO_8859_1, true) - assertKeyValues(t, "", p, "key", "value", "key2", "value2") -} - -func TestLoadURL(t *testing.T) { - srv := testServer() - defer srv.Close() - p := MustLoadURL(srv.URL + "/a") - assertKeyValues(t, "", p, "key", "value") -} - -func TestLoadURLs(t *testing.T) { - srv := testServer() - defer srv.Close() - p := MustLoadURLs([]string{srv.URL + "/a", srv.URL + "/b"}, false) - assertKeyValues(t, "", p, "key", "value", "key2", "value2") -} - -func TestLoadURLsAndFailMissing(t *testing.T) { - srv := testServer() - defer srv.Close() - p, err := LoadURLs([]string{srv.URL + "/a", srv.URL + "/c"}, false) - assert.Equal(t, p, (*Properties)(nil)) - assert.Matches(t, err.Error(), ".*returned 404.*") -} - -func TestLoadURLsAndIgnoreMissing(t *testing.T) { - srv := testServer() - defer srv.Close() - p := MustLoadURLs([]string{srv.URL + "/a", srv.URL + "/b", srv.URL + "/c"}, true) - assertKeyValues(t, "", p, "key", "value", "key2", "value2") -} - -func TestLoadURLEncoding(t *testing.T) { - srv := testServer() - defer srv.Close() - - uris := []string{"/none", "/utf8", "/plain", "/latin1", "/iso88591"} - for i, uri := range uris { - p := MustLoadURL(srv.URL + uri) - assert.Equal(t, p.GetString("key", ""), "äöü", fmt.Sprintf("%d", i)) - } -} - -func TestLoadURLFailInvalidEncoding(t *testing.T) { - srv := testServer() - defer srv.Close() - - p, err := LoadURL(srv.URL + "/json") - assert.Equal(t, p, (*Properties)(nil)) - assert.Matches(t, err.Error(), ".*invalid content type.*") -} - -func TestLoadAll(t *testing.T) { - tf := make(tempFiles, 0) - defer tf.removeAll() - - filename := tf.makeFile("key=value") - filename2 := tf.makeFile("key2=value3") - filename3 := tf.makeFile("key=value4") - srv := testServer() - defer srv.Close() - p := MustLoadAll([]string{filename, filename2, srv.URL + "/a", srv.URL + "/b", filename3}, UTF8, false) - assertKeyValues(t, "", p, "key", "value4", "key2", "value2") -} - -type tempFiles []string - -func (tf *tempFiles) removeAll() { - for _, path := range *tf { - err := os.Remove(path) - if err != nil { - fmt.Printf("os.Remove: %v", err) - } - } -} - -func (tf *tempFiles) makeFile(data string) string { - return tf.makeFilePrefix("properties", data) -} - -func (tf *tempFiles) makeFilePrefix(prefix, data string) string { - f, err := ioutil.TempFile("", prefix) - if err != nil { - panic("ioutil.TempFile: " + err.Error()) - } - - // remember the temp file so that we can remove it later - *tf = append(*tf, f.Name()) - - n, err := fmt.Fprint(f, data) - if err != nil { - panic("fmt.Fprintln: " + err.Error()) - } - if n != len(data) { - panic(fmt.Sprintf("Data size mismatch. expected=%d wrote=%d\n", len(data), n)) - } - - err = f.Close() - if err != nil { - panic("f.Close: " + err.Error()) - } - - return f.Name() -} - -func testServer() *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - send := func(data []byte, contentType string) { - w.Header().Set("Content-Type", contentType) - if _, err := w.Write(data); err != nil { - panic(err) - } - } - - utf8 := []byte("key=äöü") - iso88591 := []byte{0x6b, 0x65, 0x79, 0x3d, 0xe4, 0xf6, 0xfc} // key=äöü - - switch r.RequestURI { - case "/a": - send([]byte("key=value"), "") - case "/b": - send([]byte("key2=value2"), "") - case "/none": - send(utf8, "") - case "/utf8": - send(utf8, "text/plain; charset=utf-8") - case "/json": - send(utf8, "application/json; charset=utf-8") - case "/plain": - send(iso88591, "text/plain") - case "/latin1": - send(iso88591, "text/plain; charset=latin1") - case "/iso88591": - send(iso88591, "text/plain; charset=iso-8859-1") - default: - w.WriteHeader(404) - } - })) -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/parser.go b/Godeps/_workspace/src/github.com/magiconair/properties/parser.go deleted file mode 100644 index 90f555c..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/parser.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "runtime" -) - -type parser struct { - lex *lexer -} - -func parse(input string) (properties *Properties, err error) { - p := &parser{lex: lex(input)} - defer p.recover(&err) - - properties = NewProperties() - key := "" - comments := []string{} - - for { - token := p.expectOneOf(itemComment, itemKey, itemEOF) - switch token.typ { - case itemEOF: - goto done - case itemComment: - comments = append(comments, token.val) - continue - case itemKey: - key = token.val - if _, ok := properties.m[key]; !ok { - properties.k = append(properties.k, key) - } - } - - token = p.expectOneOf(itemValue, itemEOF) - if len(comments) > 0 { - properties.c[key] = comments - comments = []string{} - } - switch token.typ { - case itemEOF: - properties.m[key] = "" - goto done - case itemValue: - properties.m[key] = token.val - } - } - -done: - return properties, nil -} - -func (p *parser) errorf(format string, args ...interface{}) { - format = fmt.Sprintf("properties: Line %d: %s", p.lex.lineNumber(), format) - panic(fmt.Errorf(format, args...)) -} - -func (p *parser) expect(expected itemType) (token item) { - token = p.lex.nextItem() - if token.typ != expected { - p.unexpected(token) - } - return token -} - -func (p *parser) expectOneOf(expected ...itemType) (token item) { - token = p.lex.nextItem() - for _, v := range expected { - if token.typ == v { - return token - } - } - p.unexpected(token) - panic("unexpected token") -} - -func (p *parser) unexpected(token item) { - p.errorf(token.String()) -} - -// recover is the handler that turns panics into returns from the top level of Parse. -func (p *parser) recover(errp *error) { - e := recover() - if e != nil { - if _, ok := e.(runtime.Error); ok { - panic(e) - } - *errp = e.(error) - } - return -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/properties.go b/Godeps/_workspace/src/github.com/magiconair/properties/properties.go deleted file mode 100644 index 85bb186..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/properties.go +++ /dev/null @@ -1,811 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -// BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer. -// BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used. - -import ( - "fmt" - "io" - "log" - "os" - "regexp" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -// ErrorHandlerFunc defines the type of function which handles failures -// of the MustXXX() functions. An error handler function must exit -// the application after handling the error. -type ErrorHandlerFunc func(error) - -// ErrorHandler is the function which handles failures of the MustXXX() -// functions. The default is LogFatalHandler. -var ErrorHandler ErrorHandlerFunc = LogFatalHandler - -// LogHandlerFunc defines the function prototype for logging errors. -type LogHandlerFunc func(fmt string, args ...interface{}) - -// LogPrintf defines a log handler which uses log.Printf. -var LogPrintf LogHandlerFunc = log.Printf - -// LogFatalHandler handles the error by logging a fatal error and exiting. -func LogFatalHandler(err error) { - log.Fatal(err) -} - -// PanicHandler handles the error by panicking. -func PanicHandler(err error) { - panic(err) -} - -// ----------------------------------------------------------------------------- - -// A Properties contains the key/value pairs from the properties input. -// All values are stored in unexpanded form and are expanded at runtime -type Properties struct { - // Pre-/Postfix for property expansion. - Prefix string - Postfix string - - // DisableExpansion controls the expansion of properties on Get() - // and the check for circular references on Set(). When set to - // true Properties behaves like a simple key/value store and does - // not check for circular references on Get() or on Set(). - DisableExpansion bool - - // Stores the key/value pairs - m map[string]string - - // Stores the comments per key. - c map[string][]string - - // Stores the keys in order of appearance. - k []string -} - -// NewProperties creates a new Properties struct with the default -// configuration for "${key}" expressions. -func NewProperties() *Properties { - return &Properties{ - Prefix: "${", - Postfix: "}", - m: map[string]string{}, - c: map[string][]string{}, - k: []string{}, - } -} - -// Get returns the expanded value for the given key if exists. -// Otherwise, ok is false. -func (p *Properties) Get(key string) (value string, ok bool) { - v, ok := p.m[key] - if p.DisableExpansion { - return v, ok - } - if !ok { - return "", false - } - - expanded, err := p.expand(v) - - // we guarantee that the expanded value is free of - // circular references and malformed expressions - // so we panic if we still get an error here. - if err != nil { - ErrorHandler(fmt.Errorf("%s in %q", err, key+" = "+v)) - } - - return expanded, true -} - -// MustGet returns the expanded value for the given key if exists. -// Otherwise, it panics. -func (p *Properties) MustGet(key string) string { - if v, ok := p.Get(key); ok { - return v - } - ErrorHandler(invalidKeyError(key)) - panic("ErrorHandler should exit") -} - -// ---------------------------------------------------------------------------- - -// ClearComments removes the comments for all keys. -func (p *Properties) ClearComments() { - p.c = map[string][]string{} -} - -// ---------------------------------------------------------------------------- - -// GetComment returns the last comment before the given key or an empty string. -func (p *Properties) GetComment(key string) string { - comments, ok := p.c[key] - if !ok || len(comments) == 0 { - return "" - } - return comments[len(comments)-1] -} - -// ---------------------------------------------------------------------------- - -// GetComments returns all comments that appeared before the given key or nil. -func (p *Properties) GetComments(key string) []string { - if comments, ok := p.c[key]; ok { - return comments - } - return nil -} - -// ---------------------------------------------------------------------------- - -// SetComment sets the comment for the key. -func (p *Properties) SetComment(key, comment string) { - p.c[key] = []string{comment} -} - -// ---------------------------------------------------------------------------- - -// SetComments sets the comments for the key. If the comments are nil then -// all comments for this key are deleted. -func (p *Properties) SetComments(key string, comments []string) { - if comments == nil { - delete(p.c, key) - return - } - p.c[key] = comments -} - -// ---------------------------------------------------------------------------- - -// GetBool checks if the expanded value is one of '1', 'yes', -// 'true' or 'on' if the key exists. The comparison is case-insensitive. -// If the key does not exist the default value is returned. -func (p *Properties) GetBool(key string, def bool) bool { - v, err := p.getBool(key) - if err != nil { - return def - } - return v -} - -// MustGetBool checks if the expanded value is one of '1', 'yes', -// 'true' or 'on' if the key exists. The comparison is case-insensitive. -// If the key does not exist the function panics. -func (p *Properties) MustGetBool(key string) bool { - v, err := p.getBool(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getBool(key string) (value bool, err error) { - if v, ok := p.Get(key); ok { - return boolVal(v), nil - } - return false, invalidKeyError(key) -} - -func boolVal(v string) bool { - v = strings.ToLower(v) - return v == "1" || v == "true" || v == "yes" || v == "on" -} - -// ---------------------------------------------------------------------------- - -// GetDuration parses the expanded value as an time.Duration (in ns) if the -// key exists. If key does not exist or the value cannot be parsed the default -// value is returned. In almost all cases you want to use GetParsedDuration(). -func (p *Properties) GetDuration(key string, def time.Duration) time.Duration { - v, err := p.getInt64(key) - if err != nil { - return def - } - return time.Duration(v) -} - -// MustGetDuration parses the expanded value as an time.Duration (in ns) if -// the key exists. If key does not exist or the value cannot be parsed the -// function panics. In almost all cases you want to use MustGetParsedDuration(). -func (p *Properties) MustGetDuration(key string) time.Duration { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return time.Duration(v) -} - -// ---------------------------------------------------------------------------- - -// GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration { - s, ok := p.Get(key) - if !ok { - return def - } - v, err := time.ParseDuration(s) - if err != nil { - return def - } - return v -} - -// MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetParsedDuration(key string) time.Duration { - s, ok := p.Get(key) - if !ok { - ErrorHandler(invalidKeyError(key)) - } - v, err := time.ParseDuration(s) - if err != nil { - ErrorHandler(err) - } - return v -} - -// ---------------------------------------------------------------------------- - -// GetFloat64 parses the expanded value as a float64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetFloat64(key string, def float64) float64 { - v, err := p.getFloat64(key) - if err != nil { - return def - } - return v -} - -// MustGetFloat64 parses the expanded value as a float64 if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetFloat64(key string) float64 { - v, err := p.getFloat64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getFloat64(key string) (value float64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseFloat(v, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetInt parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. If the value does not fit into an int the -// function panics with an out of range error. -func (p *Properties) GetInt(key string, def int) int { - v, err := p.getInt64(key) - if err != nil { - return def - } - return intRangeCheck(key, v) -} - -// MustGetInt parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -// If the value does not fit into an int the function panics with -// an out of range error. -func (p *Properties) MustGetInt(key string) int { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return intRangeCheck(key, v) -} - -// ---------------------------------------------------------------------------- - -// GetInt64 parses the expanded value as an int64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetInt64(key string, def int64) int64 { - v, err := p.getInt64(key) - if err != nil { - return def - } - return v -} - -// MustGetInt64 parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetInt64(key string) int64 { - v, err := p.getInt64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getInt64(key string) (value int64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseInt(v, 10, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetUint parses the expanded value as an uint if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. If the value does not fit into an int the -// function panics with an out of range error. -func (p *Properties) GetUint(key string, def uint) uint { - v, err := p.getUint64(key) - if err != nil { - return def - } - return uintRangeCheck(key, v) -} - -// MustGetUint parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -// If the value does not fit into an int the function panics with -// an out of range error. -func (p *Properties) MustGetUint(key string) uint { - v, err := p.getUint64(key) - if err != nil { - ErrorHandler(err) - } - return uintRangeCheck(key, v) -} - -// ---------------------------------------------------------------------------- - -// GetUint64 parses the expanded value as an uint64 if the key exists. -// If key does not exist or the value cannot be parsed the default -// value is returned. -func (p *Properties) GetUint64(key string, def uint64) uint64 { - v, err := p.getUint64(key) - if err != nil { - return def - } - return v -} - -// MustGetUint64 parses the expanded value as an int if the key exists. -// If key does not exist or the value cannot be parsed the function panics. -func (p *Properties) MustGetUint64(key string) uint64 { - v, err := p.getUint64(key) - if err != nil { - ErrorHandler(err) - } - return v -} - -func (p *Properties) getUint64(key string) (value uint64, err error) { - if v, ok := p.Get(key); ok { - value, err = strconv.ParseUint(v, 10, 64) - if err != nil { - return 0, err - } - return value, nil - } - return 0, invalidKeyError(key) -} - -// ---------------------------------------------------------------------------- - -// GetString returns the expanded value for the given key if exists or -// the default value otherwise. -func (p *Properties) GetString(key, def string) string { - if v, ok := p.Get(key); ok { - return v - } - return def -} - -// MustGetString returns the expanded value for the given key if exists or -// panics otherwise. -func (p *Properties) MustGetString(key string) string { - if v, ok := p.Get(key); ok { - return v - } - ErrorHandler(invalidKeyError(key)) - panic("ErrorHandler should exit") -} - -// ---------------------------------------------------------------------------- - -// Filter returns a new properties object which contains all properties -// for which the key matches the pattern. -func (p *Properties) Filter(pattern string) (*Properties, error) { - re, err := regexp.Compile(pattern) - if err != nil { - return nil, err - } - - return p.FilterRegexp(re), nil -} - -// FilterRegexp returns a new properties object which contains all properties -// for which the key matches the regular expression. -func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties { - pp := NewProperties() - for _, k := range p.k { - if re.MatchString(k) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed) - pp.Set(k, p.m[k]) - } - } - return pp -} - -// FilterPrefix returns a new properties object with a subset of all keys -// with the given prefix. -func (p *Properties) FilterPrefix(prefix string) *Properties { - pp := NewProperties() - for _, k := range p.k { - if strings.HasPrefix(k, prefix) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed) - pp.Set(k, p.m[k]) - } - } - return pp -} - -// FilterStripPrefix returns a new properties object with a subset of all keys -// with the given prefix and the prefix removed from the keys. -func (p *Properties) FilterStripPrefix(prefix string) *Properties { - pp := NewProperties() - n := len(prefix) - for _, k := range p.k { - if len(k) > len(prefix) && strings.HasPrefix(k, prefix) { - // TODO(fs): we are ignoring the error which flags a circular reference. - // TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference - // TODO(fs): this function should probably return an error but the signature is fixed - pp.Set(k[n:], p.m[k]) - } - } - return pp -} - -// Len returns the number of keys. -func (p *Properties) Len() int { - return len(p.m) -} - -// Keys returns all keys in the same order as in the input. -func (p *Properties) Keys() []string { - keys := make([]string, len(p.k)) - copy(keys, p.k) - return keys -} - -// Set sets the property key to the corresponding value. -// If a value for key existed before then ok is true and prev -// contains the previous value. If the value contains a -// circular reference or a malformed expression then -// an error is returned. -// An empty key is silently ignored. -func (p *Properties) Set(key, value string) (prev string, ok bool, err error) { - if key == "" { - return "", false, nil - } - - // if expansion is disabled we allow circular references - if p.DisableExpansion { - prev, ok = p.Get(key) - p.m[key] = value - if !ok { - p.k = append(p.k, key) - } - return prev, ok, nil - } - - // to check for a circular reference we temporarily need - // to set the new value. If there is an error then revert - // to the previous state. Only if all tests are successful - // then we add the key to the p.k list. - prev, ok = p.Get(key) - p.m[key] = value - - // now check for a circular reference - _, err = p.expand(value) - if err != nil { - - // revert to the previous state - if ok { - p.m[key] = prev - } else { - delete(p.m, key) - } - - return "", false, err - } - - if !ok { - p.k = append(p.k, key) - } - - return prev, ok, nil -} - -// SetValue sets property key to the default string value -// as defined by fmt.Sprintf("%v"). -func (p *Properties) SetValue(key string, value interface{}) error { - _, _, err := p.Set(key, fmt.Sprintf("%v", value)) - return err -} - -// MustSet sets the property key to the corresponding value. -// If a value for key existed before then ok is true and prev -// contains the previous value. An empty key is silently ignored. -func (p *Properties) MustSet(key, value string) (prev string, ok bool) { - prev, ok, err := p.Set(key, value) - if err != nil { - ErrorHandler(err) - } - return prev, ok -} - -// String returns a string of all expanded 'key = value' pairs. -func (p *Properties) String() string { - var s string - for _, key := range p.k { - value, _ := p.Get(key) - s = fmt.Sprintf("%s%s = %s\n", s, key, value) - } - return s -} - -// Write writes all unexpanded 'key = value' pairs to the given writer. -// Write returns the number of bytes written and any write error encountered. -func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) { - return p.WriteComment(w, "", enc) -} - -// WriteComment writes all unexpanced 'key = value' pairs to the given writer. -// If prefix is not empty then comments are written with a blank line and the -// given prefix. The prefix should be either "# " or "! " to be compatible with -// the properties file format. Otherwise, the properties parser will not be -// able to read the file back in. It returns the number of bytes written and -// any write error encountered. -func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) { - var x int - - for _, key := range p.k { - value := p.m[key] - - if prefix != "" { - if comments, ok := p.c[key]; ok { - // don't print comments if they are all empty - allEmpty := true - for _, c := range comments { - if c != "" { - allEmpty = false - break - } - } - - if !allEmpty { - // add a blank line between entries but not at the top - if len(comments) > 0 && n > 0 { - x, err = fmt.Fprintln(w) - if err != nil { - return - } - n += x - } - - for _, c := range comments { - x, err = fmt.Fprintf(w, "%s%s\n", prefix, encode(c, "", enc)) - if err != nil { - return - } - n += x - } - } - } - } - - x, err = fmt.Fprintf(w, "%s = %s\n", encode(key, " :", enc), encode(value, "", enc)) - if err != nil { - return - } - n += x - } - return -} - -// Map returns a copy of the properties as a map. -func (p *Properties) Map() map[string]string { - m := make(map[string]string) - for k, v := range p.m { - m[k] = v - } - return m -} - -// FilterFunc returns a copy of the properties which includes the values which passed all filters. -func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties { - pp := NewProperties() -outer: - for k, v := range p.m { - for _, f := range filters { - if !f(k, v) { - continue outer - } - pp.Set(k, v) - } - } - return pp -} - -// ---------------------------------------------------------------------------- - -// Delete removes the key and its comments. -func (p *Properties) Delete(key string) { - delete(p.m, key) - delete(p.c, key) - newKeys := []string{} - for _, k := range p.k { - if k != key { - newKeys = append(newKeys, k) - } - } - p.k = newKeys -} - -// Merge merges properties, comments and keys from other *Properties into p -func (p *Properties) Merge(other *Properties) { - for k, v := range other.m { - p.m[k] = v - } - for k, v := range other.c { - p.c[k] = v - } - -outer: - for _, otherKey := range other.k { - for _, key := range p.k { - if otherKey == key { - continue outer - } - } - p.k = append(p.k, otherKey) - } -} - -// ---------------------------------------------------------------------------- - -// check expands all values and returns an error if a circular reference or -// a malformed expression was found. -func (p *Properties) check() error { - for _, value := range p.m { - if _, err := p.expand(value); err != nil { - return err - } - } - return nil -} - -func (p *Properties) expand(input string) (string, error) { - // no pre/postfix -> nothing to expand - if p.Prefix == "" && p.Postfix == "" { - return input, nil - } - - return expand(input, make(map[string]bool), p.Prefix, p.Postfix, p.m) -} - -// expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values. -// The function keeps track of the keys that were already expanded and stops if it -// detects a circular reference or a malformed expression of the form '(prefix)key'. -func expand(s string, keys map[string]bool, prefix, postfix string, values map[string]string) (string, error) { - start := strings.Index(s, prefix) - if start == -1 { - return s, nil - } - - keyStart := start + len(prefix) - keyLen := strings.Index(s[keyStart:], postfix) - if keyLen == -1 { - return "", fmt.Errorf("malformed expression") - } - - end := keyStart + keyLen + len(postfix) - 1 - key := s[keyStart : keyStart+keyLen] - - // fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key) - - if _, ok := keys[key]; ok { - return "", fmt.Errorf("circular reference") - } - - val, ok := values[key] - if !ok { - val = os.Getenv(key) - } - - // remember that we've seen the key - keys[key] = true - - return expand(s[:start]+val+s[end+1:], keys, prefix, postfix, values) -} - -// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters. -func encode(s string, special string, enc Encoding) string { - switch enc { - case UTF8: - return encodeUtf8(s, special) - case ISO_8859_1: - return encodeIso(s, special) - default: - panic(fmt.Sprintf("unsupported encoding %v", enc)) - } -} - -func encodeUtf8(s string, special string) string { - v := "" - for pos := 0; pos < len(s); { - r, w := utf8.DecodeRuneInString(s[pos:]) - pos += w - v += escape(r, special) - } - return v -} - -func encodeIso(s string, special string) string { - var r rune - var w int - var v string - for pos := 0; pos < len(s); { - switch r, w = utf8.DecodeRuneInString(s[pos:]); { - case r < 1<<8: // single byte rune -> escape special chars only - v += escape(r, special) - case r < 1<<16: // two byte rune -> unicode literal - v += fmt.Sprintf("\\u%04x", r) - default: // more than two bytes per rune -> can't encode - v += "?" - } - pos += w - } - return v -} - -func escape(r rune, special string) string { - switch r { - case '\f': - return "\\f" - case '\n': - return "\\n" - case '\r': - return "\\r" - case '\t': - return "\\t" - default: - if strings.ContainsRune(special, r) { - return "\\" + string(r) - } - return string(r) - } -} - -func invalidKeyError(key string) error { - return fmt.Errorf("unknown property: %s", key) -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/properties_test.go b/Godeps/_workspace/src/github.com/magiconair/properties/properties_test.go deleted file mode 100644 index a22f48d..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/properties_test.go +++ /dev/null @@ -1,949 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "bytes" - "flag" - "fmt" - "math" - "os" - "reflect" - "strings" - "testing" - "time" - - "github.com/magiconair/properties/assert" -) - -var verbose = flag.Bool("verbose", false, "Verbose output") - -func init() { - ErrorHandler = PanicHandler -} - -// ---------------------------------------------------------------------------- - -// define test cases in the form of -// {"input", "key1", "value1", "key2", "value2", ...} -var complexTests = [][]string{ - // whitespace prefix - {" key=value", "key", "value"}, // SPACE prefix - {"\fkey=value", "key", "value"}, // FF prefix - {"\tkey=value", "key", "value"}, // TAB prefix - {" \f\tkey=value", "key", "value"}, // mix prefix - - // multiple keys - {"key1=value1\nkey2=value2\n", "key1", "value1", "key2", "value2"}, - {"key1=value1\rkey2=value2\r", "key1", "value1", "key2", "value2"}, - {"key1=value1\r\nkey2=value2\r\n", "key1", "value1", "key2", "value2"}, - - // blank lines - {"\nkey=value\n", "key", "value"}, - {"\rkey=value\r", "key", "value"}, - {"\r\nkey=value\r\n", "key", "value"}, - {"\nkey=value\n \nkey2=value2", "key", "value", "key2", "value2"}, - {"\nkey=value\n\t\nkey2=value2", "key", "value", "key2", "value2"}, - - // escaped chars in key - {"k\\ ey = value", "k ey", "value"}, - {"k\\:ey = value", "k:ey", "value"}, - {"k\\=ey = value", "k=ey", "value"}, - {"k\\fey = value", "k\fey", "value"}, - {"k\\ney = value", "k\ney", "value"}, - {"k\\rey = value", "k\rey", "value"}, - {"k\\tey = value", "k\tey", "value"}, - - // escaped chars in value - {"key = v\\ alue", "key", "v alue"}, - {"key = v\\:alue", "key", "v:alue"}, - {"key = v\\=alue", "key", "v=alue"}, - {"key = v\\falue", "key", "v\falue"}, - {"key = v\\nalue", "key", "v\nalue"}, - {"key = v\\ralue", "key", "v\ralue"}, - {"key = v\\talue", "key", "v\talue"}, - - // silently dropped escape character - {"k\\zey = value", "kzey", "value"}, - {"key = v\\zalue", "key", "vzalue"}, - - // unicode literals - {"key\\u2318 = value", "key⌘", "value"}, - {"k\\u2318ey = value", "k⌘ey", "value"}, - {"key = value\\u2318", "key", "value⌘"}, - {"key = valu\\u2318e", "key", "valu⌘e"}, - - // multiline values - {"key = valueA,\\\n valueB", "key", "valueA,valueB"}, // SPACE indent - {"key = valueA,\\\n\f\f\fvalueB", "key", "valueA,valueB"}, // FF indent - {"key = valueA,\\\n\t\t\tvalueB", "key", "valueA,valueB"}, // TAB indent - {"key = valueA,\\\n \f\tvalueB", "key", "valueA,valueB"}, // mix indent - - // comments - {"# this is a comment\n! and so is this\nkey1=value1\nkey#2=value#2\n\nkey!3=value!3\n# and another one\n! and the final one", "key1", "value1", "key#2", "value#2", "key!3", "value!3"}, - - // expansion tests - {"key=value\nkey2=${key}", "key", "value", "key2", "value"}, - {"key=value\nkey2=aa${key}", "key", "value", "key2", "aavalue"}, - {"key=value\nkey2=${key}bb", "key", "value", "key2", "valuebb"}, - {"key=value\nkey2=aa${key}bb", "key", "value", "key2", "aavaluebb"}, - {"key=value\nkey2=${key}\nkey3=${key2}", "key", "value", "key2", "value", "key3", "value"}, - {"key=${USER}", "key", os.Getenv("USER")}, - {"key=${USER}\nUSER=value", "key", "value", "USER", "value"}, -} - -// ---------------------------------------------------------------------------- - -var commentTests = []struct { - input, key, value string - comments []string -}{ - {"key=value", "key", "value", nil}, - {"#\nkey=value", "key", "value", []string{""}}, - {"#comment\nkey=value", "key", "value", []string{"comment"}}, - {"# comment\nkey=value", "key", "value", []string{"comment"}}, - {"# comment\nkey=value", "key", "value", []string{"comment"}}, - {"# comment\n\nkey=value", "key", "value", []string{"comment"}}, - {"# comment1\n# comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}}, - {"# comment1\n\n# comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}}, - {"!comment\nkey=value", "key", "value", []string{"comment"}}, - {"! comment\nkey=value", "key", "value", []string{"comment"}}, - {"! comment\nkey=value", "key", "value", []string{"comment"}}, - {"! comment\n\nkey=value", "key", "value", []string{"comment"}}, - {"! comment1\n! comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}}, - {"! comment1\n\n! comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}}, -} - -// ---------------------------------------------------------------------------- - -var errorTests = []struct { - input, msg string -}{ - // unicode literals - {"key\\u1 = value", "invalid unicode literal"}, - {"key\\u12 = value", "invalid unicode literal"}, - {"key\\u123 = value", "invalid unicode literal"}, - {"key\\u123g = value", "invalid unicode literal"}, - {"key\\u123", "invalid unicode literal"}, - - // circular references - {"key=${key}", "circular reference"}, - {"key1=${key2}\nkey2=${key1}", "circular reference"}, - - // malformed expressions - {"key=${ke", "malformed expression"}, - {"key=valu${ke", "malformed expression"}, -} - -// ---------------------------------------------------------------------------- - -var writeTests = []struct { - input, output, encoding string -}{ - // ISO-8859-1 tests - {"key = value", "key = value\n", "ISO-8859-1"}, - {"key = value \\\n continued", "key = value continued\n", "ISO-8859-1"}, - {"key⌘ = value", "key\\u2318 = value\n", "ISO-8859-1"}, - {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "ISO-8859-1"}, - - // UTF-8 tests - {"key = value", "key = value\n", "UTF-8"}, - {"key = value \\\n continued", "key = value continued\n", "UTF-8"}, - {"key⌘ = value⌘", "key⌘ = value⌘\n", "UTF-8"}, - {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "UTF-8"}, -} - -// ---------------------------------------------------------------------------- - -var writeCommentTests = []struct { - input, output, encoding string -}{ - // ISO-8859-1 tests - {"key = value", "key = value\n", "ISO-8859-1"}, - {"#\nkey = value", "key = value\n", "ISO-8859-1"}, - {"#\n#\n#\nkey = value", "key = value\n", "ISO-8859-1"}, - {"# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"}, - {"\n# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"}, - {"# comment\n\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"}, - {"# comment1\n# comment2\nkey = value", "# comment1\n# comment2\nkey = value\n", "ISO-8859-1"}, - {"#comment1\nkey1 = value1\n#comment2\nkey2 = value2", "# comment1\nkey1 = value1\n\n# comment2\nkey2 = value2\n", "ISO-8859-1"}, - - // UTF-8 tests - {"key = value", "key = value\n", "UTF-8"}, - {"# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"}, - {"\n# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"}, - {"# comment⌘\n\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"}, - {"# comment1⌘\n# comment2⌘\nkey = value⌘", "# comment1⌘\n# comment2⌘\nkey = value⌘\n", "UTF-8"}, - {"#comment1⌘\nkey1 = value1⌘\n#comment2⌘\nkey2 = value2⌘", "# comment1⌘\nkey1 = value1⌘\n\n# comment2⌘\nkey2 = value2⌘\n", "UTF-8"}, -} - -// ---------------------------------------------------------------------------- - -var boolTests = []struct { - input, key string - def, value bool -}{ - // valid values for TRUE - {"key = 1", "key", false, true}, - {"key = on", "key", false, true}, - {"key = On", "key", false, true}, - {"key = ON", "key", false, true}, - {"key = true", "key", false, true}, - {"key = True", "key", false, true}, - {"key = TRUE", "key", false, true}, - {"key = yes", "key", false, true}, - {"key = Yes", "key", false, true}, - {"key = YES", "key", false, true}, - - // valid values for FALSE (all other) - {"key = 0", "key", true, false}, - {"key = off", "key", true, false}, - {"key = false", "key", true, false}, - {"key = no", "key", true, false}, - - // non existent key - {"key = true", "key2", false, false}, -} - -// ---------------------------------------------------------------------------- - -var durationTests = []struct { - input, key string - def, value time.Duration -}{ - // valid values - {"key = 1", "key", 999, 1}, - {"key = 0", "key", 999, 0}, - {"key = -1", "key", 999, -1}, - {"key = 0123", "key", 999, 123}, - - // invalid values - {"key = 0xff", "key", 999, 999}, - {"key = 1.0", "key", 999, 999}, - {"key = a", "key", 999, 999}, - - // non existent key - {"key = 1", "key2", 999, 999}, -} - -// ---------------------------------------------------------------------------- - -var parsedDurationTests = []struct { - input, key string - def, value time.Duration -}{ - // valid values - {"key = -1ns", "key", 999, -1 * time.Nanosecond}, - {"key = 300ms", "key", 999, 300 * time.Millisecond}, - {"key = 5s", "key", 999, 5 * time.Second}, - {"key = 3h", "key", 999, 3 * time.Hour}, - {"key = 2h45m", "key", 999, 2*time.Hour + 45*time.Minute}, - - // invalid values - {"key = 0xff", "key", 999, 999}, - {"key = 1.0", "key", 999, 999}, - {"key = a", "key", 999, 999}, - {"key = 1", "key", 999, 999}, - {"key = 0", "key", 999, 0}, - - // non existent key - {"key = 1", "key2", 999, 999}, -} - -// ---------------------------------------------------------------------------- - -var floatTests = []struct { - input, key string - def, value float64 -}{ - // valid values - {"key = 1.0", "key", 999, 1.0}, - {"key = 0.0", "key", 999, 0.0}, - {"key = -1.0", "key", 999, -1.0}, - {"key = 1", "key", 999, 1}, - {"key = 0", "key", 999, 0}, - {"key = -1", "key", 999, -1}, - {"key = 0123", "key", 999, 123}, - - // invalid values - {"key = 0xff", "key", 999, 999}, - {"key = a", "key", 999, 999}, - - // non existent key - {"key = 1", "key2", 999, 999}, -} - -// ---------------------------------------------------------------------------- - -var int64Tests = []struct { - input, key string - def, value int64 -}{ - // valid values - {"key = 1", "key", 999, 1}, - {"key = 0", "key", 999, 0}, - {"key = -1", "key", 999, -1}, - {"key = 0123", "key", 999, 123}, - - // invalid values - {"key = 0xff", "key", 999, 999}, - {"key = 1.0", "key", 999, 999}, - {"key = a", "key", 999, 999}, - - // non existent key - {"key = 1", "key2", 999, 999}, -} - -// ---------------------------------------------------------------------------- - -var uint64Tests = []struct { - input, key string - def, value uint64 -}{ - // valid values - {"key = 1", "key", 999, 1}, - {"key = 0", "key", 999, 0}, - {"key = 0123", "key", 999, 123}, - - // invalid values - {"key = -1", "key", 999, 999}, - {"key = 0xff", "key", 999, 999}, - {"key = 1.0", "key", 999, 999}, - {"key = a", "key", 999, 999}, - - // non existent key - {"key = 1", "key2", 999, 999}, -} - -// ---------------------------------------------------------------------------- - -var stringTests = []struct { - input, key string - def, value string -}{ - // valid values - {"key = abc", "key", "def", "abc"}, - - // non existent key - {"key = abc", "key2", "def", "def"}, -} - -// ---------------------------------------------------------------------------- - -var keysTests = []struct { - input string - keys []string -}{ - {"", []string{}}, - {"key = abc", []string{"key"}}, - {"key = abc\nkey2=def", []string{"key", "key2"}}, - {"key2 = abc\nkey=def", []string{"key2", "key"}}, - {"key = abc\nkey=def", []string{"key"}}, -} - -// ---------------------------------------------------------------------------- - -var filterTests = []struct { - input string - pattern string - keys []string - err string -}{ - {"", "", []string{}, ""}, - {"", "abc", []string{}, ""}, - {"key=value", "", []string{"key"}, ""}, - {"key=value", "key=", []string{}, ""}, - {"key=value\nfoo=bar", "", []string{"foo", "key"}, ""}, - {"key=value\nfoo=bar", "f", []string{"foo"}, ""}, - {"key=value\nfoo=bar", "fo", []string{"foo"}, ""}, - {"key=value\nfoo=bar", "foo", []string{"foo"}, ""}, - {"key=value\nfoo=bar", "fooo", []string{}, ""}, - {"key=value\nkey2=value2\nfoo=bar", "ey", []string{"key", "key2"}, ""}, - {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}, ""}, - {"key=value\nkey2=value2\nfoo=bar", "^key", []string{"key", "key2"}, ""}, - {"key=value\nkey2=value2\nfoo=bar", "^(key|foo)", []string{"foo", "key", "key2"}, ""}, - {"key=value\nkey2=value2\nfoo=bar", "[ abc", nil, "error parsing regexp.*"}, -} - -// ---------------------------------------------------------------------------- - -var filterPrefixTests = []struct { - input string - prefix string - keys []string -}{ - {"", "", []string{}}, - {"", "abc", []string{}}, - {"key=value", "", []string{"key"}}, - {"key=value", "key=", []string{}}, - {"key=value\nfoo=bar", "", []string{"foo", "key"}}, - {"key=value\nfoo=bar", "f", []string{"foo"}}, - {"key=value\nfoo=bar", "fo", []string{"foo"}}, - {"key=value\nfoo=bar", "foo", []string{"foo"}}, - {"key=value\nfoo=bar", "fooo", []string{}}, - {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}}, -} - -// ---------------------------------------------------------------------------- - -var filterStripPrefixTests = []struct { - input string - prefix string - keys []string -}{ - {"", "", []string{}}, - {"", "abc", []string{}}, - {"key=value", "", []string{"key"}}, - {"key=value", "key=", []string{}}, - {"key=value\nfoo=bar", "", []string{"foo", "key"}}, - {"key=value\nfoo=bar", "f", []string{"foo"}}, - {"key=value\nfoo=bar", "fo", []string{"foo"}}, - {"key=value\nfoo=bar", "foo", []string{"foo"}}, - {"key=value\nfoo=bar", "fooo", []string{}}, - {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}}, -} - -// ---------------------------------------------------------------------------- - -var setTests = []struct { - input string - key, value string - prev string - ok bool - err string - keys []string -}{ - {"", "", "", "", false, "", []string{}}, - {"", "key", "value", "", false, "", []string{"key"}}, - {"key=value", "key2", "value2", "", false, "", []string{"key", "key2"}}, - {"key=value", "abc", "value3", "", false, "", []string{"key", "abc"}}, - {"key=value", "key", "value3", "value", true, "", []string{"key"}}, -} - -// ---------------------------------------------------------------------------- - -// TestBasic tests basic single key/value combinations with all possible -// whitespace, delimiter and newline permutations. -func TestBasic(t *testing.T) { - testWhitespaceAndDelimiterCombinations(t, "key", "") - testWhitespaceAndDelimiterCombinations(t, "key", "value") - testWhitespaceAndDelimiterCombinations(t, "key", "value ") -} - -func TestComplex(t *testing.T) { - for _, test := range complexTests { - testKeyValue(t, test[0], test[1:]...) - } -} - -func TestErrors(t *testing.T) { - for _, test := range errorTests { - _, err := Load([]byte(test.input), ISO_8859_1) - assert.Equal(t, err != nil, true, "want error") - assert.Equal(t, strings.Contains(err.Error(), test.msg), true) - } -} - -func TestDisableExpansion(t *testing.T) { - input := "key=value\nkey2=${key}" - p := mustParse(t, input) - p.DisableExpansion = true - assert.Equal(t, p.MustGet("key"), "value") - assert.Equal(t, p.MustGet("key2"), "${key}") - - // with expansion disabled we can introduce circular references - p.MustSet("keyA", "${keyB}") - p.MustSet("keyB", "${keyA}") - assert.Equal(t, p.MustGet("keyA"), "${keyB}") - assert.Equal(t, p.MustGet("keyB"), "${keyA}") -} - -func TestDisableExpansionStillUpdatesKeys(t *testing.T) { - p := NewProperties() - p.MustSet("p1", "a") - assert.Equal(t, p.Keys(), []string{"p1"}) - assert.Equal(t, p.String(), "p1 = a\n") - - p.DisableExpansion = true - p.MustSet("p2", "b") - - assert.Equal(t, p.Keys(), []string{"p1", "p2"}) - assert.Equal(t, p.String(), "p1 = a\np2 = b\n") -} - -func TestMustGet(t *testing.T) { - input := "key = value\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGet("key"), "value") - assert.Panic(t, func() { p.MustGet("invalid") }, "unknown property: invalid") -} - -func TestGetBool(t *testing.T) { - for _, test := range boolTests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetBool(test.key, test.def), test.value) - } -} - -func TestMustGetBool(t *testing.T) { - input := "key = true\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGetBool("key"), true) - assert.Panic(t, func() { p.MustGetBool("invalid") }, "unknown property: invalid") -} - -func TestGetDuration(t *testing.T) { - for _, test := range durationTests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetDuration(test.key, test.def), test.value) - } -} - -func TestMustGetDuration(t *testing.T) { - input := "key = 123\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGetDuration("key"), time.Duration(123)) - assert.Panic(t, func() { p.MustGetDuration("key2") }, "strconv.ParseInt: parsing.*") - assert.Panic(t, func() { p.MustGetDuration("invalid") }, "unknown property: invalid") -} - -func TestGetParsedDuration(t *testing.T) { - for _, test := range parsedDurationTests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetParsedDuration(test.key, test.def), test.value) - } -} - -func TestMustGetParsedDuration(t *testing.T) { - input := "key = 123ms\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGetParsedDuration("key"), 123*time.Millisecond) - assert.Panic(t, func() { p.MustGetParsedDuration("key2") }, "time: invalid duration ghi") - assert.Panic(t, func() { p.MustGetParsedDuration("invalid") }, "unknown property: invalid") -} - -func TestGetFloat64(t *testing.T) { - for _, test := range floatTests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetFloat64(test.key, test.def), test.value) - } -} - -func TestMustGetFloat64(t *testing.T) { - input := "key = 123\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGetFloat64("key"), float64(123)) - assert.Panic(t, func() { p.MustGetFloat64("key2") }, "strconv.ParseFloat: parsing.*") - assert.Panic(t, func() { p.MustGetFloat64("invalid") }, "unknown property: invalid") -} - -func TestGetInt(t *testing.T) { - for _, test := range int64Tests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetInt(test.key, int(test.def)), int(test.value)) - } -} - -func TestMustGetInt(t *testing.T) { - input := "key = 123\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGetInt("key"), int(123)) - assert.Panic(t, func() { p.MustGetInt("key2") }, "strconv.ParseInt: parsing.*") - assert.Panic(t, func() { p.MustGetInt("invalid") }, "unknown property: invalid") -} - -func TestGetInt64(t *testing.T) { - for _, test := range int64Tests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetInt64(test.key, test.def), test.value) - } -} - -func TestMustGetInt64(t *testing.T) { - input := "key = 123\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGetInt64("key"), int64(123)) - assert.Panic(t, func() { p.MustGetInt64("key2") }, "strconv.ParseInt: parsing.*") - assert.Panic(t, func() { p.MustGetInt64("invalid") }, "unknown property: invalid") -} - -func TestGetUint(t *testing.T) { - for _, test := range uint64Tests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetUint(test.key, uint(test.def)), uint(test.value)) - } -} - -func TestMustGetUint(t *testing.T) { - input := "key = 123\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGetUint("key"), uint(123)) - assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*") - assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid") -} - -func TestGetUint64(t *testing.T) { - for _, test := range uint64Tests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetUint64(test.key, test.def), test.value) - } -} - -func TestMustGetUint64(t *testing.T) { - input := "key = 123\nkey2 = ghi" - p := mustParse(t, input) - assert.Equal(t, p.MustGetUint64("key"), uint64(123)) - assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*") - assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid") -} - -func TestGetString(t *testing.T) { - for _, test := range stringTests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), 1) - assert.Equal(t, p.GetString(test.key, test.def), test.value) - } -} - -func TestMustGetString(t *testing.T) { - input := `key = value` - p := mustParse(t, input) - assert.Equal(t, p.MustGetString("key"), "value") - assert.Panic(t, func() { p.MustGetString("invalid") }, "unknown property: invalid") -} - -func TestComment(t *testing.T) { - for _, test := range commentTests { - p := mustParse(t, test.input) - assert.Equal(t, p.MustGetString(test.key), test.value) - assert.Equal(t, p.GetComments(test.key), test.comments) - if test.comments != nil { - assert.Equal(t, p.GetComment(test.key), test.comments[len(test.comments)-1]) - } else { - assert.Equal(t, p.GetComment(test.key), "") - } - - // test setting comments - if len(test.comments) > 0 { - // set single comment - p.ClearComments() - assert.Equal(t, len(p.c), 0) - p.SetComment(test.key, test.comments[0]) - assert.Equal(t, p.GetComment(test.key), test.comments[0]) - - // set multiple comments - p.ClearComments() - assert.Equal(t, len(p.c), 0) - p.SetComments(test.key, test.comments) - assert.Equal(t, p.GetComments(test.key), test.comments) - - // clear comments for a key - p.SetComments(test.key, nil) - assert.Equal(t, p.GetComment(test.key), "") - assert.Equal(t, p.GetComments(test.key), ([]string)(nil)) - } - } -} - -func TestFilter(t *testing.T) { - for _, test := range filterTests { - p := mustParse(t, test.input) - pp, err := p.Filter(test.pattern) - if err != nil { - assert.Matches(t, err.Error(), test.err) - continue - } - assert.Equal(t, pp != nil, true, "want properties") - assert.Equal(t, pp.Len(), len(test.keys)) - for _, key := range test.keys { - v1, ok1 := p.Get(key) - v2, ok2 := pp.Get(key) - assert.Equal(t, ok1, true) - assert.Equal(t, ok2, true) - assert.Equal(t, v1, v2) - } - } -} - -func TestFilterPrefix(t *testing.T) { - for _, test := range filterPrefixTests { - p := mustParse(t, test.input) - pp := p.FilterPrefix(test.prefix) - assert.Equal(t, pp != nil, true, "want properties") - assert.Equal(t, pp.Len(), len(test.keys)) - for _, key := range test.keys { - v1, ok1 := p.Get(key) - v2, ok2 := pp.Get(key) - assert.Equal(t, ok1, true) - assert.Equal(t, ok2, true) - assert.Equal(t, v1, v2) - } - } -} - -func TestFilterStripPrefix(t *testing.T) { - for _, test := range filterStripPrefixTests { - p := mustParse(t, test.input) - pp := p.FilterPrefix(test.prefix) - assert.Equal(t, pp != nil, true, "want properties") - assert.Equal(t, pp.Len(), len(test.keys)) - for _, key := range test.keys { - v1, ok1 := p.Get(key) - v2, ok2 := pp.Get(key) - assert.Equal(t, ok1, true) - assert.Equal(t, ok2, true) - assert.Equal(t, v1, v2) - } - } -} - -func TestKeys(t *testing.T) { - for _, test := range keysTests { - p := mustParse(t, test.input) - assert.Equal(t, p.Len(), len(test.keys)) - assert.Equal(t, len(p.Keys()), len(test.keys)) - assert.Equal(t, p.Keys(), test.keys) - } -} - -func TestSet(t *testing.T) { - for _, test := range setTests { - p := mustParse(t, test.input) - prev, ok, err := p.Set(test.key, test.value) - if test.err != "" { - assert.Matches(t, err.Error(), test.err) - continue - } - - assert.Equal(t, err, nil) - assert.Equal(t, ok, test.ok) - if ok { - assert.Equal(t, prev, test.prev) - } - assert.Equal(t, p.Keys(), test.keys) - } -} - -func TestSetValue(t *testing.T) { - tests := []interface{}{ - true, false, - int8(123), int16(123), int32(123), int64(123), int(123), - uint8(123), uint16(123), uint32(123), uint64(123), uint(123), - float32(1.23), float64(1.23), - "abc", - } - - for _, v := range tests { - p := NewProperties() - err := p.SetValue("x", v) - assert.Equal(t, err, nil) - assert.Equal(t, p.GetString("x", ""), fmt.Sprintf("%v", v)) - } -} - -func TestMustSet(t *testing.T) { - input := "key=${key}" - p := mustParse(t, input) - assert.Panic(t, func() { p.MustSet("key", "${key}") }, "circular reference .*") -} - -func TestWrite(t *testing.T) { - for _, test := range writeTests { - p, err := parse(test.input) - - buf := new(bytes.Buffer) - var n int - switch test.encoding { - case "UTF-8": - n, err = p.Write(buf, UTF8) - case "ISO-8859-1": - n, err = p.Write(buf, ISO_8859_1) - } - assert.Equal(t, err, nil) - s := string(buf.Bytes()) - assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s)) - assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s)) - } -} - -func TestWriteComment(t *testing.T) { - for _, test := range writeCommentTests { - p, err := parse(test.input) - - buf := new(bytes.Buffer) - var n int - switch test.encoding { - case "UTF-8": - n, err = p.WriteComment(buf, "# ", UTF8) - case "ISO-8859-1": - n, err = p.WriteComment(buf, "# ", ISO_8859_1) - } - assert.Equal(t, err, nil) - s := string(buf.Bytes()) - assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s)) - assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s)) - } -} - -func TestCustomExpansionExpression(t *testing.T) { - testKeyValuePrePostfix(t, "*[", "]*", "key=value\nkey2=*[key]*", "key", "value", "key2", "value") -} - -func TestPanicOn32BitIntOverflow(t *testing.T) { - is32Bit = true - var min, max int64 = math.MinInt32 - 1, math.MaxInt32 + 1 - input := fmt.Sprintf("min=%d\nmax=%d", min, max) - p := mustParse(t, input) - assert.Equal(t, p.MustGetInt64("min"), min) - assert.Equal(t, p.MustGetInt64("max"), max) - assert.Panic(t, func() { p.MustGetInt("min") }, ".* out of range") - assert.Panic(t, func() { p.MustGetInt("max") }, ".* out of range") -} - -func TestPanicOn32BitUintOverflow(t *testing.T) { - is32Bit = true - var max uint64 = math.MaxUint32 + 1 - input := fmt.Sprintf("max=%d", max) - p := mustParse(t, input) - assert.Equal(t, p.MustGetUint64("max"), max) - assert.Panic(t, func() { p.MustGetUint("max") }, ".* out of range") -} - -func TestDeleteKey(t *testing.T) { - input := "#comments should also be gone\nkey=to-be-deleted\nsecond=key" - p := mustParse(t, input) - assert.Equal(t, len(p.m), 2) - assert.Equal(t, len(p.c), 1) - assert.Equal(t, len(p.k), 2) - p.Delete("key") - assert.Equal(t, len(p.m), 1) - assert.Equal(t, len(p.c), 0) - assert.Equal(t, len(p.k), 1) - assert.Equal(t, p.k[0], "second") - assert.Equal(t, p.m["second"], "key") -} - -func TestDeleteUnknownKey(t *testing.T) { - input := "#comments should also be gone\nkey=to-be-deleted" - p := mustParse(t, input) - assert.Equal(t, len(p.m), 1) - assert.Equal(t, len(p.c), 1) - assert.Equal(t, len(p.k), 1) - p.Delete("wrong-key") - assert.Equal(t, len(p.m), 1) - assert.Equal(t, len(p.c), 1) - assert.Equal(t, len(p.k), 1) -} - -func TestMerge(t *testing.T) { - input1 := "#comment\nkey=value\nkey2=value2" - input2 := "#another comment\nkey=another value\nkey3=value3" - p1 := mustParse(t, input1) - p2 := mustParse(t, input2) - p1.Merge(p2) - assert.Equal(t, len(p1.m), 3) - assert.Equal(t, len(p1.c), 1) - assert.Equal(t, len(p1.k), 3) - assert.Equal(t, p1.MustGet("key"), "another value") - assert.Equal(t, p1.GetComment("key"), "another comment") -} - -func TestMap(t *testing.T) { - input := "key=value\nabc=def" - p := mustParse(t, input) - m := map[string]string{"key": "value", "abc": "def"} - assert.Equal(t, p.Map(), m) -} - -func TestFilterFunc(t *testing.T) { - input := "key=value\nabc=def" - p := mustParse(t, input) - pp := p.FilterFunc(func(k, v string) bool { - return k != "abc" - }) - m := map[string]string{"key": "value"} - assert.Equal(t, pp.Map(), m) -} - -// ---------------------------------------------------------------------------- - -// tests all combinations of delimiters, leading and/or trailing whitespace and newlines. -func testWhitespaceAndDelimiterCombinations(t *testing.T, key, value string) { - whitespace := []string{"", " ", "\f", "\t"} - delimiters := []string{"", " ", "=", ":"} - newlines := []string{"", "\r", "\n", "\r\n"} - for _, dl := range delimiters { - for _, ws1 := range whitespace { - for _, ws2 := range whitespace { - for _, nl := range newlines { - // skip the one case where there is nothing between a key and a value - if ws1 == "" && dl == "" && ws2 == "" && value != "" { - continue - } - - input := fmt.Sprintf("%s%s%s%s%s%s", key, ws1, dl, ws2, value, nl) - testKeyValue(t, input, key, value) - } - } - } - } -} - -// tests whether key/value pairs exist for a given input. -// keyvalues is expected to be an even number of strings of "key", "value", ... -func testKeyValue(t *testing.T, input string, keyvalues ...string) { - testKeyValuePrePostfix(t, "${", "}", input, keyvalues...) -} - -// tests whether key/value pairs exist for a given input. -// keyvalues is expected to be an even number of strings of "key", "value", ... -func testKeyValuePrePostfix(t *testing.T, prefix, postfix, input string, keyvalues ...string) { - p, err := Load([]byte(input), ISO_8859_1) - assert.Equal(t, err, nil) - p.Prefix = prefix - p.Postfix = postfix - assertKeyValues(t, input, p, keyvalues...) -} - -// tests whether key/value pairs exist for a given input. -// keyvalues is expected to be an even number of strings of "key", "value", ... -func assertKeyValues(t *testing.T, input string, p *Properties, keyvalues ...string) { - assert.Equal(t, p != nil, true, "want properties") - assert.Equal(t, 2*p.Len(), len(keyvalues), "Odd number of key/value pairs.") - - for i := 0; i < len(keyvalues); i += 2 { - key, value := keyvalues[i], keyvalues[i+1] - v, ok := p.Get(key) - if !ok { - t.Errorf("No key %q found (input=%q)", key, input) - } - if got, want := v, value; !reflect.DeepEqual(got, want) { - t.Errorf("Value %q does not match %q (input=%q)", v, value, input) - } - } -} - -func mustParse(t *testing.T, s string) *Properties { - p, err := parse(s) - if err != nil { - t.Fatalf("parse failed with %s", err) - } - return p -} - -// prints to stderr if the -verbose flag was given. -func printf(format string, args ...interface{}) { - if *verbose { - fmt.Fprintf(os.Stderr, format, args...) - } -} diff --git a/Godeps/_workspace/src/github.com/magiconair/properties/rangecheck.go b/Godeps/_workspace/src/github.com/magiconair/properties/rangecheck.go deleted file mode 100644 index 2e907d5..0000000 --- a/Godeps/_workspace/src/github.com/magiconair/properties/rangecheck.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2017 Frank Schroeder. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package properties - -import ( - "fmt" - "math" -) - -// make this a var to overwrite it in a test -var is32Bit = ^uint(0) == math.MaxUint32 - -// intRangeCheck checks if the value fits into the int type and -// panics if it does not. -func intRangeCheck(key string, v int64) int { - if is32Bit && (v < math.MinInt32 || v > math.MaxInt32) { - panic(fmt.Sprintf("Value %d for key %s out of range", v, key)) - } - return int(v) -} - -// uintRangeCheck checks if the value fits into the uint type and -// panics if it does not. -func uintRangeCheck(key string, v uint64) uint { - if is32Bit && v > math.MaxUint32 { - panic(fmt.Sprintf("Value %d for key %s out of range", v, key)) - } - return uint(v) -} diff --git a/check/check_test.go b/check/check_test.go index af339ab..c036a4d 100644 --- a/check/check_test.go +++ b/check/check_test.go @@ -64,7 +64,7 @@ var _ = Describe("Check", func() { BeforeEach(func() { version = &models.TimestampVersion{ - Version: "1" + Version: "1", } }) diff --git a/check/main.go b/check/main.go index 1d65acc..97df7da 100644 --- a/check/main.go +++ b/check/main.go @@ -17,14 +17,11 @@ func main() { fmt.Fprintln(os.Stderr, "parse error:", err.Error()) os.Exit(1) } - t := strconv.Itoa(time.Now().UnixNano()) - models.InResponse{ - Version: inVersion, - } + t := strconv.FormatInt(time.Now().UnixNano(),10) versions := models.CheckResponse { models.TimestampVersion { - Version: t - } + Version: t, + }, } json.NewEncoder(os.Stdout).Encode(versions) } diff --git a/in/in_test.go b/in/in_test.go index f977675..c61b3de 100644 --- a/in/in_test.go +++ b/in/in_test.go @@ -12,7 +12,6 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" "path/filepath" - "github.com/magiconair/properties" ) var _ = Describe("In", func() { @@ -31,12 +30,12 @@ var _ = Describe("In", func() { inCmd = exec.Command(inPath, destination) - inCmd.Env = append( + inCmd.Env = append(os.Environ(), "BUILD_ID=1", "BUILD_NAME=2", "BUILD_JOB_NAME=3", "BUILD_PIPELINE_NAME=4", - "ATC_EXTERNAL_URL=5" + "ATC_EXTERNAL_URL=5", ) }) @@ -52,7 +51,7 @@ var _ = Describe("In", func() { request = models.InRequest{ Version: models.TimestampVersion{ - "version": "1" + Version: "1", }, Source: models.Source{}, } @@ -78,8 +77,7 @@ var _ = Describe("In", func() { }) It("reports the version to be the input version", func() { - Expect(len(response.Version)).To(Equal(1)) - Expect(response.Version["version"]).To(Equal("1")) + Expect(response.Version.Version).To(Equal("1")) }) It("writes the requested data the destination", func() { @@ -97,10 +95,7 @@ var _ = Describe("In", func() { func checkProp(destination string, filename string, prop string, valueToCheck string, meta models.Metadata) { output := filepath.Join(destination, filename) file, err := ioutil.ReadFile(output) - if err != nil { - fatal("reading output file "+output, err) - } - defer file.Close() + Expect(err).NotTo(HaveOccurred()) val := string(file) Expect(val).To(Equal(valueToCheck)) Expect(meta[prop]).To(Equal(valueToCheck)) diff --git a/in/main.go b/in/main.go index 795153f..f0fca76 100644 --- a/in/main.go +++ b/in/main.go @@ -4,12 +4,10 @@ import ( "encoding/json" "os" "path/filepath" - "strconv" "github.com/swce/metadata-resource/models" "fmt" "bufio" - "sort" ) func main() { @@ -34,7 +32,7 @@ func main() { fatal("reading request", err) } - var inVersion = request.TimestampVersion + var inVersion = request.Version handleProp(destination, "build-id", "BUILD_ID", meta) handleProp(destination, "build-name", "BUILD_NAME", meta) @@ -44,7 +42,7 @@ func main() { json.NewEncoder(os.Stdout).Encode(models.InResponse{ Version: inVersion, - Metadata: meta + Metadata: meta, }) log("Done") diff --git a/out/out_test.go b/out/out_test.go index f13b362..20f062f 100644 --- a/out/out_test.go +++ b/out/out_test.go @@ -1,17 +1,13 @@ package main_test import ( - "bytes" - "encoding/json" "io/ioutil" "os" "os/exec" "path" - "github.com/swce/metadata-resource/models" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" - "bufio" "fmt" "github.com/onsi/gomega/gbytes" ) @@ -20,6 +16,7 @@ var _ = Describe("Out", func() { var tmpdir string var source string + var session *gexec.Session var outCmd *exec.Cmd BeforeEach(func() { @@ -41,9 +38,9 @@ var _ = Describe("Out", func() { Context("when executed", func() { JustBeforeEach(func() { - stdin := new(bytes.Buffer) + var err error - session, err := gexec.Start(outCmd, GinkgoWriter, GinkgoWriter) + session, err = gexec.Start(outCmd, GinkgoWriter, GinkgoWriter) Expect(err).NotTo(HaveOccurred()) })