go vendor

This commit is contained in:
lealife
2017-11-30 19:55:33 +08:00
parent 2856da6888
commit 0fb92efbf3
670 changed files with 199010 additions and 0 deletions

19
vendor/github.com/revel/config/Doc/AUTHORS.md generated vendored Normal file
View File

@@ -0,0 +1,19 @@
###### Notice
*This is the official list of **config** authors for copyright purposes.*
*This file is distinct from the CONTRIBUTORS file. See the latter for an
explanation.*
*Names should be added to this file as: `Organization`;
`[Name](web address)` or `Name <email>` for individuals*
*Please keep the list sorted.*
* * *
[Jonas mg](https://github.com/kless)
[Miguel Branco](https://github.com/msbranco)
[Rob Figueiredo](https://github.com/robfig)
[Tom Bruggeman](https://github.com/tmbrggmn)

28
vendor/github.com/revel/config/Doc/CONTRIBUTORS.md generated vendored Normal file
View File

@@ -0,0 +1,28 @@
###### Notice
*This is the official list of people who can contribute (and typically have
contributed) code to the **config** repository.*
*The AUTHORS file lists the copyright holders; this file lists people. For
example, the employees of an organization are listed here but not in AUTHORS,
because the organization holds the copyright.*
*Names should be added to this file as: `[Name](web address)` or `Name <email>`*
*Please keep the list sorted.*
* * *
### Initial author
[Miguel Branco](https://github.com/msbranco)
### Maintainer
[Rob Figueiredo](https://github.com/robfig)
### Other authors
[Jonas mg](https://github.com/kless)
[Tom Bruggeman](https://github.com/tmbrggmn)

202
vendor/github.com/revel/config/Doc/LICENSE_Apache.txt generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

52
vendor/github.com/revel/config/Doc/NEWS.md generated vendored Normal file
View File

@@ -0,0 +1,52 @@
###### Notice
*This file documents the changes in **config** versions that are listed below.*
*Items should be added to this file as:*
### YYYY-MM-DD Release
+ Additional changes.
+ More changes.
* * *
### 2011-??-?? v0.9.6
+ Changed to line comments.
### 2010-09-15 v0.9.5
+ Sections, options and values are all case-sensitive.
+ Changed API:
Type *File* -> *Config*
*NewFile()* -> *NewDefault*
*ReadFile()* -> *ReadDefault*
+ Added functions, *New()*, *Read()*, which allow to choose the character of
comment and separator, and the spaces around separator.
+ Better error handling.
+ Both sections and options are showed by its input order.
### 2010-08-22 v0.9
+ The files has been splitted, formatted via *gomft*.
+ Methods use *self* to refer to its own type.
+ *Get* has been removed from the functions names.
+ Fixed some errors. All tests are passed.
+ At write the header in configuration file, it is added the comment character
after of each new line.
+ Better documentation.

90
vendor/github.com/revel/config/README.md generated vendored Normal file
View File

@@ -0,0 +1,90 @@
config
======
This package implements a basic configuration file parser language which
provides a structure similar to what you would find on Microsoft Windows INI
files.
The configuration file consists of sections, led by a "*[section]*" header and
followed by "*name: value*" entries; "*name=value*" is also accepted. Note that
leading whitespace is removed from values. The optional values can contain
format strings which refer to other values in the same section, or values in a
special *DEFAULT* section. Additional defaults can be provided on initialization
and retrieval. Comments are indicated by ";" or "#"; a comment may begin
anywhere on a line, including on the same line after parameters or section
declarations.
For example:
[My Section]
foodir: %(dir)s/whatever
dir=foo
would resolve the "*%(dir)s*" to the value of "*dir*" (*foo* in this case). All
reference expansions are done on demand.
The functionality and workflow is loosely based on the *configparser* package of
the Python Standard Library.
## Installation
go get github.com/revel/config
## Operating instructions
Given a sample configuration file:
[DEFAULT]
host: www.example.com
protocol: http://
base-url: %(protocol)s%(host)s
[service-1]
url: %(base-url)s/some/path
delegation: on
maxclients: 200 # do not set this higher
comments: This is a multi-line
entry # And this is a comment
To read this configuration file, do:
c, _ := config.ReadDefault("config.cfg")
c.String("service-1", "url")
// result is string "http://www.example.com/some/path"
c.Int("service-1", "maxclients")
// result is int 200
c.Bool("service-1", "delegation")
// result is bool true
c.String("service-1", "comments")
// result is string "This is a multi-line\nentry"
Note the support for unfolding variables (such as *%(base-url)s*), which are read
from the special (reserved) section name *[DEFAULT]*.
A new configuration file can also be created with:
c := config.NewDefault()
c.AddSection("Section")
c.AddOption("Section", "option", "value")
c.WriteFile("config.cfg", 0644, "A header for this file")
This results in the file:
# A header for this file
[Section]
option: value
Note that sections, options and values are all case-sensitive.
## License
The source files are distributed under the [Mozilla Public License, version 2.0](http://mozilla.org/MPL/2.0/),
unless otherwise noted.
Please read the [FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html)
if you have further questions regarding the license.

474
vendor/github.com/revel/config/all_test.go generated vendored Normal file
View File

@@ -0,0 +1,474 @@
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"bufio"
"os"
"reflect"
"strings"
"testing"
)
const (
tmpFilename = "testdata/__test.go"
sourceFilename = "testdata/source.cfg"
targetFilename = "testdata/target.cfg"
)
func testGet(t *testing.T, c *Config, section string, option string,
expected interface{}) {
ok := false
switch expected.(type) {
case string:
v, _ := c.String(section, option)
if v == expected.(string) {
ok = true
}
case int:
v, _ := c.Int(section, option)
if v == expected.(int) {
ok = true
}
case bool:
v, _ := c.Bool(section, option)
if v == expected.(bool) {
ok = true
}
default:
t.Fatalf("Bad test case")
}
if !ok {
v, _ := c.String(section, option)
t.Errorf("Get failure: expected different value for %s %s (expected: [%#v] got: [%#v])", section, option, expected, v)
}
}
// TestInMemory creates configuration representation and run multiple tests in-memory.
func TestInMemory(t *testing.T) {
c := NewDefault()
// == Test empty structure
// should be empty
if len(c.Sections()) != 1 {
t.Errorf("Sections failure: invalid length")
}
// test presence of missing section
if c.HasSection("no-section") {
t.Errorf("HasSection failure: invalid section")
}
// get options for missing section
_, err := c.Options("no-section")
if err == nil {
t.Errorf("Options failure: invalid section")
}
// test presence of option for missing section
if c.HasOption("no-section", "no-option") {
t.Errorf("HasSection failure: invalid/section/option")
}
// get value from missing section/option
_, err = c.String("no-section", "no-option")
if err == nil {
t.Errorf("String failure: got value for missing section/option")
}
// get value from missing section/option
_, err = c.Int("no-section", "no-option")
if err == nil {
t.Errorf("Int failure: got value for missing section/option")
}
// remove missing section
if c.RemoveSection("no-section") {
t.Errorf("RemoveSection failure: removed missing section")
}
// remove missing section/option
if c.RemoveOption("no-section", "no-option") {
t.Errorf("RemoveOption failure: removed missing section/option")
}
// == Fill up structure
// add section
if !c.AddSection("section1") {
t.Errorf("AddSection failure: false on first insert")
}
// re-add same section
if c.AddSection("section1") {
t.Errorf("AddSection failure: true on second insert")
}
// default section always exists
if c.AddSection(DefaultSection) {
t.Errorf("AddSection failure: true on default section insert")
}
// add option/value
if !c.AddOption("section1", "option1", "value1") {
t.Errorf("AddOption failure: false on first insert")
}
testGet(t, c, "section1", "option1", "value1") // read it back
// overwrite value
if c.AddOption("section1", "option1", "value2") {
t.Errorf("AddOption failure: true on second insert")
}
testGet(t, c, "section1", "option1", "value2") // read it back again
// remove option/value
if !c.RemoveOption("section1", "option1") {
t.Errorf("RemoveOption failure: false on first remove")
}
// remove again
if c.RemoveOption("section1", "option1") {
t.Errorf("RemoveOption failure: true on second remove")
}
// read it back again
_, err = c.String("section1", "option1")
if err == nil {
t.Errorf("String failure: got value for removed section/option")
}
// remove existing section
if !c.RemoveSection("section1") {
t.Errorf("RemoveSection failure: false on first remove")
}
// remove again
if c.RemoveSection("section1") {
t.Errorf("RemoveSection failure: true on second remove")
}
// == Test types
// add section
if !c.AddSection("section2") {
t.Errorf("AddSection failure: false on first insert")
}
// add number
if !c.AddOption("section2", "test-number", "666") {
t.Errorf("AddOption failure: false on first insert")
}
testGet(t, c, "section2", "test-number", 666) // read it back
// add 'yes' (bool)
if !c.AddOption("section2", "test-yes", "yes") {
t.Errorf("AddOption failure: false on first insert")
}
testGet(t, c, "section2", "test-yes", true) // read it back
// add 'false' (bool)
if !c.AddOption("section2", "test-false", "false") {
t.Errorf("AddOption failure: false on first insert")
}
testGet(t, c, "section2", "test-false", false) // read it back
// == Test cycle
c.AddOption(DefaultSection, "opt1", "%(opt2)s")
c.AddOption(DefaultSection, "opt2", "%(opt1)s")
_, err = c.String(DefaultSection, "opt1")
if err == nil {
t.Errorf("String failure: no error for cycle")
} else if !strings.Contains(err.Error(), "cycle") {
t.Errorf("String failure: incorrect error for cycle")
}
}
// TestReadFile creates a 'tough' configuration file and test (read) parsing.
func TestReadFile(t *testing.T) {
file, err := os.Create(tmpFilename)
if err != nil {
t.Fatal("Test cannot run because cannot write temporary file: " + tmpFilename)
}
err = os.Setenv("GO_CONFIGFILE_TEST_ENV_VAR", "configvalue12345")
if err != nil {
t.Fatalf("Test cannot run because cannot set environment variable GO_CONFIGFILE_TEST_ENV_VAR: %#v", err)
}
buf := bufio.NewWriter(file)
buf.WriteString("optionInDefaultSection=true\n")
buf.WriteString("[section-1]\n")
buf.WriteString("option1=value1 ; This is a comment\n")
buf.WriteString("option2 : 2#Not a comment\t#Now this is a comment after a TAB\n")
buf.WriteString(" # Let me put another comment\n")
buf.WriteString("option3= line1\n line2: \n\tline3=v # Comment multiline with := in value\n")
buf.WriteString("; Another comment\n")
buf.WriteString("[" + DefaultSection + "]\n")
buf.WriteString("variable1=small\n")
buf.WriteString("variable2=a_part_of_a_%(variable1)s_test\n")
buf.WriteString("[secTION-2]\n")
buf.WriteString("IS-flag-TRUE=Yes\n")
buf.WriteString("[section-1] # comment on section header\n") // continue again [section-1]
buf.WriteString("option4=this_is_%(variable2)s.\n")
buf.WriteString("envoption1=this_uses_${GO_CONFIGFILE_TEST_ENV_VAR}_env\n")
buf.WriteString("optionInDefaultSection=false")
buf.Flush()
file.Close()
c, err := ReadDefault(tmpFilename)
if err != nil {
t.Fatalf("ReadDefault failure: %s", err)
}
// check number of sections
if len(c.Sections()) != 3 {
t.Errorf("Sections failure: wrong number of sections")
}
// check number of options 6 of [section-1] plus 2 of [default]
opts, _ := c.Options("section-1")
if len(opts) != 8 {
t.Errorf("Options failure: wrong number of options: %d", len(opts))
}
testGet(t, c, "section-1", "option1", "value1")
testGet(t, c, "section-1", "option2", "2#Not a comment")
testGet(t, c, "section-1", "option3", "line1\nline2:\nline3=v")
testGet(t, c, "section-1", "option4", "this_is_a_part_of_a_small_test.")
testGet(t, c, "section-1", "envoption1", "this_uses_configvalue12345_env")
testGet(t, c, "section-1", "optionInDefaultSection", false)
testGet(t, c, "section-2", "optionInDefaultSection", true)
testGet(t, c, "secTION-2", "IS-flag-TRUE", true) // case-sensitive
}
// TestWriteReadFile tests writing and reading back a configuration file.
func TestWriteReadFile(t *testing.T) {
cw := NewDefault()
// write file; will test only read later on
cw.AddSection("First-Section")
cw.AddOption("First-Section", "option1", "value option1")
cw.AddOption("First-Section", "option2", "2")
cw.AddOption("", "host", "www.example.com")
cw.AddOption(DefaultSection, "protocol", "https://")
cw.AddOption(DefaultSection, "base-url", "%(protocol)s%(host)s")
cw.AddOption("Another-Section", "useHTTPS", "y")
cw.AddOption("Another-Section", "url", "%(base-url)s/some/path")
cw.WriteFile(tmpFilename, 0644, "Test file for test-case")
// read back file and test
cr, err := ReadDefault(tmpFilename)
if err != nil {
t.Fatalf("ReadDefault failure: %s", err)
}
testGet(t, cr, "First-Section", "option1", "value option1")
testGet(t, cr, "First-Section", "option2", 2)
testGet(t, cr, "Another-Section", "useHTTPS", true)
testGet(t, cr, "Another-Section", "url", "https://www.example.com/some/path")
defer os.Remove(tmpFilename)
}
// TestSectionOptions tests read options in a section without default options.
func TestSectionOptions(t *testing.T) {
cw := NewDefault()
// write file; will test only read later on
cw.AddSection("First-Section")
cw.AddOption("First-Section", "option1", "value option1")
cw.AddOption("First-Section", "option2", "2")
cw.AddOption("", "host", "www.example.com")
cw.AddOption(DefaultSection, "protocol", "https://")
cw.AddOption(DefaultSection, "base-url", "%(protocol)s%(host)s")
cw.AddOption("Another-Section", "useHTTPS", "y")
cw.AddOption("Another-Section", "url", "%(base-url)s/some/path")
cw.WriteFile(tmpFilename, 0644, "Test file for test-case")
// read back file and test
cr, err := ReadDefault(tmpFilename)
if err != nil {
t.Fatalf("ReadDefault failure: %s", err)
}
options, err := cr.SectionOptions("First-Section")
if err != nil {
t.Fatalf("SectionOptions failure: %s", err)
}
if len(options) != 2 {
t.Fatalf("SectionOptions reads wrong data: %v", options)
}
expected := map[string]bool{
"option1": true,
"option2": true,
}
actual := map[string]bool{}
for _, v := range options {
actual[v] = true
}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("SectionOptions reads wrong data: %v", options)
}
options, err = cr.SectionOptions(DefaultSection)
if err != nil {
t.Fatalf("SectionOptions failure: %s", err)
}
expected = map[string]bool{
"host": true,
"protocol": true,
"base-url": true,
}
actual = map[string]bool{}
for _, v := range options {
actual[v] = true
}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("SectionOptions reads wrong data: %v", options)
}
defer os.Remove(tmpFilename)
}
// TestMerge tests merging 2 configurations.
func TestMerge(t *testing.T) {
target, error := ReadDefault(targetFilename)
if error != nil {
t.Fatalf("Unable to read target config file '%s'", targetFilename)
}
source, error := ReadDefault(sourceFilename)
if error != nil {
t.Fatalf("Unable to read source config file '%s'", sourceFilename)
}
target.Merge(source)
// Assert whether a regular option was merged from source -> target
if result, _ := target.String(DefaultSection, "one"); result != "source1" {
t.Errorf("Expected 'one' to be '1' but instead it was '%s'", result)
}
// Assert that a non-existent option in source was not overwritten
if result, _ := target.String(DefaultSection, "five"); result != "5" {
t.Errorf("Expected 'five' to be '5' but instead it was '%s'", result)
}
// Assert that a folded option was correctly unfolded
if result, _ := target.String(DefaultSection, "two_+_three"); result != "source2 + source3" {
t.Errorf("Expected 'two_+_three' to be 'source2 + source3' but instead it was '%s'", result)
}
if result, _ := target.String(DefaultSection, "four"); result != "4" {
t.Errorf("Expected 'four' to be '4' but instead it was '%s'", result)
}
// Assert that a section option has been merged
if result, _ := target.String("X", "x.one"); result != "sourcex1" {
t.Errorf("Expected '[X] x.one' to be 'sourcex1' but instead it was '%s'", result)
}
if result, _ := target.String("X", "x.four"); result != "x4" {
t.Errorf("Expected '[X] x.four' to be 'x4' but instead it was '%s'", result)
}
}
func TestLoadContextOneConf(t *testing.T) {
ctx, err := LoadContext("app.conf", []string{"testdata/conf-path1"})
if err != nil {
t.Errorf("Error: %v", err)
t.FailNow()
}
ctx.SetSection("X")
result, found := ctx.String("x.three")
if !strings.EqualFold("conf1-sourcex3", result) {
t.Errorf("Expected '[X] x.three' to be 'conf1-sourcex3' but instead it was '%s'", result)
}
_, found = ctx.String("x.notexists")
if found {
t.Error("Config 'x.notexists' shouldn't found")
}
ctx.SetSection("Y")
result, found = ctx.String("y.one")
if !strings.EqualFold("conf1-sourcey1", result) {
t.Errorf("Expected '[Y] y.one' to be 'conf1-sourcey1' but instead it was '%s'", result)
}
_, found = ctx.String("y.notexists")
if found {
t.Error("Config 'y.notexists' shouldn't found")
}
}
func TestLoadContextMultipleConfWithPriority(t *testing.T) {
ctx, err := LoadContext("app.conf", []string{"testdata/conf-path1", "testdata/conf-path2"})
if err != nil {
t.Errorf("Error: %v", err)
t.FailNow()
}
ctx.SetSection("X")
result, found := ctx.String("x.two")
if !strings.EqualFold("override-conf2-sourcex2", result) {
t.Errorf("Expected '[X] x.two' to be 'override-conf2-sourcex2' but instead it was '%s'", result)
}
_, found = ctx.String("x.notexists")
if found {
t.Error("Config 'x.notexists' shouldn't be found")
}
ctx.SetSection("Y")
result, found = ctx.String("y.three")
if !strings.EqualFold("override-conf2-sourcey3", result) {
t.Errorf("Expected '[Y] y.three' to be 'override-conf2-sourcey3' but instead it was '%s'", result)
}
_, found = ctx.String("y.notexists")
if found {
t.Error("Config 'y.notexists' shouldn't be found")
}
}
func TestLoadContextConfNotFound(t *testing.T) {
_, err := LoadContext("notfound.conf", []string{"testdata/conf-path1"})
if err != nil && !strings.EqualFold("open testdata/conf-path1/notfound.conf: no such file or directory", err.Error()) {
t.Errorf("This is not expected error: %v", err)
}
}
func TestLoadContextInvalidConf(t *testing.T) {
_, err := LoadContext("app-invalid.conf", []string{"testdata"})
if err != nil && !strings.EqualFold("testdata/app-invalid.conf: could not parse line #7: %(two)s + %(four)s", err.Error()) {
t.Errorf("This is not expected error: %v", err)
}
}

152
vendor/github.com/revel/config/config.go generated vendored Normal file
View File

@@ -0,0 +1,152 @@
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"regexp"
"strings"
)
// config constants
const (
// Default section name.
DefaultSection = "DEFAULT"
// Maximum allowed depth when recursively substituing variable names.
DepthValues = 200
DefaultComment = "# "
AlternativeComment = "; "
DefaultSeparator = ":"
AlternativeSeparator = "="
)
var (
// Strings accepted as boolean.
boolString = map[string]bool{
"t": true,
"true": true,
"y": true,
"yes": true,
"on": true,
"1": true,
"f": false,
"false": false,
"n": false,
"no": false,
"off": false,
"0": false,
}
varRegExp = regexp.MustCompile(`%\(([a-zA-Z0-9_.\-]+)\)s`) // %(variable)s
envVarRegExp = regexp.MustCompile(`\${([a-zA-Z0-9_.\-]+)}`) // ${envvar}
)
// Config is the representation of configuration settings.
type Config struct {
comment string
separator string
// Sections order
lastIDSection int // Last section identifier
idSection map[string]int // Section : position
// The last option identifier used for each section.
lastIDOption map[string]int // Section : last identifier
// Section -> option : value
data map[string]map[string]*tValue
}
// tValue holds the input position for a value.
type tValue struct {
position int // Option order
v string // value
}
// New creates an empty configuration representation.
// This representation can be filled with AddSection and AddOption and then
// saved to a file using WriteFile.
//
// == Arguments
//
// comment: has to be `DefaultComment` or `AlternativeComment`
// separator: has to be `DefaultSeparator` or `AlternativeSeparator`
// preSpace: indicate if is inserted a space before of the separator
// postSpace: indicate if is added a space after of the separator
func New(comment, separator string, preSpace, postSpace bool) *Config {
if comment != DefaultComment && comment != AlternativeComment {
panic("comment character not valid")
}
if separator != DefaultSeparator && separator != AlternativeSeparator {
panic("separator character not valid")
}
// == Get spaces around separator
if preSpace {
separator = " " + separator
}
if postSpace {
separator += " "
}
//==
c := new(Config)
c.comment = comment
c.separator = separator
c.idSection = make(map[string]int)
c.lastIDOption = make(map[string]int)
c.data = make(map[string]map[string]*tValue)
c.AddSection(DefaultSection) // Default section always exists.
return c
}
// NewDefault creates a configuration representation with values by default.
func NewDefault() *Config {
return New(DefaultComment, DefaultSeparator, false, true)
}
// Merge merges the given configuration "source" with this one ("target").
//
// Merging means that any option (under any section) from source that is not in
// target will be copied into target. When the target already has an option with
// the same name and section then it is overwritten (i.o.w. the source wins).
func (target *Config) Merge(source *Config) {
if source == nil || source.data == nil || len(source.data) == 0 {
return
}
for section, option := range source.data {
for optionName, optionValue := range option {
target.AddOption(section, optionName, optionValue.v)
}
}
}
// == Utility
func stripComments(l string) string {
// Comments are preceded by space or TAB
for _, c := range []string{" ;", "\t;", " #", "\t#"} {
if i := strings.Index(l, c); i != -1 {
l = l[0:i]
}
}
return l
}

169
vendor/github.com/revel/config/context.go generated vendored Normal file
View File

@@ -0,0 +1,169 @@
// Copyright 2016 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// Context structure handles the parsing of app.conf
// It has a "preferred" section that is checked first for option queries.
// If the preferred section does not have the option, the DEFAULT section is
// checked fallback.
type Context struct {
config *Config
section string // Check this section first, then fall back to DEFAULT
}
// NewContext creates a default section and returns config context
func NewContext() *Context {
return &Context{config: NewDefault()}
}
// LoadContext loads the ini config from gives multiple conf paths
func LoadContext(confName string, confPaths []string) (*Context, error) {
ctx := NewContext()
for _, confPath := range confPaths {
path := filepath.Join(confPath, confName)
conf, err := ReadDefault(path)
if err != nil {
if _, isPathErr := err.(*os.PathError); !isPathErr {
return nil, fmt.Errorf("%v: %v", path, err)
}
continue
}
ctx.config.Merge(conf)
}
return ctx, nil
}
// Raw returns raw config instance
func (c *Context) Raw() *Config {
return c.config
}
// SetSection the section scope of ini config
// For e.g.: dev or prod
func (c *Context) SetSection(section string) {
c.section = section
}
// SetOption sets the value for the given key
func (c *Context) SetOption(name, value string) {
c.config.AddOption(c.section, name, value)
}
// Int returns `int` config value and if found returns true
// otherwise false
func (c *Context) Int(option string) (result int, found bool) {
result, err := c.config.Int(c.section, option)
if err == nil {
return result, true
}
if _, ok := err.(OptionError); ok {
return 0, false
}
// If it wasn't an OptionError, it must have failed to parse.
return 0, false
}
// IntDefault returns `int` config value if found otherwise
// returns given default int value
func (c *Context) IntDefault(option string, dfault int) int {
if r, found := c.Int(option); found {
return r
}
return dfault
}
// Bool returns `bool` config value and if found returns true
// otherwise false
func (c *Context) Bool(option string) (result, found bool) {
result, err := c.config.Bool(c.section, option)
if err == nil {
return result, true
}
if _, ok := err.(OptionError); ok {
return false, false
}
// If it wasn't an OptionError, it must have failed to parse.
return false, false
}
// BoolDefault returns `bool` config value if found otherwise
// returns given default bool value
func (c *Context) BoolDefault(option string, dfault bool) bool {
if r, found := c.Bool(option); found {
return r
}
return dfault
}
// String returns `string` config value and if found returns true
// otherwise false
func (c *Context) String(option string) (result string, found bool) {
if r, err := c.config.String(c.section, option); err == nil {
return stripQuotes(r), true
}
return "", false
}
// StringDefault returns `string` config value if found otherwise
// returns given default string value
func (c *Context) StringDefault(option, dfault string) string {
if r, found := c.String(option); found {
return r
}
return dfault
}
// HasSection checks if the configuration has the given section.
// (The default section always exists.)
func (c *Context) HasSection(section string) bool {
return c.config.HasSection(section)
}
// Options returns all configuration option keys.
// If a prefix is provided, then that is applied as a filter.
func (c *Context) Options(prefix string) []string {
var options []string
keys, _ := c.config.Options(c.section)
for _, key := range keys {
if strings.HasPrefix(key, prefix) {
options = append(options, key)
}
}
return options
}
// Helpers
func stripQuotes(s string) string {
if s == "" {
return s
}
if s[0] == '"' && s[len(s)-1] == '"' {
return s[1 : len(s)-1]
}
return s
}

29
vendor/github.com/revel/config/error.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
// SectionError type string
type SectionError string
func (e SectionError) Error() string {
return "section not found: " + string(e)
}
// OptionError type string
type OptionError string
func (e OptionError) Error() string {
return "option not found: " + string(e)
}

113
vendor/github.com/revel/config/option.go generated vendored Normal file
View File

@@ -0,0 +1,113 @@
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import "errors"
// AddOption adds a new option and value to the configuration.
//
// If the section is nil then uses the section by default; if it does not exist,
// it is created in advance.
//
// It returns true if the option and value were inserted, and false if the value
// was overwritten.
func (c *Config) AddOption(section string, option string, value string) bool {
c.AddSection(section) // Make sure section exists
if section == "" {
section = DefaultSection
}
_, ok := c.data[section][option]
c.data[section][option] = &tValue{c.lastIDOption[section], value}
c.lastIDOption[section]++
return !ok
}
// RemoveOption removes a option and value from the configuration.
// It returns true if the option and value were removed, and false otherwise,
// including if the section did not exist.
func (c *Config) RemoveOption(section string, option string) bool {
if _, ok := c.data[section]; !ok {
return false
}
_, ok := c.data[section][option]
delete(c.data[section], option)
return ok
}
// HasOption checks if the configuration has the given option in the section.
// It returns false if either the option or section do not exist.
func (c *Config) HasOption(section string, option string) bool {
if _, ok := c.data[section]; !ok {
return false
}
_, okd := c.data[DefaultSection][option]
_, oknd := c.data[section][option]
return okd || oknd
}
// Options returns the list of options available in the given section.
// It returns an error if the section does not exist and an empty list if the
// section is empty. Options within the default section are also included.
func (c *Config) Options(section string) (options []string, err error) {
if _, ok := c.data[section]; !ok {
return nil, errors.New(SectionError(section).Error())
}
// Keep a map of option names we've seen to deduplicate.
optionMap := make(map[string]struct{},
len(c.data[DefaultSection])+len(c.data[section]))
for s := range c.data[DefaultSection] {
optionMap[s] = struct{}{}
}
for s := range c.data[section] {
optionMap[s] = struct{}{}
}
// Get the keys.
i := 0
options = make([]string, len(optionMap))
for k := range optionMap {
options[i] = k
i++
}
return options, nil
}
// SectionOptions returns only the list of options available in the given section.
// Unlike Options, SectionOptions doesn't return options in default section.
// It returns an error if the section doesn't exist.
func (c *Config) SectionOptions(section string) (options []string, err error) {
if _, ok := c.data[section]; !ok {
return nil, errors.New(SectionError(section).Error())
}
options = make([]string, len(c.data[section]))
i := 0
for s := range c.data[section] {
options[i] = s
i++
}
return options, nil
}

102
vendor/github.com/revel/config/read.go generated vendored Normal file
View File

@@ -0,0 +1,102 @@
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"bufio"
"fmt"
"os"
"strings"
"unicode"
)
// _read is the base to read a file and get the configuration representation.
// That representation can be queried with GetString, etc.
func _read(fname string, c *Config) (*Config, error) {
file, err := os.Open(fname)
if err != nil {
return nil, err
}
if err = c.read(bufio.NewReader(file)); err != nil {
return nil, err
}
if err = file.Close(); err != nil {
return nil, err
}
return c, nil
}
// Read reads a configuration file and returns its representation.
// All arguments, except `fname`, are related to `New()`
func Read(fname string, comment, separator string, preSpace, postSpace bool) (*Config, error) {
return _read(fname, New(comment, separator, preSpace, postSpace))
}
// ReadDefault reads a configuration file and returns its representation.
// It uses values by default.
func ReadDefault(fname string) (*Config, error) {
return _read(fname, NewDefault())
}
// * * *
func (c *Config) read(buf *bufio.Reader) (err error) {
var section, option string
var scanner = bufio.NewScanner(buf)
lineNo := 0
for scanner.Scan() {
l := strings.TrimRightFunc(stripComments(scanner.Text()), unicode.IsSpace)
lineNo++
// Switch written for readability (not performance)
switch {
// Empty line and comments
case len(l) == 0, l[0] == '#', l[0] == ';':
continue
// New section. The [ must be at the start of the line
case l[0] == '[' && l[len(l)-1] == ']':
option = "" // reset multi-line value
section = strings.TrimSpace(l[1 : len(l)-1])
c.AddSection(section)
// Continuation of multi-line value
// starts with whitespace, we're in a section and working on an option
case section != "" && option != "" && (l[0] == ' ' || l[0] == '\t'):
prev, _ := c.RawString(section, option)
value := strings.TrimSpace(l)
c.AddOption(section, option, prev+"\n"+value)
// Other alternatives
default:
i := strings.IndexAny(l, "=:")
switch {
// Option and value
case i > 0 && l[0] != ' ' && l[0] != '\t': // found an =: and it's not a multiline continuation
option = strings.TrimSpace(l[0:i])
value := strings.TrimSpace(l[i+1:])
c.AddOption(section, option, value)
default:
return fmt.Errorf("could not parse line #%v: %v", lineNo, l)
}
}
}
return scanner.Err()
}

88
vendor/github.com/revel/config/section.go generated vendored Normal file
View File

@@ -0,0 +1,88 @@
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
// AddSection adds a new section to the configuration.
//
// If the section is nil then uses the section by default which it's already
// created.
//
// It returns true if the new section was inserted, and false if the section
// already existed.
func (c *Config) AddSection(section string) bool {
// DefaultSection
if section == "" {
return false
}
if _, ok := c.data[section]; ok {
return false
}
c.data[section] = make(map[string]*tValue)
// Section order
c.idSection[section] = c.lastIDSection
c.lastIDSection++
return true
}
// RemoveSection removes a section from the configuration.
// It returns true if the section was removed, and false if section did not exist.
func (c *Config) RemoveSection(section string) bool {
_, ok := c.data[section]
// Default section cannot be removed.
if !ok || section == DefaultSection {
return false
}
for o := range c.data[section] {
delete(c.data[section], o) // *value
}
delete(c.data, section)
delete(c.lastIDOption, section)
delete(c.idSection, section)
return true
}
// HasSection checks if the configuration has the given section.
// (The default section always exists.)
func (c *Config) HasSection(section string) bool {
_, ok := c.data[section]
return ok
}
// Sections returns the list of sections in the configuration.
// (The default section always exists).
func (c *Config) Sections() (sections []string) {
sections = make([]string, len(c.idSection))
pos := 0 // Position in sections
for i := 0; i < c.lastIDSection; i++ {
for section, id := range c.idSection {
if id == i {
sections[pos] = section
pos++
}
}
}
return sections
}

View File

@@ -0,0 +1,17 @@
one=source1
two=source2
three=source3
four=4
#invalid spot
%(two)s + %(four)s
[X]
x.one=conf1-sourcex1
x.two=conf1-sourcex2
x.three=conf1-sourcex3
[Y]
y.one=conf1-sourcey1
y.two=conf1-sourcey2
y.three=conf1-sourcey3

View File

@@ -0,0 +1,16 @@
one=source1
two=source2
three=source3
four=4
two_+_four=%(two)s + %(four)s
[X]
x.one=conf1-sourcex1
x.two=conf1-sourcex2
x.three=conf1-sourcex3
[Y]
y.one=conf1-sourcey1
y.two=conf1-sourcey2
y.three=conf1-sourcey3

View File

@@ -0,0 +1,18 @@
one=source1
two=source2
three=source3
four=4
two_+_four=%(two)s + %(four)s
[X]
x.one=conf2-sourcex1
x.two=override-conf2-sourcex2
x.three=conf2-sourcex3
x.four=exists here only
[Y]
y.one=conf2-sourcey1
y.two=conf2-sourcey2
y.three=override-conf2-sourcey3

17
vendor/github.com/revel/config/testdata/source.cfg generated vendored Normal file
View File

@@ -0,0 +1,17 @@
one=source1
two=source2
three=source3
four=4
two_+_four=%(two)s + %(four)s
[X]
x.one=sourcex1
x.two=sourcex2
x.three=sourcex3
[Y]
y.one=sourcey1
y.two=sourcey2
y.three=sourcey3

19
vendor/github.com/revel/config/testdata/target.cfg generated vendored Normal file
View File

@@ -0,0 +1,19 @@
one=1
two=2
three=3
five=5
two_+_three=%(two)s + %(three)s
[X]
x.one=x1
x.two=x2
x.three=x3
x.four=x4
[Y]
y.one=y1
y.two=y2
y.three=y3
y.four=y4

155
vendor/github.com/revel/config/type.go generated vendored Normal file
View File

@@ -0,0 +1,155 @@
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"errors"
"fmt"
"os"
"regexp"
"strconv"
"strings"
)
// Substitutes values, calculated by callback, on matching regex
func (c *Config) computeVar(beforeValue *string, regx *regexp.Regexp, headsz, tailsz int, withVar func(*string) string) (*string, error) {
var i int
computedVal := beforeValue
for i = 0; i < DepthValues; i++ { // keep a sane depth
vr := regx.FindStringSubmatchIndex(*computedVal)
if len(vr) == 0 {
break
}
varname := (*computedVal)[vr[headsz]:vr[headsz+1]]
varVal := withVar(&varname)
if varVal == "" {
return &varVal, fmt.Errorf("Option not found: %s", varname)
}
// substitute by new value and take off leading '%(' and trailing ')s'
// %(foo)s => headsz=2, tailsz=2
// ${foo} => headsz=2, tailsz=1
newVal := (*computedVal)[0:vr[headsz]-headsz] + varVal + (*computedVal)[vr[headsz+1]+tailsz:]
computedVal = &newVal
}
if i == DepthValues {
retVal := ""
return &retVal,
fmt.Errorf("Possible cycle while unfolding variables: max depth of %d reached", DepthValues)
}
return computedVal, nil
}
// Bool has the same behaviour as String but converts the response to bool.
// See "boolString" for string values converted to bool.
func (c *Config) Bool(section string, option string) (value bool, err error) {
sv, err := c.String(section, option)
if err != nil {
return false, err
}
value, ok := boolString[strings.ToLower(sv)]
if !ok {
return false, errors.New("could not parse bool value: " + sv)
}
return value, nil
}
// Float has the same behaviour as String but converts the response to float.
func (c *Config) Float(section string, option string) (value float64, err error) {
sv, err := c.String(section, option)
if err == nil {
value, err = strconv.ParseFloat(sv, 64)
}
return value, err
}
// Int has the same behaviour as String but converts the response to int.
func (c *Config) Int(section string, option string) (value int, err error) {
sv, err := c.String(section, option)
if err == nil {
value, err = strconv.Atoi(sv)
}
return value, err
}
// RawString gets the (raw) string value for the given option in the section.
// The raw string value is not subjected to unfolding, which was illustrated in
// the beginning of this documentation.
//
// It returns an error if either the section or the option do not exist.
func (c *Config) RawString(section string, option string) (value string, err error) {
if _, ok := c.data[section]; ok {
if tValue, ok := c.data[section][option]; ok {
return tValue.v, nil
}
}
return c.RawStringDefault(option)
}
// RawStringDefault gets the (raw) string value for the given option from the
// DEFAULT section.
//
// It returns an error if the option does not exist in the DEFAULT section.
func (c *Config) RawStringDefault(option string) (value string, err error) {
if tValue, ok := c.data[DefaultSection][option]; ok {
return tValue.v, nil
}
return "", OptionError(option)
}
// String gets the string value for the given option in the section.
// If the value needs to be unfolded (see e.g. %(host)s example in the beginning
// of this documentation), then String does this unfolding automatically, up to
// `DepthValues` number of iterations.
//
// It returns an error if either the section or the option do not exist, or the
// unfolding cycled.
func (c *Config) String(section string, option string) (value string, err error) {
value, err = c.RawString(section, option)
if err != nil {
return "", err
}
// % variables
computedVal, err := c.computeVar(&value, varRegExp, 2, 2, func(varName *string) string {
lowerVar := *varName
// search variable in default section as well as current section
varVal, _ := c.data[DefaultSection][lowerVar]
if _, ok := c.data[section][lowerVar]; ok {
varVal = c.data[section][lowerVar]
}
return varVal.v
})
value = *computedVal
if err != nil {
return value, err
}
// $ environment variables
computedVal, err = c.computeVar(&value, envVarRegExp, 2, 1, func(varName *string) string {
return os.Getenv(*varName)
})
value = *computedVal
return value, err
}

87
vendor/github.com/revel/config/write.go generated vendored Normal file
View File

@@ -0,0 +1,87 @@
// Copyright 2009 The "config" Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"bufio"
"fmt"
"os"
"strings"
)
// WriteFile saves the configuration representation to a file.
// The desired file permissions must be passed as in os.Open. The header is a
// string that is saved as a comment in the first line of the file.
func (c *Config) WriteFile(fname string, perm os.FileMode, header string) error {
file, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
}
buf := bufio.NewWriter(file)
if err = c.write(buf, header); err != nil {
return err
}
_ = buf.Flush()
return file.Close()
}
func (c *Config) write(buf *bufio.Writer, header string) (err error) {
if header != "" {
// Add comment character after of each new line.
if i := strings.Index(header, "\n"); i != -1 {
header = strings.Replace(header, "\n", "\n"+c.comment, -1)
}
if _, err = buf.WriteString(c.comment + header + "\n"); err != nil {
return err
}
}
for _, orderedSection := range c.Sections() {
for section, sectionMap := range c.data {
if section == orderedSection {
// Skip default section if empty.
if section == DefaultSection && len(sectionMap) == 0 {
continue
}
if _, err = buf.WriteString("\n[" + section + "]\n"); err != nil {
return err
}
// Follow the input order in options.
for i := 0; i < c.lastIDOption[section]; i++ {
for option, tValue := range sectionMap {
if tValue.position == i {
if _, err = buf.WriteString(fmt.Sprint(
option, c.separator, tValue.v, "\n")); err != nil {
return err
}
c.RemoveOption(section, option)
break
}
}
}
}
}
}
_, err = buf.WriteString("\n")
return err
}