Vendor github.com/pelletier/go-toml
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
This commit is contained in:
parent
75a0c2b7d3
commit
499c2f7d4a
1
go.mod
1
go.mod
@ -43,6 +43,7 @@ require (
|
|||||||
github.com/opencontainers/runc v1.0.0-rc93
|
github.com/opencontainers/runc v1.0.0-rc93
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d
|
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d
|
||||||
github.com/opencontainers/selinux v1.8.0
|
github.com/opencontainers/selinux v1.8.0
|
||||||
|
github.com/pelletier/go-toml v1.8.1
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/prometheus/client_golang v1.7.1
|
github.com/prometheus/client_golang v1.7.1
|
||||||
github.com/sirupsen/logrus v1.7.0
|
github.com/sirupsen/logrus v1.7.0
|
||||||
|
2
go.sum
2
go.sum
@ -437,6 +437,8 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo
|
|||||||
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
|
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
|
||||||
github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
|
github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
|
||||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||||
|
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
|
||||||
|
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
2
vendor/github.com/pelletier/go-toml/.dockerignore
generated
vendored
Normal file
2
vendor/github.com/pelletier/go-toml/.dockerignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
cmd/tomll/tomll
|
||||||
|
cmd/tomljson/tomljson
|
5
vendor/github.com/pelletier/go-toml/.gitignore
generated
vendored
Normal file
5
vendor/github.com/pelletier/go-toml/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
test_program/test_program_bin
|
||||||
|
fuzz/
|
||||||
|
cmd/tomll/tomll
|
||||||
|
cmd/tomljson/tomljson
|
||||||
|
cmd/tomltestgen/tomltestgen
|
132
vendor/github.com/pelletier/go-toml/CONTRIBUTING.md
generated
vendored
Normal file
132
vendor/github.com/pelletier/go-toml/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
## Contributing
|
||||||
|
|
||||||
|
Thank you for your interest in go-toml! We appreciate you considering
|
||||||
|
contributing to go-toml!
|
||||||
|
|
||||||
|
The main goal is the project is to provide an easy-to-use TOML
|
||||||
|
implementation for Go that gets the job done and gets out of your way –
|
||||||
|
dealing with TOML is probably not the central piece of your project.
|
||||||
|
|
||||||
|
As the single maintainer of go-toml, time is scarce. All help, big or
|
||||||
|
small, is more than welcomed!
|
||||||
|
|
||||||
|
### Ask questions
|
||||||
|
|
||||||
|
Any question you may have, somebody else might have it too. Always feel
|
||||||
|
free to ask them on the [issues tracker][issues-tracker]. We will try to
|
||||||
|
answer them as clearly and quickly as possible, time permitting.
|
||||||
|
|
||||||
|
Asking questions also helps us identify areas where the documentation needs
|
||||||
|
improvement, or new features that weren't envisioned before. Sometimes, a
|
||||||
|
seemingly innocent question leads to the fix of a bug. Don't hesitate and
|
||||||
|
ask away!
|
||||||
|
|
||||||
|
### Improve the documentation
|
||||||
|
|
||||||
|
The best way to share your knowledge and experience with go-toml is to
|
||||||
|
improve the documentation. Fix a typo, clarify an interface, add an
|
||||||
|
example, anything goes!
|
||||||
|
|
||||||
|
The documentation is present in the [README][readme] and thorough the
|
||||||
|
source code. On release, it gets updated on [GoDoc][godoc]. To make a
|
||||||
|
change to the documentation, create a pull request with your proposed
|
||||||
|
changes. For simple changes like that, the easiest way to go is probably
|
||||||
|
the "Fork this project and edit the file" button on Github, displayed at
|
||||||
|
the top right of the file. Unless it's a trivial change (for example a
|
||||||
|
typo), provide a little bit of context in your pull request description or
|
||||||
|
commit message.
|
||||||
|
|
||||||
|
### Report a bug
|
||||||
|
|
||||||
|
Found a bug! Sorry to hear that :(. Help us and other track them down and
|
||||||
|
fix by reporting it. [File a new bug report][bug-report] on the [issues
|
||||||
|
tracker][issues-tracker]. The template should provide enough guidance on
|
||||||
|
what to include. When in doubt: add more details! By reducing ambiguity and
|
||||||
|
providing more information, it decreases back and forth and saves everyone
|
||||||
|
time.
|
||||||
|
|
||||||
|
### Code changes
|
||||||
|
|
||||||
|
Want to contribute a patch? Very happy to hear that!
|
||||||
|
|
||||||
|
First, some high-level rules:
|
||||||
|
|
||||||
|
* A short proposal with some POC code is better than a lengthy piece of
|
||||||
|
text with no code. Code speaks louder than words.
|
||||||
|
* No backward-incompatible patch will be accepted unless discussed.
|
||||||
|
Sometimes it's hard, and Go's lack of versioning by default does not
|
||||||
|
help, but we try not to break people's programs unless we absolutely have
|
||||||
|
to.
|
||||||
|
* If you are writing a new feature or extending an existing one, make sure
|
||||||
|
to write some documentation.
|
||||||
|
* Bug fixes need to be accompanied with regression tests.
|
||||||
|
* New code needs to be tested.
|
||||||
|
* Your commit messages need to explain why the change is needed, even if
|
||||||
|
already included in the PR description.
|
||||||
|
|
||||||
|
It does sound like a lot, but those best practices are here to save time
|
||||||
|
overall and continuously improve the quality of the project, which is
|
||||||
|
something everyone benefits from.
|
||||||
|
|
||||||
|
#### Get started
|
||||||
|
|
||||||
|
The fairly standard code contribution process looks like that:
|
||||||
|
|
||||||
|
1. [Fork the project][fork].
|
||||||
|
2. Make your changes, commit on any branch you like.
|
||||||
|
3. [Open up a pull request][pull-request]
|
||||||
|
4. Review, potential ask for changes.
|
||||||
|
5. Merge. You're in!
|
||||||
|
|
||||||
|
Feel free to ask for help! You can create draft pull requests to gather
|
||||||
|
some early feedback!
|
||||||
|
|
||||||
|
#### Run the tests
|
||||||
|
|
||||||
|
You can run tests for go-toml using Go's test tool: `go test ./...`.
|
||||||
|
When creating a pull requests, all tests will be ran on Linux on a few Go
|
||||||
|
versions (Travis CI), and on Windows using the latest Go version
|
||||||
|
(AppVeyor).
|
||||||
|
|
||||||
|
#### Style
|
||||||
|
|
||||||
|
Try to look around and follow the same format and structure as the rest of
|
||||||
|
the code. We enforce using `go fmt` on the whole code base.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Maintainers-only
|
||||||
|
|
||||||
|
#### Merge pull request
|
||||||
|
|
||||||
|
Checklist:
|
||||||
|
|
||||||
|
* Passing CI.
|
||||||
|
* Does not introduce backward-incompatible changes (unless discussed).
|
||||||
|
* Has relevant doc changes.
|
||||||
|
* Has relevant unit tests.
|
||||||
|
|
||||||
|
1. Merge using "squash and merge".
|
||||||
|
2. Make sure to edit the commit message to keep all the useful information
|
||||||
|
nice and clean.
|
||||||
|
3. Make sure the commit title is clear and contains the PR number (#123).
|
||||||
|
|
||||||
|
#### New release
|
||||||
|
|
||||||
|
1. Go to [releases][releases]. Click on "X commits to master since this
|
||||||
|
release".
|
||||||
|
2. Make note of all the changes. Look for backward incompatible changes,
|
||||||
|
new features, and bug fixes.
|
||||||
|
3. Pick the new version using the above and semver.
|
||||||
|
4. Create a [new release][new-release].
|
||||||
|
5. Follow the same format as [1.1.0][release-110].
|
||||||
|
|
||||||
|
[issues-tracker]: https://github.com/pelletier/go-toml/issues
|
||||||
|
[bug-report]: https://github.com/pelletier/go-toml/issues/new?template=bug_report.md
|
||||||
|
[godoc]: https://godoc.org/github.com/pelletier/go-toml
|
||||||
|
[readme]: ./README.md
|
||||||
|
[fork]: https://help.github.com/articles/fork-a-repo
|
||||||
|
[pull-request]: https://help.github.com/en/articles/creating-a-pull-request
|
||||||
|
[releases]: https://github.com/pelletier/go-toml/releases
|
||||||
|
[new-release]: https://github.com/pelletier/go-toml/releases/new
|
||||||
|
[release-110]: https://github.com/pelletier/go-toml/releases/tag/v1.1.0
|
11
vendor/github.com/pelletier/go-toml/Dockerfile
generated
vendored
Normal file
11
vendor/github.com/pelletier/go-toml/Dockerfile
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM golang:1.12-alpine3.9 as builder
|
||||||
|
WORKDIR /go/src/github.com/pelletier/go-toml
|
||||||
|
COPY . .
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
ENV GOOS=linux
|
||||||
|
RUN go install ./...
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=builder /go/bin/tomll /usr/bin/tomll
|
||||||
|
COPY --from=builder /go/bin/tomljson /usr/bin/tomljson
|
||||||
|
COPY --from=builder /go/bin/jsontoml /usr/bin/jsontoml
|
21
vendor/github.com/pelletier/go-toml/LICENSE
generated
vendored
Normal file
21
vendor/github.com/pelletier/go-toml/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
29
vendor/github.com/pelletier/go-toml/Makefile
generated
vendored
Normal file
29
vendor/github.com/pelletier/go-toml/Makefile
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
export CGO_ENABLED=0
|
||||||
|
go := go
|
||||||
|
go.goos ?= $(shell echo `go version`|cut -f4 -d ' '|cut -d '/' -f1)
|
||||||
|
go.goarch ?= $(shell echo `go version`|cut -f4 -d ' '|cut -d '/' -f2)
|
||||||
|
|
||||||
|
out.tools := tomll tomljson jsontoml
|
||||||
|
out.dist := $(out.tools:=_$(go.goos)_$(go.goarch).tar.xz)
|
||||||
|
sources := $(wildcard **/*.go)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY:
|
||||||
|
tools: $(out.tools)
|
||||||
|
|
||||||
|
$(out.tools): $(sources)
|
||||||
|
GOOS=$(go.goos) GOARCH=$(go.goarch) $(go) build ./cmd/$@
|
||||||
|
|
||||||
|
.PHONY:
|
||||||
|
dist: $(out.dist)
|
||||||
|
|
||||||
|
$(out.dist):%_$(go.goos)_$(go.goarch).tar.xz: %
|
||||||
|
if [ "$(go.goos)" = "windows" ]; then \
|
||||||
|
tar -cJf $@ $^.exe; \
|
||||||
|
else \
|
||||||
|
tar -cJf $@ $^; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
.PHONY:
|
||||||
|
clean:
|
||||||
|
rm -rf $(out.tools) $(out.dist)
|
5
vendor/github.com/pelletier/go-toml/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
5
vendor/github.com/pelletier/go-toml/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
**Issue:** add link to pelletier/go-toml issue here
|
||||||
|
|
||||||
|
Explanation of what this pull request does.
|
||||||
|
|
||||||
|
More detailed description of the decisions being made and the reasons why (if the patch is non-trivial).
|
151
vendor/github.com/pelletier/go-toml/README.md
generated
vendored
Normal file
151
vendor/github.com/pelletier/go-toml/README.md
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
# go-toml
|
||||||
|
|
||||||
|
Go library for the [TOML](https://github.com/mojombo/toml) format.
|
||||||
|
|
||||||
|
This library supports TOML version
|
||||||
|
[v1.0.0-rc.1](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v1.0.0-rc.1.md)
|
||||||
|
|
||||||
|
[](http://godoc.org/github.com/pelletier/go-toml)
|
||||||
|
[](https://github.com/pelletier/go-toml/blob/master/LICENSE)
|
||||||
|
[](https://dev.azure.com/pelletierthomas/go-toml-ci/_build/latest?definitionId=1&branchName=master)
|
||||||
|
[](https://codecov.io/gh/pelletier/go-toml)
|
||||||
|
[](https://goreportcard.com/report/github.com/pelletier/go-toml)
|
||||||
|
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fpelletier%2Fgo-toml?ref=badge_shield)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Go-toml provides the following features for using data parsed from TOML documents:
|
||||||
|
|
||||||
|
* Load TOML documents from files and string data
|
||||||
|
* Easily navigate TOML structure using Tree
|
||||||
|
* Marshaling and unmarshaling to and from data structures
|
||||||
|
* Line & column position data for all parsed elements
|
||||||
|
* [Query support similar to JSON-Path](query/)
|
||||||
|
* Syntax errors contain line and column numbers
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/pelletier/go-toml"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage example
|
||||||
|
|
||||||
|
Read a TOML document:
|
||||||
|
|
||||||
|
```go
|
||||||
|
config, _ := toml.Load(`
|
||||||
|
[postgres]
|
||||||
|
user = "pelletier"
|
||||||
|
password = "mypassword"`)
|
||||||
|
// retrieve data directly
|
||||||
|
user := config.Get("postgres.user").(string)
|
||||||
|
|
||||||
|
// or using an intermediate object
|
||||||
|
postgresConfig := config.Get("postgres").(*toml.Tree)
|
||||||
|
password := postgresConfig.Get("password").(string)
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use Unmarshal:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Postgres struct {
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
type Config struct {
|
||||||
|
Postgres Postgres
|
||||||
|
}
|
||||||
|
|
||||||
|
doc := []byte(`
|
||||||
|
[Postgres]
|
||||||
|
User = "pelletier"
|
||||||
|
Password = "mypassword"`)
|
||||||
|
|
||||||
|
config := Config{}
|
||||||
|
toml.Unmarshal(doc, &config)
|
||||||
|
fmt.Println("user=", config.Postgres.User)
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use a query:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// use a query to gather elements without walking the tree
|
||||||
|
q, _ := query.Compile("$..[user,password]")
|
||||||
|
results := q.Execute(config)
|
||||||
|
for ii, item := range results.Values() {
|
||||||
|
fmt.Printf("Query result %d: %v\n", ii, item)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The documentation and additional examples are available at
|
||||||
|
[godoc.org](http://godoc.org/github.com/pelletier/go-toml).
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
Go-toml provides two handy command line tools:
|
||||||
|
|
||||||
|
* `tomll`: Reads TOML files and lints them.
|
||||||
|
|
||||||
|
```
|
||||||
|
go install github.com/pelletier/go-toml/cmd/tomll
|
||||||
|
tomll --help
|
||||||
|
```
|
||||||
|
* `tomljson`: Reads a TOML file and outputs its JSON representation.
|
||||||
|
|
||||||
|
```
|
||||||
|
go install github.com/pelletier/go-toml/cmd/tomljson
|
||||||
|
tomljson --help
|
||||||
|
```
|
||||||
|
|
||||||
|
* `jsontoml`: Reads a JSON file and outputs a TOML representation.
|
||||||
|
|
||||||
|
```
|
||||||
|
go install github.com/pelletier/go-toml/cmd/jsontoml
|
||||||
|
jsontoml --help
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker image
|
||||||
|
|
||||||
|
Those tools are also availble as a Docker image from
|
||||||
|
[dockerhub](https://hub.docker.com/r/pelletier/go-toml). For example, to
|
||||||
|
use `tomljson`:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -v $PWD:/workdir pelletier/go-toml tomljson /workdir/example.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
Only master (`latest`) and tagged versions are published to dockerhub. You
|
||||||
|
can build your own image as usual:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -t go-toml .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
Feel free to report bugs and patches using GitHub's pull requests system on
|
||||||
|
[pelletier/go-toml](https://github.com/pelletier/go-toml). Any feedback would be
|
||||||
|
much appreciated!
|
||||||
|
|
||||||
|
### Run tests
|
||||||
|
|
||||||
|
`go test ./...`
|
||||||
|
|
||||||
|
### Fuzzing
|
||||||
|
|
||||||
|
The script `./fuzz.sh` is available to
|
||||||
|
run [go-fuzz](https://github.com/dvyukov/go-fuzz) on go-toml.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
Go-toml follows [Semantic Versioning](http://semver.org/). The supported version
|
||||||
|
of [TOML](https://github.com/toml-lang/toml) is indicated at the beginning of
|
||||||
|
this document. The last two major versions of Go are supported
|
||||||
|
(see [Go Release Policy](https://golang.org/doc/devel/release.html#policy)).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The MIT License (MIT). Read [LICENSE](LICENSE).
|
230
vendor/github.com/pelletier/go-toml/azure-pipelines.yml
generated
vendored
Normal file
230
vendor/github.com/pelletier/go-toml/azure-pipelines.yml
generated
vendored
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
trigger:
|
||||||
|
- master
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- stage: fuzzit
|
||||||
|
displayName: "Run Fuzzit"
|
||||||
|
dependsOn: []
|
||||||
|
condition: and(succeeded(), eq(variables['Build.SourceBranchName'], 'master'))
|
||||||
|
jobs:
|
||||||
|
- job: submit
|
||||||
|
displayName: "Submit"
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: GoTool@0
|
||||||
|
displayName: "Install Go 1.15"
|
||||||
|
inputs:
|
||||||
|
version: "1.15"
|
||||||
|
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||||
|
- script: mkdir -p ${HOME}/go/src/github.com/pelletier/go-toml
|
||||||
|
- script: cp -R . ${HOME}/go/src/github.com/pelletier/go-toml
|
||||||
|
- task: Bash@3
|
||||||
|
inputs:
|
||||||
|
filePath: './fuzzit.sh'
|
||||||
|
env:
|
||||||
|
TYPE: fuzzing
|
||||||
|
FUZZIT_API_KEY: $(FUZZIT_API_KEY)
|
||||||
|
|
||||||
|
- stage: run_checks
|
||||||
|
displayName: "Check"
|
||||||
|
dependsOn: []
|
||||||
|
jobs:
|
||||||
|
- job: fmt
|
||||||
|
displayName: "fmt"
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: GoTool@0
|
||||||
|
displayName: "Install Go 1.15"
|
||||||
|
inputs:
|
||||||
|
version: "1.15"
|
||||||
|
- task: Go@0
|
||||||
|
displayName: "go fmt ./..."
|
||||||
|
inputs:
|
||||||
|
command: 'custom'
|
||||||
|
customCommand: 'fmt'
|
||||||
|
arguments: './...'
|
||||||
|
- job: coverage
|
||||||
|
displayName: "coverage"
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: GoTool@0
|
||||||
|
displayName: "Install Go 1.15"
|
||||||
|
inputs:
|
||||||
|
version: "1.15"
|
||||||
|
- task: Go@0
|
||||||
|
displayName: "Generate coverage"
|
||||||
|
inputs:
|
||||||
|
command: 'test'
|
||||||
|
arguments: "-race -coverprofile=coverage.txt -covermode=atomic"
|
||||||
|
- task: Bash@3
|
||||||
|
inputs:
|
||||||
|
targetType: 'inline'
|
||||||
|
script: 'bash <(curl -s https://codecov.io/bash) -t ${CODECOV_TOKEN}'
|
||||||
|
env:
|
||||||
|
CODECOV_TOKEN: $(CODECOV_TOKEN)
|
||||||
|
- job: benchmark
|
||||||
|
displayName: "benchmark"
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: GoTool@0
|
||||||
|
displayName: "Install Go 1.15"
|
||||||
|
inputs:
|
||||||
|
version: "1.15"
|
||||||
|
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||||
|
- task: Bash@3
|
||||||
|
inputs:
|
||||||
|
filePath: './benchmark.sh'
|
||||||
|
arguments: "master $(Build.Repository.Uri)"
|
||||||
|
|
||||||
|
- job: fuzzing
|
||||||
|
displayName: "fuzzing"
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: GoTool@0
|
||||||
|
displayName: "Install Go 1.15"
|
||||||
|
inputs:
|
||||||
|
version: "1.15"
|
||||||
|
- script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
|
||||||
|
- script: mkdir -p ${HOME}/go/src/github.com/pelletier/go-toml
|
||||||
|
- script: cp -R . ${HOME}/go/src/github.com/pelletier/go-toml
|
||||||
|
- task: Bash@3
|
||||||
|
inputs:
|
||||||
|
filePath: './fuzzit.sh'
|
||||||
|
env:
|
||||||
|
TYPE: local-regression
|
||||||
|
|
||||||
|
- job: go_unit_tests
|
||||||
|
displayName: "unit tests"
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
linux 1.15:
|
||||||
|
goVersion: '1.15'
|
||||||
|
imageName: 'ubuntu-latest'
|
||||||
|
mac 1.15:
|
||||||
|
goVersion: '1.15'
|
||||||
|
imageName: 'macOS-latest'
|
||||||
|
windows 1.15:
|
||||||
|
goVersion: '1.15'
|
||||||
|
imageName: 'windows-latest'
|
||||||
|
linux 1.14:
|
||||||
|
goVersion: '1.14'
|
||||||
|
imageName: 'ubuntu-latest'
|
||||||
|
mac 1.14:
|
||||||
|
goVersion: '1.14'
|
||||||
|
imageName: 'macOS-latest'
|
||||||
|
windows 1.14:
|
||||||
|
goVersion: '1.14'
|
||||||
|
imageName: 'windows-latest'
|
||||||
|
pool:
|
||||||
|
vmImage: $(imageName)
|
||||||
|
steps:
|
||||||
|
- task: GoTool@0
|
||||||
|
displayName: "Install Go $(goVersion)"
|
||||||
|
inputs:
|
||||||
|
version: $(goVersion)
|
||||||
|
- task: Go@0
|
||||||
|
displayName: "go test ./..."
|
||||||
|
inputs:
|
||||||
|
command: 'test'
|
||||||
|
arguments: './...'
|
||||||
|
- stage: build_binaries
|
||||||
|
displayName: "Build binaries"
|
||||||
|
dependsOn: run_checks
|
||||||
|
jobs:
|
||||||
|
- job: build_binary
|
||||||
|
displayName: "Build binary"
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
linux_amd64:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: amd64
|
||||||
|
darwin_amd64:
|
||||||
|
GOOS: darwin
|
||||||
|
GOARCH: amd64
|
||||||
|
windows_amd64:
|
||||||
|
GOOS: windows
|
||||||
|
GOARCH: amd64
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: GoTool@0
|
||||||
|
displayName: "Install Go"
|
||||||
|
inputs:
|
||||||
|
version: 1.15
|
||||||
|
- task: Bash@3
|
||||||
|
inputs:
|
||||||
|
targetType: inline
|
||||||
|
script: "make dist"
|
||||||
|
env:
|
||||||
|
go.goos: $(GOOS)
|
||||||
|
go.goarch: $(GOARCH)
|
||||||
|
- task: CopyFiles@2
|
||||||
|
inputs:
|
||||||
|
sourceFolder: '$(Build.SourcesDirectory)'
|
||||||
|
contents: '*.tar.xz'
|
||||||
|
TargetFolder: '$(Build.ArtifactStagingDirectory)'
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
inputs:
|
||||||
|
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||||
|
artifactName: binaries
|
||||||
|
- stage: build_binaries_manifest
|
||||||
|
displayName: "Build binaries manifest"
|
||||||
|
dependsOn: build_binaries
|
||||||
|
jobs:
|
||||||
|
- job: build_manifest
|
||||||
|
displayName: "Build binaries manifest"
|
||||||
|
steps:
|
||||||
|
- task: DownloadBuildArtifacts@0
|
||||||
|
inputs:
|
||||||
|
buildType: 'current'
|
||||||
|
downloadType: 'single'
|
||||||
|
artifactName: 'binaries'
|
||||||
|
downloadPath: '$(Build.SourcesDirectory)'
|
||||||
|
- task: Bash@3
|
||||||
|
inputs:
|
||||||
|
targetType: inline
|
||||||
|
script: "cd binaries && sha256sum --binary *.tar.xz | tee $(Build.ArtifactStagingDirectory)/sha256sums.txt"
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
inputs:
|
||||||
|
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||||
|
artifactName: manifest
|
||||||
|
|
||||||
|
- stage: build_docker_image
|
||||||
|
displayName: "Build Docker image"
|
||||||
|
dependsOn: run_checks
|
||||||
|
jobs:
|
||||||
|
- job: build
|
||||||
|
displayName: "Build"
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: Docker@2
|
||||||
|
inputs:
|
||||||
|
command: 'build'
|
||||||
|
Dockerfile: 'Dockerfile'
|
||||||
|
buildContext: '.'
|
||||||
|
addPipelineData: false
|
||||||
|
|
||||||
|
- stage: publish_docker_image
|
||||||
|
displayName: "Publish Docker image"
|
||||||
|
dependsOn: build_docker_image
|
||||||
|
condition: and(succeeded(), eq(variables['Build.SourceBranchName'], 'master'))
|
||||||
|
jobs:
|
||||||
|
- job: publish
|
||||||
|
displayName: "Publish"
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: Docker@2
|
||||||
|
inputs:
|
||||||
|
containerRegistry: 'DockerHub'
|
||||||
|
repository: 'pelletier/go-toml'
|
||||||
|
command: 'buildAndPush'
|
||||||
|
Dockerfile: 'Dockerfile'
|
||||||
|
buildContext: '.'
|
||||||
|
tags: 'latest'
|
35
vendor/github.com/pelletier/go-toml/benchmark.sh
generated
vendored
Normal file
35
vendor/github.com/pelletier/go-toml/benchmark.sh
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
reference_ref=${1:-master}
|
||||||
|
reference_git=${2:-.}
|
||||||
|
|
||||||
|
if ! `hash benchstat 2>/dev/null`; then
|
||||||
|
echo "Installing benchstat"
|
||||||
|
go get golang.org/x/perf/cmd/benchstat
|
||||||
|
fi
|
||||||
|
|
||||||
|
tempdir=`mktemp -d /tmp/go-toml-benchmark-XXXXXX`
|
||||||
|
ref_tempdir="${tempdir}/ref"
|
||||||
|
ref_benchmark="${ref_tempdir}/benchmark-`echo -n ${reference_ref}|tr -s '/' '-'`.txt"
|
||||||
|
local_benchmark="`pwd`/benchmark-local.txt"
|
||||||
|
|
||||||
|
echo "=== ${reference_ref} (${ref_tempdir})"
|
||||||
|
git clone ${reference_git} ${ref_tempdir} >/dev/null 2>/dev/null
|
||||||
|
pushd ${ref_tempdir} >/dev/null
|
||||||
|
git checkout ${reference_ref} >/dev/null 2>/dev/null
|
||||||
|
go test -bench=. -benchmem | tee ${ref_benchmark}
|
||||||
|
cd benchmark
|
||||||
|
go test -bench=. -benchmem | tee -a ${ref_benchmark}
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== local"
|
||||||
|
go test -bench=. -benchmem | tee ${local_benchmark}
|
||||||
|
cd benchmark
|
||||||
|
go test -bench=. -benchmem | tee -a ${local_benchmark}
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== diff"
|
||||||
|
benchstat -delta-test=none ${ref_benchmark} ${local_benchmark}
|
23
vendor/github.com/pelletier/go-toml/doc.go
generated
vendored
Normal file
23
vendor/github.com/pelletier/go-toml/doc.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Package toml is a TOML parser and manipulation library.
|
||||||
|
//
|
||||||
|
// This version supports the specification as described in
|
||||||
|
// https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md
|
||||||
|
//
|
||||||
|
// Marshaling
|
||||||
|
//
|
||||||
|
// Go-toml can marshal and unmarshal TOML documents from and to data
|
||||||
|
// structures.
|
||||||
|
//
|
||||||
|
// TOML document as a tree
|
||||||
|
//
|
||||||
|
// Go-toml can operate on a TOML document as a tree. Use one of the Load*
|
||||||
|
// functions to parse TOML data and obtain a Tree instance, then one of its
|
||||||
|
// methods to manipulate the tree.
|
||||||
|
//
|
||||||
|
// JSONPath-like queries
|
||||||
|
//
|
||||||
|
// The package github.com/pelletier/go-toml/query implements a system
|
||||||
|
// similar to JSONPath to quickly retrieve elements of a TOML document using a
|
||||||
|
// single expression. See the package documentation for more information.
|
||||||
|
//
|
||||||
|
package toml
|
30
vendor/github.com/pelletier/go-toml/example-crlf.toml
generated
vendored
Normal file
30
vendor/github.com/pelletier/go-toml/example-crlf.toml
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# This is a TOML document. Boom.
|
||||||
|
|
||||||
|
title = "TOML Example"
|
||||||
|
|
||||||
|
[owner]
|
||||||
|
name = "Tom Preston-Werner"
|
||||||
|
organization = "GitHub"
|
||||||
|
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
|
||||||
|
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
||||||
|
|
||||||
|
[database]
|
||||||
|
server = "192.168.1.1"
|
||||||
|
ports = [ 8001, 8001, 8002 ]
|
||||||
|
connection_max = 5000
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[servers]
|
||||||
|
|
||||||
|
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||||
|
[servers.alpha]
|
||||||
|
ip = "10.0.0.1"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
[servers.beta]
|
||||||
|
ip = "10.0.0.2"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
[clients]
|
||||||
|
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
||||||
|
score = 4e-08 # to make sure leading zeroes in exponent parts of floats are supported
|
30
vendor/github.com/pelletier/go-toml/example.toml
generated
vendored
Normal file
30
vendor/github.com/pelletier/go-toml/example.toml
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# This is a TOML document. Boom.
|
||||||
|
|
||||||
|
title = "TOML Example"
|
||||||
|
|
||||||
|
[owner]
|
||||||
|
name = "Tom Preston-Werner"
|
||||||
|
organization = "GitHub"
|
||||||
|
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
|
||||||
|
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
||||||
|
|
||||||
|
[database]
|
||||||
|
server = "192.168.1.1"
|
||||||
|
ports = [ 8001, 8001, 8002 ]
|
||||||
|
connection_max = 5000
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[servers]
|
||||||
|
|
||||||
|
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||||
|
[servers.alpha]
|
||||||
|
ip = "10.0.0.1"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
[servers.beta]
|
||||||
|
ip = "10.0.0.2"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
[clients]
|
||||||
|
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
||||||
|
score = 4e-08 # to make sure leading zeroes in exponent parts of floats are supported
|
31
vendor/github.com/pelletier/go-toml/fuzz.go
generated
vendored
Normal file
31
vendor/github.com/pelletier/go-toml/fuzz.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// +build gofuzz
|
||||||
|
|
||||||
|
package toml
|
||||||
|
|
||||||
|
func Fuzz(data []byte) int {
|
||||||
|
tree, err := LoadBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
if tree != nil {
|
||||||
|
panic("tree must be nil if there is an error")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
str, err := tree.ToTomlString()
|
||||||
|
if err != nil {
|
||||||
|
if str != "" {
|
||||||
|
panic(`str must be "" if there is an error`)
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree, err = Load(str)
|
||||||
|
if err != nil {
|
||||||
|
if tree != nil {
|
||||||
|
panic("tree must be nil if there is an error")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
15
vendor/github.com/pelletier/go-toml/fuzz.sh
generated
vendored
Normal file
15
vendor/github.com/pelletier/go-toml/fuzz.sh
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
go get github.com/dvyukov/go-fuzz/go-fuzz
|
||||||
|
go get github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||||
|
|
||||||
|
if [ ! -e toml-fuzz.zip ]; then
|
||||||
|
go-fuzz-build github.com/pelletier/go-toml
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -fr fuzz
|
||||||
|
mkdir -p fuzz/corpus
|
||||||
|
cp *.toml fuzz/corpus
|
||||||
|
|
||||||
|
go-fuzz -bin=toml-fuzz.zip -workdir=fuzz
|
26
vendor/github.com/pelletier/go-toml/fuzzit.sh
generated
vendored
Normal file
26
vendor/github.com/pelletier/go-toml/fuzzit.sh
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -xe
|
||||||
|
|
||||||
|
# go-fuzz doesn't support modules yet, so ensure we do everything
|
||||||
|
# in the old style GOPATH way
|
||||||
|
export GO111MODULE="off"
|
||||||
|
|
||||||
|
# install go-fuzz
|
||||||
|
go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||||
|
|
||||||
|
# target name can only contain lower-case letters (a-z), digits (0-9) and a dash (-)
|
||||||
|
# to add another target, make sure to create it with `fuzzit create target`
|
||||||
|
# before using `fuzzit create job`
|
||||||
|
TARGET=toml-fuzzer
|
||||||
|
|
||||||
|
go-fuzz-build -libfuzzer -o ${TARGET}.a github.com/pelletier/go-toml
|
||||||
|
clang -fsanitize=fuzzer ${TARGET}.a -o ${TARGET}
|
||||||
|
|
||||||
|
# install fuzzit for talking to fuzzit.dev service
|
||||||
|
# or latest version:
|
||||||
|
# https://github.com/fuzzitdev/fuzzit/releases/latest/download/fuzzit_Linux_x86_64
|
||||||
|
wget -q -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/download/v2.4.52/fuzzit_Linux_x86_64
|
||||||
|
chmod a+x fuzzit
|
||||||
|
|
||||||
|
# TODO: change kkowalczyk to go-toml and create toml-fuzzer target there
|
||||||
|
./fuzzit create job --type $TYPE go-toml/${TARGET} ${TARGET}
|
5
vendor/github.com/pelletier/go-toml/go.mod
generated
vendored
Normal file
5
vendor/github.com/pelletier/go-toml/go.mod
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module github.com/pelletier/go-toml
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require github.com/davecgh/go-spew v1.1.1
|
19
vendor/github.com/pelletier/go-toml/go.sum
generated
vendored
Normal file
19
vendor/github.com/pelletier/go-toml/go.sum
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
||||||
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
112
vendor/github.com/pelletier/go-toml/keysparsing.go
generated
vendored
Normal file
112
vendor/github.com/pelletier/go-toml/keysparsing.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Parsing keys handling both bare and quoted keys.
|
||||||
|
|
||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Convert the bare key group string to an array.
|
||||||
|
// The input supports double quotation and single quotation,
|
||||||
|
// but escape sequences are not supported. Lexers must unescape them beforehand.
|
||||||
|
func parseKey(key string) ([]string, error) {
|
||||||
|
runes := []rune(key)
|
||||||
|
var groups []string
|
||||||
|
|
||||||
|
if len(key) == 0 {
|
||||||
|
return nil, errors.New("empty key")
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := 0
|
||||||
|
for idx < len(runes) {
|
||||||
|
for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
|
||||||
|
// skip leading whitespace
|
||||||
|
}
|
||||||
|
if idx >= len(runes) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
r := runes[idx]
|
||||||
|
if isValidBareChar(r) {
|
||||||
|
// parse bare key
|
||||||
|
startIdx := idx
|
||||||
|
endIdx := -1
|
||||||
|
idx++
|
||||||
|
for idx < len(runes) {
|
||||||
|
r = runes[idx]
|
||||||
|
if isValidBareChar(r) {
|
||||||
|
idx++
|
||||||
|
} else if r == '.' {
|
||||||
|
endIdx = idx
|
||||||
|
break
|
||||||
|
} else if isSpace(r) {
|
||||||
|
endIdx = idx
|
||||||
|
for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
|
||||||
|
// skip trailing whitespace
|
||||||
|
}
|
||||||
|
if idx < len(runes) && runes[idx] != '.' {
|
||||||
|
return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("invalid bare key character: %c", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if endIdx == -1 {
|
||||||
|
endIdx = idx
|
||||||
|
}
|
||||||
|
groups = append(groups, string(runes[startIdx:endIdx]))
|
||||||
|
} else if r == '\'' {
|
||||||
|
// parse single quoted key
|
||||||
|
idx++
|
||||||
|
startIdx := idx
|
||||||
|
for {
|
||||||
|
if idx >= len(runes) {
|
||||||
|
return nil, fmt.Errorf("unclosed single-quoted key")
|
||||||
|
}
|
||||||
|
r = runes[idx]
|
||||||
|
if r == '\'' {
|
||||||
|
groups = append(groups, string(runes[startIdx:idx]))
|
||||||
|
idx++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
} else if r == '"' {
|
||||||
|
// parse double quoted key
|
||||||
|
idx++
|
||||||
|
startIdx := idx
|
||||||
|
for {
|
||||||
|
if idx >= len(runes) {
|
||||||
|
return nil, fmt.Errorf("unclosed double-quoted key")
|
||||||
|
}
|
||||||
|
r = runes[idx]
|
||||||
|
if r == '"' {
|
||||||
|
groups = append(groups, string(runes[startIdx:idx]))
|
||||||
|
idx++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
} else if r == '.' {
|
||||||
|
idx++
|
||||||
|
if idx >= len(runes) {
|
||||||
|
return nil, fmt.Errorf("unexpected end of key")
|
||||||
|
}
|
||||||
|
r = runes[idx]
|
||||||
|
if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
|
||||||
|
return nil, fmt.Errorf("expecting key part after dot")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("invalid key character: %c", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(groups) == 0 {
|
||||||
|
return nil, fmt.Errorf("empty key")
|
||||||
|
}
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidBareChar(r rune) bool {
|
||||||
|
return isAlphanumeric(r) || r == '-' || isDigit(r)
|
||||||
|
}
|
807
vendor/github.com/pelletier/go-toml/lexer.go
generated
vendored
Normal file
807
vendor/github.com/pelletier/go-toml/lexer.go
generated
vendored
Normal file
@ -0,0 +1,807 @@
|
|||||||
|
// TOML lexer.
|
||||||
|
//
|
||||||
|
// Written using the principles developed by Rob Pike in
|
||||||
|
// http://www.youtube.com/watch?v=HxaD_trXwRE
|
||||||
|
|
||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dateRegexp *regexp.Regexp
|
||||||
|
|
||||||
|
// Define state functions
|
||||||
|
type tomlLexStateFn func() tomlLexStateFn
|
||||||
|
|
||||||
|
// Define lexer
|
||||||
|
type tomlLexer struct {
|
||||||
|
inputIdx int
|
||||||
|
input []rune // Textual source
|
||||||
|
currentTokenStart int
|
||||||
|
currentTokenStop int
|
||||||
|
tokens []token
|
||||||
|
brackets []rune
|
||||||
|
line int
|
||||||
|
col int
|
||||||
|
endbufferLine int
|
||||||
|
endbufferCol int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic read operations on input
|
||||||
|
|
||||||
|
func (l *tomlLexer) read() rune {
|
||||||
|
r := l.peek()
|
||||||
|
if r == '\n' {
|
||||||
|
l.endbufferLine++
|
||||||
|
l.endbufferCol = 1
|
||||||
|
} else {
|
||||||
|
l.endbufferCol++
|
||||||
|
}
|
||||||
|
l.inputIdx++
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) next() rune {
|
||||||
|
r := l.read()
|
||||||
|
|
||||||
|
if r != eof {
|
||||||
|
l.currentTokenStop++
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) ignore() {
|
||||||
|
l.currentTokenStart = l.currentTokenStop
|
||||||
|
l.line = l.endbufferLine
|
||||||
|
l.col = l.endbufferCol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) skip() {
|
||||||
|
l.next()
|
||||||
|
l.ignore()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) fastForward(n int) {
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) emitWithValue(t tokenType, value string) {
|
||||||
|
l.tokens = append(l.tokens, token{
|
||||||
|
Position: Position{l.line, l.col},
|
||||||
|
typ: t,
|
||||||
|
val: value,
|
||||||
|
})
|
||||||
|
l.ignore()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) emit(t tokenType) {
|
||||||
|
l.emitWithValue(t, string(l.input[l.currentTokenStart:l.currentTokenStop]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) peek() rune {
|
||||||
|
if l.inputIdx >= len(l.input) {
|
||||||
|
return eof
|
||||||
|
}
|
||||||
|
return l.input[l.inputIdx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) peekString(size int) string {
|
||||||
|
maxIdx := len(l.input)
|
||||||
|
upperIdx := l.inputIdx + size // FIXME: potential overflow
|
||||||
|
if upperIdx > maxIdx {
|
||||||
|
upperIdx = maxIdx
|
||||||
|
}
|
||||||
|
return string(l.input[l.inputIdx:upperIdx])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) follow(next string) bool {
|
||||||
|
return next == l.peekString(len(next))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error management
|
||||||
|
|
||||||
|
func (l *tomlLexer) errorf(format string, args ...interface{}) tomlLexStateFn {
|
||||||
|
l.tokens = append(l.tokens, token{
|
||||||
|
Position: Position{l.line, l.col},
|
||||||
|
typ: tokenError,
|
||||||
|
val: fmt.Sprintf(format, args...),
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// State functions
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexVoid() tomlLexStateFn {
|
||||||
|
for {
|
||||||
|
next := l.peek()
|
||||||
|
switch next {
|
||||||
|
case '}': // after '{'
|
||||||
|
return l.lexRightCurlyBrace
|
||||||
|
case '[':
|
||||||
|
return l.lexTableKey
|
||||||
|
case '#':
|
||||||
|
return l.lexComment(l.lexVoid)
|
||||||
|
case '=':
|
||||||
|
return l.lexEqual
|
||||||
|
case '\r':
|
||||||
|
fallthrough
|
||||||
|
case '\n':
|
||||||
|
l.skip()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if isSpace(next) {
|
||||||
|
l.skip()
|
||||||
|
}
|
||||||
|
|
||||||
|
if isKeyStartChar(next) {
|
||||||
|
return l.lexKey
|
||||||
|
}
|
||||||
|
|
||||||
|
if next == eof {
|
||||||
|
l.next()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l.emit(tokenEOF)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexRvalue() tomlLexStateFn {
|
||||||
|
for {
|
||||||
|
next := l.peek()
|
||||||
|
switch next {
|
||||||
|
case '.':
|
||||||
|
return l.errorf("cannot start float with a dot")
|
||||||
|
case '=':
|
||||||
|
return l.lexEqual
|
||||||
|
case '[':
|
||||||
|
return l.lexLeftBracket
|
||||||
|
case ']':
|
||||||
|
return l.lexRightBracket
|
||||||
|
case '{':
|
||||||
|
return l.lexLeftCurlyBrace
|
||||||
|
case '}':
|
||||||
|
return l.lexRightCurlyBrace
|
||||||
|
case '#':
|
||||||
|
return l.lexComment(l.lexRvalue)
|
||||||
|
case '"':
|
||||||
|
return l.lexString
|
||||||
|
case '\'':
|
||||||
|
return l.lexLiteralString
|
||||||
|
case ',':
|
||||||
|
return l.lexComma
|
||||||
|
case '\r':
|
||||||
|
fallthrough
|
||||||
|
case '\n':
|
||||||
|
l.skip()
|
||||||
|
if len(l.brackets) > 0 && l.brackets[len(l.brackets)-1] == '[' {
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
return l.lexVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.follow("true") {
|
||||||
|
return l.lexTrue
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.follow("false") {
|
||||||
|
return l.lexFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.follow("inf") {
|
||||||
|
return l.lexInf
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.follow("nan") {
|
||||||
|
return l.lexNan
|
||||||
|
}
|
||||||
|
|
||||||
|
if isSpace(next) {
|
||||||
|
l.skip()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if next == eof {
|
||||||
|
l.next()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
possibleDate := l.peekString(35)
|
||||||
|
dateSubmatches := dateRegexp.FindStringSubmatch(possibleDate)
|
||||||
|
if dateSubmatches != nil && dateSubmatches[0] != "" {
|
||||||
|
l.fastForward(len(dateSubmatches[0]))
|
||||||
|
if dateSubmatches[2] == "" { // no timezone information => local date
|
||||||
|
return l.lexLocalDate
|
||||||
|
}
|
||||||
|
return l.lexDate
|
||||||
|
}
|
||||||
|
|
||||||
|
if next == '+' || next == '-' || isDigit(next) {
|
||||||
|
return l.lexNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
return l.errorf("no value can start with %c", next)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.emit(tokenEOF)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn {
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenLeftCurlyBrace)
|
||||||
|
l.brackets = append(l.brackets, '{')
|
||||||
|
return l.lexVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn {
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenRightCurlyBrace)
|
||||||
|
if len(l.brackets) == 0 || l.brackets[len(l.brackets)-1] != '{' {
|
||||||
|
return l.errorf("cannot have '}' here")
|
||||||
|
}
|
||||||
|
l.brackets = l.brackets[:len(l.brackets)-1]
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexDate() tomlLexStateFn {
|
||||||
|
l.emit(tokenDate)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexLocalDate() tomlLexStateFn {
|
||||||
|
l.emit(tokenLocalDate)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexTrue() tomlLexStateFn {
|
||||||
|
l.fastForward(4)
|
||||||
|
l.emit(tokenTrue)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexFalse() tomlLexStateFn {
|
||||||
|
l.fastForward(5)
|
||||||
|
l.emit(tokenFalse)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexInf() tomlLexStateFn {
|
||||||
|
l.fastForward(3)
|
||||||
|
l.emit(tokenInf)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexNan() tomlLexStateFn {
|
||||||
|
l.fastForward(3)
|
||||||
|
l.emit(tokenNan)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexEqual() tomlLexStateFn {
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenEqual)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexComma() tomlLexStateFn {
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenComma)
|
||||||
|
if len(l.brackets) > 0 && l.brackets[len(l.brackets)-1] == '{' {
|
||||||
|
return l.lexVoid
|
||||||
|
}
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the key and emits its value without escape sequences.
|
||||||
|
// bare keys, basic string keys and literal string keys are supported.
|
||||||
|
func (l *tomlLexer) lexKey() tomlLexStateFn {
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
for r := l.peek(); isKeyChar(r) || r == '\n' || r == '\r'; r = l.peek() {
|
||||||
|
if r == '"' {
|
||||||
|
l.next()
|
||||||
|
str, err := l.lexStringAsString(`"`, false, true)
|
||||||
|
if err != nil {
|
||||||
|
return l.errorf(err.Error())
|
||||||
|
}
|
||||||
|
sb.WriteString("\"")
|
||||||
|
sb.WriteString(str)
|
||||||
|
sb.WriteString("\"")
|
||||||
|
l.next()
|
||||||
|
continue
|
||||||
|
} else if r == '\'' {
|
||||||
|
l.next()
|
||||||
|
str, err := l.lexLiteralStringAsString(`'`, false)
|
||||||
|
if err != nil {
|
||||||
|
return l.errorf(err.Error())
|
||||||
|
}
|
||||||
|
sb.WriteString("'")
|
||||||
|
sb.WriteString(str)
|
||||||
|
sb.WriteString("'")
|
||||||
|
l.next()
|
||||||
|
continue
|
||||||
|
} else if r == '\n' {
|
||||||
|
return l.errorf("keys cannot contain new lines")
|
||||||
|
} else if isSpace(r) {
|
||||||
|
var str strings.Builder
|
||||||
|
str.WriteString(" ")
|
||||||
|
|
||||||
|
// skip trailing whitespace
|
||||||
|
l.next()
|
||||||
|
for r = l.peek(); isSpace(r); r = l.peek() {
|
||||||
|
str.WriteRune(r)
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
// break loop if not a dot
|
||||||
|
if r != '.' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
str.WriteString(".")
|
||||||
|
// skip trailing whitespace after dot
|
||||||
|
l.next()
|
||||||
|
for r = l.peek(); isSpace(r); r = l.peek() {
|
||||||
|
str.WriteRune(r)
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
sb.WriteString(str.String())
|
||||||
|
continue
|
||||||
|
} else if r == '.' {
|
||||||
|
// skip
|
||||||
|
} else if !isValidBareChar(r) {
|
||||||
|
return l.errorf("keys cannot contain %c character", r)
|
||||||
|
}
|
||||||
|
sb.WriteRune(r)
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
l.emitWithValue(tokenKey, sb.String())
|
||||||
|
return l.lexVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexComment(previousState tomlLexStateFn) tomlLexStateFn {
|
||||||
|
return func() tomlLexStateFn {
|
||||||
|
for next := l.peek(); next != '\n' && next != eof; next = l.peek() {
|
||||||
|
if next == '\r' && l.follow("\r\n") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
l.ignore()
|
||||||
|
return previousState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexLeftBracket() tomlLexStateFn {
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenLeftBracket)
|
||||||
|
l.brackets = append(l.brackets, '[')
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexLiteralStringAsString(terminator string, discardLeadingNewLine bool) (string, error) {
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
if discardLeadingNewLine {
|
||||||
|
if l.follow("\r\n") {
|
||||||
|
l.skip()
|
||||||
|
l.skip()
|
||||||
|
} else if l.peek() == '\n' {
|
||||||
|
l.skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find end of string
|
||||||
|
for {
|
||||||
|
if l.follow(terminator) {
|
||||||
|
return sb.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
next := l.peek()
|
||||||
|
if next == eof {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sb.WriteRune(l.next())
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("unclosed string")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexLiteralString() tomlLexStateFn {
|
||||||
|
l.skip()
|
||||||
|
|
||||||
|
// handle special case for triple-quote
|
||||||
|
terminator := "'"
|
||||||
|
discardLeadingNewLine := false
|
||||||
|
if l.follow("''") {
|
||||||
|
l.skip()
|
||||||
|
l.skip()
|
||||||
|
terminator = "'''"
|
||||||
|
discardLeadingNewLine = true
|
||||||
|
}
|
||||||
|
|
||||||
|
str, err := l.lexLiteralStringAsString(terminator, discardLeadingNewLine)
|
||||||
|
if err != nil {
|
||||||
|
return l.errorf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
l.emitWithValue(tokenString, str)
|
||||||
|
l.fastForward(len(terminator))
|
||||||
|
l.ignore()
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lex a string and return the results as a string.
|
||||||
|
// Terminator is the substring indicating the end of the token.
|
||||||
|
// The resulting string does not include the terminator.
|
||||||
|
func (l *tomlLexer) lexStringAsString(terminator string, discardLeadingNewLine, acceptNewLines bool) (string, error) {
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
if discardLeadingNewLine {
|
||||||
|
if l.follow("\r\n") {
|
||||||
|
l.skip()
|
||||||
|
l.skip()
|
||||||
|
} else if l.peek() == '\n' {
|
||||||
|
l.skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if l.follow(terminator) {
|
||||||
|
return sb.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.follow("\\") {
|
||||||
|
l.next()
|
||||||
|
switch l.peek() {
|
||||||
|
case '\r':
|
||||||
|
fallthrough
|
||||||
|
case '\n':
|
||||||
|
fallthrough
|
||||||
|
case '\t':
|
||||||
|
fallthrough
|
||||||
|
case ' ':
|
||||||
|
// skip all whitespace chars following backslash
|
||||||
|
for strings.ContainsRune("\r\n\t ", l.peek()) {
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
sb.WriteString("\"")
|
||||||
|
l.next()
|
||||||
|
case 'n':
|
||||||
|
sb.WriteString("\n")
|
||||||
|
l.next()
|
||||||
|
case 'b':
|
||||||
|
sb.WriteString("\b")
|
||||||
|
l.next()
|
||||||
|
case 'f':
|
||||||
|
sb.WriteString("\f")
|
||||||
|
l.next()
|
||||||
|
case '/':
|
||||||
|
sb.WriteString("/")
|
||||||
|
l.next()
|
||||||
|
case 't':
|
||||||
|
sb.WriteString("\t")
|
||||||
|
l.next()
|
||||||
|
case 'r':
|
||||||
|
sb.WriteString("\r")
|
||||||
|
l.next()
|
||||||
|
case '\\':
|
||||||
|
sb.WriteString("\\")
|
||||||
|
l.next()
|
||||||
|
case 'u':
|
||||||
|
l.next()
|
||||||
|
var code strings.Builder
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
c := l.peek()
|
||||||
|
if !isHexDigit(c) {
|
||||||
|
return "", errors.New("unfinished unicode escape")
|
||||||
|
}
|
||||||
|
l.next()
|
||||||
|
code.WriteRune(c)
|
||||||
|
}
|
||||||
|
intcode, err := strconv.ParseInt(code.String(), 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("invalid unicode escape: \\u" + code.String())
|
||||||
|
}
|
||||||
|
sb.WriteRune(rune(intcode))
|
||||||
|
case 'U':
|
||||||
|
l.next()
|
||||||
|
var code strings.Builder
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
c := l.peek()
|
||||||
|
if !isHexDigit(c) {
|
||||||
|
return "", errors.New("unfinished unicode escape")
|
||||||
|
}
|
||||||
|
l.next()
|
||||||
|
code.WriteRune(c)
|
||||||
|
}
|
||||||
|
intcode, err := strconv.ParseInt(code.String(), 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("invalid unicode escape: \\U" + code.String())
|
||||||
|
}
|
||||||
|
sb.WriteRune(rune(intcode))
|
||||||
|
default:
|
||||||
|
return "", errors.New("invalid escape sequence: \\" + string(l.peek()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r := l.peek()
|
||||||
|
|
||||||
|
if 0x00 <= r && r <= 0x1F && r != '\t' && !(acceptNewLines && (r == '\n' || r == '\r')) {
|
||||||
|
return "", fmt.Errorf("unescaped control character %U", r)
|
||||||
|
}
|
||||||
|
l.next()
|
||||||
|
sb.WriteRune(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.peek() == eof {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("unclosed string")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexString() tomlLexStateFn {
|
||||||
|
l.skip()
|
||||||
|
|
||||||
|
// handle special case for triple-quote
|
||||||
|
terminator := `"`
|
||||||
|
discardLeadingNewLine := false
|
||||||
|
acceptNewLines := false
|
||||||
|
if l.follow(`""`) {
|
||||||
|
l.skip()
|
||||||
|
l.skip()
|
||||||
|
terminator = `"""`
|
||||||
|
discardLeadingNewLine = true
|
||||||
|
acceptNewLines = true
|
||||||
|
}
|
||||||
|
|
||||||
|
str, err := l.lexStringAsString(terminator, discardLeadingNewLine, acceptNewLines)
|
||||||
|
if err != nil {
|
||||||
|
return l.errorf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
l.emitWithValue(tokenString, str)
|
||||||
|
l.fastForward(len(terminator))
|
||||||
|
l.ignore()
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexTableKey() tomlLexStateFn {
|
||||||
|
l.next()
|
||||||
|
|
||||||
|
if l.peek() == '[' {
|
||||||
|
// token '[[' signifies an array of tables
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenDoubleLeftBracket)
|
||||||
|
return l.lexInsideTableArrayKey
|
||||||
|
}
|
||||||
|
// vanilla table key
|
||||||
|
l.emit(tokenLeftBracket)
|
||||||
|
return l.lexInsideTableKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the key till "]]", but only bare keys are supported
|
||||||
|
func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
|
||||||
|
for r := l.peek(); r != eof; r = l.peek() {
|
||||||
|
switch r {
|
||||||
|
case ']':
|
||||||
|
if l.currentTokenStop > l.currentTokenStart {
|
||||||
|
l.emit(tokenKeyGroupArray)
|
||||||
|
}
|
||||||
|
l.next()
|
||||||
|
if l.peek() != ']' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenDoubleRightBracket)
|
||||||
|
return l.lexVoid
|
||||||
|
case '[':
|
||||||
|
return l.errorf("table array key cannot contain ']'")
|
||||||
|
default:
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l.errorf("unclosed table array key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the key till "]" but only bare keys are supported
|
||||||
|
func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn {
|
||||||
|
for r := l.peek(); r != eof; r = l.peek() {
|
||||||
|
switch r {
|
||||||
|
case ']':
|
||||||
|
if l.currentTokenStop > l.currentTokenStart {
|
||||||
|
l.emit(tokenKeyGroup)
|
||||||
|
}
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenRightBracket)
|
||||||
|
return l.lexVoid
|
||||||
|
case '[':
|
||||||
|
return l.errorf("table key cannot contain ']'")
|
||||||
|
default:
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l.errorf("unclosed table key")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexRightBracket() tomlLexStateFn {
|
||||||
|
l.next()
|
||||||
|
l.emit(tokenRightBracket)
|
||||||
|
if len(l.brackets) == 0 || l.brackets[len(l.brackets)-1] != '[' {
|
||||||
|
return l.errorf("cannot have ']' here")
|
||||||
|
}
|
||||||
|
l.brackets = l.brackets[:len(l.brackets)-1]
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
type validRuneFn func(r rune) bool
|
||||||
|
|
||||||
|
func isValidHexRune(r rune) bool {
|
||||||
|
return r >= 'a' && r <= 'f' ||
|
||||||
|
r >= 'A' && r <= 'F' ||
|
||||||
|
r >= '0' && r <= '9' ||
|
||||||
|
r == '_'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidOctalRune(r rune) bool {
|
||||||
|
return r >= '0' && r <= '7' || r == '_'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidBinaryRune(r rune) bool {
|
||||||
|
return r == '0' || r == '1' || r == '_'
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexNumber() tomlLexStateFn {
|
||||||
|
r := l.peek()
|
||||||
|
|
||||||
|
if r == '0' {
|
||||||
|
follow := l.peekString(2)
|
||||||
|
if len(follow) == 2 {
|
||||||
|
var isValidRune validRuneFn
|
||||||
|
switch follow[1] {
|
||||||
|
case 'x':
|
||||||
|
isValidRune = isValidHexRune
|
||||||
|
case 'o':
|
||||||
|
isValidRune = isValidOctalRune
|
||||||
|
case 'b':
|
||||||
|
isValidRune = isValidBinaryRune
|
||||||
|
default:
|
||||||
|
if follow[1] >= 'a' && follow[1] <= 'z' || follow[1] >= 'A' && follow[1] <= 'Z' {
|
||||||
|
return l.errorf("unknown number base: %s. possible options are x (hex) o (octal) b (binary)", string(follow[1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isValidRune != nil {
|
||||||
|
l.next()
|
||||||
|
l.next()
|
||||||
|
digitSeen := false
|
||||||
|
for {
|
||||||
|
next := l.peek()
|
||||||
|
if !isValidRune(next) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
digitSeen = true
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !digitSeen {
|
||||||
|
return l.errorf("number needs at least one digit")
|
||||||
|
}
|
||||||
|
|
||||||
|
l.emit(tokenInteger)
|
||||||
|
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r == '+' || r == '-' {
|
||||||
|
l.next()
|
||||||
|
if l.follow("inf") {
|
||||||
|
return l.lexInf
|
||||||
|
}
|
||||||
|
if l.follow("nan") {
|
||||||
|
return l.lexNan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pointSeen := false
|
||||||
|
expSeen := false
|
||||||
|
digitSeen := false
|
||||||
|
for {
|
||||||
|
next := l.peek()
|
||||||
|
if next == '.' {
|
||||||
|
if pointSeen {
|
||||||
|
return l.errorf("cannot have two dots in one float")
|
||||||
|
}
|
||||||
|
l.next()
|
||||||
|
if !isDigit(l.peek()) {
|
||||||
|
return l.errorf("float cannot end with a dot")
|
||||||
|
}
|
||||||
|
pointSeen = true
|
||||||
|
} else if next == 'e' || next == 'E' {
|
||||||
|
expSeen = true
|
||||||
|
l.next()
|
||||||
|
r := l.peek()
|
||||||
|
if r == '+' || r == '-' {
|
||||||
|
l.next()
|
||||||
|
}
|
||||||
|
} else if isDigit(next) {
|
||||||
|
digitSeen = true
|
||||||
|
l.next()
|
||||||
|
} else if next == '_' {
|
||||||
|
l.next()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if pointSeen && !digitSeen {
|
||||||
|
return l.errorf("cannot start float with a dot")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !digitSeen {
|
||||||
|
return l.errorf("no digit in that number")
|
||||||
|
}
|
||||||
|
if pointSeen || expSeen {
|
||||||
|
l.emit(tokenFloat)
|
||||||
|
} else {
|
||||||
|
l.emit(tokenInteger)
|
||||||
|
}
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) run() {
|
||||||
|
for state := l.lexVoid; state != nil; {
|
||||||
|
state = state()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Regexp for all date/time formats supported by TOML.
|
||||||
|
// Group 1: nano precision
|
||||||
|
// Group 2: timezone
|
||||||
|
//
|
||||||
|
// /!\ also matches the empty string
|
||||||
|
//
|
||||||
|
// Example matches:
|
||||||
|
// 1979-05-27T07:32:00Z
|
||||||
|
// 1979-05-27T00:32:00-07:00
|
||||||
|
// 1979-05-27T00:32:00.999999-07:00
|
||||||
|
// 1979-05-27 07:32:00Z
|
||||||
|
// 1979-05-27 00:32:00-07:00
|
||||||
|
// 1979-05-27 00:32:00.999999-07:00
|
||||||
|
// 1979-05-27T07:32:00
|
||||||
|
// 1979-05-27T00:32:00.999999
|
||||||
|
// 1979-05-27 07:32:00
|
||||||
|
// 1979-05-27 00:32:00.999999
|
||||||
|
// 1979-05-27
|
||||||
|
// 07:32:00
|
||||||
|
// 00:32:00.999999
|
||||||
|
dateRegexp = regexp.MustCompile(`^(?:\d{1,4}-\d{2}-\d{2})?(?:[T ]?\d{2}:\d{2}:\d{2}(\.\d{1,9})?(Z|[+-]\d{2}:\d{2})?)?`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry point
|
||||||
|
func lexToml(inputBytes []byte) []token {
|
||||||
|
runes := bytes.Runes(inputBytes)
|
||||||
|
l := &tomlLexer{
|
||||||
|
input: runes,
|
||||||
|
tokens: make([]token, 0, 256),
|
||||||
|
line: 1,
|
||||||
|
col: 1,
|
||||||
|
endbufferLine: 1,
|
||||||
|
endbufferCol: 1,
|
||||||
|
}
|
||||||
|
l.run()
|
||||||
|
return l.tokens
|
||||||
|
}
|
281
vendor/github.com/pelletier/go-toml/localtime.go
generated
vendored
Normal file
281
vendor/github.com/pelletier/go-toml/localtime.go
generated
vendored
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
// Implementation of TOML's local date/time.
|
||||||
|
// Copied over from https://github.com/googleapis/google-cloud-go/blob/master/civil/civil.go
|
||||||
|
// to avoid pulling all the Google dependencies.
|
||||||
|
//
|
||||||
|
// Copyright 2016 Google LLC
|
||||||
|
//
|
||||||
|
// 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 civil implements types for civil time, a time-zone-independent
|
||||||
|
// representation of time that follows the rules of the proleptic
|
||||||
|
// Gregorian calendar with exactly 24-hour days, 60-minute hours, and 60-second
|
||||||
|
// minutes.
|
||||||
|
//
|
||||||
|
// Because they lack location information, these types do not represent unique
|
||||||
|
// moments or intervals of time. Use time.Time for that purpose.
|
||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A LocalDate represents a date (year, month, day).
|
||||||
|
//
|
||||||
|
// This type does not include location information, and therefore does not
|
||||||
|
// describe a unique 24-hour timespan.
|
||||||
|
type LocalDate struct {
|
||||||
|
Year int // Year (e.g., 2014).
|
||||||
|
Month time.Month // Month of the year (January = 1, ...).
|
||||||
|
Day int // Day of the month, starting at 1.
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalDateOf returns the LocalDate in which a time occurs in that time's location.
|
||||||
|
func LocalDateOf(t time.Time) LocalDate {
|
||||||
|
var d LocalDate
|
||||||
|
d.Year, d.Month, d.Day = t.Date()
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLocalDate parses a string in RFC3339 full-date format and returns the date value it represents.
|
||||||
|
func ParseLocalDate(s string) (LocalDate, error) {
|
||||||
|
t, err := time.Parse("2006-01-02", s)
|
||||||
|
if err != nil {
|
||||||
|
return LocalDate{}, err
|
||||||
|
}
|
||||||
|
return LocalDateOf(t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the date in RFC3339 full-date format.
|
||||||
|
func (d LocalDate) String() string {
|
||||||
|
return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid reports whether the date is valid.
|
||||||
|
func (d LocalDate) IsValid() bool {
|
||||||
|
return LocalDateOf(d.In(time.UTC)) == d
|
||||||
|
}
|
||||||
|
|
||||||
|
// In returns the time corresponding to time 00:00:00 of the date in the location.
|
||||||
|
//
|
||||||
|
// In is always consistent with time.LocalDate, even when time.LocalDate returns a time
|
||||||
|
// on a different day. For example, if loc is America/Indiana/Vincennes, then both
|
||||||
|
// time.LocalDate(1955, time.May, 1, 0, 0, 0, 0, loc)
|
||||||
|
// and
|
||||||
|
// civil.LocalDate{Year: 1955, Month: time.May, Day: 1}.In(loc)
|
||||||
|
// return 23:00:00 on April 30, 1955.
|
||||||
|
//
|
||||||
|
// In panics if loc is nil.
|
||||||
|
func (d LocalDate) In(loc *time.Location) time.Time {
|
||||||
|
return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDays returns the date that is n days in the future.
|
||||||
|
// n can also be negative to go into the past.
|
||||||
|
func (d LocalDate) AddDays(n int) LocalDate {
|
||||||
|
return LocalDateOf(d.In(time.UTC).AddDate(0, 0, n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DaysSince returns the signed number of days between the date and s, not including the end day.
|
||||||
|
// This is the inverse operation to AddDays.
|
||||||
|
func (d LocalDate) DaysSince(s LocalDate) (days int) {
|
||||||
|
// We convert to Unix time so we do not have to worry about leap seconds:
|
||||||
|
// Unix time increases by exactly 86400 seconds per day.
|
||||||
|
deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix()
|
||||||
|
return int(deltaUnix / 86400)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before reports whether d1 occurs before d2.
|
||||||
|
func (d1 LocalDate) Before(d2 LocalDate) bool {
|
||||||
|
if d1.Year != d2.Year {
|
||||||
|
return d1.Year < d2.Year
|
||||||
|
}
|
||||||
|
if d1.Month != d2.Month {
|
||||||
|
return d1.Month < d2.Month
|
||||||
|
}
|
||||||
|
return d1.Day < d2.Day
|
||||||
|
}
|
||||||
|
|
||||||
|
// After reports whether d1 occurs after d2.
|
||||||
|
func (d1 LocalDate) After(d2 LocalDate) bool {
|
||||||
|
return d2.Before(d1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
// The output is the result of d.String().
|
||||||
|
func (d LocalDate) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(d.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
// The date is expected to be a string in a format accepted by ParseLocalDate.
|
||||||
|
func (d *LocalDate) UnmarshalText(data []byte) error {
|
||||||
|
var err error
|
||||||
|
*d, err = ParseLocalDate(string(data))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// A LocalTime represents a time with nanosecond precision.
|
||||||
|
//
|
||||||
|
// This type does not include location information, and therefore does not
|
||||||
|
// describe a unique moment in time.
|
||||||
|
//
|
||||||
|
// This type exists to represent the TIME type in storage-based APIs like BigQuery.
|
||||||
|
// Most operations on Times are unlikely to be meaningful. Prefer the LocalDateTime type.
|
||||||
|
type LocalTime struct {
|
||||||
|
Hour int // The hour of the day in 24-hour format; range [0-23]
|
||||||
|
Minute int // The minute of the hour; range [0-59]
|
||||||
|
Second int // The second of the minute; range [0-59]
|
||||||
|
Nanosecond int // The nanosecond of the second; range [0-999999999]
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalTimeOf returns the LocalTime representing the time of day in which a time occurs
|
||||||
|
// in that time's location. It ignores the date.
|
||||||
|
func LocalTimeOf(t time.Time) LocalTime {
|
||||||
|
var tm LocalTime
|
||||||
|
tm.Hour, tm.Minute, tm.Second = t.Clock()
|
||||||
|
tm.Nanosecond = t.Nanosecond()
|
||||||
|
return tm
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLocalTime parses a string and returns the time value it represents.
|
||||||
|
// ParseLocalTime accepts an extended form of the RFC3339 partial-time format. After
|
||||||
|
// the HH:MM:SS part of the string, an optional fractional part may appear,
|
||||||
|
// consisting of a decimal point followed by one to nine decimal digits.
|
||||||
|
// (RFC3339 admits only one digit after the decimal point).
|
||||||
|
func ParseLocalTime(s string) (LocalTime, error) {
|
||||||
|
t, err := time.Parse("15:04:05.999999999", s)
|
||||||
|
if err != nil {
|
||||||
|
return LocalTime{}, err
|
||||||
|
}
|
||||||
|
return LocalTimeOf(t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the date in the format described in ParseLocalTime. If Nanoseconds
|
||||||
|
// is zero, no fractional part will be generated. Otherwise, the result will
|
||||||
|
// end with a fractional part consisting of a decimal point and nine digits.
|
||||||
|
func (t LocalTime) String() string {
|
||||||
|
s := fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second)
|
||||||
|
if t.Nanosecond == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return s + fmt.Sprintf(".%09d", t.Nanosecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid reports whether the time is valid.
|
||||||
|
func (t LocalTime) IsValid() bool {
|
||||||
|
// Construct a non-zero time.
|
||||||
|
tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC)
|
||||||
|
return LocalTimeOf(tm) == t
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
// The output is the result of t.String().
|
||||||
|
func (t LocalTime) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(t.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
// The time is expected to be a string in a format accepted by ParseLocalTime.
|
||||||
|
func (t *LocalTime) UnmarshalText(data []byte) error {
|
||||||
|
var err error
|
||||||
|
*t, err = ParseLocalTime(string(data))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// A LocalDateTime represents a date and time.
|
||||||
|
//
|
||||||
|
// This type does not include location information, and therefore does not
|
||||||
|
// describe a unique moment in time.
|
||||||
|
type LocalDateTime struct {
|
||||||
|
Date LocalDate
|
||||||
|
Time LocalTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: We deliberately do not embed LocalDate into LocalDateTime, to avoid promoting AddDays and Sub.
|
||||||
|
|
||||||
|
// LocalDateTimeOf returns the LocalDateTime in which a time occurs in that time's location.
|
||||||
|
func LocalDateTimeOf(t time.Time) LocalDateTime {
|
||||||
|
return LocalDateTime{
|
||||||
|
Date: LocalDateOf(t),
|
||||||
|
Time: LocalTimeOf(t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLocalDateTime parses a string and returns the LocalDateTime it represents.
|
||||||
|
// ParseLocalDateTime accepts a variant of the RFC3339 date-time format that omits
|
||||||
|
// the time offset but includes an optional fractional time, as described in
|
||||||
|
// ParseLocalTime. Informally, the accepted format is
|
||||||
|
// YYYY-MM-DDTHH:MM:SS[.FFFFFFFFF]
|
||||||
|
// where the 'T' may be a lower-case 't'.
|
||||||
|
func ParseLocalDateTime(s string) (LocalDateTime, error) {
|
||||||
|
t, err := time.Parse("2006-01-02T15:04:05.999999999", s)
|
||||||
|
if err != nil {
|
||||||
|
t, err = time.Parse("2006-01-02t15:04:05.999999999", s)
|
||||||
|
if err != nil {
|
||||||
|
return LocalDateTime{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LocalDateTimeOf(t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the date in the format described in ParseLocalDate.
|
||||||
|
func (dt LocalDateTime) String() string {
|
||||||
|
return dt.Date.String() + "T" + dt.Time.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid reports whether the datetime is valid.
|
||||||
|
func (dt LocalDateTime) IsValid() bool {
|
||||||
|
return dt.Date.IsValid() && dt.Time.IsValid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// In returns the time corresponding to the LocalDateTime in the given location.
|
||||||
|
//
|
||||||
|
// If the time is missing or ambigous at the location, In returns the same
|
||||||
|
// result as time.LocalDate. For example, if loc is America/Indiana/Vincennes, then
|
||||||
|
// both
|
||||||
|
// time.LocalDate(1955, time.May, 1, 0, 30, 0, 0, loc)
|
||||||
|
// and
|
||||||
|
// civil.LocalDateTime{
|
||||||
|
// civil.LocalDate{Year: 1955, Month: time.May, Day: 1}},
|
||||||
|
// civil.LocalTime{Minute: 30}}.In(loc)
|
||||||
|
// return 23:30:00 on April 30, 1955.
|
||||||
|
//
|
||||||
|
// In panics if loc is nil.
|
||||||
|
func (dt LocalDateTime) In(loc *time.Location) time.Time {
|
||||||
|
return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before reports whether dt1 occurs before dt2.
|
||||||
|
func (dt1 LocalDateTime) Before(dt2 LocalDateTime) bool {
|
||||||
|
return dt1.In(time.UTC).Before(dt2.In(time.UTC))
|
||||||
|
}
|
||||||
|
|
||||||
|
// After reports whether dt1 occurs after dt2.
|
||||||
|
func (dt1 LocalDateTime) After(dt2 LocalDateTime) bool {
|
||||||
|
return dt2.Before(dt1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
// The output is the result of dt.String().
|
||||||
|
func (dt LocalDateTime) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(dt.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
// The datetime is expected to be a string in a format accepted by ParseLocalDateTime
|
||||||
|
func (dt *LocalDateTime) UnmarshalText(data []byte) error {
|
||||||
|
var err error
|
||||||
|
*dt, err = ParseLocalDateTime(string(data))
|
||||||
|
return err
|
||||||
|
}
|
1269
vendor/github.com/pelletier/go-toml/marshal.go
generated
vendored
Normal file
1269
vendor/github.com/pelletier/go-toml/marshal.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
39
vendor/github.com/pelletier/go-toml/marshal_OrderPreserve_test.toml
generated
vendored
Normal file
39
vendor/github.com/pelletier/go-toml/marshal_OrderPreserve_test.toml
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
title = "TOML Marshal Testing"
|
||||||
|
|
||||||
|
[basic_lists]
|
||||||
|
floats = [12.3,45.6,78.9]
|
||||||
|
bools = [true,false,true]
|
||||||
|
dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z]
|
||||||
|
ints = [8001,8001,8002]
|
||||||
|
uints = [5002,5003]
|
||||||
|
strings = ["One","Two","Three"]
|
||||||
|
|
||||||
|
[[subdocptrs]]
|
||||||
|
name = "Second"
|
||||||
|
|
||||||
|
[basic_map]
|
||||||
|
one = "one"
|
||||||
|
two = "two"
|
||||||
|
|
||||||
|
[subdoc]
|
||||||
|
|
||||||
|
[subdoc.second]
|
||||||
|
name = "Second"
|
||||||
|
|
||||||
|
[subdoc.first]
|
||||||
|
name = "First"
|
||||||
|
|
||||||
|
[basic]
|
||||||
|
uint = 5001
|
||||||
|
bool = true
|
||||||
|
float = 123.4
|
||||||
|
float64 = 123.456782132399
|
||||||
|
int = 5000
|
||||||
|
string = "Bite me"
|
||||||
|
date = 1979-05-27T07:32:00Z
|
||||||
|
|
||||||
|
[[subdoclist]]
|
||||||
|
name = "List.First"
|
||||||
|
|
||||||
|
[[subdoclist]]
|
||||||
|
name = "List.Second"
|
39
vendor/github.com/pelletier/go-toml/marshal_test.toml
generated
vendored
Normal file
39
vendor/github.com/pelletier/go-toml/marshal_test.toml
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
title = "TOML Marshal Testing"
|
||||||
|
|
||||||
|
[basic]
|
||||||
|
bool = true
|
||||||
|
date = 1979-05-27T07:32:00Z
|
||||||
|
float = 123.4
|
||||||
|
float64 = 123.456782132399
|
||||||
|
int = 5000
|
||||||
|
string = "Bite me"
|
||||||
|
uint = 5001
|
||||||
|
|
||||||
|
[basic_lists]
|
||||||
|
bools = [true,false,true]
|
||||||
|
dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z]
|
||||||
|
floats = [12.3,45.6,78.9]
|
||||||
|
ints = [8001,8001,8002]
|
||||||
|
strings = ["One","Two","Three"]
|
||||||
|
uints = [5002,5003]
|
||||||
|
|
||||||
|
[basic_map]
|
||||||
|
one = "one"
|
||||||
|
two = "two"
|
||||||
|
|
||||||
|
[subdoc]
|
||||||
|
|
||||||
|
[subdoc.first]
|
||||||
|
name = "First"
|
||||||
|
|
||||||
|
[subdoc.second]
|
||||||
|
name = "Second"
|
||||||
|
|
||||||
|
[[subdoclist]]
|
||||||
|
name = "List.First"
|
||||||
|
|
||||||
|
[[subdoclist]]
|
||||||
|
name = "List.Second"
|
||||||
|
|
||||||
|
[[subdocptrs]]
|
||||||
|
name = "Second"
|
493
vendor/github.com/pelletier/go-toml/parser.go
generated
vendored
Normal file
493
vendor/github.com/pelletier/go-toml/parser.go
generated
vendored
Normal file
@ -0,0 +1,493 @@
|
|||||||
|
// TOML Parser.
|
||||||
|
|
||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tomlParser struct {
|
||||||
|
flowIdx int
|
||||||
|
flow []token
|
||||||
|
tree *Tree
|
||||||
|
currentTable []string
|
||||||
|
seenTableKeys []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type tomlParserStateFn func() tomlParserStateFn
|
||||||
|
|
||||||
|
// Formats and panics an error message based on a token
|
||||||
|
func (p *tomlParser) raiseError(tok *token, msg string, args ...interface{}) {
|
||||||
|
panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) run() {
|
||||||
|
for state := p.parseStart; state != nil; {
|
||||||
|
state = state()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) peek() *token {
|
||||||
|
if p.flowIdx >= len(p.flow) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &p.flow[p.flowIdx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) assume(typ tokenType) {
|
||||||
|
tok := p.getToken()
|
||||||
|
if tok == nil {
|
||||||
|
p.raiseError(tok, "was expecting token %s, but token stream is empty", tok)
|
||||||
|
}
|
||||||
|
if tok.typ != typ {
|
||||||
|
p.raiseError(tok, "was expecting token %s, but got %s instead", typ, tok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) getToken() *token {
|
||||||
|
tok := p.peek()
|
||||||
|
if tok == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p.flowIdx++
|
||||||
|
return tok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) parseStart() tomlParserStateFn {
|
||||||
|
tok := p.peek()
|
||||||
|
|
||||||
|
// end of stream, parsing is finished
|
||||||
|
if tok == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tok.typ {
|
||||||
|
case tokenDoubleLeftBracket:
|
||||||
|
return p.parseGroupArray
|
||||||
|
case tokenLeftBracket:
|
||||||
|
return p.parseGroup
|
||||||
|
case tokenKey:
|
||||||
|
return p.parseAssign
|
||||||
|
case tokenEOF:
|
||||||
|
return nil
|
||||||
|
case tokenError:
|
||||||
|
p.raiseError(tok, "parsing error: %s", tok.String())
|
||||||
|
default:
|
||||||
|
p.raiseError(tok, "unexpected token %s", tok.typ)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) parseGroupArray() tomlParserStateFn {
|
||||||
|
startToken := p.getToken() // discard the [[
|
||||||
|
key := p.getToken()
|
||||||
|
if key.typ != tokenKeyGroupArray {
|
||||||
|
p.raiseError(key, "unexpected token %s, was expecting a table array key", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get or create table array element at the indicated part in the path
|
||||||
|
keys, err := parseKey(key.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(key, "invalid table array key: %s", err)
|
||||||
|
}
|
||||||
|
p.tree.createSubTree(keys[:len(keys)-1], startToken.Position) // create parent entries
|
||||||
|
destTree := p.tree.GetPath(keys)
|
||||||
|
var array []*Tree
|
||||||
|
if destTree == nil {
|
||||||
|
array = make([]*Tree, 0)
|
||||||
|
} else if target, ok := destTree.([]*Tree); ok && target != nil {
|
||||||
|
array = destTree.([]*Tree)
|
||||||
|
} else {
|
||||||
|
p.raiseError(key, "key %s is already assigned and not of type table array", key)
|
||||||
|
}
|
||||||
|
p.currentTable = keys
|
||||||
|
|
||||||
|
// add a new tree to the end of the table array
|
||||||
|
newTree := newTree()
|
||||||
|
newTree.position = startToken.Position
|
||||||
|
array = append(array, newTree)
|
||||||
|
p.tree.SetPath(p.currentTable, array)
|
||||||
|
|
||||||
|
// remove all keys that were children of this table array
|
||||||
|
prefix := key.val + "."
|
||||||
|
found := false
|
||||||
|
for ii := 0; ii < len(p.seenTableKeys); {
|
||||||
|
tableKey := p.seenTableKeys[ii]
|
||||||
|
if strings.HasPrefix(tableKey, prefix) {
|
||||||
|
p.seenTableKeys = append(p.seenTableKeys[:ii], p.seenTableKeys[ii+1:]...)
|
||||||
|
} else {
|
||||||
|
found = (tableKey == key.val)
|
||||||
|
ii++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep this key name from use by other kinds of assignments
|
||||||
|
if !found {
|
||||||
|
p.seenTableKeys = append(p.seenTableKeys, key.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// move to next parser state
|
||||||
|
p.assume(tokenDoubleRightBracket)
|
||||||
|
return p.parseStart
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) parseGroup() tomlParserStateFn {
|
||||||
|
startToken := p.getToken() // discard the [
|
||||||
|
key := p.getToken()
|
||||||
|
if key.typ != tokenKeyGroup {
|
||||||
|
p.raiseError(key, "unexpected token %s, was expecting a table key", key)
|
||||||
|
}
|
||||||
|
for _, item := range p.seenTableKeys {
|
||||||
|
if item == key.val {
|
||||||
|
p.raiseError(key, "duplicated tables")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.seenTableKeys = append(p.seenTableKeys, key.val)
|
||||||
|
keys, err := parseKey(key.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(key, "invalid table array key: %s", err)
|
||||||
|
}
|
||||||
|
if err := p.tree.createSubTree(keys, startToken.Position); err != nil {
|
||||||
|
p.raiseError(key, "%s", err)
|
||||||
|
}
|
||||||
|
destTree := p.tree.GetPath(keys)
|
||||||
|
if target, ok := destTree.(*Tree); ok && target != nil && target.inline {
|
||||||
|
p.raiseError(key, "could not re-define exist inline table or its sub-table : %s",
|
||||||
|
strings.Join(keys, "."))
|
||||||
|
}
|
||||||
|
p.assume(tokenRightBracket)
|
||||||
|
p.currentTable = keys
|
||||||
|
return p.parseStart
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) parseAssign() tomlParserStateFn {
|
||||||
|
key := p.getToken()
|
||||||
|
p.assume(tokenEqual)
|
||||||
|
|
||||||
|
parsedKey, err := parseKey(key.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(key, "invalid key: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
value := p.parseRvalue()
|
||||||
|
var tableKey []string
|
||||||
|
if len(p.currentTable) > 0 {
|
||||||
|
tableKey = p.currentTable
|
||||||
|
} else {
|
||||||
|
tableKey = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixKey := parsedKey[0 : len(parsedKey)-1]
|
||||||
|
tableKey = append(tableKey, prefixKey...)
|
||||||
|
|
||||||
|
// find the table to assign, looking out for arrays of tables
|
||||||
|
var targetNode *Tree
|
||||||
|
switch node := p.tree.GetPath(tableKey).(type) {
|
||||||
|
case []*Tree:
|
||||||
|
targetNode = node[len(node)-1]
|
||||||
|
case *Tree:
|
||||||
|
targetNode = node
|
||||||
|
case nil:
|
||||||
|
// create intermediate
|
||||||
|
if err := p.tree.createSubTree(tableKey, key.Position); err != nil {
|
||||||
|
p.raiseError(key, "could not create intermediate group: %s", err)
|
||||||
|
}
|
||||||
|
targetNode = p.tree.GetPath(tableKey).(*Tree)
|
||||||
|
default:
|
||||||
|
p.raiseError(key, "Unknown table type for path: %s",
|
||||||
|
strings.Join(tableKey, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetNode.inline {
|
||||||
|
p.raiseError(key, "could not add key or sub-table to exist inline table or its sub-table : %s",
|
||||||
|
strings.Join(tableKey, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign value to the found table
|
||||||
|
keyVal := parsedKey[len(parsedKey)-1]
|
||||||
|
localKey := []string{keyVal}
|
||||||
|
finalKey := append(tableKey, keyVal)
|
||||||
|
if targetNode.GetPath(localKey) != nil {
|
||||||
|
p.raiseError(key, "The following key was defined twice: %s",
|
||||||
|
strings.Join(finalKey, "."))
|
||||||
|
}
|
||||||
|
var toInsert interface{}
|
||||||
|
|
||||||
|
switch value.(type) {
|
||||||
|
case *Tree, []*Tree:
|
||||||
|
toInsert = value
|
||||||
|
default:
|
||||||
|
toInsert = &tomlValue{value: value, position: key.Position}
|
||||||
|
}
|
||||||
|
targetNode.values[keyVal] = toInsert
|
||||||
|
return p.parseStart
|
||||||
|
}
|
||||||
|
|
||||||
|
var numberUnderscoreInvalidRegexp *regexp.Regexp
|
||||||
|
var hexNumberUnderscoreInvalidRegexp *regexp.Regexp
|
||||||
|
|
||||||
|
func numberContainsInvalidUnderscore(value string) error {
|
||||||
|
if numberUnderscoreInvalidRegexp.MatchString(value) {
|
||||||
|
return errors.New("invalid use of _ in number")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexNumberContainsInvalidUnderscore(value string) error {
|
||||||
|
if hexNumberUnderscoreInvalidRegexp.MatchString(value) {
|
||||||
|
return errors.New("invalid use of _ in hex number")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupNumberToken(value string) string {
|
||||||
|
cleanedVal := strings.Replace(value, "_", "", -1)
|
||||||
|
return cleanedVal
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) parseRvalue() interface{} {
|
||||||
|
tok := p.getToken()
|
||||||
|
if tok == nil || tok.typ == tokenEOF {
|
||||||
|
p.raiseError(tok, "expecting a value")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tok.typ {
|
||||||
|
case tokenString:
|
||||||
|
return tok.val
|
||||||
|
case tokenTrue:
|
||||||
|
return true
|
||||||
|
case tokenFalse:
|
||||||
|
return false
|
||||||
|
case tokenInf:
|
||||||
|
if tok.val[0] == '-' {
|
||||||
|
return math.Inf(-1)
|
||||||
|
}
|
||||||
|
return math.Inf(1)
|
||||||
|
case tokenNan:
|
||||||
|
return math.NaN()
|
||||||
|
case tokenInteger:
|
||||||
|
cleanedVal := cleanupNumberToken(tok.val)
|
||||||
|
var err error
|
||||||
|
var val int64
|
||||||
|
if len(cleanedVal) >= 3 && cleanedVal[0] == '0' {
|
||||||
|
switch cleanedVal[1] {
|
||||||
|
case 'x':
|
||||||
|
err = hexNumberContainsInvalidUnderscore(tok.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
val, err = strconv.ParseInt(cleanedVal[2:], 16, 64)
|
||||||
|
case 'o':
|
||||||
|
err = numberContainsInvalidUnderscore(tok.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
val, err = strconv.ParseInt(cleanedVal[2:], 8, 64)
|
||||||
|
case 'b':
|
||||||
|
err = numberContainsInvalidUnderscore(tok.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
val, err = strconv.ParseInt(cleanedVal[2:], 2, 64)
|
||||||
|
default:
|
||||||
|
panic("invalid base") // the lexer should catch this first
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = numberContainsInvalidUnderscore(tok.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
val, err = strconv.ParseInt(cleanedVal, 10, 64)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
case tokenFloat:
|
||||||
|
err := numberContainsInvalidUnderscore(tok.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
cleanedVal := cleanupNumberToken(tok.val)
|
||||||
|
val, err := strconv.ParseFloat(cleanedVal, 64)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
case tokenDate:
|
||||||
|
layout := time.RFC3339Nano
|
||||||
|
if !strings.Contains(tok.val, "T") {
|
||||||
|
layout = strings.Replace(layout, "T", " ", 1)
|
||||||
|
}
|
||||||
|
val, err := time.ParseInLocation(layout, tok.val, time.UTC)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
case tokenLocalDate:
|
||||||
|
v := strings.Replace(tok.val, " ", "T", -1)
|
||||||
|
isDateTime := false
|
||||||
|
isTime := false
|
||||||
|
for _, c := range v {
|
||||||
|
if c == 'T' || c == 't' {
|
||||||
|
isDateTime = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if c == ':' {
|
||||||
|
isTime = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var val interface{}
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if isDateTime {
|
||||||
|
val, err = ParseLocalDateTime(v)
|
||||||
|
} else if isTime {
|
||||||
|
val, err = ParseLocalTime(v)
|
||||||
|
} else {
|
||||||
|
val, err = ParseLocalDate(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
case tokenLeftBracket:
|
||||||
|
return p.parseArray()
|
||||||
|
case tokenLeftCurlyBrace:
|
||||||
|
return p.parseInlineTable()
|
||||||
|
case tokenEqual:
|
||||||
|
p.raiseError(tok, "cannot have multiple equals for the same key")
|
||||||
|
case tokenError:
|
||||||
|
p.raiseError(tok, "%s", tok)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.raiseError(tok, "never reached")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenIsComma(t *token) bool {
|
||||||
|
return t != nil && t.typ == tokenComma
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) parseInlineTable() *Tree {
|
||||||
|
tree := newTree()
|
||||||
|
var previous *token
|
||||||
|
Loop:
|
||||||
|
for {
|
||||||
|
follow := p.peek()
|
||||||
|
if follow == nil || follow.typ == tokenEOF {
|
||||||
|
p.raiseError(follow, "unterminated inline table")
|
||||||
|
}
|
||||||
|
switch follow.typ {
|
||||||
|
case tokenRightCurlyBrace:
|
||||||
|
p.getToken()
|
||||||
|
break Loop
|
||||||
|
case tokenKey, tokenInteger, tokenString:
|
||||||
|
if !tokenIsComma(previous) && previous != nil {
|
||||||
|
p.raiseError(follow, "comma expected between fields in inline table")
|
||||||
|
}
|
||||||
|
key := p.getToken()
|
||||||
|
p.assume(tokenEqual)
|
||||||
|
|
||||||
|
parsedKey, err := parseKey(key.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(key, "invalid key: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value := p.parseRvalue()
|
||||||
|
tree.SetPath(parsedKey, value)
|
||||||
|
case tokenComma:
|
||||||
|
if tokenIsComma(previous) {
|
||||||
|
p.raiseError(follow, "need field between two commas in inline table")
|
||||||
|
}
|
||||||
|
p.getToken()
|
||||||
|
default:
|
||||||
|
p.raiseError(follow, "unexpected token type in inline table: %s", follow.String())
|
||||||
|
}
|
||||||
|
previous = follow
|
||||||
|
}
|
||||||
|
if tokenIsComma(previous) {
|
||||||
|
p.raiseError(previous, "trailing comma at the end of inline table")
|
||||||
|
}
|
||||||
|
tree.inline = true
|
||||||
|
return tree
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tomlParser) parseArray() interface{} {
|
||||||
|
var array []interface{}
|
||||||
|
arrayType := reflect.TypeOf(newTree())
|
||||||
|
for {
|
||||||
|
follow := p.peek()
|
||||||
|
if follow == nil || follow.typ == tokenEOF {
|
||||||
|
p.raiseError(follow, "unterminated array")
|
||||||
|
}
|
||||||
|
if follow.typ == tokenRightBracket {
|
||||||
|
p.getToken()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
val := p.parseRvalue()
|
||||||
|
if reflect.TypeOf(val) != arrayType {
|
||||||
|
arrayType = nil
|
||||||
|
}
|
||||||
|
array = append(array, val)
|
||||||
|
follow = p.peek()
|
||||||
|
if follow == nil || follow.typ == tokenEOF {
|
||||||
|
p.raiseError(follow, "unterminated array")
|
||||||
|
}
|
||||||
|
if follow.typ != tokenRightBracket && follow.typ != tokenComma {
|
||||||
|
p.raiseError(follow, "missing comma")
|
||||||
|
}
|
||||||
|
if follow.typ == tokenComma {
|
||||||
|
p.getToken()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the array is a mixed-type array or its length is 0,
|
||||||
|
// don't convert it to a table array
|
||||||
|
if len(array) <= 0 {
|
||||||
|
arrayType = nil
|
||||||
|
}
|
||||||
|
// An array of Trees is actually an array of inline
|
||||||
|
// tables, which is a shorthand for a table array. If the
|
||||||
|
// array was not converted from []interface{} to []*Tree,
|
||||||
|
// the two notations would not be equivalent.
|
||||||
|
if arrayType == reflect.TypeOf(newTree()) {
|
||||||
|
tomlArray := make([]*Tree, len(array))
|
||||||
|
for i, v := range array {
|
||||||
|
tomlArray[i] = v.(*Tree)
|
||||||
|
}
|
||||||
|
return tomlArray
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseToml(flow []token) *Tree {
|
||||||
|
result := newTree()
|
||||||
|
result.position = Position{1, 1}
|
||||||
|
parser := &tomlParser{
|
||||||
|
flowIdx: 0,
|
||||||
|
flow: flow,
|
||||||
|
tree: result,
|
||||||
|
currentTable: make([]string, 0),
|
||||||
|
seenTableKeys: make([]string, 0),
|
||||||
|
}
|
||||||
|
parser.run()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d])|_$|^_`)
|
||||||
|
hexNumberUnderscoreInvalidRegexp = regexp.MustCompile(`(^0x_)|([^\da-f]_|_[^\da-f])|_$|^_`)
|
||||||
|
}
|
29
vendor/github.com/pelletier/go-toml/position.go
generated
vendored
Normal file
29
vendor/github.com/pelletier/go-toml/position.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Position support for go-toml
|
||||||
|
|
||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Position of a document element within a TOML document.
|
||||||
|
//
|
||||||
|
// Line and Col are both 1-indexed positions for the element's line number and
|
||||||
|
// column number, respectively. Values of zero or less will cause Invalid(),
|
||||||
|
// to return true.
|
||||||
|
type Position struct {
|
||||||
|
Line int // line within the document
|
||||||
|
Col int // column within the line
|
||||||
|
}
|
||||||
|
|
||||||
|
// String representation of the position.
|
||||||
|
// Displays 1-indexed line and column numbers.
|
||||||
|
func (p Position) String() string {
|
||||||
|
return fmt.Sprintf("(%d, %d)", p.Line, p.Col)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid returns whether or not the position is valid (i.e. with negative or
|
||||||
|
// null values)
|
||||||
|
func (p Position) Invalid() bool {
|
||||||
|
return p.Line <= 0 || p.Col <= 0
|
||||||
|
}
|
134
vendor/github.com/pelletier/go-toml/token.go
generated
vendored
Normal file
134
vendor/github.com/pelletier/go-toml/token.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Define tokens
|
||||||
|
type tokenType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
eof = -(iota + 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tokenError tokenType = iota
|
||||||
|
tokenEOF
|
||||||
|
tokenComment
|
||||||
|
tokenKey
|
||||||
|
tokenString
|
||||||
|
tokenInteger
|
||||||
|
tokenTrue
|
||||||
|
tokenFalse
|
||||||
|
tokenFloat
|
||||||
|
tokenInf
|
||||||
|
tokenNan
|
||||||
|
tokenEqual
|
||||||
|
tokenLeftBracket
|
||||||
|
tokenRightBracket
|
||||||
|
tokenLeftCurlyBrace
|
||||||
|
tokenRightCurlyBrace
|
||||||
|
tokenLeftParen
|
||||||
|
tokenRightParen
|
||||||
|
tokenDoubleLeftBracket
|
||||||
|
tokenDoubleRightBracket
|
||||||
|
tokenDate
|
||||||
|
tokenLocalDate
|
||||||
|
tokenKeyGroup
|
||||||
|
tokenKeyGroupArray
|
||||||
|
tokenComma
|
||||||
|
tokenColon
|
||||||
|
tokenDollar
|
||||||
|
tokenStar
|
||||||
|
tokenQuestion
|
||||||
|
tokenDot
|
||||||
|
tokenDotDot
|
||||||
|
tokenEOL
|
||||||
|
)
|
||||||
|
|
||||||
|
var tokenTypeNames = []string{
|
||||||
|
"Error",
|
||||||
|
"EOF",
|
||||||
|
"Comment",
|
||||||
|
"Key",
|
||||||
|
"String",
|
||||||
|
"Integer",
|
||||||
|
"True",
|
||||||
|
"False",
|
||||||
|
"Float",
|
||||||
|
"Inf",
|
||||||
|
"NaN",
|
||||||
|
"=",
|
||||||
|
"[",
|
||||||
|
"]",
|
||||||
|
"{",
|
||||||
|
"}",
|
||||||
|
"(",
|
||||||
|
")",
|
||||||
|
"]]",
|
||||||
|
"[[",
|
||||||
|
"LocalDate",
|
||||||
|
"LocalDate",
|
||||||
|
"KeyGroup",
|
||||||
|
"KeyGroupArray",
|
||||||
|
",",
|
||||||
|
":",
|
||||||
|
"$",
|
||||||
|
"*",
|
||||||
|
"?",
|
||||||
|
".",
|
||||||
|
"..",
|
||||||
|
"EOL",
|
||||||
|
}
|
||||||
|
|
||||||
|
type token struct {
|
||||||
|
Position
|
||||||
|
typ tokenType
|
||||||
|
val string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tt tokenType) String() string {
|
||||||
|
idx := int(tt)
|
||||||
|
if idx < len(tokenTypeNames) {
|
||||||
|
return tokenTypeNames[idx]
|
||||||
|
}
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t token) String() string {
|
||||||
|
switch t.typ {
|
||||||
|
case tokenEOF:
|
||||||
|
return "EOF"
|
||||||
|
case tokenError:
|
||||||
|
return t.val
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%q", t.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSpace(r rune) bool {
|
||||||
|
return r == ' ' || r == '\t'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAlphanumeric(r rune) bool {
|
||||||
|
return 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || r == '_'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isKeyChar(r rune) bool {
|
||||||
|
// Keys start with the first character that isn't whitespace or [ and end
|
||||||
|
// with the last non-whitespace character before the equals sign. Keys
|
||||||
|
// cannot contain a # character."
|
||||||
|
return !(r == '\r' || r == '\n' || r == eof || r == '=')
|
||||||
|
}
|
||||||
|
|
||||||
|
func isKeyStartChar(r rune) bool {
|
||||||
|
return !(isSpace(r) || r == '\r' || r == '\n' || r == eof || r == '[')
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDigit(r rune) bool {
|
||||||
|
return '0' <= r && r <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHexDigit(r rune) bool {
|
||||||
|
return isDigit(r) ||
|
||||||
|
(r >= 'a' && r <= 'f') ||
|
||||||
|
(r >= 'A' && r <= 'F')
|
||||||
|
}
|
529
vendor/github.com/pelletier/go-toml/toml.go
generated
vendored
Normal file
529
vendor/github.com/pelletier/go-toml/toml.go
generated
vendored
Normal file
@ -0,0 +1,529 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tomlValue struct {
|
||||||
|
value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
|
||||||
|
comment string
|
||||||
|
commented bool
|
||||||
|
multiline bool
|
||||||
|
position Position
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tree is the result of the parsing of a TOML file.
|
||||||
|
type Tree struct {
|
||||||
|
values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
|
||||||
|
comment string
|
||||||
|
commented bool
|
||||||
|
inline bool
|
||||||
|
position Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTree() *Tree {
|
||||||
|
return newTreeWithPosition(Position{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTreeWithPosition(pos Position) *Tree {
|
||||||
|
return &Tree{
|
||||||
|
values: make(map[string]interface{}),
|
||||||
|
position: pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TreeFromMap initializes a new Tree object using the given map.
|
||||||
|
func TreeFromMap(m map[string]interface{}) (*Tree, error) {
|
||||||
|
result, err := toTree(m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.(*Tree), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position returns the position of the tree.
|
||||||
|
func (t *Tree) Position() Position {
|
||||||
|
return t.position
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has returns a boolean indicating if the given key exists.
|
||||||
|
func (t *Tree) Has(key string) bool {
|
||||||
|
if key == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return t.HasPath(strings.Split(key, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPath returns true if the given path of keys exists, false otherwise.
|
||||||
|
func (t *Tree) HasPath(keys []string) bool {
|
||||||
|
return t.GetPath(keys) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys returns the keys of the toplevel tree (does not recurse).
|
||||||
|
func (t *Tree) Keys() []string {
|
||||||
|
keys := make([]string, len(t.values))
|
||||||
|
i := 0
|
||||||
|
for k := range t.values {
|
||||||
|
keys[i] = k
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the value at key in the Tree.
|
||||||
|
// Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
|
||||||
|
// If you need to retrieve non-bare keys, use GetPath.
|
||||||
|
// Returns nil if the path does not exist in the tree.
|
||||||
|
// If keys is of length zero, the current tree is returned.
|
||||||
|
func (t *Tree) Get(key string) interface{} {
|
||||||
|
if key == "" {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
return t.GetPath(strings.Split(key, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPath returns the element in the tree indicated by 'keys'.
|
||||||
|
// If keys is of length zero, the current tree is returned.
|
||||||
|
func (t *Tree) GetPath(keys []string) interface{} {
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
subtree := t
|
||||||
|
for _, intermediateKey := range keys[:len(keys)-1] {
|
||||||
|
value, exists := subtree.values[intermediateKey]
|
||||||
|
if !exists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch node := value.(type) {
|
||||||
|
case *Tree:
|
||||||
|
subtree = node
|
||||||
|
case []*Tree:
|
||||||
|
// go to most recent element
|
||||||
|
if len(node) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
subtree = node[len(node)-1]
|
||||||
|
default:
|
||||||
|
return nil // cannot navigate through other node types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// branch based on final node type
|
||||||
|
switch node := subtree.values[keys[len(keys)-1]].(type) {
|
||||||
|
case *tomlValue:
|
||||||
|
return node.value
|
||||||
|
default:
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArray returns the value at key in the Tree.
|
||||||
|
// It returns []string, []int64, etc type if key has homogeneous lists
|
||||||
|
// Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
|
||||||
|
// Returns nil if the path does not exist in the tree.
|
||||||
|
// If keys is of length zero, the current tree is returned.
|
||||||
|
func (t *Tree) GetArray(key string) interface{} {
|
||||||
|
if key == "" {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
return t.GetArrayPath(strings.Split(key, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArrayPath returns the element in the tree indicated by 'keys'.
|
||||||
|
// If keys is of length zero, the current tree is returned.
|
||||||
|
func (t *Tree) GetArrayPath(keys []string) interface{} {
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
subtree := t
|
||||||
|
for _, intermediateKey := range keys[:len(keys)-1] {
|
||||||
|
value, exists := subtree.values[intermediateKey]
|
||||||
|
if !exists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch node := value.(type) {
|
||||||
|
case *Tree:
|
||||||
|
subtree = node
|
||||||
|
case []*Tree:
|
||||||
|
// go to most recent element
|
||||||
|
if len(node) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
subtree = node[len(node)-1]
|
||||||
|
default:
|
||||||
|
return nil // cannot navigate through other node types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// branch based on final node type
|
||||||
|
switch node := subtree.values[keys[len(keys)-1]].(type) {
|
||||||
|
case *tomlValue:
|
||||||
|
switch n := node.value.(type) {
|
||||||
|
case []interface{}:
|
||||||
|
return getArray(n)
|
||||||
|
default:
|
||||||
|
return node.value
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if homogeneous array, then return slice type object over []interface{}
|
||||||
|
func getArray(n []interface{}) interface{} {
|
||||||
|
var s []string
|
||||||
|
var i64 []int64
|
||||||
|
var f64 []float64
|
||||||
|
var bl []bool
|
||||||
|
for _, value := range n {
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
s = append(s, v)
|
||||||
|
case int64:
|
||||||
|
i64 = append(i64, v)
|
||||||
|
case float64:
|
||||||
|
f64 = append(f64, v)
|
||||||
|
case bool:
|
||||||
|
bl = append(bl, v)
|
||||||
|
default:
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(s) == len(n) {
|
||||||
|
return s
|
||||||
|
} else if len(i64) == len(n) {
|
||||||
|
return i64
|
||||||
|
} else if len(f64) == len(n) {
|
||||||
|
return f64
|
||||||
|
} else if len(bl) == len(n) {
|
||||||
|
return bl
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPosition returns the position of the given key.
|
||||||
|
func (t *Tree) GetPosition(key string) Position {
|
||||||
|
if key == "" {
|
||||||
|
return t.position
|
||||||
|
}
|
||||||
|
return t.GetPositionPath(strings.Split(key, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPositionPath sets the position of element in the tree indicated by 'keys'.
|
||||||
|
// If keys is of length zero, the current tree position is set.
|
||||||
|
func (t *Tree) SetPositionPath(keys []string, pos Position) {
|
||||||
|
if len(keys) == 0 {
|
||||||
|
t.position = pos
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subtree := t
|
||||||
|
for _, intermediateKey := range keys[:len(keys)-1] {
|
||||||
|
value, exists := subtree.values[intermediateKey]
|
||||||
|
if !exists {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch node := value.(type) {
|
||||||
|
case *Tree:
|
||||||
|
subtree = node
|
||||||
|
case []*Tree:
|
||||||
|
// go to most recent element
|
||||||
|
if len(node) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subtree = node[len(node)-1]
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// branch based on final node type
|
||||||
|
switch node := subtree.values[keys[len(keys)-1]].(type) {
|
||||||
|
case *tomlValue:
|
||||||
|
node.position = pos
|
||||||
|
return
|
||||||
|
case *Tree:
|
||||||
|
node.position = pos
|
||||||
|
return
|
||||||
|
case []*Tree:
|
||||||
|
// go to most recent element
|
||||||
|
if len(node) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node[len(node)-1].position = pos
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPositionPath returns the element in the tree indicated by 'keys'.
|
||||||
|
// If keys is of length zero, the current tree is returned.
|
||||||
|
func (t *Tree) GetPositionPath(keys []string) Position {
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return t.position
|
||||||
|
}
|
||||||
|
subtree := t
|
||||||
|
for _, intermediateKey := range keys[:len(keys)-1] {
|
||||||
|
value, exists := subtree.values[intermediateKey]
|
||||||
|
if !exists {
|
||||||
|
return Position{0, 0}
|
||||||
|
}
|
||||||
|
switch node := value.(type) {
|
||||||
|
case *Tree:
|
||||||
|
subtree = node
|
||||||
|
case []*Tree:
|
||||||
|
// go to most recent element
|
||||||
|
if len(node) == 0 {
|
||||||
|
return Position{0, 0}
|
||||||
|
}
|
||||||
|
subtree = node[len(node)-1]
|
||||||
|
default:
|
||||||
|
return Position{0, 0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// branch based on final node type
|
||||||
|
switch node := subtree.values[keys[len(keys)-1]].(type) {
|
||||||
|
case *tomlValue:
|
||||||
|
return node.position
|
||||||
|
case *Tree:
|
||||||
|
return node.position
|
||||||
|
case []*Tree:
|
||||||
|
// go to most recent element
|
||||||
|
if len(node) == 0 {
|
||||||
|
return Position{0, 0}
|
||||||
|
}
|
||||||
|
return node[len(node)-1].position
|
||||||
|
default:
|
||||||
|
return Position{0, 0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefault works like Get but with a default value
|
||||||
|
func (t *Tree) GetDefault(key string, def interface{}) interface{} {
|
||||||
|
val := t.Get(key)
|
||||||
|
if val == nil {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOptions arguments are supplied to the SetWithOptions and SetPathWithOptions functions to modify marshalling behaviour.
|
||||||
|
// The default values within the struct are valid default options.
|
||||||
|
type SetOptions struct {
|
||||||
|
Comment string
|
||||||
|
Commented bool
|
||||||
|
Multiline bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWithOptions is the same as Set, but allows you to provide formatting
|
||||||
|
// instructions to the key, that will be used by Marshal().
|
||||||
|
func (t *Tree) SetWithOptions(key string, opts SetOptions, value interface{}) {
|
||||||
|
t.SetPathWithOptions(strings.Split(key, "."), opts, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPathWithOptions is the same as SetPath, but allows you to provide
|
||||||
|
// formatting instructions to the key, that will be reused by Marshal().
|
||||||
|
func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interface{}) {
|
||||||
|
subtree := t
|
||||||
|
for i, intermediateKey := range keys[:len(keys)-1] {
|
||||||
|
nextTree, exists := subtree.values[intermediateKey]
|
||||||
|
if !exists {
|
||||||
|
nextTree = newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
|
||||||
|
subtree.values[intermediateKey] = nextTree // add new element here
|
||||||
|
}
|
||||||
|
switch node := nextTree.(type) {
|
||||||
|
case *Tree:
|
||||||
|
subtree = node
|
||||||
|
case []*Tree:
|
||||||
|
// go to most recent element
|
||||||
|
if len(node) == 0 {
|
||||||
|
// create element if it does not exist
|
||||||
|
node = append(node, newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col}))
|
||||||
|
subtree.values[intermediateKey] = node
|
||||||
|
}
|
||||||
|
subtree = node[len(node)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var toInsert interface{}
|
||||||
|
|
||||||
|
switch v := value.(type) {
|
||||||
|
case *Tree:
|
||||||
|
v.comment = opts.Comment
|
||||||
|
v.commented = opts.Commented
|
||||||
|
toInsert = value
|
||||||
|
case []*Tree:
|
||||||
|
for i := range v {
|
||||||
|
v[i].commented = opts.Commented
|
||||||
|
}
|
||||||
|
toInsert = value
|
||||||
|
case *tomlValue:
|
||||||
|
v.comment = opts.Comment
|
||||||
|
v.commented = opts.Commented
|
||||||
|
v.multiline = opts.Multiline
|
||||||
|
toInsert = v
|
||||||
|
default:
|
||||||
|
toInsert = &tomlValue{value: value,
|
||||||
|
comment: opts.Comment,
|
||||||
|
commented: opts.Commented,
|
||||||
|
multiline: opts.Multiline,
|
||||||
|
position: Position{Line: subtree.position.Line + len(subtree.values) + 1, Col: subtree.position.Col}}
|
||||||
|
}
|
||||||
|
|
||||||
|
subtree.values[keys[len(keys)-1]] = toInsert
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set an element in the tree.
|
||||||
|
// Key is a dot-separated path (e.g. a.b.c).
|
||||||
|
// Creates all necessary intermediate trees, if needed.
|
||||||
|
func (t *Tree) Set(key string, value interface{}) {
|
||||||
|
t.SetWithComment(key, "", false, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWithComment is the same as Set, but allows you to provide comment
|
||||||
|
// information to the key, that will be reused by Marshal().
|
||||||
|
func (t *Tree) SetWithComment(key string, comment string, commented bool, value interface{}) {
|
||||||
|
t.SetPathWithComment(strings.Split(key, "."), comment, commented, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPath sets an element in the tree.
|
||||||
|
// Keys is an array of path elements (e.g. {"a","b","c"}).
|
||||||
|
// Creates all necessary intermediate trees, if needed.
|
||||||
|
func (t *Tree) SetPath(keys []string, value interface{}) {
|
||||||
|
t.SetPathWithComment(keys, "", false, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPathWithComment is the same as SetPath, but allows you to provide comment
|
||||||
|
// information to the key, that will be reused by Marshal().
|
||||||
|
func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool, value interface{}) {
|
||||||
|
t.SetPathWithOptions(keys, SetOptions{Comment: comment, Commented: commented}, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a key from the tree.
|
||||||
|
// Key is a dot-separated path (e.g. a.b.c).
|
||||||
|
func (t *Tree) Delete(key string) error {
|
||||||
|
keys, err := parseKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return t.DeletePath(keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePath removes a key from the tree.
|
||||||
|
// Keys is an array of path elements (e.g. {"a","b","c"}).
|
||||||
|
func (t *Tree) DeletePath(keys []string) error {
|
||||||
|
keyLen := len(keys)
|
||||||
|
if keyLen == 1 {
|
||||||
|
delete(t.values, keys[0])
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tree := t.GetPath(keys[:keyLen-1])
|
||||||
|
item := keys[keyLen-1]
|
||||||
|
switch node := tree.(type) {
|
||||||
|
case *Tree:
|
||||||
|
delete(node.values, item)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("no such key to delete")
|
||||||
|
}
|
||||||
|
|
||||||
|
// createSubTree takes a tree and a key and create the necessary intermediate
|
||||||
|
// subtrees to create a subtree at that point. In-place.
|
||||||
|
//
|
||||||
|
// e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b]
|
||||||
|
// and tree[a][b][c]
|
||||||
|
//
|
||||||
|
// Returns nil on success, error object on failure
|
||||||
|
func (t *Tree) createSubTree(keys []string, pos Position) error {
|
||||||
|
subtree := t
|
||||||
|
for i, intermediateKey := range keys {
|
||||||
|
nextTree, exists := subtree.values[intermediateKey]
|
||||||
|
if !exists {
|
||||||
|
tree := newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
|
||||||
|
tree.position = pos
|
||||||
|
tree.inline = subtree.inline
|
||||||
|
subtree.values[intermediateKey] = tree
|
||||||
|
nextTree = tree
|
||||||
|
}
|
||||||
|
|
||||||
|
switch node := nextTree.(type) {
|
||||||
|
case []*Tree:
|
||||||
|
subtree = node[len(node)-1]
|
||||||
|
case *Tree:
|
||||||
|
subtree = node
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown type for path %s (%s): %T (%#v)",
|
||||||
|
strings.Join(keys, "."), intermediateKey, nextTree, nextTree)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadBytes creates a Tree from a []byte.
|
||||||
|
func LoadBytes(b []byte) (tree *Tree, err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
if _, ok := r.(runtime.Error); ok {
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
err = errors.New(r.(string))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if len(b) >= 4 && (hasUTF32BigEndianBOM4(b) || hasUTF32LittleEndianBOM4(b)) {
|
||||||
|
b = b[4:]
|
||||||
|
} else if len(b) >= 3 && hasUTF8BOM3(b) {
|
||||||
|
b = b[3:]
|
||||||
|
} else if len(b) >= 2 && (hasUTF16BigEndianBOM2(b) || hasUTF16LittleEndianBOM2(b)) {
|
||||||
|
b = b[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
tree = parseToml(lexToml(b))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasUTF16BigEndianBOM2(b []byte) bool {
|
||||||
|
return b[0] == 0xFE && b[1] == 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasUTF16LittleEndianBOM2(b []byte) bool {
|
||||||
|
return b[0] == 0xFF && b[1] == 0xFE
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasUTF8BOM3(b []byte) bool {
|
||||||
|
return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasUTF32BigEndianBOM4(b []byte) bool {
|
||||||
|
return b[0] == 0x00 && b[1] == 0x00 && b[2] == 0xFE && b[3] == 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasUTF32LittleEndianBOM4(b []byte) bool {
|
||||||
|
return b[0] == 0xFF && b[1] == 0xFE && b[2] == 0x00 && b[3] == 0x00
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadReader creates a Tree from any io.Reader.
|
||||||
|
func LoadReader(reader io.Reader) (tree *Tree, err error) {
|
||||||
|
inputBytes, err := ioutil.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tree, err = LoadBytes(inputBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load creates a Tree from a string.
|
||||||
|
func Load(content string) (tree *Tree, err error) {
|
||||||
|
return LoadBytes([]byte(content))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadFile creates a Tree from a file.
|
||||||
|
func LoadFile(path string) (tree *Tree, err error) {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return LoadReader(file)
|
||||||
|
}
|
155
vendor/github.com/pelletier/go-toml/tomltree_create.go
generated
vendored
Normal file
155
vendor/github.com/pelletier/go-toml/tomltree_create.go
generated
vendored
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var kindToType = [reflect.String + 1]reflect.Type{
|
||||||
|
reflect.Bool: reflect.TypeOf(true),
|
||||||
|
reflect.String: reflect.TypeOf(""),
|
||||||
|
reflect.Float32: reflect.TypeOf(float64(1)),
|
||||||
|
reflect.Float64: reflect.TypeOf(float64(1)),
|
||||||
|
reflect.Int: reflect.TypeOf(int64(1)),
|
||||||
|
reflect.Int8: reflect.TypeOf(int64(1)),
|
||||||
|
reflect.Int16: reflect.TypeOf(int64(1)),
|
||||||
|
reflect.Int32: reflect.TypeOf(int64(1)),
|
||||||
|
reflect.Int64: reflect.TypeOf(int64(1)),
|
||||||
|
reflect.Uint: reflect.TypeOf(uint64(1)),
|
||||||
|
reflect.Uint8: reflect.TypeOf(uint64(1)),
|
||||||
|
reflect.Uint16: reflect.TypeOf(uint64(1)),
|
||||||
|
reflect.Uint32: reflect.TypeOf(uint64(1)),
|
||||||
|
reflect.Uint64: reflect.TypeOf(uint64(1)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeFor returns a reflect.Type for a reflect.Kind, or nil if none is found.
|
||||||
|
// supported values:
|
||||||
|
// string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32
|
||||||
|
func typeFor(k reflect.Kind) reflect.Type {
|
||||||
|
if k > 0 && int(k) < len(kindToType) {
|
||||||
|
return kindToType[k]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func simpleValueCoercion(object interface{}) (interface{}, error) {
|
||||||
|
switch original := object.(type) {
|
||||||
|
case string, bool, int64, uint64, float64, time.Time:
|
||||||
|
return original, nil
|
||||||
|
case int:
|
||||||
|
return int64(original), nil
|
||||||
|
case int8:
|
||||||
|
return int64(original), nil
|
||||||
|
case int16:
|
||||||
|
return int64(original), nil
|
||||||
|
case int32:
|
||||||
|
return int64(original), nil
|
||||||
|
case uint:
|
||||||
|
return uint64(original), nil
|
||||||
|
case uint8:
|
||||||
|
return uint64(original), nil
|
||||||
|
case uint16:
|
||||||
|
return uint64(original), nil
|
||||||
|
case uint32:
|
||||||
|
return uint64(original), nil
|
||||||
|
case float32:
|
||||||
|
return float64(original), nil
|
||||||
|
case fmt.Stringer:
|
||||||
|
return original.String(), nil
|
||||||
|
case []interface{}:
|
||||||
|
value := reflect.ValueOf(original)
|
||||||
|
length := value.Len()
|
||||||
|
arrayValue := reflect.MakeSlice(value.Type(), 0, length)
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
val := value.Index(i).Interface()
|
||||||
|
simpleValue, err := simpleValueCoercion(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
|
||||||
|
}
|
||||||
|
return arrayValue.Interface(), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("cannot convert type %T to Tree", object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sliceToTree(object interface{}) (interface{}, error) {
|
||||||
|
// arrays are a bit tricky, since they can represent either a
|
||||||
|
// collection of simple values, which is represented by one
|
||||||
|
// *tomlValue, or an array of tables, which is represented by an
|
||||||
|
// array of *Tree.
|
||||||
|
|
||||||
|
// holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice
|
||||||
|
value := reflect.ValueOf(object)
|
||||||
|
insideType := value.Type().Elem()
|
||||||
|
length := value.Len()
|
||||||
|
if length > 0 {
|
||||||
|
insideType = reflect.ValueOf(value.Index(0).Interface()).Type()
|
||||||
|
}
|
||||||
|
if insideType.Kind() == reflect.Map {
|
||||||
|
// this is considered as an array of tables
|
||||||
|
tablesArray := make([]*Tree, 0, length)
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
table := value.Index(i)
|
||||||
|
tree, err := toTree(table.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tablesArray = append(tablesArray, tree.(*Tree))
|
||||||
|
}
|
||||||
|
return tablesArray, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sliceType := typeFor(insideType.Kind())
|
||||||
|
if sliceType == nil {
|
||||||
|
sliceType = insideType
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length)
|
||||||
|
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
val := value.Index(i).Interface()
|
||||||
|
simpleValue, err := simpleValueCoercion(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
|
||||||
|
}
|
||||||
|
return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toTree(object interface{}) (interface{}, error) {
|
||||||
|
value := reflect.ValueOf(object)
|
||||||
|
|
||||||
|
if value.Kind() == reflect.Map {
|
||||||
|
values := map[string]interface{}{}
|
||||||
|
keys := value.MapKeys()
|
||||||
|
for _, key := range keys {
|
||||||
|
if key.Kind() != reflect.String {
|
||||||
|
if _, ok := key.Interface().(string); !ok {
|
||||||
|
return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v := value.MapIndex(key)
|
||||||
|
newValue, err := toTree(v.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
values[key.String()] = newValue
|
||||||
|
}
|
||||||
|
return &Tree{values: values, position: Position{}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
|
||||||
|
return sliceToTree(object)
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleValue, err := simpleValueCoercion(object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &tomlValue{value: simpleValue, position: Position{}}, nil
|
||||||
|
}
|
517
vendor/github.com/pelletier/go-toml/tomltree_write.go
generated
vendored
Normal file
517
vendor/github.com/pelletier/go-toml/tomltree_write.go
generated
vendored
Normal file
@ -0,0 +1,517 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type valueComplexity int
|
||||||
|
|
||||||
|
const (
|
||||||
|
valueSimple valueComplexity = iota + 1
|
||||||
|
valueComplex
|
||||||
|
)
|
||||||
|
|
||||||
|
type sortNode struct {
|
||||||
|
key string
|
||||||
|
complexity valueComplexity
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes a string to a TOML-compliant multi-line string value
|
||||||
|
// This function is a clone of the existing encodeTomlString function, except that whitespace characters
|
||||||
|
// are preserved. Quotation marks and backslashes are also not escaped.
|
||||||
|
func encodeMultilineTomlString(value string, commented string) string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
adjacentQuoteCount := 0
|
||||||
|
|
||||||
|
b.WriteString(commented)
|
||||||
|
for i, rr := range value {
|
||||||
|
if rr != '"' {
|
||||||
|
adjacentQuoteCount = 0
|
||||||
|
} else {
|
||||||
|
adjacentQuoteCount++
|
||||||
|
}
|
||||||
|
switch rr {
|
||||||
|
case '\b':
|
||||||
|
b.WriteString(`\b`)
|
||||||
|
case '\t':
|
||||||
|
b.WriteString("\t")
|
||||||
|
case '\n':
|
||||||
|
b.WriteString("\n" + commented)
|
||||||
|
case '\f':
|
||||||
|
b.WriteString(`\f`)
|
||||||
|
case '\r':
|
||||||
|
b.WriteString("\r")
|
||||||
|
case '"':
|
||||||
|
if adjacentQuoteCount >= 3 || i == len(value)-1 {
|
||||||
|
adjacentQuoteCount = 0
|
||||||
|
b.WriteString(`\"`)
|
||||||
|
} else {
|
||||||
|
b.WriteString(`"`)
|
||||||
|
}
|
||||||
|
case '\\':
|
||||||
|
b.WriteString(`\`)
|
||||||
|
default:
|
||||||
|
intRr := uint16(rr)
|
||||||
|
if intRr < 0x001F {
|
||||||
|
b.WriteString(fmt.Sprintf("\\u%0.4X", intRr))
|
||||||
|
} else {
|
||||||
|
b.WriteRune(rr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes a string to a TOML-compliant string value
|
||||||
|
func encodeTomlString(value string) string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
|
||||||
|
for _, rr := range value {
|
||||||
|
switch rr {
|
||||||
|
case '\b':
|
||||||
|
b.WriteString(`\b`)
|
||||||
|
case '\t':
|
||||||
|
b.WriteString(`\t`)
|
||||||
|
case '\n':
|
||||||
|
b.WriteString(`\n`)
|
||||||
|
case '\f':
|
||||||
|
b.WriteString(`\f`)
|
||||||
|
case '\r':
|
||||||
|
b.WriteString(`\r`)
|
||||||
|
case '"':
|
||||||
|
b.WriteString(`\"`)
|
||||||
|
case '\\':
|
||||||
|
b.WriteString(`\\`)
|
||||||
|
default:
|
||||||
|
intRr := uint16(rr)
|
||||||
|
if intRr < 0x001F {
|
||||||
|
b.WriteString(fmt.Sprintf("\\u%0.4X", intRr))
|
||||||
|
} else {
|
||||||
|
b.WriteRune(rr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func tomlTreeStringRepresentation(t *Tree, ord marshalOrder) (string, error) {
|
||||||
|
var orderedVals []sortNode
|
||||||
|
switch ord {
|
||||||
|
case OrderPreserve:
|
||||||
|
orderedVals = sortByLines(t)
|
||||||
|
default:
|
||||||
|
orderedVals = sortAlphabetical(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
var values []string
|
||||||
|
for _, node := range orderedVals {
|
||||||
|
k := node.key
|
||||||
|
v := t.values[k]
|
||||||
|
|
||||||
|
repr, err := tomlValueStringRepresentation(v, "", "", ord, false)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
values = append(values, quoteKeyIfNeeded(k)+" = "+repr)
|
||||||
|
}
|
||||||
|
return "{ " + strings.Join(values, ", ") + " }", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tomlValueStringRepresentation(v interface{}, commented string, indent string, ord marshalOrder, arraysOneElementPerLine bool) (string, error) {
|
||||||
|
// this interface check is added to dereference the change made in the writeTo function.
|
||||||
|
// That change was made to allow this function to see formatting options.
|
||||||
|
tv, ok := v.(*tomlValue)
|
||||||
|
if ok {
|
||||||
|
v = tv.value
|
||||||
|
} else {
|
||||||
|
tv = &tomlValue{}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := v.(type) {
|
||||||
|
case uint64:
|
||||||
|
return strconv.FormatUint(value, 10), nil
|
||||||
|
case int64:
|
||||||
|
return strconv.FormatInt(value, 10), nil
|
||||||
|
case float64:
|
||||||
|
// Default bit length is full 64
|
||||||
|
bits := 64
|
||||||
|
// Float panics if nan is used
|
||||||
|
if !math.IsNaN(value) {
|
||||||
|
// if 32 bit accuracy is enough to exactly show, use 32
|
||||||
|
_, acc := big.NewFloat(value).Float32()
|
||||||
|
if acc == big.Exact {
|
||||||
|
bits = 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if math.Trunc(value) == value {
|
||||||
|
return strings.ToLower(strconv.FormatFloat(value, 'f', 1, bits)), nil
|
||||||
|
}
|
||||||
|
return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil
|
||||||
|
case string:
|
||||||
|
if tv.multiline {
|
||||||
|
return "\"\"\"\n" + encodeMultilineTomlString(value, commented) + "\"\"\"", nil
|
||||||
|
}
|
||||||
|
return "\"" + encodeTomlString(value) + "\"", nil
|
||||||
|
case []byte:
|
||||||
|
b, _ := v.([]byte)
|
||||||
|
return string(b), nil
|
||||||
|
case bool:
|
||||||
|
if value {
|
||||||
|
return "true", nil
|
||||||
|
}
|
||||||
|
return "false", nil
|
||||||
|
case time.Time:
|
||||||
|
return value.Format(time.RFC3339), nil
|
||||||
|
case LocalDate:
|
||||||
|
return value.String(), nil
|
||||||
|
case LocalDateTime:
|
||||||
|
return value.String(), nil
|
||||||
|
case LocalTime:
|
||||||
|
return value.String(), nil
|
||||||
|
case *Tree:
|
||||||
|
return tomlTreeStringRepresentation(value, ord)
|
||||||
|
case nil:
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
|
||||||
|
if rv.Kind() == reflect.Slice {
|
||||||
|
var values []string
|
||||||
|
for i := 0; i < rv.Len(); i++ {
|
||||||
|
item := rv.Index(i).Interface()
|
||||||
|
itemRepr, err := tomlValueStringRepresentation(item, commented, indent, ord, arraysOneElementPerLine)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
values = append(values, itemRepr)
|
||||||
|
}
|
||||||
|
if arraysOneElementPerLine && len(values) > 1 {
|
||||||
|
stringBuffer := bytes.Buffer{}
|
||||||
|
valueIndent := indent + ` ` // TODO: move that to a shared encoder state
|
||||||
|
|
||||||
|
stringBuffer.WriteString("[\n")
|
||||||
|
|
||||||
|
for _, value := range values {
|
||||||
|
stringBuffer.WriteString(valueIndent)
|
||||||
|
stringBuffer.WriteString(commented + value)
|
||||||
|
stringBuffer.WriteString(`,`)
|
||||||
|
stringBuffer.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
stringBuffer.WriteString(indent + commented + "]")
|
||||||
|
|
||||||
|
return stringBuffer.String(), nil
|
||||||
|
}
|
||||||
|
return "[" + strings.Join(values, ", ") + "]", nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("unsupported value type %T: %v", v, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTreeArrayLine(trees []*Tree) (line int) {
|
||||||
|
// get lowest line number that is not 0
|
||||||
|
for _, tv := range trees {
|
||||||
|
if tv.position.Line < line || line == 0 {
|
||||||
|
line = tv.position.Line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortByLines(t *Tree) (vals []sortNode) {
|
||||||
|
var (
|
||||||
|
line int
|
||||||
|
lines []int
|
||||||
|
tv *Tree
|
||||||
|
tom *tomlValue
|
||||||
|
node sortNode
|
||||||
|
)
|
||||||
|
vals = make([]sortNode, 0)
|
||||||
|
m := make(map[int]sortNode)
|
||||||
|
|
||||||
|
for k := range t.values {
|
||||||
|
v := t.values[k]
|
||||||
|
switch v.(type) {
|
||||||
|
case *Tree:
|
||||||
|
tv = v.(*Tree)
|
||||||
|
line = tv.position.Line
|
||||||
|
node = sortNode{key: k, complexity: valueComplex}
|
||||||
|
case []*Tree:
|
||||||
|
line = getTreeArrayLine(v.([]*Tree))
|
||||||
|
node = sortNode{key: k, complexity: valueComplex}
|
||||||
|
default:
|
||||||
|
tom = v.(*tomlValue)
|
||||||
|
line = tom.position.Line
|
||||||
|
node = sortNode{key: k, complexity: valueSimple}
|
||||||
|
}
|
||||||
|
lines = append(lines, line)
|
||||||
|
vals = append(vals, node)
|
||||||
|
m[line] = node
|
||||||
|
}
|
||||||
|
sort.Ints(lines)
|
||||||
|
|
||||||
|
for i, line := range lines {
|
||||||
|
vals[i] = m[line]
|
||||||
|
}
|
||||||
|
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortAlphabetical(t *Tree) (vals []sortNode) {
|
||||||
|
var (
|
||||||
|
node sortNode
|
||||||
|
simpVals []string
|
||||||
|
compVals []string
|
||||||
|
)
|
||||||
|
vals = make([]sortNode, 0)
|
||||||
|
m := make(map[string]sortNode)
|
||||||
|
|
||||||
|
for k := range t.values {
|
||||||
|
v := t.values[k]
|
||||||
|
switch v.(type) {
|
||||||
|
case *Tree, []*Tree:
|
||||||
|
node = sortNode{key: k, complexity: valueComplex}
|
||||||
|
compVals = append(compVals, node.key)
|
||||||
|
default:
|
||||||
|
node = sortNode{key: k, complexity: valueSimple}
|
||||||
|
simpVals = append(simpVals, node.key)
|
||||||
|
}
|
||||||
|
vals = append(vals, node)
|
||||||
|
m[node.key] = node
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simples first to match previous implementation
|
||||||
|
sort.Strings(simpVals)
|
||||||
|
i := 0
|
||||||
|
for _, key := range simpVals {
|
||||||
|
vals[i] = m[key]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(compVals)
|
||||||
|
for _, key := range compVals {
|
||||||
|
vals[i] = m[key]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
|
||||||
|
return t.writeToOrdered(w, indent, keyspace, bytesCount, arraysOneElementPerLine, OrderAlphabetical, " ", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool, ord marshalOrder, indentString string, parentCommented bool) (int64, error) {
|
||||||
|
var orderedVals []sortNode
|
||||||
|
|
||||||
|
switch ord {
|
||||||
|
case OrderPreserve:
|
||||||
|
orderedVals = sortByLines(t)
|
||||||
|
default:
|
||||||
|
orderedVals = sortAlphabetical(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, node := range orderedVals {
|
||||||
|
switch node.complexity {
|
||||||
|
case valueComplex:
|
||||||
|
k := node.key
|
||||||
|
v := t.values[k]
|
||||||
|
|
||||||
|
combinedKey := quoteKeyIfNeeded(k)
|
||||||
|
if keyspace != "" {
|
||||||
|
combinedKey = keyspace + "." + combinedKey
|
||||||
|
}
|
||||||
|
|
||||||
|
switch node := v.(type) {
|
||||||
|
// node has to be of those two types given how keys are sorted above
|
||||||
|
case *Tree:
|
||||||
|
tv, ok := t.values[k].(*Tree)
|
||||||
|
if !ok {
|
||||||
|
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
|
||||||
|
}
|
||||||
|
if tv.comment != "" {
|
||||||
|
comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1)
|
||||||
|
start := "# "
|
||||||
|
if strings.HasPrefix(comment, "#") {
|
||||||
|
start = ""
|
||||||
|
}
|
||||||
|
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment)
|
||||||
|
bytesCount += int64(writtenBytesCountComment)
|
||||||
|
if errc != nil {
|
||||||
|
return bytesCount, errc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var commented string
|
||||||
|
if parentCommented || t.commented || tv.commented {
|
||||||
|
commented = "# "
|
||||||
|
}
|
||||||
|
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
|
||||||
|
bytesCount += int64(writtenBytesCount)
|
||||||
|
if err != nil {
|
||||||
|
return bytesCount, err
|
||||||
|
}
|
||||||
|
bytesCount, err = node.writeToOrdered(w, indent+indentString, combinedKey, bytesCount, arraysOneElementPerLine, ord, indentString, parentCommented || t.commented || tv.commented)
|
||||||
|
if err != nil {
|
||||||
|
return bytesCount, err
|
||||||
|
}
|
||||||
|
case []*Tree:
|
||||||
|
for _, subTree := range node {
|
||||||
|
var commented string
|
||||||
|
if parentCommented || t.commented || subTree.commented {
|
||||||
|
commented = "# "
|
||||||
|
}
|
||||||
|
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
|
||||||
|
bytesCount += int64(writtenBytesCount)
|
||||||
|
if err != nil {
|
||||||
|
return bytesCount, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesCount, err = subTree.writeToOrdered(w, indent+indentString, combinedKey, bytesCount, arraysOneElementPerLine, ord, indentString, parentCommented || t.commented || subTree.commented)
|
||||||
|
if err != nil {
|
||||||
|
return bytesCount, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: // Simple
|
||||||
|
k := node.key
|
||||||
|
v, ok := t.values[k].(*tomlValue)
|
||||||
|
if !ok {
|
||||||
|
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
|
||||||
|
}
|
||||||
|
|
||||||
|
var commented string
|
||||||
|
if parentCommented || t.commented || v.commented {
|
||||||
|
commented = "# "
|
||||||
|
}
|
||||||
|
repr, err := tomlValueStringRepresentation(v, commented, indent, ord, arraysOneElementPerLine)
|
||||||
|
if err != nil {
|
||||||
|
return bytesCount, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.comment != "" {
|
||||||
|
comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1)
|
||||||
|
start := "# "
|
||||||
|
if strings.HasPrefix(comment, "#") {
|
||||||
|
start = ""
|
||||||
|
}
|
||||||
|
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n")
|
||||||
|
bytesCount += int64(writtenBytesCountComment)
|
||||||
|
if errc != nil {
|
||||||
|
return bytesCount, errc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quotedKey := quoteKeyIfNeeded(k)
|
||||||
|
writtenBytesCount, err := writeStrings(w, indent, commented, quotedKey, " = ", repr, "\n")
|
||||||
|
bytesCount += int64(writtenBytesCount)
|
||||||
|
if err != nil {
|
||||||
|
return bytesCount, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// quote a key if it does not fit the bare key format (A-Za-z0-9_-)
|
||||||
|
// quoted keys use the same rules as strings
|
||||||
|
func quoteKeyIfNeeded(k string) string {
|
||||||
|
// when encoding a map with the 'quoteMapKeys' option enabled, the tree will contain
|
||||||
|
// keys that have already been quoted.
|
||||||
|
// not an ideal situation, but good enough of a stop gap.
|
||||||
|
if len(k) >= 2 && k[0] == '"' && k[len(k)-1] == '"' {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
isBare := true
|
||||||
|
for _, r := range k {
|
||||||
|
if !isValidBareChar(r) {
|
||||||
|
isBare = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isBare {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
return quoteKey(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func quoteKey(k string) string {
|
||||||
|
return "\"" + encodeTomlString(k) + "\""
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeStrings(w io.Writer, s ...string) (int, error) {
|
||||||
|
var n int
|
||||||
|
for i := range s {
|
||||||
|
b, err := io.WriteString(w, s[i])
|
||||||
|
n += b
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteTo encode the Tree as Toml and writes it to the writer w.
|
||||||
|
// Returns the number of bytes written in case of success, or an error if anything happened.
|
||||||
|
func (t *Tree) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
return t.writeTo(w, "", "", 0, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTomlString generates a human-readable representation of the current tree.
|
||||||
|
// Output spans multiple lines, and is suitable for ingest by a TOML parser.
|
||||||
|
// If the conversion cannot be performed, ToString returns a non-nil error.
|
||||||
|
func (t *Tree) ToTomlString() (string, error) {
|
||||||
|
b, err := t.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String generates a human-readable representation of the current tree.
|
||||||
|
// Alias of ToString. Present to implement the fmt.Stringer interface.
|
||||||
|
func (t *Tree) String() string {
|
||||||
|
result, _ := t.ToTomlString()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMap recursively generates a representation of the tree using Go built-in structures.
|
||||||
|
// The following types are used:
|
||||||
|
//
|
||||||
|
// * bool
|
||||||
|
// * float64
|
||||||
|
// * int64
|
||||||
|
// * string
|
||||||
|
// * uint64
|
||||||
|
// * time.Time
|
||||||
|
// * map[string]interface{} (where interface{} is any of this list)
|
||||||
|
// * []interface{} (where interface{} is any of this list)
|
||||||
|
func (t *Tree) ToMap() map[string]interface{} {
|
||||||
|
result := map[string]interface{}{}
|
||||||
|
|
||||||
|
for k, v := range t.values {
|
||||||
|
switch node := v.(type) {
|
||||||
|
case []*Tree:
|
||||||
|
var array []interface{}
|
||||||
|
for _, item := range node {
|
||||||
|
array = append(array, item.ToMap())
|
||||||
|
}
|
||||||
|
result[k] = array
|
||||||
|
case *Tree:
|
||||||
|
result[k] = node.ToMap()
|
||||||
|
case *tomlValue:
|
||||||
|
result[k] = node.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@ -278,6 +278,9 @@ github.com/opencontainers/runtime-spec/specs-go
|
|||||||
github.com/opencontainers/selinux/go-selinux
|
github.com/opencontainers/selinux/go-selinux
|
||||||
github.com/opencontainers/selinux/go-selinux/label
|
github.com/opencontainers/selinux/go-selinux/label
|
||||||
github.com/opencontainers/selinux/pkg/pwalk
|
github.com/opencontainers/selinux/pkg/pwalk
|
||||||
|
# github.com/pelletier/go-toml v1.8.1
|
||||||
|
## explicit
|
||||||
|
github.com/pelletier/go-toml
|
||||||
# github.com/pkg/errors v0.9.1
|
# github.com/pkg/errors v0.9.1
|
||||||
## explicit
|
## explicit
|
||||||
github.com/pkg/errors
|
github.com/pkg/errors
|
||||||
|
Loading…
Reference in New Issue
Block a user