mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 00:32:25 -05:00 
			
		
		
		
	Implement Cobra CLI tooling, Viper config tooling (#336)
* start pulling out + replacing urfave and config * replace many many instances of config * move more stuff => viper * properly remove urfave * move some flags to root command * add testrig commands to root * alias config file keys * start adding cli parsing tests * reorder viper init * remove config path alias * fmt * change config file keys to non-nested * we're more or less in business now * tidy up the common func * go fmt * get tests passing again * add note about the cliparsing tests * reorganize * update docs with changes * structure cmd dir better * rename + move some files around * fix dangling comma
This commit is contained in:
		
					parent
					
						
							
								182b4eea73
							
						
					
				
			
			
				commit
				
					
						0884f89431
					
				
			
		
					 487 changed files with 46667 additions and 8831 deletions
				
			
		
							
								
								
									
										6
									
								
								vendor/github.com/magiconair/properties/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/magiconair/properties/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| *.sublime-project | ||||
| *.sublime-workspace | ||||
| *.un~ | ||||
| *.swp | ||||
| .idea/ | ||||
| *.iml | ||||
							
								
								
									
										17
									
								
								vendor/github.com/magiconair/properties/.travis.yml
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/magiconair/properties/.travis.yml
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| language: go | ||||
| go: | ||||
|     - 1.3.x | ||||
|     - 1.4.x | ||||
|     - 1.5.x | ||||
|     - 1.6.x | ||||
|     - 1.7.x | ||||
|     - 1.8.x | ||||
|     - 1.9.x | ||||
|     - "1.10.x" | ||||
|     - "1.11.x" | ||||
|     - "1.12.x" | ||||
|     - "1.13.x" | ||||
|     - "1.14.x" | ||||
|     - "1.15.x" | ||||
|     - "1.16.x" | ||||
|     - tip | ||||
							
								
								
									
										160
									
								
								vendor/github.com/magiconair/properties/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								vendor/github.com/magiconair/properties/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,160 @@ | |||
| ## Changelog | ||||
| 
 | ||||
| ### [1.8.2](https://github.com/magiconair/properties/tree/v1.8.2) - 25 Aug 2020 | ||||
| 
 | ||||
|  * [PR #36](https://github.com/magiconair/properties/pull/36): Escape backslash on write | ||||
| 
 | ||||
|    This patch ensures that backslashes are escaped on write. Existing applications which | ||||
|    rely on the old behavior may need to be updated. | ||||
| 
 | ||||
|    Thanks to [@apesternikov](https://github.com/apesternikov) for the patch. | ||||
| 
 | ||||
|  * [PR #42](https://github.com/magiconair/properties/pull/42): Made Content-Type check whitespace agnostic in LoadURL() | ||||
| 
 | ||||
|    Thanks to [@aliras1](https://github.com/aliras1) for the patch. | ||||
| 
 | ||||
|  * [PR #41](https://github.com/magiconair/properties/pull/41): Make key/value separator configurable on Write() | ||||
| 
 | ||||
|    Thanks to [@mkjor](https://github.com/mkjor) for the patch. | ||||
| 
 | ||||
|  * [PR #40](https://github.com/magiconair/properties/pull/40): Add method to return a sorted list of keys | ||||
| 
 | ||||
|    Thanks to [@mkjor](https://github.com/mkjor) for the patch. | ||||
| 
 | ||||
| ### [1.8.1](https://github.com/magiconair/properties/tree/v1.8.1) - 10 May 2019 | ||||
| 
 | ||||
|  * [PR #35](https://github.com/magiconair/properties/pull/35): Close body always after request | ||||
| 
 | ||||
|    This patch ensures that in `LoadURL` the response body is always closed. | ||||
| 
 | ||||
|    Thanks to [@liubog2008](https://github.com/liubog2008) for the patch. | ||||
| 
 | ||||
| ### [1.8](https://github.com/magiconair/properties/tree/v1.8) - 15 May 2018 | ||||
| 
 | ||||
|  * [PR #26](https://github.com/magiconair/properties/pull/26): Disable expansion during loading | ||||
| 
 | ||||
|    This adds the option to disable property expansion during loading. | ||||
| 
 | ||||
|    Thanks to [@kmala](https://github.com/kmala) for the patch. | ||||
| 
 | ||||
| ### [1.7.6](https://github.com/magiconair/properties/tree/v1.7.6) - 14 Feb 2018 | ||||
| 
 | ||||
|  * [PR #29](https://github.com/magiconair/properties/pull/29): Reworked expansion logic to handle more complex cases. | ||||
| 
 | ||||
|    See PR for an example. | ||||
| 
 | ||||
|    Thanks to [@yobert](https://github.com/yobert) for the fix. | ||||
| 
 | ||||
| ### [1.7.5](https://github.com/magiconair/properties/tree/v1.7.5) - 13 Feb 2018 | ||||
| 
 | ||||
|  * [PR #28](https://github.com/magiconair/properties/pull/28): Support duplicate expansions in the same value | ||||
| 
 | ||||
|    Values which expand the same key multiple times (e.g. `key=${a} ${a}`) will no longer fail | ||||
|    with a `circular reference error`. | ||||
| 
 | ||||
|    Thanks to [@yobert](https://github.com/yobert) for the fix. | ||||
| 
 | ||||
| ### [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](https://github.com/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 | ||||
							
								
								
									
										24
									
								
								vendor/github.com/magiconair/properties/LICENSE.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/magiconair/properties/LICENSE.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| Copyright (c) 2013-2020, 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: | ||||
| 
 | ||||
|  * Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
| 
 | ||||
|  * 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. | ||||
							
								
								
									
										128
									
								
								vendor/github.com/magiconair/properties/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/magiconair/properties/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,128 @@ | |||
| [](https://github.com/magiconair/properties/releases) | ||||
| [](https://travis-ci.org/magiconair/properties) | ||||
| [](https://raw.githubusercontent.com/magiconair/properties/master/LICENSE) | ||||
| [](http://godoc.org/github.com/magiconair/properties) | ||||
| 
 | ||||
| # Overview | ||||
| 
 | ||||
| #### Please run `git pull --tags` to update the tags. See [below](#updated-git-tags) why. | ||||
| 
 | ||||
| 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 [](http://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 | ||||
| 
 | ||||
| ## Updated Git tags | ||||
| 
 | ||||
| #### 13 Feb 2018 | ||||
| 
 | ||||
| I realized that all of the git tags I had pushed before v1.7.5 were lightweight tags | ||||
| and I've only recently learned that this doesn't play well with `git describe` 😞 | ||||
| 
 | ||||
| I have replaced all lightweight tags with signed tags using this script which should | ||||
| retain the commit date, name and email address. Please run `git pull --tags` to update them. | ||||
| 
 | ||||
| Worst case you have to reclone the repo. | ||||
| 
 | ||||
| ```shell | ||||
| #!/bin/bash | ||||
| tag=$1 | ||||
| echo "Updating $tag" | ||||
| date=$(git show ${tag}^0 --format=%aD | head -1) | ||||
| email=$(git show ${tag}^0 --format=%aE | head -1) | ||||
| name=$(git show ${tag}^0 --format=%aN | head -1) | ||||
| GIT_COMMITTER_DATE="$date" GIT_COMMITTER_NAME="$name" GIT_COMMITTER_EMAIL="$email" git tag -s -f ${tag} ${tag}^0 -m ${tag} | ||||
| ``` | ||||
| 
 | ||||
| I apologize for the inconvenience. | ||||
| 
 | ||||
| Frank | ||||
| 
 | ||||
							
								
								
									
										289
									
								
								vendor/github.com/magiconair/properties/decode.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								vendor/github.com/magiconair/properties/decode.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,289 @@ | |||
| // Copyright 2018 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 | ||||
| } | ||||
							
								
								
									
										156
									
								
								vendor/github.com/magiconair/properties/doc.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								vendor/github.com/magiconair/properties/doc.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,156 @@ | |||
| // Copyright 2018 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 precedence 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 alternative 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 | ||||
							
								
								
									
										34
									
								
								vendor/github.com/magiconair/properties/integrate.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/magiconair/properties/integrate.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| // Copyright 2018 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) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										407
									
								
								vendor/github.com/magiconair/properties/lex.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								vendor/github.com/magiconair/properties/lex.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,407 @@ | |||
| // Copyright 2018 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) | ||||
| } | ||||
							
								
								
									
										293
									
								
								vendor/github.com/magiconair/properties/load.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								vendor/github.com/magiconair/properties/load.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,293 @@ | |||
| // Copyright 2018 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 ( | ||||
| 	// utf8Default is a private placeholder for the zero value of Encoding to | ||||
| 	// ensure that it has the correct meaning. UTF8 is the default encoding but | ||||
| 	// was assigned a non-zero value which cannot be changed without breaking | ||||
| 	// existing code. Clients should continue to use the public constants. | ||||
| 	utf8Default Encoding = iota | ||||
| 
 | ||||
| 	// UTF8 interprets the input data as UTF-8. | ||||
| 	UTF8 | ||||
| 
 | ||||
| 	// ISO_8859_1 interprets the input data as ISO-8859-1. | ||||
| 	ISO_8859_1 | ||||
| ) | ||||
| 
 | ||||
| type Loader struct { | ||||
| 	// Encoding determines how the data from files and byte buffers | ||||
| 	// is interpreted. For URLs the Content-Type header is used | ||||
| 	// to determine the encoding of the data. | ||||
| 	Encoding Encoding | ||||
| 
 | ||||
| 	// DisableExpansion configures the property expansion of the | ||||
| 	// returned property object. When set to true, the property values | ||||
| 	// will not be expanded and the Property object will not be checked | ||||
| 	// for invalid expansion expressions. | ||||
| 	DisableExpansion bool | ||||
| 
 | ||||
| 	// IgnoreMissing configures whether missing files or URLs which return | ||||
| 	// 404 are reported as errors. When set to true, missing files and 404 | ||||
| 	// status codes are not reported as errors. | ||||
| 	IgnoreMissing bool | ||||
| } | ||||
| 
 | ||||
| // Load reads a buffer into a Properties struct. | ||||
| func (l *Loader) LoadBytes(buf []byte) (*Properties, error) { | ||||
| 	return l.loadBytes(buf, l.Encoding) | ||||
| } | ||||
| 
 | ||||
| // 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 see LoadURL for the Content-Type header and the | ||||
| // encoding. | ||||
| func (l *Loader) LoadAll(names []string) (*Properties, error) { | ||||
| 	all := NewProperties() | ||||
| 	for _, name := range names { | ||||
| 		n, err := expandName(name) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		var p *Properties | ||||
| 		switch { | ||||
| 		case strings.HasPrefix(n, "http://"): | ||||
| 			p, err = l.LoadURL(n) | ||||
| 		case strings.HasPrefix(n, "https://"): | ||||
| 			p, err = l.LoadURL(n) | ||||
| 		default: | ||||
| 			p, err = l.LoadFile(n) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		all.Merge(p) | ||||
| 	} | ||||
| 
 | ||||
| 	all.DisableExpansion = l.DisableExpansion | ||||
| 	if all.DisableExpansion { | ||||
| 		return all, nil | ||||
| 	} | ||||
| 	return all, all.check() | ||||
| } | ||||
| 
 | ||||
| // LoadFile reads a file into a Properties struct. | ||||
| // If IgnoreMissing is true then a missing file will not be | ||||
| // reported as error. | ||||
| func (l *Loader) LoadFile(filename string) (*Properties, error) { | ||||
| 	data, err := ioutil.ReadFile(filename) | ||||
| 	if err != nil { | ||||
| 		if l.IgnoreMissing && os.IsNotExist(err) { | ||||
| 			LogPrintf("properties: %s not found. skipping", filename) | ||||
| 			return NewProperties(), nil | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return l.loadBytes(data, l.Encoding) | ||||
| } | ||||
| 
 | ||||
| // 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 (l *Loader) LoadURL(url string) (*Properties, error) { | ||||
| 	resp, err := http.Get(url) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("properties: error fetching %q. %s", url, err) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 
 | ||||
| 	if resp.StatusCode == 404 && l.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) | ||||
| 	} | ||||
| 
 | ||||
| 	ct := resp.Header.Get("Content-Type") | ||||
| 	ct = strings.Join(strings.Fields(ct), "") | ||||
| 	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) | ||||
| 	} | ||||
| 
 | ||||
| 	return l.loadBytes(body, enc) | ||||
| } | ||||
| 
 | ||||
| func (l *Loader) loadBytes(buf []byte, enc Encoding) (*Properties, error) { | ||||
| 	p, err := parse(convert(buf, enc)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	p.DisableExpansion = l.DisableExpansion | ||||
| 	if p.DisableExpansion { | ||||
| 		return p, nil | ||||
| 	} | ||||
| 	return p, p.check() | ||||
| } | ||||
| 
 | ||||
| // Load reads a buffer into a Properties struct. | ||||
| func Load(buf []byte, enc Encoding) (*Properties, error) { | ||||
| 	l := &Loader{Encoding: enc} | ||||
| 	return l.LoadBytes(buf) | ||||
| } | ||||
| 
 | ||||
| // LoadString reads an UTF8 string into a properties struct. | ||||
| func LoadString(s string) (*Properties, error) { | ||||
| 	l := &Loader{Encoding: UTF8} | ||||
| 	return l.LoadBytes([]byte(s)) | ||||
| } | ||||
| 
 | ||||
| // 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) { | ||||
| 	l := &Loader{Encoding: enc} | ||||
| 	return l.LoadAll([]string{filename}) | ||||
| } | ||||
| 
 | ||||
| // 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) { | ||||
| 	l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing} | ||||
| 	return l.LoadAll(filenames) | ||||
| } | ||||
| 
 | ||||
| // LoadURL reads the content of the URL into a Properties struct. | ||||
| // See Loader#LoadURL for details. | ||||
| func LoadURL(url string) (*Properties, error) { | ||||
| 	l := &Loader{Encoding: UTF8} | ||||
| 	return l.LoadAll([]string{url}) | ||||
| } | ||||
| 
 | ||||
| // 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 Loader#LoadURL for the Content-Type header | ||||
| // and the encoding. | ||||
| func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) { | ||||
| 	l := &Loader{Encoding: UTF8, IgnoreMissing: ignoreMissing} | ||||
| 	return l.LoadAll(urls) | ||||
| } | ||||
| 
 | ||||
| // 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) { | ||||
| 	l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing} | ||||
| 	return l.LoadAll(names) | ||||
| } | ||||
| 
 | ||||
| // 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 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, []string{}, "${", "}", 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 utf8Default, 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") | ||||
| } | ||||
							
								
								
									
										95
									
								
								vendor/github.com/magiconair/properties/parser.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								vendor/github.com/magiconair/properties/parser.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| // Copyright 2018 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 | ||||
| } | ||||
							
								
								
									
										854
									
								
								vendor/github.com/magiconair/properties/properties.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										854
									
								
								vendor/github.com/magiconair/properties/properties.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,854 @@ | |||
| // Copyright 2018 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 ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
| 
 | ||||
| const maxExpansionDepth = 64 | ||||
| 
 | ||||
| // 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 | ||||
| 
 | ||||
| 	// WriteSeparator specifies the separator of key and value while writing the properties. | ||||
| 	WriteSeparator 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{}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Load reads a buffer into the given Properties struct. | ||||
| func (p *Properties) Load(buf []byte, enc Encoding) error { | ||||
| 	l := &Loader{Encoding: enc, DisableExpansion: p.DisableExpansion} | ||||
| 	newProperties, err := l.LoadBytes(buf) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	p.Merge(newProperties) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // 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(key, 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(err) | ||||
| 	} | ||||
| 
 | ||||
| 	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(key, 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 | ||||
| } | ||||
| 
 | ||||
| // Sort sorts the properties keys in alphabetical order. | ||||
| // This is helpfully before writing the properties. | ||||
| func (p *Properties) Sort() { | ||||
| 	sort.Strings(p.k) | ||||
| } | ||||
| 
 | ||||
| // 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, c) | ||||
| 						if err != nil { | ||||
| 							return | ||||
| 						} | ||||
| 						n += x | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		sep := " = " | ||||
| 		if p.WriteSeparator != "" { | ||||
| 			sep = p.WriteSeparator | ||||
| 		} | ||||
| 		x, err = fmt.Fprintf(w, "%s%s%s\n", encode(key, " :", enc), sep, 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 key, value := range p.m { | ||||
| 		if _, err := p.expand(key, value); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (p *Properties) expand(key, input string) (string, error) { | ||||
| 	// no pre/postfix -> nothing to expand | ||||
| 	if p.Prefix == "" && p.Postfix == "" { | ||||
| 		return input, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return expand(input, []string{key}, 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 []string, prefix, postfix string, values map[string]string) (string, error) { | ||||
| 	if len(keys) > maxExpansionDepth { | ||||
| 		return "", fmt.Errorf("expansion too deep") | ||||
| 	} | ||||
| 
 | ||||
| 	for { | ||||
| 		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) | ||||
| 
 | ||||
| 		for _, k := range keys { | ||||
| 			if key == k { | ||||
| 				var b bytes.Buffer | ||||
| 				b.WriteString("circular reference in:\n") | ||||
| 				for _, k1 := range keys { | ||||
| 					fmt.Fprintf(&b, "%s=%s\n", k1, values[k1]) | ||||
| 				} | ||||
| 				return "", fmt.Errorf(b.String()) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		val, ok := values[key] | ||||
| 		if !ok { | ||||
| 			val = os.Getenv(key) | ||||
| 		} | ||||
| 		new_val, err := expand(val, append(keys, key), prefix, postfix, values) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		s = s[:start] + new_val + s[end+1:] | ||||
| 	} | ||||
| 	return s, nil | ||||
| } | ||||
| 
 | ||||
| // 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" | ||||
| 	case '\\': | ||||
| 		return "\\\\" | ||||
| 	default: | ||||
| 		if strings.ContainsRune(special, r) { | ||||
| 			return "\\" + string(r) | ||||
| 		} | ||||
| 		return string(r) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func invalidKeyError(key string) error { | ||||
| 	return fmt.Errorf("unknown property: %s", key) | ||||
| } | ||||
							
								
								
									
										31
									
								
								vendor/github.com/magiconair/properties/rangecheck.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/magiconair/properties/rangecheck.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| // Copyright 2018 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) | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue