ini released v1.48.0 and deprecated the ini.AllCapsUnderscore symbol, as such, during the upgrade we migrated to using ini.SnackCase.tags/v1.11.0-rc1
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | ||||
gopkg.in/editorconfig/editorconfig-core-go.v1 v1.3.0 | gopkg.in/editorconfig/editorconfig-core-go.v1 v1.3.0 | ||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | ||||
gopkg.in/ini.v1 v1.46.0 | |||||
gopkg.in/ini.v1 v1.48.0 | |||||
gopkg.in/ldap.v3 v3.0.2 | gopkg.in/ldap.v3 v3.0.2 | ||||
gopkg.in/src-d/go-billy.v4 v4.3.2 | gopkg.in/src-d/go-billy.v4 v4.3.2 | ||||
gopkg.in/src-d/go-git.v4 v4.13.1 | gopkg.in/src-d/go-git.v4 v4.13.1 |
gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= | gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= | ||||
gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag= | gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag= | ||||
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
gopkg.in/ini.v1 v1.48.0 h1:URjZc+8ugRY5mL5uUeQH/a63JcHwdX9xZaWvmNWD7z8= | |||||
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||||
gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= | gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= | ||||
gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= | gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= | ||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= |
} else { | } else { | ||||
log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf) | log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf) | ||||
} | } | ||||
Cfg.NameMapper = ini.AllCapsUnderscore | |||||
Cfg.NameMapper = ini.SnackCase | |||||
homeDir, err := com.HomeDir() | homeDir, err := com.HomeDir() | ||||
if err != nil { | if err != nil { |
Please add `-u` flag to update in the future. | Please add `-u` flag to update in the future. | ||||
## Go Modules | |||||
For historical reason, people use two different import paths for this package: `github.com/go-ini/ini` and `gopkg.in/ini.v1`. If you get error similar to the following one: | |||||
``` | |||||
go: finding github.com/go-ini/ini v0.0.0-00010101000000-000000000000 | |||||
go: github.com/go-ini/ini@v0.0.0-00010101000000-000000000000: unknown revision 000000000000 | |||||
go: error loading module requirements | |||||
``` | |||||
It is because one of your dependencies is using deprecated import path `github.com/go-ini/ini`, you can make a quick fix by adding the following line to your `go.mod` file (`v.1.44.0` was the latest version tagged on `master` branch): | |||||
``` | |||||
replace github.com/go-ini/ini => gopkg.in/ini.v1 v1.44.0 | |||||
``` | |||||
## Getting Help | ## Getting Help | ||||
- [Getting Started](https://ini.unknwon.io/docs/intro/getting_started) | - [Getting Started](https://ini.unknwon.io/docs/intro/getting_started) |
// Copyright 2019 Unknwon | |||||
// | |||||
// 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 ini | |||||
import ( | |||||
"bytes" | |||||
"fmt" | |||||
"io" | |||||
"io/ioutil" | |||||
"os" | |||||
) | |||||
var ( | |||||
_ dataSource = (*sourceFile)(nil) | |||||
_ dataSource = (*sourceData)(nil) | |||||
_ dataSource = (*sourceReadCloser)(nil) | |||||
) | |||||
// dataSource is an interface that returns object which can be read and closed. | |||||
type dataSource interface { | |||||
ReadCloser() (io.ReadCloser, error) | |||||
} | |||||
// sourceFile represents an object that contains content on the local file system. | |||||
type sourceFile struct { | |||||
name string | |||||
} | |||||
func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { | |||||
return os.Open(s.name) | |||||
} | |||||
// sourceData represents an object that contains content in memory. | |||||
type sourceData struct { | |||||
data []byte | |||||
} | |||||
func (s *sourceData) ReadCloser() (io.ReadCloser, error) { | |||||
return ioutil.NopCloser(bytes.NewReader(s.data)), nil | |||||
} | |||||
// sourceReadCloser represents an input stream with Close method. | |||||
type sourceReadCloser struct { | |||||
reader io.ReadCloser | |||||
} | |||||
func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { | |||||
return s.reader, nil | |||||
} | |||||
func parseDataSource(source interface{}) (dataSource, error) { | |||||
switch s := source.(type) { | |||||
case string: | |||||
return sourceFile{s}, nil | |||||
case []byte: | |||||
return &sourceData{s}, nil | |||||
case io.ReadCloser: | |||||
return &sourceReadCloser{s}, nil | |||||
default: | |||||
return nil, fmt.Errorf("error parsing data source: unknown type %q", s) | |||||
} | |||||
} |
// Copyright 2019 Unknwon | |||||
// | |||||
// 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 ini | |||||
const ( | |||||
// Deprecated: Use "DefaultSection" instead. | |||||
DEFAULT_SECTION = DefaultSection | |||||
) | |||||
var ( | |||||
// Deprecated: AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. | |||||
AllCapsUnderscore = SnackCase | |||||
) |
} | } | ||||
alignSpaces := bytes.Repeat([]byte(" "), alignLength) | alignSpaces := bytes.Repeat([]byte(" "), alignLength) | ||||
KEY_LIST: | |||||
KeyList: | |||||
for _, kname := range sec.keyList { | for _, kname := range sec.keyList { | ||||
key := sec.Key(kname) | key := sec.Key(kname) | ||||
if len(key.Comment) > 0 { | if len(key.Comment) > 0 { | ||||
if kname != sec.keyList[len(sec.keyList)-1] { | if kname != sec.keyList[len(sec.keyList)-1] { | ||||
buf.WriteString(LineBreak) | buf.WriteString(LineBreak) | ||||
} | } | ||||
continue KEY_LIST | |||||
continue KeyList | |||||
} | } | ||||
// Write out alignment spaces before "=" sign | // Write out alignment spaces before "=" sign |
// Copyright 2019 Unknwon | |||||
// | |||||
// 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 ini | |||||
func inSlice(str string, s []string) bool { | |||||
for _, v := range s { | |||||
if str == v { | |||||
return true | |||||
} | |||||
} | |||||
return false | |||||
} |
package ini | package ini | ||||
import ( | import ( | ||||
"bytes" | |||||
"fmt" | |||||
"io" | |||||
"io/ioutil" | |||||
"os" | |||||
"regexp" | "regexp" | ||||
"runtime" | "runtime" | ||||
) | ) | ||||
// DefaultSection is the name of default section. You can use this constant or the string literal. | // DefaultSection is the name of default section. You can use this constant or the string literal. | ||||
// In most of cases, an empty string is all you need to access the section. | // In most of cases, an empty string is all you need to access the section. | ||||
DefaultSection = "DEFAULT" | DefaultSection = "DEFAULT" | ||||
// Deprecated: Use "DefaultSection" instead. | |||||
DEFAULT_SECTION = DefaultSection | |||||
// Maximum allowed depth when recursively substituing variable names. | // Maximum allowed depth when recursively substituing variable names. | ||||
depthValues = 99 | depthValues = 99 | ||||
version = "1.46.0" | |||||
version = "1.48.0" | |||||
) | ) | ||||
// Version returns current package version literal. | // Version returns current package version literal. | ||||
// This variable will be changed to "\r\n" automatically on Windows at package init time. | // This variable will be changed to "\r\n" automatically on Windows at package init time. | ||||
LineBreak = "\n" | LineBreak = "\n" | ||||
// DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. | |||||
DefaultFormatLeft = "" | |||||
// DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. | |||||
DefaultFormatRight = "" | |||||
// Variable regexp pattern: %(variable)s | // Variable regexp pattern: %(variable)s | ||||
varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`) | |||||
// PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output | |||||
// or reduce all possible spaces for compact format. | |||||
PrettyFormat = true | |||||
// PrettyEqual places spaces around "=" sign even when PrettyFormat is false. | |||||
PrettyEqual = false | |||||
varPattern = regexp.MustCompile(`%\(([^)]+)\)s`) | |||||
// DefaultHeader explicitly writes default section header. | // DefaultHeader explicitly writes default section header. | ||||
DefaultHeader = false | DefaultHeader = false | ||||
// PrettySection indicates whether to put a line between sections. | // PrettySection indicates whether to put a line between sections. | ||||
PrettySection = true | PrettySection = true | ||||
// PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output | |||||
// or reduce all possible spaces for compact format. | |||||
PrettyFormat = true | |||||
// PrettyEqual places spaces around "=" sign even when PrettyFormat is false. | |||||
PrettyEqual = false | |||||
// DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. | |||||
DefaultFormatLeft = "" | |||||
// DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. | |||||
DefaultFormatRight = "" | |||||
) | ) | ||||
func init() { | func init() { | ||||
} | } | ||||
} | } | ||||
func inSlice(str string, s []string) bool { | |||||
for _, v := range s { | |||||
if str == v { | |||||
return true | |||||
} | |||||
} | |||||
return false | |||||
} | |||||
// dataSource is an interface that returns object which can be read and closed. | |||||
type dataSource interface { | |||||
ReadCloser() (io.ReadCloser, error) | |||||
} | |||||
// sourceFile represents an object that contains content on the local file system. | |||||
type sourceFile struct { | |||||
name string | |||||
} | |||||
func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { | |||||
return os.Open(s.name) | |||||
} | |||||
// sourceData represents an object that contains content in memory. | |||||
type sourceData struct { | |||||
data []byte | |||||
} | |||||
func (s *sourceData) ReadCloser() (io.ReadCloser, error) { | |||||
return ioutil.NopCloser(bytes.NewReader(s.data)), nil | |||||
} | |||||
// sourceReadCloser represents an input stream with Close method. | |||||
type sourceReadCloser struct { | |||||
reader io.ReadCloser | |||||
} | |||||
func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { | |||||
return s.reader, nil | |||||
} | |||||
func parseDataSource(source interface{}) (dataSource, error) { | |||||
switch s := source.(type) { | |||||
case string: | |||||
return sourceFile{s}, nil | |||||
case []byte: | |||||
return &sourceData{s}, nil | |||||
case io.ReadCloser: | |||||
return &sourceReadCloser{s}, nil | |||||
default: | |||||
return nil, fmt.Errorf("error parsing data source: unknown type '%s'", s) | |||||
} | |||||
} | |||||
// LoadOptions contains all customized options used for load data source(s). | // LoadOptions contains all customized options used for load data source(s). | ||||
type LoadOptions struct { | type LoadOptions struct { | ||||
// Loose indicates whether the parser should ignore nonexistent files or return error. | // Loose indicates whether the parser should ignore nonexistent files or return error. |
return errors.New("cannot add shadow to auto-increment or boolean key") | return errors.New("cannot add shadow to auto-increment or boolean key") | ||||
} | } | ||||
// Deduplicate shadows based on their values. | |||||
if k.value == val { | |||||
return nil | |||||
} | |||||
for i := range k.shadows { | |||||
if k.shadows[i].value == val { | |||||
return nil | |||||
} | |||||
} | |||||
shadow := newKey(k.s, k.name, val) | shadow := newKey(k.s, k.name, val) | ||||
shadow.isShadow = true | shadow.isShadow = true | ||||
k.shadows = append(k.shadows, shadow) | k.shadows = append(k.shadows, shadow) | ||||
return vals | return vals | ||||
} | } | ||||
// Bools returns list of bool divided by given delimiter. Any invalid input will be treated as zero value. | |||||
func (k *Key) Bools(delim string) []bool { | |||||
vals, _ := k.parseBools(k.Strings(delim), true, false) | |||||
return vals | |||||
} | |||||
// TimesFormat parses with given format and returns list of time.Time divided by given delimiter. | // TimesFormat parses with given format and returns list of time.Time divided by given delimiter. | ||||
// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). | // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). | ||||
func (k *Key) TimesFormat(format, delim string) []time.Time { | func (k *Key) TimesFormat(format, delim string) []time.Time { | ||||
return vals | return vals | ||||
} | } | ||||
// ValidBools returns list of bool divided by given delimiter. If some value is not 64-bit unsigned | |||||
// integer, then it will not be included to result list. | |||||
func (k *Key) ValidBools(delim string) []bool { | |||||
vals, _ := k.parseBools(k.Strings(delim), false, false) | |||||
return vals | |||||
} | |||||
// ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. | // ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. | ||||
func (k *Key) ValidTimesFormat(format, delim string) []time.Time { | func (k *Key) ValidTimesFormat(format, delim string) []time.Time { | ||||
vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) | vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) | ||||
return k.parseUint64s(k.Strings(delim), false, true) | return k.parseUint64s(k.Strings(delim), false, true) | ||||
} | } | ||||
// StrictBools returns list of bool divided by given delimiter or error on first invalid input. | |||||
func (k *Key) StrictBools(delim string) ([]bool, error) { | |||||
return k.parseBools(k.Strings(delim), false, true) | |||||
} | |||||
// StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter | // StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter | ||||
// or error on first invalid input. | // or error on first invalid input. | ||||
func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { | func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { | ||||
return k.StrictTimesFormat(time.RFC3339, delim) | return k.StrictTimesFormat(time.RFC3339, delim) | ||||
} | } | ||||
// parseBools transforms strings to bools. | |||||
func (k *Key) parseBools(strs []string, addInvalid, returnOnInvalid bool) ([]bool, error) { | |||||
vals := make([]bool, 0, len(strs)) | |||||
for _, str := range strs { | |||||
val, err := parseBool(str) | |||||
if err != nil && returnOnInvalid { | |||||
return nil, err | |||||
} | |||||
if err == nil || addInvalid { | |||||
vals = append(vals, val) | |||||
} | |||||
} | |||||
return vals, nil | |||||
} | |||||
// parseFloat64s transforms strings to float64s. | // parseFloat64s transforms strings to float64s. | ||||
func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { | func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { | ||||
vals := make([]float64, 0, len(strs)) | vals := make([]float64, 0, len(strs)) |
// Built-in name getters. | // Built-in name getters. | ||||
var ( | var ( | ||||
// AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. | |||||
AllCapsUnderscore NameMapper = func(raw string) string { | |||||
// SnackCase converts to format SNACK_CASE. | |||||
SnackCase NameMapper = func(raw string) string { | |||||
newstr := make([]rune, 0, len(raw)) | newstr := make([]rune, 0, len(raw)) | ||||
for i, chr := range raw { | for i, chr := range raw { | ||||
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { | if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { | ||||
if i > 0 { | if i > 0 { | ||||
newstr = append(newstr, '_') | newstr = append(newstr, '_') | ||||
} | } | ||||
chr -= ('A' - 'a') | |||||
chr -= 'A' - 'a' | |||||
} | } | ||||
newstr = append(newstr, chr) | newstr = append(newstr, chr) | ||||
} | } | ||||
vals, err = key.parseUint64s(strs, true, false) | vals, err = key.parseUint64s(strs, true, false) | ||||
case reflect.Float64: | case reflect.Float64: | ||||
vals, err = key.parseFloat64s(strs, true, false) | vals, err = key.parseFloat64s(strs, true, false) | ||||
case reflect.Bool: | |||||
vals, err = key.parseBools(strs, true, false) | |||||
case reflectTime: | case reflectTime: | ||||
vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) | vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) | ||||
default: | default: | ||||
slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) | slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) | ||||
case reflect.Float64: | case reflect.Float64: | ||||
slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) | slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) | ||||
case reflect.Bool: | |||||
slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i])) | |||||
case reflectTime: | case reflectTime: | ||||
slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) | slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) | ||||
} | } | ||||
val = fmt.Sprint(slice.Index(i).Uint()) | val = fmt.Sprint(slice.Index(i).Uint()) | ||||
case reflect.Float64: | case reflect.Float64: | ||||
val = fmt.Sprint(slice.Index(i).Float()) | val = fmt.Sprint(slice.Index(i).Float()) | ||||
case reflect.Bool: | |||||
val = fmt.Sprint(slice.Index(i).Bool()) | |||||
case reflectTime: | case reflectTime: | ||||
val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339) | val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339) | ||||
default: | default: | ||||
buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) | buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) | ||||
case reflect.Float64: | case reflect.Float64: | ||||
buf.WriteString(fmt.Sprint(slice.Index(i).Float())) | buf.WriteString(fmt.Sprint(slice.Index(i).Float())) | ||||
case reflect.Bool: | |||||
buf.WriteString(fmt.Sprint(slice.Index(i).Bool())) | |||||
case reflectTime: | case reflectTime: | ||||
buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) | buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) | ||||
default: | default: |
gopkg.in/editorconfig/editorconfig-core-go.v1 | gopkg.in/editorconfig/editorconfig-core-go.v1 | ||||
# gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | ||||
gopkg.in/gomail.v2 | gopkg.in/gomail.v2 | ||||
# gopkg.in/ini.v1 v1.46.0 | |||||
# gopkg.in/ini.v1 v1.48.0 | |||||
gopkg.in/ini.v1 | gopkg.in/ini.v1 | ||||
# gopkg.in/ldap.v3 v3.0.2 | # gopkg.in/ldap.v3 v3.0.2 | ||||
gopkg.in/ldap.v3 | gopkg.in/ldap.v3 |