ini released v1.48.0 and deprecated the ini.AllCapsUnderscore symbol, as such, during the upgrade we migrated to using ini.SnackCase.tags/v1.21.12.1
| @@ -109,7 +109,7 @@ require ( | |||
| gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | |||
| gopkg.in/editorconfig/editorconfig-core-go.v1 v1.3.0 | |||
| 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/src-d/go-billy.v4 v4.3.2 | |||
| gopkg.in/src-d/go-git.v4 v4.13.1 | |||
| @@ -774,6 +774,8 @@ gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
| 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/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/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= | |||
| gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= | |||
| @@ -519,7 +519,7 @@ func NewContext() { | |||
| } else { | |||
| 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() | |||
| if err != nil { | |||
| @@ -28,22 +28,6 @@ $ go get gopkg.in/ini.v1 | |||
| 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 Started](https://ini.unknwon.io/docs/intro/getting_started) | |||
| @@ -0,0 +1,74 @@ | |||
| // 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) | |||
| } | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| // 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 | |||
| ) | |||
| @@ -302,7 +302,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { | |||
| } | |||
| alignSpaces := bytes.Repeat([]byte(" "), alignLength) | |||
| KEY_LIST: | |||
| KeyList: | |||
| for _, kname := range sec.keyList { | |||
| key := sec.Key(kname) | |||
| if len(key.Comment) > 0 { | |||
| @@ -347,7 +347,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { | |||
| if kname != sec.keyList[len(sec.keyList)-1] { | |||
| buf.WriteString(LineBreak) | |||
| } | |||
| continue KEY_LIST | |||
| continue KeyList | |||
| } | |||
| // Write out alignment spaces before "=" sign | |||
| @@ -0,0 +1,24 @@ | |||
| // 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 | |||
| } | |||
| @@ -18,11 +18,6 @@ | |||
| package ini | |||
| import ( | |||
| "bytes" | |||
| "fmt" | |||
| "io" | |||
| "io/ioutil" | |||
| "os" | |||
| "regexp" | |||
| "runtime" | |||
| ) | |||
| @@ -31,12 +26,10 @@ const ( | |||
| // 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. | |||
| DefaultSection = "DEFAULT" | |||
| // Deprecated: Use "DefaultSection" instead. | |||
| DEFAULT_SECTION = DefaultSection | |||
| // Maximum allowed depth when recursively substituing variable names. | |||
| depthValues = 99 | |||
| version = "1.46.0" | |||
| version = "1.48.0" | |||
| ) | |||
| // Version returns current package version literal. | |||
| @@ -49,26 +42,23 @@ var ( | |||
| // This variable will be changed to "\r\n" automatically on Windows at package init time. | |||
| 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 | |||
| 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 = false | |||
| // PrettySection indicates whether to put a line between sections. | |||
| 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() { | |||
| @@ -77,60 +67,6 @@ 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). | |||
| type LoadOptions struct { | |||
| // Loose indicates whether the parser should ignore nonexistent files or return error. | |||
| @@ -54,6 +54,16 @@ func (k *Key) addShadow(val string) error { | |||
| 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.isShadow = true | |||
| k.shadows = append(k.shadows, shadow) | |||
| @@ -554,6 +564,12 @@ func (k *Key) Uint64s(delim string) []uint64 { | |||
| 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. | |||
| // 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 { | |||
| @@ -602,6 +618,13 @@ func (k *Key) ValidUint64s(delim string) []uint64 { | |||
| 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. | |||
| func (k *Key) ValidTimesFormat(format, delim string) []time.Time { | |||
| vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) | |||
| @@ -638,6 +661,11 @@ func (k *Key) StrictUint64s(delim string) ([]uint64, error) { | |||
| 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 | |||
| // or error on first invalid input. | |||
| func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { | |||
| @@ -650,6 +678,21 @@ func (k *Key) StrictTimes(delim string) ([]time.Time, error) { | |||
| 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. | |||
| func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { | |||
| vals := make([]float64, 0, len(strs)) | |||
| @@ -29,8 +29,8 @@ type NameMapper func(string) string | |||
| // Built-in name getters. | |||
| 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)) | |||
| for i, chr := range raw { | |||
| if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { | |||
| @@ -50,7 +50,7 @@ var ( | |||
| if i > 0 { | |||
| newstr = append(newstr, '_') | |||
| } | |||
| chr -= ('A' - 'a') | |||
| chr -= 'A' - 'a' | |||
| } | |||
| newstr = append(newstr, chr) | |||
| } | |||
| @@ -108,6 +108,8 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowSh | |||
| vals, err = key.parseUint64s(strs, true, false) | |||
| case reflect.Float64: | |||
| vals, err = key.parseFloat64s(strs, true, false) | |||
| case reflect.Bool: | |||
| vals, err = key.parseBools(strs, true, false) | |||
| case reflectTime: | |||
| vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) | |||
| default: | |||
| @@ -132,6 +134,8 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowSh | |||
| slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) | |||
| case reflect.Float64: | |||
| slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) | |||
| case reflect.Bool: | |||
| slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i])) | |||
| case reflectTime: | |||
| slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) | |||
| } | |||
| @@ -380,6 +384,8 @@ func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, all | |||
| val = fmt.Sprint(slice.Index(i).Uint()) | |||
| case reflect.Float64: | |||
| val = fmt.Sprint(slice.Index(i).Float()) | |||
| case reflect.Bool: | |||
| val = fmt.Sprint(slice.Index(i).Bool()) | |||
| case reflectTime: | |||
| val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339) | |||
| default: | |||
| @@ -407,6 +413,8 @@ func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, all | |||
| buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) | |||
| case reflect.Float64: | |||
| buf.WriteString(fmt.Sprint(slice.Index(i).Float())) | |||
| case reflect.Bool: | |||
| buf.WriteString(fmt.Sprint(slice.Index(i).Bool())) | |||
| case reflectTime: | |||
| buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) | |||
| default: | |||
| @@ -541,7 +541,7 @@ gopkg.in/asn1-ber.v1 | |||
| gopkg.in/editorconfig/editorconfig-core-go.v1 | |||
| # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | |||
| gopkg.in/gomail.v2 | |||
| # gopkg.in/ini.v1 v1.46.0 | |||
| # gopkg.in/ini.v1 v1.48.0 | |||
| gopkg.in/ini.v1 | |||
| # gopkg.in/ldap.v3 v3.0.2 | |||
| gopkg.in/ldap.v3 | |||