Use mcdsl/terminal for all password prompts
Replace direct golang.org/x/term calls with mcdsl/terminal.ReadPassword across mciasctl (6 sites), mciasgrpcctl (1 site), and mciasdb (1 site). Aligns with the new CLI security standard in engineering-standards.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1
vendor/github.com/pelletier/go-toml/v2/.gitignore
generated
vendored
1
vendor/github.com/pelletier/go-toml/v2/.gitignore
generated
vendored
@@ -5,3 +5,4 @@ cmd/tomljson/tomljson
|
||||
cmd/tomltestgen/tomltestgen
|
||||
dist
|
||||
tests/
|
||||
test-results
|
||||
|
||||
74
vendor/github.com/pelletier/go-toml/v2/.golangci.toml
generated
vendored
74
vendor/github.com/pelletier/go-toml/v2/.golangci.toml
generated
vendored
@@ -1,84 +1,76 @@
|
||||
[service]
|
||||
golangci-lint-version = "1.39.0"
|
||||
|
||||
[linters-settings.wsl]
|
||||
allow-assign-and-anything = true
|
||||
|
||||
[linters-settings.exhaustive]
|
||||
default-signifies-exhaustive = true
|
||||
version = "2"
|
||||
|
||||
[linters]
|
||||
disable-all = true
|
||||
default = "none"
|
||||
enable = [
|
||||
"asciicheck",
|
||||
"bodyclose",
|
||||
"cyclop",
|
||||
"deadcode",
|
||||
"depguard",
|
||||
"dogsled",
|
||||
"dupl",
|
||||
"durationcheck",
|
||||
"errcheck",
|
||||
"errorlint",
|
||||
"exhaustive",
|
||||
# "exhaustivestruct",
|
||||
"exportloopref",
|
||||
"forbidigo",
|
||||
# "forcetypeassert",
|
||||
"funlen",
|
||||
"gci",
|
||||
# "gochecknoglobals",
|
||||
"gochecknoinits",
|
||||
"gocognit",
|
||||
"goconst",
|
||||
"gocritic",
|
||||
"gocyclo",
|
||||
"godot",
|
||||
"godox",
|
||||
# "goerr113",
|
||||
"gofmt",
|
||||
"gofumpt",
|
||||
"godoclint",
|
||||
"goheader",
|
||||
"goimports",
|
||||
"golint",
|
||||
"gomnd",
|
||||
# "gomoddirectives",
|
||||
"gomodguard",
|
||||
"goprintffuncname",
|
||||
"gosec",
|
||||
"gosimple",
|
||||
"govet",
|
||||
# "ifshort",
|
||||
"importas",
|
||||
"ineffassign",
|
||||
"lll",
|
||||
"makezero",
|
||||
"mirror",
|
||||
"misspell",
|
||||
"nakedret",
|
||||
"nestif",
|
||||
"nilerr",
|
||||
# "nlreturn",
|
||||
"noctx",
|
||||
"nolintlint",
|
||||
#"paralleltest",
|
||||
"perfsprint",
|
||||
"prealloc",
|
||||
"predeclared",
|
||||
"revive",
|
||||
"rowserrcheck",
|
||||
"sqlclosecheck",
|
||||
"staticcheck",
|
||||
"structcheck",
|
||||
"stylecheck",
|
||||
# "testpackage",
|
||||
"thelper",
|
||||
"tparallel",
|
||||
"typecheck",
|
||||
"unconvert",
|
||||
"unparam",
|
||||
"unused",
|
||||
"varcheck",
|
||||
"usetesting",
|
||||
"wastedassign",
|
||||
"whitespace",
|
||||
# "wrapcheck",
|
||||
# "wsl"
|
||||
]
|
||||
|
||||
[linters.settings.exhaustive]
|
||||
default-signifies-exhaustive = true
|
||||
|
||||
[linters.settings.lll]
|
||||
line-length = 150
|
||||
|
||||
[[linters.exclusions.rules]]
|
||||
path = ".test.go"
|
||||
linters = ["goconst", "gosec"]
|
||||
|
||||
[[linters.exclusions.rules]]
|
||||
path = "main.go"
|
||||
linters = ["forbidigo"]
|
||||
|
||||
[[linters.exclusions.rules]]
|
||||
path = "internal"
|
||||
linters = ["revive"]
|
||||
text = "(exported|indent-error-flow): "
|
||||
|
||||
[formatters]
|
||||
enable = [
|
||||
"gci",
|
||||
"gofmt",
|
||||
"gofumpt",
|
||||
"goimports",
|
||||
]
|
||||
|
||||
3
vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml
generated
vendored
3
vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml
generated
vendored
@@ -22,7 +22,6 @@ builds:
|
||||
- linux_riscv64
|
||||
- windows_amd64
|
||||
- windows_arm64
|
||||
- windows_arm
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
- id: tomljson
|
||||
@@ -42,7 +41,6 @@ builds:
|
||||
- linux_riscv64
|
||||
- windows_amd64
|
||||
- windows_arm64
|
||||
- windows_arm
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
- id: jsontoml
|
||||
@@ -62,7 +60,6 @@ builds:
|
||||
- linux_arm
|
||||
- windows_amd64
|
||||
- windows_arm64
|
||||
- windows_arm
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
universal_binaries:
|
||||
|
||||
64
vendor/github.com/pelletier/go-toml/v2/AGENTS.md
generated
vendored
Normal file
64
vendor/github.com/pelletier/go-toml/v2/AGENTS.md
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
# Agent Guidelines for go-toml
|
||||
|
||||
This file provides guidelines for AI agents contributing to go-toml. All agents must follow these rules derived from [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
## Project Overview
|
||||
|
||||
go-toml is a TOML library for Go. The goal is to provide an easy-to-use and efficient TOML implementation that gets the job done without getting in the way.
|
||||
|
||||
## Code Change Rules
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
- **No backward-incompatible changes** unless explicitly discussed and approved
|
||||
- Avoid breaking people's programs unless absolutely necessary
|
||||
|
||||
### Testing Requirements
|
||||
|
||||
- **All bug fixes must include regression tests**
|
||||
- **All new code must be tested**
|
||||
- Run tests before submitting: `go test -race ./...`
|
||||
- Test coverage must not decrease. Check with:
|
||||
```bash
|
||||
go test -covermode=atomic -coverprofile=coverage.out
|
||||
go tool cover -func=coverage.out
|
||||
```
|
||||
- All lines of code touched by changes should be covered by tests
|
||||
|
||||
### Performance Requirements
|
||||
|
||||
- go-toml aims to stay efficient; avoid performance regressions
|
||||
- Run benchmarks to verify: `go test ./... -bench=. -count=10`
|
||||
- Compare results using [benchstat](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat)
|
||||
|
||||
### Documentation
|
||||
|
||||
- New features or feature extensions must include documentation
|
||||
- Documentation lives in [README.md](./README.md) and throughout source code
|
||||
|
||||
### Code Style
|
||||
|
||||
- Follow existing code format and structure
|
||||
- Code must pass `go fmt`
|
||||
- Code must pass linting with the same golangci-lint version as CI (see version in `.github/workflows/lint.yml`):
|
||||
```bash
|
||||
# Install specific version (check lint.yml for current version)
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin <version>
|
||||
# Run linter
|
||||
golangci-lint run ./...
|
||||
```
|
||||
|
||||
### Commit Messages
|
||||
|
||||
- Commit messages must explain **why** the change is needed
|
||||
- Keep messages clear and informative even if details are in the PR description
|
||||
|
||||
## Pull Request Checklist
|
||||
|
||||
Before submitting:
|
||||
|
||||
1. Tests pass (`go test -race ./...`)
|
||||
2. No backward-incompatible changes (unless discussed)
|
||||
3. Relevant documentation added/updated
|
||||
4. No performance regression (verify with benchmarks)
|
||||
5. Title is clear and understandable for changelog
|
||||
60
vendor/github.com/pelletier/go-toml/v2/CONTRIBUTING.md
generated
vendored
60
vendor/github.com/pelletier/go-toml/v2/CONTRIBUTING.md
generated
vendored
@@ -33,7 +33,7 @@ The documentation is present in the [README][readme] and thorough the source
|
||||
code. On release, it gets updated on [pkg.go.dev][pkg.go.dev]. 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
|
||||
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.
|
||||
|
||||
@@ -92,6 +92,48 @@ However, given GitHub's new policy to _not_ run Actions on pull requests until a
|
||||
maintainer clicks on button, it is highly recommended that you run them locally
|
||||
as you make changes.
|
||||
|
||||
### Test across Go versions
|
||||
|
||||
The repository includes tooling to test go-toml across multiple Go versions
|
||||
(1.11 through 1.25) both locally and in GitHub Actions.
|
||||
|
||||
#### Local testing with Docker
|
||||
|
||||
Prerequisites: Docker installed and running, Bash shell, `rsync` command.
|
||||
|
||||
```bash
|
||||
# Test all Go versions in parallel (default)
|
||||
./test-go-versions.sh
|
||||
|
||||
# Test specific versions
|
||||
./test-go-versions.sh 1.21 1.22 1.23
|
||||
|
||||
# Test sequentially (slower but uses less resources)
|
||||
./test-go-versions.sh --sequential
|
||||
|
||||
# Verbose output with custom results directory
|
||||
./test-go-versions.sh --verbose --output ./my-results 1.24 1.25
|
||||
|
||||
# Show all options
|
||||
./test-go-versions.sh --help
|
||||
```
|
||||
|
||||
The script creates Docker containers for each Go version and runs the full test
|
||||
suite. Results are saved to a `test-results/` directory with individual logs and
|
||||
a comprehensive summary report.
|
||||
|
||||
The script only exits with a non-zero status code if either of the two most
|
||||
recent Go versions fail.
|
||||
|
||||
#### GitHub Actions testing (maintainers)
|
||||
|
||||
1. Go to the **Actions** tab in the GitHub repository
|
||||
2. Select **"Go Versions Compatibility Test"** from the workflow list
|
||||
3. Click **"Run workflow"**
|
||||
4. Optionally customize:
|
||||
- **Go versions**: Space-separated list (e.g., `1.21 1.22 1.23`)
|
||||
- **Execution mode**: Parallel (faster) or sequential (more stable)
|
||||
|
||||
### Check coverage
|
||||
|
||||
We use `go tool cover` to compute test coverage. Most code editors have a way to
|
||||
@@ -111,7 +153,7 @@ code lowers the coverage.
|
||||
|
||||
Go-toml aims to stay efficient. We rely on a set of scenarios executed with Go's
|
||||
builtin benchmark systems. Because of their noisy nature, containers provided by
|
||||
Github Actions cannot be reliably used for benchmarking. As a result, you are
|
||||
GitHub Actions cannot be reliably used for benchmarking. As a result, you are
|
||||
responsible for checking that your changes do not incur a performance penalty.
|
||||
You can run their following to execute benchmarks:
|
||||
|
||||
@@ -168,13 +210,13 @@ Checklist:
|
||||
1. Decide on the next version number. Use semver. Review commits since last
|
||||
version to assess.
|
||||
2. Tag release. For example:
|
||||
```
|
||||
git checkout v2
|
||||
git pull
|
||||
git tag v2.2.0
|
||||
git push --tags
|
||||
```
|
||||
3. CI automatically builds a draft Github release. Review it and edit as
|
||||
```
|
||||
git checkout v2
|
||||
git pull
|
||||
git tag v2.2.0
|
||||
git push --tags
|
||||
```
|
||||
3. CI automatically builds a draft GitHub release. Review it and edit as
|
||||
necessary. Look for "Other changes". That would indicate a pull request not
|
||||
labeled properly. Tweak labels and pull request titles until changelog looks
|
||||
good for users.
|
||||
|
||||
116
vendor/github.com/pelletier/go-toml/v2/README.md
generated
vendored
116
vendor/github.com/pelletier/go-toml/v2/README.md
generated
vendored
@@ -107,7 +107,11 @@ type MyConfig struct {
|
||||
### Unmarshaling
|
||||
|
||||
[`Unmarshal`][unmarshal] reads a TOML document and fills a Go structure with its
|
||||
content. For example:
|
||||
content.
|
||||
|
||||
Note that the struct variable names are _capitalized_, while the variables in the toml document are _lowercase_.
|
||||
|
||||
For example:
|
||||
|
||||
```go
|
||||
doc := `
|
||||
@@ -133,6 +137,62 @@ fmt.Println("tags:", cfg.Tags)
|
||||
|
||||
[unmarshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Unmarshal
|
||||
|
||||
|
||||
Here is an example using tables with some simple nesting:
|
||||
|
||||
```go
|
||||
doc := `
|
||||
age = 45
|
||||
fruits = ["apple", "pear"]
|
||||
|
||||
# these are very important!
|
||||
[my-variables]
|
||||
first = 1
|
||||
second = 0.2
|
||||
third = "abc"
|
||||
|
||||
# this is not so important.
|
||||
[my-variables.b]
|
||||
bfirst = 123
|
||||
`
|
||||
|
||||
var Document struct {
|
||||
Age int
|
||||
Fruits []string
|
||||
|
||||
Myvariables struct {
|
||||
First int
|
||||
Second float64
|
||||
Third string
|
||||
|
||||
B struct {
|
||||
Bfirst int
|
||||
}
|
||||
} `toml:"my-variables"`
|
||||
}
|
||||
|
||||
err := toml.Unmarshal([]byte(doc), &Document)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("age:", Document.Age)
|
||||
fmt.Println("fruits:", Document.Fruits)
|
||||
fmt.Println("my-variables.first:", Document.Myvariables.First)
|
||||
fmt.Println("my-variables.second:", Document.Myvariables.Second)
|
||||
fmt.Println("my-variables.third:", Document.Myvariables.Third)
|
||||
fmt.Println("my-variables.B.Bfirst:", Document.Myvariables.B.Bfirst)
|
||||
|
||||
// Output:
|
||||
// age: 45
|
||||
// fruits: [apple pear]
|
||||
// my-variables.first: 1
|
||||
// my-variables.second: 0.2
|
||||
// my-variables.third: abc
|
||||
// my-variables.B.Bfirst: 123
|
||||
```
|
||||
|
||||
|
||||
### Marshaling
|
||||
|
||||
[`Marshal`][marshal] is the opposite of Unmarshal: it represents a Go structure
|
||||
@@ -175,17 +235,17 @@ the AST level. See https://pkg.go.dev/github.com/pelletier/go-toml/v2/unstable.
|
||||
Execution time speedup compared to other Go TOML libraries:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Benchmark</th><th>go-toml v1</th><th>BurntSushi/toml</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Marshal/HugoFrontMatter-2</td><td>1.9x</td><td>2.2x</td></tr>
|
||||
<tr><td>Marshal/ReferenceFile/map-2</td><td>1.7x</td><td>2.1x</td></tr>
|
||||
<tr><td>Marshal/ReferenceFile/struct-2</td><td>2.2x</td><td>3.0x</td></tr>
|
||||
<tr><td>Unmarshal/HugoFrontMatter-2</td><td>2.9x</td><td>2.7x</td></tr>
|
||||
<tr><td>Unmarshal/ReferenceFile/map-2</td><td>2.6x</td><td>2.7x</td></tr>
|
||||
<tr><td>Unmarshal/ReferenceFile/struct-2</td><td>4.6x</td><td>5.1x</td></tr>
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr><th>Benchmark</th><th>go-toml v1</th><th>BurntSushi/toml</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Marshal/HugoFrontMatter-2</td><td>2.1x</td><td>2.0x</td></tr>
|
||||
<tr><td>Marshal/ReferenceFile/map-2</td><td>2.0x</td><td>2.0x</td></tr>
|
||||
<tr><td>Marshal/ReferenceFile/struct-2</td><td>2.3x</td><td>2.5x</td></tr>
|
||||
<tr><td>Unmarshal/HugoFrontMatter-2</td><td>3.3x</td><td>2.8x</td></tr>
|
||||
<tr><td>Unmarshal/ReferenceFile/map-2</td><td>2.9x</td><td>3.0x</td></tr>
|
||||
<tr><td>Unmarshal/ReferenceFile/struct-2</td><td>4.8x</td><td>5.0x</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<details><summary>See more</summary>
|
||||
<p>The table above has the results of the most common use-cases. The table below
|
||||
@@ -193,22 +253,22 @@ contains the results of all benchmarks, including unrealistic ones. It is
|
||||
provided for completeness.</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Benchmark</th><th>go-toml v1</th><th>BurntSushi/toml</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Marshal/SimpleDocument/map-2</td><td>1.8x</td><td>2.7x</td></tr>
|
||||
<tr><td>Marshal/SimpleDocument/struct-2</td><td>2.7x</td><td>3.8x</td></tr>
|
||||
<tr><td>Unmarshal/SimpleDocument/map-2</td><td>3.8x</td><td>3.0x</td></tr>
|
||||
<tr><td>Unmarshal/SimpleDocument/struct-2</td><td>5.6x</td><td>4.1x</td></tr>
|
||||
<tr><td>UnmarshalDataset/example-2</td><td>3.0x</td><td>3.2x</td></tr>
|
||||
<tr><td>UnmarshalDataset/code-2</td><td>2.3x</td><td>2.9x</td></tr>
|
||||
<tr><td>UnmarshalDataset/twitter-2</td><td>2.6x</td><td>2.7x</td></tr>
|
||||
<tr><td>UnmarshalDataset/citm_catalog-2</td><td>2.2x</td><td>2.3x</td></tr>
|
||||
<tr><td>UnmarshalDataset/canada-2</td><td>1.8x</td><td>1.5x</td></tr>
|
||||
<tr><td>UnmarshalDataset/config-2</td><td>4.1x</td><td>2.9x</td></tr>
|
||||
<tr><td>geomean</td><td>2.7x</td><td>2.8x</td></tr>
|
||||
</tbody>
|
||||
<thead>
|
||||
<tr><th>Benchmark</th><th>go-toml v1</th><th>BurntSushi/toml</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Marshal/SimpleDocument/map-2</td><td>2.0x</td><td>2.9x</td></tr>
|
||||
<tr><td>Marshal/SimpleDocument/struct-2</td><td>2.5x</td><td>3.6x</td></tr>
|
||||
<tr><td>Unmarshal/SimpleDocument/map-2</td><td>4.2x</td><td>3.4x</td></tr>
|
||||
<tr><td>Unmarshal/SimpleDocument/struct-2</td><td>5.9x</td><td>4.4x</td></tr>
|
||||
<tr><td>UnmarshalDataset/example-2</td><td>3.2x</td><td>2.9x</td></tr>
|
||||
<tr><td>UnmarshalDataset/code-2</td><td>2.4x</td><td>2.8x</td></tr>
|
||||
<tr><td>UnmarshalDataset/twitter-2</td><td>2.7x</td><td>2.5x</td></tr>
|
||||
<tr><td>UnmarshalDataset/citm_catalog-2</td><td>2.3x</td><td>2.3x</td></tr>
|
||||
<tr><td>UnmarshalDataset/canada-2</td><td>1.9x</td><td>1.5x</td></tr>
|
||||
<tr><td>UnmarshalDataset/config-2</td><td>5.4x</td><td>3.0x</td></tr>
|
||||
<tr><td>geomean</td><td>2.9x</td><td>2.8x</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>This table can be generated with <code>./ci.sh benchmark -a -html</code>.</p>
|
||||
</details>
|
||||
|
||||
7
vendor/github.com/pelletier/go-toml/v2/ci.sh
generated
vendored
7
vendor/github.com/pelletier/go-toml/v2/ci.sh
generated
vendored
@@ -147,7 +147,7 @@ bench() {
|
||||
pushd "$dir"
|
||||
|
||||
if [ "${replace}" != "" ]; then
|
||||
find ./benchmark/ -iname '*.go' -exec sed -i -E "s|github.com/pelletier/go-toml/v2|${replace}|g" {} \;
|
||||
find ./benchmark/ -iname '*.go' -exec sed -i -E "s|github.com/pelletier/go-toml/v2\"|${replace}\"|g" {} \;
|
||||
go get "${replace}"
|
||||
fi
|
||||
|
||||
@@ -195,6 +195,11 @@ for line in reversed(lines[2:]):
|
||||
"%.1fx" % (float(line[3])/v2), # v1
|
||||
"%.1fx" % (float(line[7])/v2), # bs
|
||||
])
|
||||
|
||||
if not results:
|
||||
print("No benchmark results to display.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# move geomean to the end
|
||||
results.append(results[0])
|
||||
del results[0]
|
||||
|
||||
5
vendor/github.com/pelletier/go-toml/v2/decode.go
generated
vendored
5
vendor/github.com/pelletier/go-toml/v2/decode.go
generated
vendored
@@ -230,8 +230,8 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
|
||||
return t, nil, err
|
||||
}
|
||||
|
||||
if t.Second > 60 {
|
||||
return t, nil, unstable.NewParserError(b[6:8], "seconds cannot be greater 60")
|
||||
if t.Second > 59 {
|
||||
return t, nil, unstable.NewParserError(b[6:8], "seconds cannot be greater than 59")
|
||||
}
|
||||
|
||||
b = b[8:]
|
||||
@@ -279,7 +279,6 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
|
||||
return t, b, nil
|
||||
}
|
||||
|
||||
//nolint:cyclop
|
||||
func parseFloat(b []byte) (float64, error) {
|
||||
if len(b) == 4 && (b[0] == '+' || b[0] == '-') && b[1] == 'n' && b[2] == 'a' && b[3] == 'n' {
|
||||
return math.NaN(), nil
|
||||
|
||||
39
vendor/github.com/pelletier/go-toml/v2/errors.go
generated
vendored
39
vendor/github.com/pelletier/go-toml/v2/errors.go
generated
vendored
@@ -2,10 +2,10 @@ package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||
"github.com/pelletier/go-toml/v2/unstable"
|
||||
)
|
||||
|
||||
@@ -54,6 +54,18 @@ func (s *StrictMissingError) String() string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Unwrap returns wrapped decode errors
|
||||
//
|
||||
// Implements errors.Join() interface.
|
||||
func (s *StrictMissingError) Unwrap() []error {
|
||||
errs := make([]error, len(s.Errors))
|
||||
for i := range s.Errors {
|
||||
errs[i] = &s.Errors[i]
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// Key represents a TOML key as a sequence of key parts.
|
||||
type Key []string
|
||||
|
||||
// Error returns the error message contained in the DecodeError.
|
||||
@@ -78,7 +90,7 @@ func (e *DecodeError) Key() Key {
|
||||
return e.key
|
||||
}
|
||||
|
||||
// decodeErrorFromHighlight creates a DecodeError referencing a highlighted
|
||||
// wrapDecodeError creates a DecodeError referencing a highlighted
|
||||
// range of bytes from document.
|
||||
//
|
||||
// highlight needs to be a sub-slice of document, or this function panics.
|
||||
@@ -88,7 +100,7 @@ func (e *DecodeError) Key() Key {
|
||||
//
|
||||
//nolint:funlen
|
||||
func wrapDecodeError(document []byte, de *unstable.ParserError) *DecodeError {
|
||||
offset := danger.SubsliceOffset(document, de.Highlight)
|
||||
offset := subsliceOffset(document, de.Highlight)
|
||||
|
||||
errMessage := de.Error()
|
||||
errLine, errColumn := positionAtEnd(document[:offset])
|
||||
@@ -248,5 +260,24 @@ func positionAtEnd(b []byte) (row int, column int) {
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return row, column
|
||||
}
|
||||
|
||||
// subsliceOffset returns the byte offset of subslice within data.
|
||||
// subslice must share the same backing array as data.
|
||||
func subsliceOffset(data []byte, subslice []byte) int {
|
||||
if len(subslice) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Use reflect to get the data pointers of both slices.
|
||||
// This is safe because we're only reading the pointer values for comparison.
|
||||
dataPtr := reflect.ValueOf(data).Pointer()
|
||||
subPtr := reflect.ValueOf(subslice).Pointer()
|
||||
|
||||
offset := int(subPtr - dataPtr)
|
||||
if offset < 0 || offset > len(data) {
|
||||
panic("subslice is not within data")
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
6
vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go
generated
vendored
6
vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go
generated
vendored
@@ -1,6 +1,6 @@
|
||||
package characters
|
||||
|
||||
var invalidAsciiTable = [256]bool{
|
||||
var invalidASCIITable = [256]bool{
|
||||
0x00: true,
|
||||
0x01: true,
|
||||
0x02: true,
|
||||
@@ -37,6 +37,6 @@ var invalidAsciiTable = [256]bool{
|
||||
0x7F: true,
|
||||
}
|
||||
|
||||
func InvalidAscii(b byte) bool {
|
||||
return invalidAsciiTable[b]
|
||||
func InvalidASCII(b byte) bool {
|
||||
return invalidASCIITable[b]
|
||||
}
|
||||
|
||||
68
vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go
generated
vendored
68
vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go
generated
vendored
@@ -1,20 +1,12 @@
|
||||
// Package characters provides functions for working with string encodings.
|
||||
package characters
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type utf8Err struct {
|
||||
Index int
|
||||
Size int
|
||||
}
|
||||
|
||||
func (u utf8Err) Zero() bool {
|
||||
return u.Size == 0
|
||||
}
|
||||
|
||||
// Verified that a given string is only made of valid UTF-8 characters allowed
|
||||
// by the TOML spec:
|
||||
// Utf8TomlValidAlreadyEscaped verifies that a given string is only made of
|
||||
// valid UTF-8 characters allowed by the TOML spec:
|
||||
//
|
||||
// Any Unicode character may be used except those that must be escaped:
|
||||
// quotation mark, backslash, and the control characters other than tab (U+0000
|
||||
@@ -23,8 +15,8 @@ func (u utf8Err) Zero() bool {
|
||||
// It is a copy of the Go 1.17 utf8.Valid implementation, tweaked to exit early
|
||||
// when a character is not allowed.
|
||||
//
|
||||
// The returned utf8Err is Zero() if the string is valid, or contains the byte
|
||||
// index and size of the invalid character.
|
||||
// The returned slice is empty if the string is valid, or contains the bytes
|
||||
// of the invalid character.
|
||||
//
|
||||
// quotation mark => already checked
|
||||
// backslash => already checked
|
||||
@@ -32,9 +24,8 @@ func (u utf8Err) Zero() bool {
|
||||
// 0x9 => tab, ok
|
||||
// 0xA - 0x1F => invalid
|
||||
// 0x7F => invalid
|
||||
func Utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
|
||||
func Utf8TomlValidAlreadyEscaped(p []byte) []byte {
|
||||
// Fast path. Check for and skip 8 bytes of ASCII characters per iteration.
|
||||
offset := 0
|
||||
for len(p) >= 8 {
|
||||
// Combining two 32 bit loads allows the same code to be used
|
||||
// for 32 and 64 bit platforms.
|
||||
@@ -48,24 +39,19 @@ func Utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
|
||||
}
|
||||
|
||||
for i, b := range p[:8] {
|
||||
if InvalidAscii(b) {
|
||||
err.Index = offset + i
|
||||
err.Size = 1
|
||||
return
|
||||
if InvalidASCII(b) {
|
||||
return p[i : i+1]
|
||||
}
|
||||
}
|
||||
|
||||
p = p[8:]
|
||||
offset += 8
|
||||
}
|
||||
n := len(p)
|
||||
for i := 0; i < n; {
|
||||
pi := p[i]
|
||||
if pi < utf8.RuneSelf {
|
||||
if InvalidAscii(pi) {
|
||||
err.Index = offset + i
|
||||
err.Size = 1
|
||||
return
|
||||
if InvalidASCII(pi) {
|
||||
return p[i : i+1]
|
||||
}
|
||||
i++
|
||||
continue
|
||||
@@ -73,44 +59,34 @@ func Utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
|
||||
x := first[pi]
|
||||
if x == xx {
|
||||
// Illegal starter byte.
|
||||
err.Index = offset + i
|
||||
err.Size = 1
|
||||
return
|
||||
return p[i : i+1]
|
||||
}
|
||||
size := int(x & 7)
|
||||
if i+size > n {
|
||||
// Short or invalid.
|
||||
err.Index = offset + i
|
||||
err.Size = n - i
|
||||
return
|
||||
return p[i:n]
|
||||
}
|
||||
accept := acceptRanges[x>>4]
|
||||
if c := p[i+1]; c < accept.lo || accept.hi < c {
|
||||
err.Index = offset + i
|
||||
err.Size = 2
|
||||
return
|
||||
} else if size == 2 {
|
||||
return p[i : i+2]
|
||||
} else if size == 2 { //revive:disable:empty-block
|
||||
} else if c := p[i+2]; c < locb || hicb < c {
|
||||
err.Index = offset + i
|
||||
err.Size = 3
|
||||
return
|
||||
} else if size == 3 {
|
||||
return p[i : i+3]
|
||||
} else if size == 3 { //revive:disable:empty-block
|
||||
} else if c := p[i+3]; c < locb || hicb < c {
|
||||
err.Index = offset + i
|
||||
err.Size = 4
|
||||
return
|
||||
return p[i : i+4]
|
||||
}
|
||||
i += size
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return the size of the next rune if valid, 0 otherwise.
|
||||
// Utf8ValidNext returns the size of the next rune if valid, 0 otherwise.
|
||||
func Utf8ValidNext(p []byte) int {
|
||||
c := p[0]
|
||||
|
||||
if c < utf8.RuneSelf {
|
||||
if InvalidAscii(c) {
|
||||
if InvalidASCII(c) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
@@ -129,10 +105,10 @@ func Utf8ValidNext(p []byte) int {
|
||||
accept := acceptRanges[x>>4]
|
||||
if c := p[1]; c < accept.lo || accept.hi < c {
|
||||
return 0
|
||||
} else if size == 2 {
|
||||
} else if size == 2 { //nolint:revive
|
||||
} else if c := p[2]; c < locb || hicb < c {
|
||||
return 0
|
||||
} else if size == 3 {
|
||||
} else if size == 3 { //nolint:revive
|
||||
} else if c := p[3]; c < locb || hicb < c {
|
||||
return 0
|
||||
}
|
||||
|
||||
65
vendor/github.com/pelletier/go-toml/v2/internal/danger/danger.go
generated
vendored
65
vendor/github.com/pelletier/go-toml/v2/internal/danger/danger.go
generated
vendored
@@ -1,65 +0,0 @@
|
||||
package danger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const maxInt = uintptr(int(^uint(0) >> 1))
|
||||
|
||||
func SubsliceOffset(data []byte, subslice []byte) int {
|
||||
datap := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||
hlp := (*reflect.SliceHeader)(unsafe.Pointer(&subslice))
|
||||
|
||||
if hlp.Data < datap.Data {
|
||||
panic(fmt.Errorf("subslice address (%d) is before data address (%d)", hlp.Data, datap.Data))
|
||||
}
|
||||
offset := hlp.Data - datap.Data
|
||||
|
||||
if offset > maxInt {
|
||||
panic(fmt.Errorf("slice offset larger than int (%d)", offset))
|
||||
}
|
||||
|
||||
intoffset := int(offset)
|
||||
|
||||
if intoffset > datap.Len {
|
||||
panic(fmt.Errorf("slice offset (%d) is farther than data length (%d)", intoffset, datap.Len))
|
||||
}
|
||||
|
||||
if intoffset+hlp.Len > datap.Len {
|
||||
panic(fmt.Errorf("slice ends (%d+%d) is farther than data length (%d)", intoffset, hlp.Len, datap.Len))
|
||||
}
|
||||
|
||||
return intoffset
|
||||
}
|
||||
|
||||
func BytesRange(start []byte, end []byte) []byte {
|
||||
if start == nil || end == nil {
|
||||
panic("cannot call BytesRange with nil")
|
||||
}
|
||||
startp := (*reflect.SliceHeader)(unsafe.Pointer(&start))
|
||||
endp := (*reflect.SliceHeader)(unsafe.Pointer(&end))
|
||||
|
||||
if startp.Data > endp.Data {
|
||||
panic(fmt.Errorf("start pointer address (%d) is after end pointer address (%d)", startp.Data, endp.Data))
|
||||
}
|
||||
|
||||
l := startp.Len
|
||||
endLen := int(endp.Data-startp.Data) + endp.Len
|
||||
if endLen > l {
|
||||
l = endLen
|
||||
}
|
||||
|
||||
if l > startp.Cap {
|
||||
panic(fmt.Errorf("range length is larger than capacity"))
|
||||
}
|
||||
|
||||
return start[:l]
|
||||
}
|
||||
|
||||
func Stride(ptr unsafe.Pointer, size uintptr, offset int) unsafe.Pointer {
|
||||
// TODO: replace with unsafe.Add when Go 1.17 is released
|
||||
// https://github.com/golang/go/issues/40481
|
||||
return unsafe.Pointer(uintptr(ptr) + uintptr(int(size)*offset))
|
||||
}
|
||||
23
vendor/github.com/pelletier/go-toml/v2/internal/danger/typeid.go
generated
vendored
23
vendor/github.com/pelletier/go-toml/v2/internal/danger/typeid.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
package danger
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// typeID is used as key in encoder and decoder caches to enable using
|
||||
// the optimize runtime.mapaccess2_fast64 function instead of the more
|
||||
// expensive lookup if we were to use reflect.Type as map key.
|
||||
//
|
||||
// typeID holds the pointer to the reflect.Type value, which is unique
|
||||
// in the program.
|
||||
//
|
||||
// https://github.com/segmentio/encoding/blob/master/json/codec.go#L59-L61
|
||||
type TypeID unsafe.Pointer
|
||||
|
||||
func MakeTypeID(t reflect.Type) TypeID {
|
||||
// reflect.Type has the fields:
|
||||
// typ unsafe.Pointer
|
||||
// ptr unsafe.Pointer
|
||||
return TypeID((*[2]unsafe.Pointer)(unsafe.Pointer(&t))[1])
|
||||
}
|
||||
2
vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
generated
vendored
2
vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
generated
vendored
@@ -36,7 +36,7 @@ func (t *KeyTracker) Pop(node *unstable.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns the current key
|
||||
// Key returns the current key.
|
||||
func (t *KeyTracker) Key() []string {
|
||||
k := make([]string, len(t.k))
|
||||
copy(k, t.k)
|
||||
|
||||
13
vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
generated
vendored
13
vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
generated
vendored
@@ -288,11 +288,12 @@ func (s *SeenTracker) checkKeyValue(node *unstable.Node) (bool, error) {
|
||||
idx = s.create(parentIdx, k, tableKind, false, true)
|
||||
} else {
|
||||
entry := s.entries[idx]
|
||||
if it.IsLast() {
|
||||
switch {
|
||||
case it.IsLast():
|
||||
return false, fmt.Errorf("toml: key %s is already defined", string(k))
|
||||
} else if entry.kind != tableKind {
|
||||
case entry.kind != tableKind:
|
||||
return false, fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
|
||||
} else if entry.explicit {
|
||||
case entry.explicit:
|
||||
return false, fmt.Errorf("toml: cannot redefine table %s that has already been explicitly defined", string(k))
|
||||
}
|
||||
}
|
||||
@@ -309,16 +310,16 @@ func (s *SeenTracker) checkKeyValue(node *unstable.Node) (bool, error) {
|
||||
return s.checkInlineTable(value)
|
||||
case unstable.Array:
|
||||
return s.checkArray(value)
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (s *SeenTracker) checkArray(node *unstable.Node) (first bool, err error) {
|
||||
it := node.Children()
|
||||
for it.Next() {
|
||||
n := it.Node()
|
||||
switch n.Kind {
|
||||
switch n.Kind { //nolint:exhaustive
|
||||
case unstable.InlineTable:
|
||||
first, err = s.checkInlineTable(n)
|
||||
if err != nil {
|
||||
|
||||
1
vendor/github.com/pelletier/go-toml/v2/internal/tracker/tracker.go
generated
vendored
1
vendor/github.com/pelletier/go-toml/v2/internal/tracker/tracker.go
generated
vendored
@@ -1 +1,2 @@
|
||||
// Package tracker provides functions for keeping track of AST nodes.
|
||||
package tracker
|
||||
|
||||
2
vendor/github.com/pelletier/go-toml/v2/localtime.go
generated
vendored
2
vendor/github.com/pelletier/go-toml/v2/localtime.go
generated
vendored
@@ -45,7 +45,7 @@ func (d *LocalDate) UnmarshalText(b []byte) error {
|
||||
type LocalTime struct {
|
||||
Hour int // Hour of the day: [0; 24[
|
||||
Minute int // Minute of the hour: [0; 60[
|
||||
Second int // Second of the minute: [0; 60[
|
||||
Second int // Second of the minute: [0; 59]
|
||||
Nanosecond int // Nanoseconds within the second: [0, 1000000000[
|
||||
Precision int // Number of digits to display for Nanosecond.
|
||||
}
|
||||
|
||||
165
vendor/github.com/pelletier/go-toml/v2/marshaler.go
generated
vendored
165
vendor/github.com/pelletier/go-toml/v2/marshaler.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -42,7 +43,7 @@ type Encoder struct {
|
||||
arraysMultiline bool
|
||||
indentSymbol string
|
||||
indentTables bool
|
||||
marshalJsonNumbers bool
|
||||
marshalJSONNumbers bool
|
||||
}
|
||||
|
||||
// NewEncoder returns a new Encoder that writes to w.
|
||||
@@ -89,14 +90,14 @@ func (enc *Encoder) SetIndentTables(indent bool) *Encoder {
|
||||
return enc
|
||||
}
|
||||
|
||||
// SetMarshalJsonNumbers forces the encoder to serialize `json.Number` as a
|
||||
// SetMarshalJSONNumbers forces the encoder to serialize `json.Number` as a
|
||||
// float or integer instead of relying on TextMarshaler to emit a string.
|
||||
//
|
||||
// *Unstable:* This method does not follow the compatibility guarantees of
|
||||
// semver. It can be changed or removed without a new major version being
|
||||
// issued.
|
||||
func (enc *Encoder) SetMarshalJsonNumbers(indent bool) *Encoder {
|
||||
enc.marshalJsonNumbers = indent
|
||||
func (enc *Encoder) SetMarshalJSONNumbers(indent bool) *Encoder {
|
||||
enc.marshalJSONNumbers = indent
|
||||
return enc
|
||||
}
|
||||
|
||||
@@ -161,6 +162,8 @@ func (enc *Encoder) SetMarshalJsonNumbers(indent bool) *Encoder {
|
||||
//
|
||||
// The "omitempty" option prevents empty values or groups from being emitted.
|
||||
//
|
||||
// The "omitzero" option prevents zero values or groups from being emitted.
|
||||
//
|
||||
// The "commented" option prefixes the value and all its children with a comment
|
||||
// symbol.
|
||||
//
|
||||
@@ -177,7 +180,7 @@ func (enc *Encoder) Encode(v interface{}) error {
|
||||
ctx.inline = enc.tablesInline
|
||||
|
||||
if v == nil {
|
||||
return fmt.Errorf("toml: cannot encode a nil interface")
|
||||
return errors.New("toml: cannot encode a nil interface")
|
||||
}
|
||||
|
||||
b, err := enc.encode(b, ctx, reflect.ValueOf(v))
|
||||
@@ -196,6 +199,7 @@ func (enc *Encoder) Encode(v interface{}) error {
|
||||
type valueOptions struct {
|
||||
multiline bool
|
||||
omitempty bool
|
||||
omitzero bool
|
||||
commented bool
|
||||
comment string
|
||||
}
|
||||
@@ -266,16 +270,15 @@ func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, e
|
||||
case LocalDateTime:
|
||||
return append(b, x.String()...), nil
|
||||
case json.Number:
|
||||
if enc.marshalJsonNumbers {
|
||||
if enc.marshalJSONNumbers {
|
||||
if x == "" { /// Useful zero value.
|
||||
return append(b, "0"...), nil
|
||||
} else if v, err := x.Int64(); err == nil {
|
||||
return enc.encode(b, ctx, reflect.ValueOf(v))
|
||||
} else if f, err := x.Float64(); err == nil {
|
||||
return enc.encode(b, ctx, reflect.ValueOf(f))
|
||||
} else {
|
||||
return nil, fmt.Errorf("toml: unable to convert %q to int64 or float64", x)
|
||||
}
|
||||
return nil, fmt.Errorf("toml: unable to convert %q to int64 or float64", x)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +312,7 @@ func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, e
|
||||
return enc.encodeSlice(b, ctx, v)
|
||||
case reflect.Interface:
|
||||
if v.IsNil() {
|
||||
return nil, fmt.Errorf("toml: encoding a nil interface is not supported")
|
||||
return nil, errors.New("toml: encoding a nil interface is not supported")
|
||||
}
|
||||
|
||||
return enc.encode(b, ctx, v.Elem())
|
||||
@@ -326,28 +329,30 @@ func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, e
|
||||
case reflect.Float32:
|
||||
f := v.Float()
|
||||
|
||||
if math.IsNaN(f) {
|
||||
switch {
|
||||
case math.IsNaN(f):
|
||||
b = append(b, "nan"...)
|
||||
} else if f > math.MaxFloat32 {
|
||||
case f > math.MaxFloat32:
|
||||
b = append(b, "inf"...)
|
||||
} else if f < -math.MaxFloat32 {
|
||||
case f < -math.MaxFloat32:
|
||||
b = append(b, "-inf"...)
|
||||
} else if math.Trunc(f) == f {
|
||||
case math.Trunc(f) == f:
|
||||
b = strconv.AppendFloat(b, f, 'f', 1, 32)
|
||||
} else {
|
||||
default:
|
||||
b = strconv.AppendFloat(b, f, 'f', -1, 32)
|
||||
}
|
||||
case reflect.Float64:
|
||||
f := v.Float()
|
||||
if math.IsNaN(f) {
|
||||
switch {
|
||||
case math.IsNaN(f):
|
||||
b = append(b, "nan"...)
|
||||
} else if f > math.MaxFloat64 {
|
||||
case f > math.MaxFloat64:
|
||||
b = append(b, "inf"...)
|
||||
} else if f < -math.MaxFloat64 {
|
||||
case f < -math.MaxFloat64:
|
||||
b = append(b, "-inf"...)
|
||||
} else if math.Trunc(f) == f {
|
||||
case math.Trunc(f) == f:
|
||||
b = strconv.AppendFloat(b, f, 'f', 1, 64)
|
||||
} else {
|
||||
default:
|
||||
b = strconv.AppendFloat(b, f, 'f', -1, 64)
|
||||
}
|
||||
case reflect.Bool:
|
||||
@@ -384,6 +389,31 @@ func shouldOmitEmpty(options valueOptions, v reflect.Value) bool {
|
||||
return options.omitempty && isEmptyValue(v)
|
||||
}
|
||||
|
||||
func shouldOmitZero(options valueOptions, v reflect.Value) bool {
|
||||
if !options.omitzero {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the type implements isZeroer interface (has a custom IsZero method).
|
||||
if v.Type().Implements(isZeroerType) {
|
||||
return v.Interface().(isZeroer).IsZero()
|
||||
}
|
||||
|
||||
// Check if pointer type implements isZeroer.
|
||||
if reflect.PointerTo(v.Type()).Implements(isZeroerType) {
|
||||
if v.CanAddr() {
|
||||
return v.Addr().Interface().(isZeroer).IsZero()
|
||||
}
|
||||
// Create a temporary addressable copy to call the pointer receiver method.
|
||||
pv := reflect.New(v.Type())
|
||||
pv.Elem().Set(v)
|
||||
return pv.Interface().(isZeroer).IsZero()
|
||||
}
|
||||
|
||||
// Fall back to reflect's IsZero for types without custom IsZero method.
|
||||
return v.IsZero()
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v reflect.Value) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
@@ -434,8 +464,9 @@ func isEmptyValue(v reflect.Value) bool {
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isEmptyStruct(v reflect.Value) bool {
|
||||
@@ -479,7 +510,7 @@ func (enc *Encoder) encodeString(b []byte, v string, options valueOptions) []byt
|
||||
func needsQuoting(v string) bool {
|
||||
// TODO: vectorize
|
||||
for _, b := range []byte(v) {
|
||||
if b == '\'' || b == '\r' || b == '\n' || characters.InvalidAscii(b) {
|
||||
if b == '\'' || b == '\r' || b == '\n' || characters.InvalidASCII(b) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -517,12 +548,26 @@ func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byt
|
||||
del = 0x7f
|
||||
)
|
||||
|
||||
for _, r := range []byte(v) {
|
||||
bv := []byte(v)
|
||||
for i := 0; i < len(bv); i++ {
|
||||
r := bv[i]
|
||||
switch r {
|
||||
case '\\':
|
||||
b = append(b, `\\`...)
|
||||
case '"':
|
||||
b = append(b, `\"`...)
|
||||
if multiline {
|
||||
// Quotation marks do not need to be quoted in multiline strings unless
|
||||
// it contains 3 consecutive. If 3+ quotes appear, quote all of them
|
||||
// because it's visually better
|
||||
if i+2 > len(bv) || bv[i+1] != '"' || bv[i+2] != '"' {
|
||||
b = append(b, r)
|
||||
} else {
|
||||
b = append(b, `\"\"\"`...)
|
||||
i += 2
|
||||
}
|
||||
} else {
|
||||
b = append(b, `\"`...)
|
||||
}
|
||||
case '\b':
|
||||
b = append(b, `\b`...)
|
||||
case '\f':
|
||||
@@ -559,9 +604,9 @@ func (enc *Encoder) encodeUnquotedKey(b []byte, v string) []byte {
|
||||
return append(b, v...)
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeTableHeader(ctx encoderCtx, b []byte) ([]byte, error) {
|
||||
func (enc *Encoder) encodeTableHeader(ctx encoderCtx, b []byte) []byte {
|
||||
if len(ctx.parentKey) == 0 {
|
||||
return b, nil
|
||||
return b
|
||||
}
|
||||
|
||||
b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
|
||||
@@ -581,10 +626,9 @@ func (enc *Encoder) encodeTableHeader(ctx encoderCtx, b []byte) ([]byte, error)
|
||||
|
||||
b = append(b, "]\n"...)
|
||||
|
||||
return b, nil
|
||||
return b
|
||||
}
|
||||
|
||||
//nolint:cyclop
|
||||
func (enc *Encoder) encodeKey(b []byte, k string) []byte {
|
||||
needsQuotation := false
|
||||
cannotUseLiteral := false
|
||||
@@ -621,30 +665,33 @@ func (enc *Encoder) encodeKey(b []byte, k string) []byte {
|
||||
|
||||
func (enc *Encoder) keyToString(k reflect.Value) (string, error) {
|
||||
keyType := k.Type()
|
||||
switch {
|
||||
case keyType.Kind() == reflect.String:
|
||||
return k.String(), nil
|
||||
|
||||
case keyType.Implements(textMarshalerType):
|
||||
if keyType.Implements(textMarshalerType) {
|
||||
keyB, err := k.Interface().(encoding.TextMarshaler).MarshalText()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("toml: error marshalling key %v from text: %w", k, err)
|
||||
}
|
||||
return string(keyB), nil
|
||||
}
|
||||
|
||||
case keyType.Kind() == reflect.Int || keyType.Kind() == reflect.Int8 || keyType.Kind() == reflect.Int16 || keyType.Kind() == reflect.Int32 || keyType.Kind() == reflect.Int64:
|
||||
switch keyType.Kind() {
|
||||
case reflect.String:
|
||||
return k.String(), nil
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(k.Int(), 10), nil
|
||||
|
||||
case keyType.Kind() == reflect.Uint || keyType.Kind() == reflect.Uint8 || keyType.Kind() == reflect.Uint16 || keyType.Kind() == reflect.Uint32 || keyType.Kind() == reflect.Uint64:
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(k.Uint(), 10), nil
|
||||
|
||||
case keyType.Kind() == reflect.Float32:
|
||||
case reflect.Float32:
|
||||
return strconv.FormatFloat(k.Float(), 'f', -1, 32), nil
|
||||
|
||||
case keyType.Kind() == reflect.Float64:
|
||||
case reflect.Float64:
|
||||
return strconv.FormatFloat(k.Float(), 'f', -1, 64), nil
|
||||
|
||||
default:
|
||||
return "", fmt.Errorf("toml: type %s is not supported as a map key", keyType.Kind())
|
||||
}
|
||||
return "", fmt.Errorf("toml: type %s is not supported as a map key", keyType.Kind())
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
|
||||
@@ -657,8 +704,18 @@ func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte
|
||||
for iter.Next() {
|
||||
v := iter.Value()
|
||||
|
||||
if isNil(v) {
|
||||
continue
|
||||
// Handle nil values: convert nil pointers to zero value,
|
||||
// skip nil interfaces and nil maps.
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
if v.IsNil() {
|
||||
v = reflect.Zero(v.Type().Elem())
|
||||
}
|
||||
case reflect.Interface, reflect.Map:
|
||||
if v.IsNil() {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
k, err := enc.keyToString(iter.Key())
|
||||
@@ -748,9 +805,8 @@ func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
|
||||
walkStruct(ctx, t, f.Elem())
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
k = fieldType.Name
|
||||
}
|
||||
k = fieldType.Name
|
||||
}
|
||||
|
||||
if isNil(f) {
|
||||
@@ -760,6 +816,7 @@ func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
|
||||
options := valueOptions{
|
||||
multiline: opts.multiline,
|
||||
omitempty: opts.omitempty,
|
||||
omitzero: opts.omitzero,
|
||||
commented: opts.commented,
|
||||
comment: fieldType.Tag.Get("comment"),
|
||||
}
|
||||
@@ -820,6 +877,7 @@ type tagOptions struct {
|
||||
multiline bool
|
||||
inline bool
|
||||
omitempty bool
|
||||
omitzero bool
|
||||
commented bool
|
||||
}
|
||||
|
||||
@@ -832,7 +890,7 @@ func parseTag(tag string) (string, tagOptions) {
|
||||
}
|
||||
|
||||
raw := tag[idx+1:]
|
||||
tag = string(tag[:idx])
|
||||
tag = tag[:idx]
|
||||
for raw != "" {
|
||||
var o string
|
||||
i := strings.Index(raw, ",")
|
||||
@@ -848,6 +906,8 @@ func parseTag(tag string) (string, tagOptions) {
|
||||
opts.inline = true
|
||||
case "omitempty":
|
||||
opts.omitempty = true
|
||||
case "omitzero":
|
||||
opts.omitzero = true
|
||||
case "commented":
|
||||
opts.commented = true
|
||||
}
|
||||
@@ -866,10 +926,7 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
|
||||
}
|
||||
|
||||
if !ctx.skipTableHeader {
|
||||
b, err = enc.encodeTableHeader(ctx, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = enc.encodeTableHeader(ctx, b)
|
||||
|
||||
if enc.indentTables && len(ctx.parentKey) > 0 {
|
||||
ctx.indent++
|
||||
@@ -882,6 +939,9 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
|
||||
if shouldOmitEmpty(kv.Options, kv.Value) {
|
||||
continue
|
||||
}
|
||||
if kv.Options.omitzero && shouldOmitZero(kv.Options, kv.Value) {
|
||||
continue
|
||||
}
|
||||
hasNonEmptyKV = true
|
||||
|
||||
ctx.setKey(kv.Key)
|
||||
@@ -901,6 +961,9 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
|
||||
if shouldOmitEmpty(table.Options, table.Value) {
|
||||
continue
|
||||
}
|
||||
if table.Options.omitzero && shouldOmitZero(table.Options, table.Value) {
|
||||
continue
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
if hasNonEmptyKV {
|
||||
@@ -935,6 +998,9 @@ func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte
|
||||
if shouldOmitEmpty(kv.Options, kv.Value) {
|
||||
continue
|
||||
}
|
||||
if kv.Options.omitzero && shouldOmitZero(kv.Options, kv.Value) {
|
||||
continue
|
||||
}
|
||||
|
||||
if first {
|
||||
first = false
|
||||
@@ -963,11 +1029,14 @@ func willConvertToTable(ctx encoderCtx, v reflect.Value) bool {
|
||||
if !v.IsValid() {
|
||||
return false
|
||||
}
|
||||
if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PointerTo(v.Type()).Implements(textMarshalerType)) {
|
||||
t := v.Type()
|
||||
if t == timeType || t.Implements(textMarshalerType) {
|
||||
return false
|
||||
}
|
||||
if v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PointerTo(t).Implements(textMarshalerType) {
|
||||
return false
|
||||
}
|
||||
|
||||
t := v.Type()
|
||||
switch t.Kind() {
|
||||
case reflect.Map, reflect.Struct:
|
||||
return !ctx.inline
|
||||
|
||||
23
vendor/github.com/pelletier/go-toml/v2/strict.go
generated
vendored
23
vendor/github.com/pelletier/go-toml/v2/strict.go
generated
vendored
@@ -1,7 +1,6 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||
"github.com/pelletier/go-toml/v2/internal/tracker"
|
||||
"github.com/pelletier/go-toml/v2/unstable"
|
||||
)
|
||||
@@ -13,6 +12,9 @@ type strict struct {
|
||||
key tracker.KeyTracker
|
||||
|
||||
missing []unstable.ParserError
|
||||
|
||||
// Reference to the document for computing key ranges.
|
||||
doc []byte
|
||||
}
|
||||
|
||||
func (s *strict) EnterTable(node *unstable.Node) {
|
||||
@@ -53,7 +55,7 @@ func (s *strict) MissingTable(node *unstable.Node) {
|
||||
}
|
||||
|
||||
s.missing = append(s.missing, unstable.ParserError{
|
||||
Highlight: keyLocation(node),
|
||||
Highlight: s.keyLocation(node),
|
||||
Message: "missing table",
|
||||
Key: s.key.Key(),
|
||||
})
|
||||
@@ -65,7 +67,7 @@ func (s *strict) MissingField(node *unstable.Node) {
|
||||
}
|
||||
|
||||
s.missing = append(s.missing, unstable.ParserError{
|
||||
Highlight: keyLocation(node),
|
||||
Highlight: s.keyLocation(node),
|
||||
Message: "missing field",
|
||||
Key: s.key.Key(),
|
||||
})
|
||||
@@ -88,7 +90,7 @@ func (s *strict) Error(doc []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func keyLocation(node *unstable.Node) []byte {
|
||||
func (s *strict) keyLocation(node *unstable.Node) []byte {
|
||||
k := node.Key()
|
||||
|
||||
hasOne := k.Next()
|
||||
@@ -96,12 +98,17 @@ func keyLocation(node *unstable.Node) []byte {
|
||||
panic("should not be called with empty key")
|
||||
}
|
||||
|
||||
start := k.Node().Data
|
||||
end := k.Node().Data
|
||||
// Get the range from the first key to the last key.
|
||||
firstRaw := k.Node().Raw
|
||||
lastRaw := firstRaw
|
||||
|
||||
for k.Next() {
|
||||
end = k.Node().Data
|
||||
lastRaw = k.Node().Raw
|
||||
}
|
||||
|
||||
return danger.BytesRange(start, end)
|
||||
// Compute the slice from the document using the ranges.
|
||||
start := firstRaw.Offset
|
||||
end := lastRaw.Offset + lastRaw.Length
|
||||
|
||||
return s.doc[start:end]
|
||||
}
|
||||
|
||||
597
vendor/github.com/pelletier/go-toml/v2/test-go-versions.sh
generated
vendored
Normal file
597
vendor/github.com/pelletier/go-toml/v2/test-go-versions.sh
generated
vendored
Normal file
@@ -0,0 +1,597 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Go versions to test (1.11 through 1.26)
|
||||
GO_VERSIONS=(
|
||||
"1.11"
|
||||
"1.12"
|
||||
"1.13"
|
||||
"1.14"
|
||||
"1.15"
|
||||
"1.16"
|
||||
"1.17"
|
||||
"1.18"
|
||||
"1.19"
|
||||
"1.20"
|
||||
"1.21"
|
||||
"1.22"
|
||||
"1.23"
|
||||
"1.24"
|
||||
"1.25"
|
||||
"1.26"
|
||||
)
|
||||
|
||||
# Default values
|
||||
PARALLEL=true
|
||||
VERBOSE=false
|
||||
OUTPUT_DIR="test-results"
|
||||
DOCKER_TIMEOUT="10m"
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $0 [OPTIONS] [GO_VERSIONS...]
|
||||
|
||||
Test go-toml across multiple Go versions using Docker containers.
|
||||
|
||||
The script reports the lowest continuous supported Go version (where all subsequent
|
||||
versions pass) and only exits with non-zero status if either of the two most recent
|
||||
Go versions fail, indicating immediate attention is needed.
|
||||
|
||||
Note: For Go versions < 1.21, the script automatically updates go.mod to match the
|
||||
target version, but older versions may still fail due to missing standard library
|
||||
features (e.g., the 'slices' package introduced in Go 1.21).
|
||||
|
||||
OPTIONS:
|
||||
-h, --help Show this help message
|
||||
-s, --sequential Run tests sequentially instead of in parallel
|
||||
-v, --verbose Enable verbose output
|
||||
-o, --output DIR Output directory for test results (default: test-results)
|
||||
-t, --timeout TIME Docker timeout for each test (default: 10m)
|
||||
--list List available Go versions and exit
|
||||
|
||||
ARGUMENTS:
|
||||
GO_VERSIONS Specific Go versions to test (default: all supported versions)
|
||||
Examples: 1.21 1.22 1.23
|
||||
|
||||
EXAMPLES:
|
||||
$0 # Test all Go versions in parallel
|
||||
$0 --sequential # Test all Go versions sequentially
|
||||
$0 1.21 1.22 1.23 # Test specific versions
|
||||
$0 --verbose --output ./results 1.25 1.26 # Verbose output to custom directory
|
||||
|
||||
EXIT CODES:
|
||||
0 Recent Go versions pass (good compatibility)
|
||||
1 Recent Go versions fail (needs attention) or script error
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
log() {
|
||||
echo -e "${BLUE}[$(date +'%H:%M:%S')]${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[$(date +'%H:%M:%S')] ✓${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[$(date +'%H:%M:%S')] ✗${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[$(date +'%H:%M:%S')] ⚠${NC} $*" >&2
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-s|--sequential)
|
||||
PARALLEL=false
|
||||
shift
|
||||
;;
|
||||
-v|--verbose)
|
||||
VERBOSE=true
|
||||
shift
|
||||
;;
|
||||
-o|--output)
|
||||
OUTPUT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-t|--timeout)
|
||||
DOCKER_TIMEOUT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--list)
|
||||
echo "Available Go versions:"
|
||||
printf '%s\n' "${GO_VERSIONS[@]}"
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
echo "Unknown option: $1" >&2
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
# Remaining arguments are Go versions
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# If specific versions provided, use those instead of defaults
|
||||
if [[ $# -gt 0 ]]; then
|
||||
GO_VERSIONS=("$@")
|
||||
fi
|
||||
|
||||
# Validate Go versions
|
||||
for version in "${GO_VERSIONS[@]}"; do
|
||||
if ! [[ "$version" =~ ^1\.(1[1-9]|2[0-6])$ ]]; then
|
||||
log_error "Invalid Go version: $version. Supported versions: 1.11-1.26"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Check if Docker is available
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker is required but not installed or not in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if Docker daemon is running
|
||||
if ! docker info &> /dev/null; then
|
||||
log_error "Docker daemon is not running"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create output directory
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# Function to test a single Go version
|
||||
test_go_version() {
|
||||
local go_version="$1"
|
||||
local container_name="go-toml-test-${go_version}"
|
||||
local result_file="${OUTPUT_DIR}/go-${go_version}.txt"
|
||||
local dockerfile_content
|
||||
|
||||
log "Testing Go $go_version..."
|
||||
|
||||
# Create a temporary Dockerfile for this version
|
||||
# For Go versions < 1.21, we need to update go.mod to match the Go version
|
||||
local needs_go_mod_update=false
|
||||
if [[ $(echo "$go_version 1.21" | tr ' ' '\n' | sort -V | head -n1) == "$go_version" && "$go_version" != "1.21" ]]; then
|
||||
needs_go_mod_update=true
|
||||
fi
|
||||
|
||||
dockerfile_content="FROM golang:${go_version}-alpine
|
||||
|
||||
# Install git (required for go mod)
|
||||
RUN apk add --no-cache git
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy source code
|
||||
COPY . ."
|
||||
|
||||
# Add go.mod update step for older Go versions
|
||||
if [[ "$needs_go_mod_update" == true ]]; then
|
||||
dockerfile_content="$dockerfile_content
|
||||
|
||||
# Update go.mod to match Go version (required for Go < 1.21)
|
||||
RUN if [ -f go.mod ]; then sed -i 's/^go [0-9]\\+\\.[0-9]\\+\\(\\.[0-9]\\+\\)\\?/go $go_version/' go.mod; fi
|
||||
|
||||
# Note: Go versions < 1.21 may fail due to missing standard library packages (e.g., slices)
|
||||
# This is expected for projects that use Go 1.21+ features"
|
||||
fi
|
||||
|
||||
dockerfile_content="$dockerfile_content
|
||||
|
||||
# Run tests
|
||||
CMD [\"sh\", \"-c\", \"go version && echo '--- Running go test ./... ---' && go test ./...\"]"
|
||||
|
||||
# Create temporary directory for this test
|
||||
local temp_dir
|
||||
temp_dir=$(mktemp -d)
|
||||
|
||||
# Copy source to temp directory (excluding test results and git)
|
||||
rsync -a --exclude="$OUTPUT_DIR" --exclude=".git" --exclude="*.test" . "$temp_dir/"
|
||||
|
||||
# Create Dockerfile in temp directory
|
||||
echo "$dockerfile_content" > "$temp_dir/Dockerfile"
|
||||
|
||||
# Build and run container
|
||||
local exit_code=0
|
||||
local output
|
||||
|
||||
if $VERBOSE; then
|
||||
log "Building Docker image for Go $go_version..."
|
||||
fi
|
||||
|
||||
# Capture both stdout and stderr, and the exit code
|
||||
if output=$(cd "$temp_dir" && timeout "$DOCKER_TIMEOUT" docker build -t "$container_name" . 2>&1 && \
|
||||
timeout "$DOCKER_TIMEOUT" docker run --rm "$container_name" 2>&1); then
|
||||
log_success "Go $go_version: PASSED"
|
||||
echo "PASSED" > "${result_file}.status"
|
||||
else
|
||||
exit_code=$?
|
||||
log_error "Go $go_version: FAILED (exit code: $exit_code)"
|
||||
echo "FAILED" > "${result_file}.status"
|
||||
fi
|
||||
|
||||
# Save full output
|
||||
echo "$output" > "$result_file"
|
||||
|
||||
# Clean up
|
||||
docker rmi "$container_name" &> /dev/null || true
|
||||
rm -rf "$temp_dir"
|
||||
|
||||
if $VERBOSE; then
|
||||
echo "--- Go $go_version output ---"
|
||||
echo "$output"
|
||||
echo "--- End Go $go_version output ---"
|
||||
fi
|
||||
|
||||
return $exit_code
|
||||
}
|
||||
|
||||
# Function to run tests in parallel
|
||||
run_parallel() {
|
||||
local pids=()
|
||||
local failed_versions=()
|
||||
|
||||
log "Starting parallel tests for ${#GO_VERSIONS[@]} Go versions..."
|
||||
|
||||
# Start all tests in background
|
||||
for version in "${GO_VERSIONS[@]}"; do
|
||||
test_go_version "$version" &
|
||||
pids+=($!)
|
||||
done
|
||||
|
||||
# Wait for all tests to complete
|
||||
for i in "${!pids[@]}"; do
|
||||
local pid=${pids[$i]}
|
||||
local version=${GO_VERSIONS[$i]}
|
||||
|
||||
if ! wait $pid; then
|
||||
failed_versions+=("$version")
|
||||
fi
|
||||
done
|
||||
|
||||
return ${#failed_versions[@]}
|
||||
}
|
||||
|
||||
# Function to run tests sequentially
|
||||
run_sequential() {
|
||||
local failed_versions=()
|
||||
|
||||
log "Starting sequential tests for ${#GO_VERSIONS[@]} Go versions..."
|
||||
|
||||
for version in "${GO_VERSIONS[@]}"; do
|
||||
if ! test_go_version "$version"; then
|
||||
failed_versions+=("$version")
|
||||
fi
|
||||
done
|
||||
|
||||
return ${#failed_versions[@]}
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
local start_time
|
||||
start_time=$(date +%s)
|
||||
|
||||
log "Starting Go version compatibility tests..."
|
||||
log "Testing versions: ${GO_VERSIONS[*]}"
|
||||
log "Output directory: $OUTPUT_DIR"
|
||||
log "Parallel execution: $PARALLEL"
|
||||
|
||||
local failed_count
|
||||
if $PARALLEL; then
|
||||
run_parallel
|
||||
failed_count=$?
|
||||
else
|
||||
run_sequential
|
||||
failed_count=$?
|
||||
fi
|
||||
|
||||
local end_time
|
||||
end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
# Collect results for display
|
||||
local passed_versions=()
|
||||
local failed_versions=()
|
||||
local unknown_versions=()
|
||||
local passed_count=0
|
||||
|
||||
for version in "${GO_VERSIONS[@]}"; do
|
||||
local status_file="${OUTPUT_DIR}/go-${version}.txt.status"
|
||||
if [[ -f "$status_file" ]]; then
|
||||
local status
|
||||
status=$(cat "$status_file")
|
||||
if [[ "$status" == "PASSED" ]]; then
|
||||
passed_versions+=("$version")
|
||||
((passed_count++))
|
||||
else
|
||||
failed_versions+=("$version")
|
||||
fi
|
||||
else
|
||||
unknown_versions+=("$version")
|
||||
fi
|
||||
done
|
||||
|
||||
# Generate summary report
|
||||
local summary_file="${OUTPUT_DIR}/summary.txt"
|
||||
{
|
||||
echo "Go Version Compatibility Test Summary"
|
||||
echo "====================================="
|
||||
echo "Date: $(date)"
|
||||
echo "Duration: ${duration}s"
|
||||
echo "Parallel: $PARALLEL"
|
||||
echo ""
|
||||
echo "Results:"
|
||||
|
||||
for version in "${GO_VERSIONS[@]}"; do
|
||||
local status_file="${OUTPUT_DIR}/go-${version}.txt.status"
|
||||
if [[ -f "$status_file" ]]; then
|
||||
local status
|
||||
status=$(cat "$status_file")
|
||||
if [[ "$status" == "PASSED" ]]; then
|
||||
echo " Go $version: ✓ PASSED"
|
||||
else
|
||||
echo " Go $version: ✗ FAILED"
|
||||
fi
|
||||
else
|
||||
echo " Go $version: ? UNKNOWN (no status file)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Summary: $passed_count/${#GO_VERSIONS[@]} versions passed"
|
||||
|
||||
if [[ $failed_count -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "Failed versions details:"
|
||||
for version in "${failed_versions[@]}"; do
|
||||
echo ""
|
||||
echo "--- Go $version (FAILED) ---"
|
||||
local result_file="${OUTPUT_DIR}/go-${version}.txt"
|
||||
if [[ -f "$result_file" ]]; then
|
||||
tail -n 30 "$result_file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
} > "$summary_file"
|
||||
|
||||
# Find lowest continuous supported version and check recent versions
|
||||
local lowest_continuous_version=""
|
||||
local recent_versions_failed=false
|
||||
|
||||
# Sort versions to ensure proper order
|
||||
local sorted_versions=()
|
||||
for version in "${GO_VERSIONS[@]}"; do
|
||||
sorted_versions+=("$version")
|
||||
done
|
||||
# Sort versions numerically (1.11, 1.12, ..., 1.25)
|
||||
IFS=$'\n' sorted_versions=($(sort -V <<< "${sorted_versions[*]}"))
|
||||
|
||||
# Find lowest continuous supported version (all versions from this point onwards pass)
|
||||
for version in "${sorted_versions[@]}"; do
|
||||
local status_file="${OUTPUT_DIR}/go-${version}.txt.status"
|
||||
local all_subsequent_pass=true
|
||||
|
||||
# Check if this version and all subsequent versions pass
|
||||
local found_current=false
|
||||
for check_version in "${sorted_versions[@]}"; do
|
||||
if [[ "$check_version" == "$version" ]]; then
|
||||
found_current=true
|
||||
fi
|
||||
|
||||
if [[ "$found_current" == true ]]; then
|
||||
local check_status_file="${OUTPUT_DIR}/go-${check_version}.txt.status"
|
||||
if [[ -f "$check_status_file" ]]; then
|
||||
local status
|
||||
status=$(cat "$check_status_file")
|
||||
if [[ "$status" != "PASSED" ]]; then
|
||||
all_subsequent_pass=false
|
||||
break
|
||||
fi
|
||||
else
|
||||
all_subsequent_pass=false
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$all_subsequent_pass" == true ]]; then
|
||||
lowest_continuous_version="$version"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Check if the two most recent versions failed
|
||||
local num_versions=${#sorted_versions[@]}
|
||||
if [[ $num_versions -ge 2 ]]; then
|
||||
local second_recent="${sorted_versions[$((num_versions-2))]}"
|
||||
local most_recent="${sorted_versions[$((num_versions-1))]}"
|
||||
|
||||
local second_recent_status_file="${OUTPUT_DIR}/go-${second_recent}.txt.status"
|
||||
local most_recent_status_file="${OUTPUT_DIR}/go-${most_recent}.txt.status"
|
||||
|
||||
local second_recent_failed=false
|
||||
local most_recent_failed=false
|
||||
|
||||
if [[ -f "$second_recent_status_file" ]]; then
|
||||
local status
|
||||
status=$(cat "$second_recent_status_file")
|
||||
if [[ "$status" != "PASSED" ]]; then
|
||||
second_recent_failed=true
|
||||
fi
|
||||
else
|
||||
second_recent_failed=true
|
||||
fi
|
||||
|
||||
if [[ -f "$most_recent_status_file" ]]; then
|
||||
local status
|
||||
status=$(cat "$most_recent_status_file")
|
||||
if [[ "$status" != "PASSED" ]]; then
|
||||
most_recent_failed=true
|
||||
fi
|
||||
else
|
||||
most_recent_failed=true
|
||||
fi
|
||||
|
||||
if [[ "$second_recent_failed" == true || "$most_recent_failed" == true ]]; then
|
||||
recent_versions_failed=true
|
||||
fi
|
||||
elif [[ $num_versions -eq 1 ]]; then
|
||||
# Only one version tested, check if it's the most recent and failed
|
||||
local only_version="${sorted_versions[0]}"
|
||||
local only_status_file="${OUTPUT_DIR}/go-${only_version}.txt.status"
|
||||
|
||||
if [[ -f "$only_status_file" ]]; then
|
||||
local status
|
||||
status=$(cat "$only_status_file")
|
||||
if [[ "$status" != "PASSED" ]]; then
|
||||
recent_versions_failed=true
|
||||
fi
|
||||
else
|
||||
recent_versions_failed=true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Display summary
|
||||
echo ""
|
||||
log "Test completed in ${duration}s"
|
||||
log "Summary report: $summary_file"
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " FINAL RESULTS"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Display passed versions
|
||||
if [[ ${#passed_versions[@]} -gt 0 ]]; then
|
||||
log_success "PASSED (${#passed_versions[@]}/${#GO_VERSIONS[@]}):"
|
||||
# Sort passed versions for display
|
||||
local sorted_passed=()
|
||||
for version in "${sorted_versions[@]}"; do
|
||||
for passed_version in "${passed_versions[@]}"; do
|
||||
if [[ "$version" == "$passed_version" ]]; then
|
||||
sorted_passed+=("$version")
|
||||
break
|
||||
fi
|
||||
done
|
||||
done
|
||||
for version in "${sorted_passed[@]}"; do
|
||||
echo -e " ${GREEN}✓${NC} Go $version"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Display failed versions
|
||||
if [[ ${#failed_versions[@]} -gt 0 ]]; then
|
||||
log_error "FAILED (${#failed_versions[@]}/${#GO_VERSIONS[@]}):"
|
||||
# Sort failed versions for display
|
||||
local sorted_failed=()
|
||||
for version in "${sorted_versions[@]}"; do
|
||||
for failed_version in "${failed_versions[@]}"; do
|
||||
if [[ "$version" == "$failed_version" ]]; then
|
||||
sorted_failed+=("$version")
|
||||
break
|
||||
fi
|
||||
done
|
||||
done
|
||||
for version in "${sorted_failed[@]}"; do
|
||||
echo -e " ${RED}✗${NC} Go $version"
|
||||
done
|
||||
echo ""
|
||||
|
||||
# Show failure details
|
||||
echo "========================================"
|
||||
echo " FAILURE DETAILS"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
for version in "${sorted_failed[@]}"; do
|
||||
echo -e "${RED}--- Go $version FAILURE LOGS (last 30 lines) ---${NC}"
|
||||
local result_file="${OUTPUT_DIR}/go-${version}.txt"
|
||||
if [[ -f "$result_file" ]]; then
|
||||
tail -n 30 "$result_file" | sed 's/^/ /'
|
||||
else
|
||||
echo " No log file found: $result_file"
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
fi
|
||||
|
||||
# Display unknown versions
|
||||
if [[ ${#unknown_versions[@]} -gt 0 ]]; then
|
||||
log_warning "UNKNOWN (${#unknown_versions[@]}/${#GO_VERSIONS[@]}):"
|
||||
for version in "${unknown_versions[@]}"; do
|
||||
echo -e " ${YELLOW}?${NC} Go $version (no status file)"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "========================================"
|
||||
echo " COMPATIBILITY SUMMARY"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
if [[ -n "$lowest_continuous_version" ]]; then
|
||||
log_success "Lowest continuous supported version: Go $lowest_continuous_version"
|
||||
echo " (All versions from Go $lowest_continuous_version onwards pass)"
|
||||
else
|
||||
log_error "No continuous version support found"
|
||||
echo " (No version has all subsequent versions passing)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "Full detailed logs available in: $OUTPUT_DIR"
|
||||
echo "========================================"
|
||||
|
||||
# Determine exit code based on recent versions
|
||||
if [[ "$recent_versions_failed" == true ]]; then
|
||||
log_error "OVERALL RESULT: Recent Go versions failed - this needs attention!"
|
||||
if [[ -n "$lowest_continuous_version" ]]; then
|
||||
echo "Note: Continuous support starts from Go $lowest_continuous_version"
|
||||
fi
|
||||
exit 1
|
||||
else
|
||||
log_success "OVERALL RESULT: Recent Go versions pass - compatibility looks good!"
|
||||
if [[ -n "$lowest_continuous_version" ]]; then
|
||||
echo "Continuous support starts from Go $lowest_continuous_version"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Trap to clean up on exit
|
||||
cleanup() {
|
||||
# Kill any remaining background processes
|
||||
jobs -p | xargs -r kill 2>/dev/null || true
|
||||
|
||||
# Clean up any remaining Docker containers
|
||||
docker ps -q --filter "name=go-toml-test-" | xargs -r docker stop 2>/dev/null || true
|
||||
docker images -q --filter "reference=go-toml-test-*" | xargs -r docker rmi 2>/dev/null || true
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# Run main function
|
||||
main
|
||||
21
vendor/github.com/pelletier/go-toml/v2/types.go
generated
vendored
21
vendor/github.com/pelletier/go-toml/v2/types.go
generated
vendored
@@ -6,9 +6,18 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||
var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}(nil))
|
||||
var sliceInterfaceType = reflect.TypeOf([]interface{}(nil))
|
||||
var stringType = reflect.TypeOf("")
|
||||
// isZeroer is used to check if a type has a custom IsZero method.
|
||||
// This allows custom types to define their own zero-value semantics.
|
||||
type isZeroer interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
var (
|
||||
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem()
|
||||
mapStringInterfaceType = reflect.TypeOf(map[string]interface{}(nil))
|
||||
sliceInterfaceType = reflect.TypeOf([]interface{}(nil))
|
||||
stringType = reflect.TypeOf("")
|
||||
)
|
||||
|
||||
228
vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
generated
vendored
228
vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
generated
vendored
@@ -12,7 +12,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||
"github.com/pelletier/go-toml/v2/internal/tracker"
|
||||
"github.com/pelletier/go-toml/v2/unstable"
|
||||
)
|
||||
@@ -57,13 +56,18 @@ func (d *Decoder) DisallowUnknownFields() *Decoder {
|
||||
|
||||
// EnableUnmarshalerInterface allows to enable unmarshaler interface.
|
||||
//
|
||||
// With this feature enabled, types implementing the unstable/Unmarshaler
|
||||
// With this feature enabled, types implementing the unstable.Unmarshaler
|
||||
// interface can be decoded from any structure of the document. It allows types
|
||||
// that don't have a straightforward TOML representation to provide their own
|
||||
// decoding logic.
|
||||
//
|
||||
// Currently, types can only decode from a single value. Tables and array tables
|
||||
// are not supported.
|
||||
// The UnmarshalTOML method receives raw TOML bytes:
|
||||
// - For single values: the raw value bytes (e.g., `"hello"` for a string)
|
||||
// - For tables: all key-value lines belonging to that table
|
||||
// - For inline tables/arrays: the raw bytes of the inline structure
|
||||
//
|
||||
// The unstable.RawMessage type can be used to capture raw TOML bytes for
|
||||
// later processing, similar to json.RawMessage.
|
||||
//
|
||||
// *Unstable:* This method does not follow the compatibility guarantees of
|
||||
// semver. It can be changed or removed without a new major version being
|
||||
@@ -123,6 +127,7 @@ func (d *Decoder) Decode(v interface{}) error {
|
||||
dec := decoder{
|
||||
strict: strict{
|
||||
Enabled: d.strict,
|
||||
doc: b,
|
||||
},
|
||||
unmarshalerInterface: d.unmarshalerInterface,
|
||||
}
|
||||
@@ -226,7 +231,7 @@ func (d *decoder) FromParser(v interface{}) error {
|
||||
}
|
||||
|
||||
if r.IsNil() {
|
||||
return fmt.Errorf("toml: decoding pointer target cannot be nil")
|
||||
return errors.New("toml: decoding pointer target cannot be nil")
|
||||
}
|
||||
|
||||
r = r.Elem()
|
||||
@@ -273,7 +278,7 @@ func (d *decoder) handleRootExpression(expr *unstable.Node, v reflect.Value) err
|
||||
var err error
|
||||
var first bool // used for to clear array tables on first use
|
||||
|
||||
if !(d.skipUntilTable && expr.Kind == unstable.KeyValue) {
|
||||
if !d.skipUntilTable || expr.Kind != unstable.KeyValue {
|
||||
first, err = d.seen.CheckExpression(expr)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -378,7 +383,7 @@ func (d *decoder) handleArrayTableCollectionLast(key unstable.Iterator, v reflec
|
||||
case reflect.Array:
|
||||
idx := d.arrayIndex(true, v)
|
||||
if idx >= v.Len() {
|
||||
return v, fmt.Errorf("%s at position %d", d.typeMismatchError("array table", v.Type()), idx)
|
||||
return v, fmt.Errorf("%w at position %d", d.typeMismatchError("array table", v.Type()), idx)
|
||||
}
|
||||
elem := v.Index(idx)
|
||||
_, err := d.handleArrayTable(key, elem)
|
||||
@@ -416,27 +421,51 @@ func (d *decoder) handleArrayTableCollection(key unstable.Iterator, v reflect.Va
|
||||
|
||||
return v, nil
|
||||
case reflect.Slice:
|
||||
elem := v.Index(v.Len() - 1)
|
||||
// Create a new element when the slice is empty; otherwise operate on
|
||||
// the last element.
|
||||
var (
|
||||
elem reflect.Value
|
||||
created bool
|
||||
)
|
||||
if v.Len() == 0 {
|
||||
created = true
|
||||
elemType := v.Type().Elem()
|
||||
if elemType.Kind() == reflect.Interface {
|
||||
elem = makeMapStringInterface()
|
||||
} else {
|
||||
elem = reflect.New(elemType).Elem()
|
||||
}
|
||||
} else {
|
||||
elem = v.Index(v.Len() - 1)
|
||||
}
|
||||
|
||||
x, err := d.handleArrayTable(key, elem)
|
||||
if err != nil || d.skipUntilTable {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
if x.IsValid() {
|
||||
elem.Set(x)
|
||||
if created {
|
||||
elem = x
|
||||
} else {
|
||||
elem.Set(x)
|
||||
}
|
||||
}
|
||||
|
||||
if created {
|
||||
return reflect.Append(v, elem), nil
|
||||
}
|
||||
return v, err
|
||||
case reflect.Array:
|
||||
idx := d.arrayIndex(false, v)
|
||||
if idx >= v.Len() {
|
||||
return v, fmt.Errorf("%s at position %d", d.typeMismatchError("array table", v.Type()), idx)
|
||||
return v, fmt.Errorf("%w at position %d", d.typeMismatchError("array table", v.Type()), idx)
|
||||
}
|
||||
elem := v.Index(idx)
|
||||
_, err := d.handleArrayTable(key, elem)
|
||||
return v, err
|
||||
default:
|
||||
return d.handleArrayTable(key, v)
|
||||
}
|
||||
|
||||
return d.handleArrayTable(key, v)
|
||||
}
|
||||
|
||||
func (d *decoder) handleKeyPart(key unstable.Iterator, v reflect.Value, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
|
||||
@@ -470,7 +499,8 @@ func (d *decoder) handleKeyPart(key unstable.Iterator, v reflect.Value, nextFn h
|
||||
|
||||
mv := v.MapIndex(mk)
|
||||
set := false
|
||||
if !mv.IsValid() {
|
||||
switch {
|
||||
case !mv.IsValid():
|
||||
// If there is no value in the map, create a new one according to
|
||||
// the map type. If the element type is interface, create either a
|
||||
// map[string]interface{} or a []interface{} depending on whether
|
||||
@@ -483,13 +513,13 @@ func (d *decoder) handleKeyPart(key unstable.Iterator, v reflect.Value, nextFn h
|
||||
mv = reflect.New(t).Elem()
|
||||
}
|
||||
set = true
|
||||
} else if mv.Kind() == reflect.Interface {
|
||||
case mv.Kind() == reflect.Interface:
|
||||
mv = mv.Elem()
|
||||
if !mv.IsValid() {
|
||||
mv = makeFn()
|
||||
}
|
||||
set = true
|
||||
} else if !mv.CanAddr() {
|
||||
case !mv.CanAddr():
|
||||
vt := v.Type()
|
||||
t := vt.Elem()
|
||||
oldmv := mv
|
||||
@@ -574,18 +604,28 @@ func (d *decoder) handleArrayTablePart(key unstable.Iterator, v reflect.Value) (
|
||||
// cannot handle it.
|
||||
func (d *decoder) handleTable(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
|
||||
if v.Kind() == reflect.Slice {
|
||||
if v.Len() == 0 {
|
||||
return reflect.Value{}, unstable.NewParserError(key.Node().Data, "cannot store a table in a slice")
|
||||
// For non-empty slices, work with the last element
|
||||
if v.Len() > 0 {
|
||||
elem := v.Index(v.Len() - 1)
|
||||
x, err := d.handleTable(key, elem)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
if x.IsValid() {
|
||||
elem.Set(x)
|
||||
}
|
||||
return reflect.Value{}, nil
|
||||
}
|
||||
elem := v.Index(v.Len() - 1)
|
||||
x, err := d.handleTable(key, elem)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
// Empty slice - check if it implements Unmarshaler (e.g., RawMessage)
|
||||
// and we're at the end of the key path
|
||||
if d.unmarshalerInterface && !key.Next() {
|
||||
if v.CanAddr() && v.Addr().CanInterface() {
|
||||
if outi, ok := v.Addr().Interface().(unstable.Unmarshaler); ok {
|
||||
return d.handleKeyValuesUnmarshaler(outi)
|
||||
}
|
||||
}
|
||||
}
|
||||
if x.IsValid() {
|
||||
elem.Set(x)
|
||||
}
|
||||
return reflect.Value{}, nil
|
||||
return reflect.Value{}, unstable.NewParserError(key.Node().Data, "cannot store a table in a slice")
|
||||
}
|
||||
if key.Next() {
|
||||
// Still scoping the key
|
||||
@@ -599,6 +639,24 @@ func (d *decoder) handleTable(key unstable.Iterator, v reflect.Value) (reflect.V
|
||||
// Handle root expressions until the end of the document or the next
|
||||
// non-key-value.
|
||||
func (d *decoder) handleKeyValues(v reflect.Value) (reflect.Value, error) {
|
||||
// Check if target implements Unmarshaler before processing key-values.
|
||||
// This allows types to handle entire tables themselves.
|
||||
if d.unmarshalerInterface {
|
||||
vv := v
|
||||
for vv.Kind() == reflect.Ptr {
|
||||
if vv.IsNil() {
|
||||
vv.Set(reflect.New(vv.Type().Elem()))
|
||||
}
|
||||
vv = vv.Elem()
|
||||
}
|
||||
if vv.CanAddr() && vv.Addr().CanInterface() {
|
||||
if outi, ok := vv.Addr().Interface().(unstable.Unmarshaler); ok {
|
||||
// Collect all key-value expressions for this table
|
||||
return d.handleKeyValuesUnmarshaler(outi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var rv reflect.Value
|
||||
for d.nextExpr() {
|
||||
expr := d.expr()
|
||||
@@ -628,6 +686,41 @@ func (d *decoder) handleKeyValues(v reflect.Value) (reflect.Value, error) {
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
// handleKeyValuesUnmarshaler collects all key-value expressions for a table
|
||||
// and passes them to the Unmarshaler as raw TOML bytes.
|
||||
func (d *decoder) handleKeyValuesUnmarshaler(u unstable.Unmarshaler) (reflect.Value, error) {
|
||||
// Collect raw bytes from all key-value expressions for this table.
|
||||
// We use the Raw field on each KeyValue expression to preserve the
|
||||
// original formatting (whitespace, quoting style, etc.) from the document.
|
||||
var buf []byte
|
||||
|
||||
for d.nextExpr() {
|
||||
expr := d.expr()
|
||||
if expr.Kind != unstable.KeyValue {
|
||||
d.stashExpr()
|
||||
break
|
||||
}
|
||||
|
||||
_, err := d.seen.CheckExpression(expr)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
// Use the raw bytes from the original document to preserve formatting
|
||||
if expr.Raw.Length > 0 {
|
||||
raw := d.p.Raw(expr.Raw)
|
||||
buf = append(buf, raw...)
|
||||
}
|
||||
buf = append(buf, '\n')
|
||||
}
|
||||
|
||||
if err := u.UnmarshalTOML(buf); err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
return reflect.Value{}, nil
|
||||
}
|
||||
|
||||
type (
|
||||
handlerFn func(key unstable.Iterator, v reflect.Value) (reflect.Value, error)
|
||||
valueMakerFn func() reflect.Value
|
||||
@@ -672,14 +765,21 @@ func (d *decoder) handleValue(value *unstable.Node, v reflect.Value) error {
|
||||
if d.unmarshalerInterface {
|
||||
if v.CanAddr() && v.Addr().CanInterface() {
|
||||
if outi, ok := v.Addr().Interface().(unstable.Unmarshaler); ok {
|
||||
return outi.UnmarshalTOML(value)
|
||||
// Pass raw bytes from the original document
|
||||
return outi.UnmarshalTOML(d.p.Raw(value.Raw))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok, err := d.tryTextUnmarshaler(value, v)
|
||||
if ok || err != nil {
|
||||
return err
|
||||
// Only try TextUnmarshaler for scalar types. For Array and InlineTable,
|
||||
// fall through to struct/map unmarshaling to allow flexible unmarshaling
|
||||
// where a type can implement UnmarshalText for string values but still
|
||||
// be populated field-by-field from a table. See issue #974.
|
||||
if value.Kind != unstable.Array && value.Kind != unstable.InlineTable {
|
||||
ok, err := d.tryTextUnmarshaler(value, v)
|
||||
if ok || err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
switch value.Kind {
|
||||
@@ -821,6 +921,9 @@ func (d *decoder) unmarshalDateTime(value *unstable.Node, v reflect.Value) error
|
||||
return err
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Interface && v.Type() != timeType {
|
||||
return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("datetime", v.Type()))
|
||||
}
|
||||
v.Set(reflect.ValueOf(dt))
|
||||
return nil
|
||||
}
|
||||
@@ -831,14 +934,14 @@ func (d *decoder) unmarshalLocalDate(value *unstable.Node, v reflect.Value) erro
|
||||
return err
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Interface && v.Type() != timeType {
|
||||
return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("local date", v.Type()))
|
||||
}
|
||||
if v.Type() == timeType {
|
||||
cast := ld.AsTime(time.Local)
|
||||
v.Set(reflect.ValueOf(cast))
|
||||
v.Set(reflect.ValueOf(ld.AsTime(time.Local)))
|
||||
return nil
|
||||
}
|
||||
|
||||
v.Set(reflect.ValueOf(ld))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -852,6 +955,9 @@ func (d *decoder) unmarshalLocalTime(value *unstable.Node, v reflect.Value) erro
|
||||
return unstable.NewParserError(rest, "extra characters at the end of a local time")
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Interface {
|
||||
return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("local time", v.Type()))
|
||||
}
|
||||
v.Set(reflect.ValueOf(lt))
|
||||
return nil
|
||||
}
|
||||
@@ -866,15 +972,14 @@ func (d *decoder) unmarshalLocalDateTime(value *unstable.Node, v reflect.Value)
|
||||
return unstable.NewParserError(rest, "extra characters at the end of a local date time")
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Interface && v.Type() != timeType {
|
||||
return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("local datetime", v.Type()))
|
||||
}
|
||||
if v.Type() == timeType {
|
||||
cast := ldt.AsTime(time.Local)
|
||||
|
||||
v.Set(reflect.ValueOf(cast))
|
||||
v.Set(reflect.ValueOf(ldt.AsTime(time.Local)))
|
||||
return nil
|
||||
}
|
||||
|
||||
v.Set(reflect.ValueOf(ldt))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -929,8 +1034,9 @@ const (
|
||||
// compile time, so it is computed during initialization.
|
||||
var maxUint int64 = math.MaxInt64
|
||||
|
||||
func init() {
|
||||
func init() { //nolint:gochecknoinits
|
||||
m := uint64(^uint(0))
|
||||
// #nosec G115
|
||||
if m < uint64(maxUint) {
|
||||
maxUint = int64(m)
|
||||
}
|
||||
@@ -1010,7 +1116,7 @@ func (d *decoder) unmarshalInteger(value *unstable.Node, v reflect.Value) error
|
||||
case reflect.Interface:
|
||||
r = reflect.ValueOf(i)
|
||||
default:
|
||||
return unstable.NewParserError(d.p.Raw(value.Raw), d.typeMismatchString("integer", v.Type()))
|
||||
return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("integer", v.Type()))
|
||||
}
|
||||
|
||||
if !r.Type().AssignableTo(v.Type()) {
|
||||
@@ -1029,7 +1135,7 @@ func (d *decoder) unmarshalString(value *unstable.Node, v reflect.Value) error {
|
||||
case reflect.Interface:
|
||||
v.Set(reflect.ValueOf(string(value.Data)))
|
||||
default:
|
||||
return unstable.NewParserError(d.p.Raw(value.Raw), d.typeMismatchString("string", v.Type()))
|
||||
return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("string", v.Type()))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -1080,35 +1186,39 @@ func (d *decoder) keyFromData(keyType reflect.Type, data []byte) (reflect.Value,
|
||||
return reflect.Value{}, fmt.Errorf("toml: error unmarshalling key type %s from text: %w", stringType, err)
|
||||
}
|
||||
return mk.Elem(), nil
|
||||
}
|
||||
|
||||
case keyType.Kind() == reflect.Int || keyType.Kind() == reflect.Int8 || keyType.Kind() == reflect.Int16 || keyType.Kind() == reflect.Int32 || keyType.Kind() == reflect.Int64:
|
||||
switch keyType.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
key, err := strconv.ParseInt(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from integer: %w", stringType, err)
|
||||
}
|
||||
return reflect.ValueOf(key).Convert(keyType), nil
|
||||
case keyType.Kind() == reflect.Uint || keyType.Kind() == reflect.Uint8 || keyType.Kind() == reflect.Uint16 || keyType.Kind() == reflect.Uint32 || keyType.Kind() == reflect.Uint64:
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
key, err := strconv.ParseUint(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from unsigned integer: %w", stringType, err)
|
||||
}
|
||||
return reflect.ValueOf(key).Convert(keyType), nil
|
||||
|
||||
case keyType.Kind() == reflect.Float32:
|
||||
case reflect.Float32:
|
||||
key, err := strconv.ParseFloat(string(data), 32)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from float: %w", stringType, err)
|
||||
}
|
||||
return reflect.ValueOf(float32(key)), nil
|
||||
|
||||
case keyType.Kind() == reflect.Float64:
|
||||
case reflect.Float64:
|
||||
key, err := strconv.ParseFloat(string(data), 64)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from float: %w", stringType, err)
|
||||
}
|
||||
return reflect.ValueOf(float64(key)), nil
|
||||
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("toml: cannot convert map key of type %s to expected type %s", stringType, keyType)
|
||||
}
|
||||
return reflect.Value{}, fmt.Errorf("toml: cannot convert map key of type %s to expected type %s", stringType, keyType)
|
||||
}
|
||||
|
||||
func (d *decoder) handleKeyValuePart(key unstable.Iterator, value *unstable.Node, v reflect.Value) (reflect.Value, error) {
|
||||
@@ -1154,6 +1264,18 @@ func (d *decoder) handleKeyValuePart(key unstable.Iterator, value *unstable.Node
|
||||
case reflect.Struct:
|
||||
path, found := structFieldPath(v, string(key.Node().Data))
|
||||
if !found {
|
||||
// If no matching struct field is found but the target implements the
|
||||
// unstable.Unmarshaler interface (and it is enabled), delegate the
|
||||
// decoding of this value to the custom unmarshaler.
|
||||
if d.unmarshalerInterface {
|
||||
if v.CanAddr() && v.Addr().CanInterface() {
|
||||
if outi, ok := v.Addr().Interface().(unstable.Unmarshaler); ok {
|
||||
// Pass raw bytes from the original document
|
||||
return reflect.Value{}, outi.UnmarshalTOML(d.p.Raw(value.Raw))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Otherwise, keep previous behavior and skip until the next table.
|
||||
d.skipUntilTable = true
|
||||
break
|
||||
}
|
||||
@@ -1259,13 +1381,13 @@ func fieldByIndex(v reflect.Value, path []int) reflect.Value {
|
||||
|
||||
type fieldPathsMap = map[string][]int
|
||||
|
||||
var globalFieldPathsCache atomic.Value // map[danger.TypeID]fieldPathsMap
|
||||
var globalFieldPathsCache atomic.Value // map[reflect.Type]fieldPathsMap
|
||||
|
||||
func structFieldPath(v reflect.Value, name string) ([]int, bool) {
|
||||
t := v.Type()
|
||||
|
||||
cache, _ := globalFieldPathsCache.Load().(map[danger.TypeID]fieldPathsMap)
|
||||
fieldPaths, ok := cache[danger.MakeTypeID(t)]
|
||||
cache, _ := globalFieldPathsCache.Load().(map[reflect.Type]fieldPathsMap)
|
||||
fieldPaths, ok := cache[t]
|
||||
|
||||
if !ok {
|
||||
fieldPaths = map[string][]int{}
|
||||
@@ -1276,8 +1398,8 @@ func structFieldPath(v reflect.Value, name string) ([]int, bool) {
|
||||
fieldPaths[strings.ToLower(name)] = path
|
||||
})
|
||||
|
||||
newCache := make(map[danger.TypeID]fieldPathsMap, len(cache)+1)
|
||||
newCache[danger.MakeTypeID(t)] = fieldPaths
|
||||
newCache := make(map[reflect.Type]fieldPathsMap, len(cache)+1)
|
||||
newCache[t] = fieldPaths
|
||||
for k, v := range cache {
|
||||
newCache[k] = v
|
||||
}
|
||||
@@ -1301,7 +1423,9 @@ func forEachField(t reflect.Type, path []int, do func(name string, path []int))
|
||||
continue
|
||||
}
|
||||
|
||||
fieldPath := append(path, i)
|
||||
fieldPath := make([]int, 0, len(path)+1)
|
||||
fieldPath = append(fieldPath, path...)
|
||||
fieldPath = append(fieldPath, i)
|
||||
fieldPath = fieldPath[:len(fieldPath):len(fieldPath)]
|
||||
|
||||
name := f.Tag.Get("toml")
|
||||
|
||||
71
vendor/github.com/pelletier/go-toml/v2/unstable/ast.go
generated
vendored
71
vendor/github.com/pelletier/go-toml/v2/unstable/ast.go
generated
vendored
@@ -1,10 +1,8 @@
|
||||
package unstable
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||
)
|
||||
|
||||
// Iterator over a sequence of nodes.
|
||||
@@ -19,30 +17,43 @@ import (
|
||||
// // do something with n
|
||||
// }
|
||||
type Iterator struct {
|
||||
nodes *[]Node
|
||||
idx int32
|
||||
started bool
|
||||
node *Node
|
||||
}
|
||||
|
||||
// Next moves the iterator forward and returns true if points to a
|
||||
// node, false otherwise.
|
||||
func (c *Iterator) Next() bool {
|
||||
if c.nodes == nil {
|
||||
return false
|
||||
}
|
||||
nodes := *c.nodes
|
||||
if !c.started {
|
||||
c.started = true
|
||||
} else if c.node.Valid() {
|
||||
c.node = c.node.Next()
|
||||
} else {
|
||||
idx := c.idx
|
||||
if idx >= 0 && int(idx) < len(nodes) {
|
||||
c.idx = nodes[idx].next
|
||||
}
|
||||
}
|
||||
return c.node.Valid()
|
||||
return c.idx >= 0 && int(c.idx) < len(nodes)
|
||||
}
|
||||
|
||||
// IsLast returns true if the current node of the iterator is the last
|
||||
// one. Subsequent calls to Next() will return false.
|
||||
func (c *Iterator) IsLast() bool {
|
||||
return c.node.next == 0
|
||||
return c.nodes == nil || c.idx < 0 || (*c.nodes)[c.idx].next < 0
|
||||
}
|
||||
|
||||
// Node returns a pointer to the node pointed at by the iterator.
|
||||
func (c *Iterator) Node() *Node {
|
||||
return c.node
|
||||
if c.nodes == nil || c.idx < 0 {
|
||||
return nil
|
||||
}
|
||||
n := &(*c.nodes)[c.idx]
|
||||
n.nodes = c.nodes
|
||||
return n
|
||||
}
|
||||
|
||||
// Node in a TOML expression AST.
|
||||
@@ -65,11 +76,12 @@ type Node struct {
|
||||
Raw Range // Raw bytes from the input.
|
||||
Data []byte // Node value (either allocated or referencing the input).
|
||||
|
||||
// References to other nodes, as offsets in the backing array
|
||||
// from this node. References can go backward, so those can be
|
||||
// negative.
|
||||
next int // 0 if last element
|
||||
child int // 0 if no child
|
||||
// Absolute indices into the backing nodes slice. -1 means none.
|
||||
next int32
|
||||
child int32
|
||||
|
||||
// Reference to the backing nodes slice for navigation.
|
||||
nodes *[]Node
|
||||
}
|
||||
|
||||
// Range of bytes in the document.
|
||||
@@ -80,24 +92,24 @@ type Range struct {
|
||||
|
||||
// Next returns a pointer to the next node, or nil if there is no next node.
|
||||
func (n *Node) Next() *Node {
|
||||
if n.next == 0 {
|
||||
if n.next < 0 {
|
||||
return nil
|
||||
}
|
||||
ptr := unsafe.Pointer(n)
|
||||
size := unsafe.Sizeof(Node{})
|
||||
return (*Node)(danger.Stride(ptr, size, n.next))
|
||||
next := &(*n.nodes)[n.next]
|
||||
next.nodes = n.nodes
|
||||
return next
|
||||
}
|
||||
|
||||
// Child returns a pointer to the first child node of this node. Other children
|
||||
// can be accessed calling Next on the first child. Returns an nil if this Node
|
||||
// can be accessed calling Next on the first child. Returns nil if this Node
|
||||
// has no child.
|
||||
func (n *Node) Child() *Node {
|
||||
if n.child == 0 {
|
||||
if n.child < 0 {
|
||||
return nil
|
||||
}
|
||||
ptr := unsafe.Pointer(n)
|
||||
size := unsafe.Sizeof(Node{})
|
||||
return (*Node)(danger.Stride(ptr, size, n.child))
|
||||
child := &(*n.nodes)[n.child]
|
||||
child.nodes = n.nodes
|
||||
return child
|
||||
}
|
||||
|
||||
// Valid returns true if the node's kind is set (not to Invalid).
|
||||
@@ -111,13 +123,14 @@ func (n *Node) Valid() bool {
|
||||
func (n *Node) Key() Iterator {
|
||||
switch n.Kind {
|
||||
case KeyValue:
|
||||
value := n.Child()
|
||||
if !value.Valid() {
|
||||
panic(fmt.Errorf("KeyValue should have at least two children"))
|
||||
child := n.child
|
||||
if child < 0 {
|
||||
panic(errors.New("KeyValue should have at least two children"))
|
||||
}
|
||||
return Iterator{node: value.Next()}
|
||||
valueNode := &(*n.nodes)[child]
|
||||
return Iterator{nodes: n.nodes, idx: valueNode.next}
|
||||
case Table, ArrayTable:
|
||||
return Iterator{node: n.Child()}
|
||||
return Iterator{nodes: n.nodes, idx: n.child}
|
||||
default:
|
||||
panic(fmt.Errorf("Key() is not supported on a %s", n.Kind))
|
||||
}
|
||||
@@ -132,5 +145,5 @@ func (n *Node) Value() *Node {
|
||||
|
||||
// Children returns an iterator over a node's children.
|
||||
func (n *Node) Children() Iterator {
|
||||
return Iterator{node: n.Child()}
|
||||
return Iterator{nodes: n.nodes, idx: n.child}
|
||||
}
|
||||
|
||||
27
vendor/github.com/pelletier/go-toml/v2/unstable/builder.go
generated
vendored
27
vendor/github.com/pelletier/go-toml/v2/unstable/builder.go
generated
vendored
@@ -7,15 +7,6 @@ type root struct {
|
||||
nodes []Node
|
||||
}
|
||||
|
||||
// Iterator over the top level nodes.
|
||||
func (r *root) Iterator() Iterator {
|
||||
it := Iterator{}
|
||||
if len(r.nodes) > 0 {
|
||||
it.node = &r.nodes[0]
|
||||
}
|
||||
return it
|
||||
}
|
||||
|
||||
func (r *root) at(idx reference) *Node {
|
||||
return &r.nodes[idx]
|
||||
}
|
||||
@@ -33,12 +24,10 @@ type builder struct {
|
||||
lastIdx int
|
||||
}
|
||||
|
||||
func (b *builder) Tree() *root {
|
||||
return &b.tree
|
||||
}
|
||||
|
||||
func (b *builder) NodeAt(ref reference) *Node {
|
||||
return b.tree.at(ref)
|
||||
n := b.tree.at(ref)
|
||||
n.nodes = &b.tree.nodes
|
||||
return n
|
||||
}
|
||||
|
||||
func (b *builder) Reset() {
|
||||
@@ -48,24 +37,28 @@ func (b *builder) Reset() {
|
||||
|
||||
func (b *builder) Push(n Node) reference {
|
||||
b.lastIdx = len(b.tree.nodes)
|
||||
n.next = -1
|
||||
n.child = -1
|
||||
b.tree.nodes = append(b.tree.nodes, n)
|
||||
return reference(b.lastIdx)
|
||||
}
|
||||
|
||||
func (b *builder) PushAndChain(n Node) reference {
|
||||
newIdx := len(b.tree.nodes)
|
||||
n.next = -1
|
||||
n.child = -1
|
||||
b.tree.nodes = append(b.tree.nodes, n)
|
||||
if b.lastIdx >= 0 {
|
||||
b.tree.nodes[b.lastIdx].next = newIdx - b.lastIdx
|
||||
b.tree.nodes[b.lastIdx].next = int32(newIdx) //nolint:gosec // TOML ASTs are small
|
||||
}
|
||||
b.lastIdx = newIdx
|
||||
return reference(b.lastIdx)
|
||||
}
|
||||
|
||||
func (b *builder) AttachChild(parent reference, child reference) {
|
||||
b.tree.nodes[parent].child = int(child) - int(parent)
|
||||
b.tree.nodes[parent].child = int32(child) //nolint:gosec // TOML ASTs are small
|
||||
}
|
||||
|
||||
func (b *builder) Chain(from reference, to reference) {
|
||||
b.tree.nodes[from].next = int(to) - int(from)
|
||||
b.tree.nodes[from].next = int32(to) //nolint:gosec // TOML ASTs are small
|
||||
}
|
||||
|
||||
20
vendor/github.com/pelletier/go-toml/v2/unstable/kind.go
generated
vendored
20
vendor/github.com/pelletier/go-toml/v2/unstable/kind.go
generated
vendored
@@ -6,28 +6,40 @@ import "fmt"
|
||||
type Kind int
|
||||
|
||||
const (
|
||||
// Meta
|
||||
// Invalid represents an invalid meta node.
|
||||
Invalid Kind = iota
|
||||
// Comment represents a comment meta node.
|
||||
Comment
|
||||
// Key represents a key meta node.
|
||||
Key
|
||||
|
||||
// Top level structures
|
||||
// Table represents a top-level table.
|
||||
Table
|
||||
// ArrayTable represents a top-level array table.
|
||||
ArrayTable
|
||||
// KeyValue represents a top-level key value.
|
||||
KeyValue
|
||||
|
||||
// Containers values
|
||||
// Array represents an array container value.
|
||||
Array
|
||||
// InlineTable represents an inline table container value.
|
||||
InlineTable
|
||||
|
||||
// Values
|
||||
// String represents a string value.
|
||||
String
|
||||
// Bool represents a boolean value.
|
||||
Bool
|
||||
// Float represents a floating point value.
|
||||
Float
|
||||
// Integer represents an integer value.
|
||||
Integer
|
||||
// LocalDate represents a a local date value.
|
||||
LocalDate
|
||||
// LocalTime represents a local time value.
|
||||
LocalTime
|
||||
// LocalDateTime represents a local date/time value.
|
||||
LocalDateTime
|
||||
// DateTime represents a data/time value.
|
||||
DateTime
|
||||
)
|
||||
|
||||
|
||||
103
vendor/github.com/pelletier/go-toml/v2/unstable/parser.go
generated
vendored
103
vendor/github.com/pelletier/go-toml/v2/unstable/parser.go
generated
vendored
@@ -6,7 +6,6 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/pelletier/go-toml/v2/internal/characters"
|
||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||
)
|
||||
|
||||
// ParserError describes an error relative to the content of the document.
|
||||
@@ -70,11 +69,26 @@ func (p *Parser) Data() []byte {
|
||||
// panics.
|
||||
func (p *Parser) Range(b []byte) Range {
|
||||
return Range{
|
||||
Offset: uint32(danger.SubsliceOffset(p.data, b)),
|
||||
Length: uint32(len(b)),
|
||||
Offset: uint32(p.subsliceOffset(b)), //nolint:gosec // TOML documents are small
|
||||
Length: uint32(len(b)), //nolint:gosec // TOML documents are small
|
||||
}
|
||||
}
|
||||
|
||||
// rangeOfToken computes the Range of a token given the remaining bytes after the token.
|
||||
// This is used when the token was extracted from the beginning of some position,
|
||||
// and 'rest' is what remains after the token.
|
||||
func (p *Parser) rangeOfToken(token, rest []byte) Range {
|
||||
offset := len(p.data) - len(token) - len(rest)
|
||||
return Range{Offset: uint32(offset), Length: uint32(len(token))} //nolint:gosec // TOML documents are small
|
||||
}
|
||||
|
||||
// subsliceOffset returns the byte offset of subslice b within p.data.
|
||||
// b must be a suffix (tail) of p.data.
|
||||
func (p *Parser) subsliceOffset(b []byte) int {
|
||||
// b is a suffix of p.data, so its offset is len(p.data) - len(b)
|
||||
return len(p.data) - len(b)
|
||||
}
|
||||
|
||||
// Raw returns the slice corresponding to the bytes in the given range.
|
||||
func (p *Parser) Raw(raw Range) []byte {
|
||||
return p.data[raw.Offset : raw.Offset+raw.Length]
|
||||
@@ -158,9 +172,17 @@ type Shape struct {
|
||||
End Position
|
||||
}
|
||||
|
||||
func (p *Parser) position(b []byte) Position {
|
||||
offset := danger.SubsliceOffset(p.data, b)
|
||||
// Shape returns the shape of the given range in the input. Will
|
||||
// panic if the range is not a subslice of the input.
|
||||
func (p *Parser) Shape(r Range) Shape {
|
||||
return Shape{
|
||||
Start: p.positionAt(int(r.Offset)),
|
||||
End: p.positionAt(int(r.Offset + r.Length)),
|
||||
}
|
||||
}
|
||||
|
||||
// positionAt returns the position at the given byte offset in the document.
|
||||
func (p *Parser) positionAt(offset int) Position {
|
||||
lead := p.data[:offset]
|
||||
|
||||
return Position{
|
||||
@@ -170,16 +192,6 @@ func (p *Parser) position(b []byte) Position {
|
||||
}
|
||||
}
|
||||
|
||||
// Shape returns the shape of the given range in the input. Will
|
||||
// panic if the range is not a subslice of the input.
|
||||
func (p *Parser) Shape(r Range) Shape {
|
||||
raw := p.Raw(r)
|
||||
return Shape{
|
||||
Start: p.position(raw),
|
||||
End: p.position(raw[r.Length:]),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) parseNewline(b []byte) ([]byte, error) {
|
||||
if b[0] == '\n' {
|
||||
return b[1:], nil
|
||||
@@ -199,7 +211,7 @@ func (p *Parser) parseComment(b []byte) (reference, []byte, error) {
|
||||
if p.KeepComments && err == nil {
|
||||
ref = p.builder.Push(Node{
|
||||
Kind: Comment,
|
||||
Raw: p.Range(data),
|
||||
Raw: p.rangeOfToken(data, rest),
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
@@ -316,6 +328,9 @@ func (p *Parser) parseStdTable(b []byte) (reference, []byte, error) {
|
||||
|
||||
func (p *Parser) parseKeyval(b []byte) (reference, []byte, error) {
|
||||
// keyval = key keyval-sep val
|
||||
// Track the start position for Raw range
|
||||
startB := b
|
||||
|
||||
ref := p.builder.Push(Node{
|
||||
Kind: KeyValue,
|
||||
})
|
||||
@@ -330,7 +345,7 @@ func (p *Parser) parseKeyval(b []byte) (reference, []byte, error) {
|
||||
b = p.parseWhitespace(b)
|
||||
|
||||
if len(b) == 0 {
|
||||
return invalidReference, nil, NewParserError(b, "expected = after a key, but the document ends there")
|
||||
return invalidReference, nil, NewParserError(startB[:len(startB)-len(b)], "expected = after a key, but the document ends there")
|
||||
}
|
||||
|
||||
b, err = expect('=', b)
|
||||
@@ -348,6 +363,11 @@ func (p *Parser) parseKeyval(b []byte) (reference, []byte, error) {
|
||||
p.builder.Chain(valRef, key)
|
||||
p.builder.AttachChild(ref, valRef)
|
||||
|
||||
// Set Raw to span the entire key-value expression.
|
||||
// Access the node directly in the slice to avoid the write barrier
|
||||
// that NodeAt's nodes-pointer setup would trigger.
|
||||
p.builder.tree.nodes[ref].Raw = p.rangeOfToken(startB[:len(startB)-len(b)], b)
|
||||
|
||||
return ref, b, err
|
||||
}
|
||||
|
||||
@@ -376,7 +396,7 @@ func (p *Parser) parseVal(b []byte) (reference, []byte, error) {
|
||||
if err == nil {
|
||||
ref = p.builder.Push(Node{
|
||||
Kind: String,
|
||||
Raw: p.Range(raw),
|
||||
Raw: p.rangeOfToken(raw, b),
|
||||
Data: v,
|
||||
})
|
||||
}
|
||||
@@ -394,7 +414,7 @@ func (p *Parser) parseVal(b []byte) (reference, []byte, error) {
|
||||
if err == nil {
|
||||
ref = p.builder.Push(Node{
|
||||
Kind: String,
|
||||
Raw: p.Range(raw),
|
||||
Raw: p.rangeOfToken(raw, b),
|
||||
Data: v,
|
||||
})
|
||||
}
|
||||
@@ -456,7 +476,7 @@ func (p *Parser) parseInlineTable(b []byte) (reference, []byte, error) {
|
||||
// inline-table-keyvals = keyval [ inline-table-sep inline-table-keyvals ]
|
||||
parent := p.builder.Push(Node{
|
||||
Kind: InlineTable,
|
||||
Raw: p.Range(b[:1]),
|
||||
Raw: p.rangeOfToken(b[:1], b[1:]),
|
||||
})
|
||||
|
||||
first := true
|
||||
@@ -542,7 +562,7 @@ func (p *Parser) parseValArray(b []byte) (reference, []byte, error) {
|
||||
|
||||
var err error
|
||||
for len(b) > 0 {
|
||||
cref := invalidReference
|
||||
var cref reference
|
||||
cref, b, err = p.parseOptionalWhitespaceCommentNewline(b)
|
||||
if err != nil {
|
||||
return parent, nil, err
|
||||
@@ -611,12 +631,13 @@ func (p *Parser) parseOptionalWhitespaceCommentNewline(b []byte) (reference, []b
|
||||
latestCommentRef := invalidReference
|
||||
|
||||
addComment := func(ref reference) {
|
||||
if rootCommentRef == invalidReference {
|
||||
switch {
|
||||
case rootCommentRef == invalidReference:
|
||||
rootCommentRef = ref
|
||||
} else if latestCommentRef == invalidReference {
|
||||
case latestCommentRef == invalidReference:
|
||||
p.builder.AttachChild(rootCommentRef, ref)
|
||||
latestCommentRef = ref
|
||||
} else {
|
||||
default:
|
||||
p.builder.Chain(latestCommentRef, ref)
|
||||
latestCommentRef = ref
|
||||
}
|
||||
@@ -704,11 +725,11 @@ func (p *Parser) parseMultilineBasicString(b []byte) ([]byte, []byte, []byte, er
|
||||
|
||||
if !escaped {
|
||||
str := token[startIdx:endIdx]
|
||||
verr := characters.Utf8TomlValidAlreadyEscaped(str)
|
||||
if verr.Zero() {
|
||||
highlight := characters.Utf8TomlValidAlreadyEscaped(str)
|
||||
if len(highlight) == 0 {
|
||||
return token, str, rest, nil
|
||||
}
|
||||
return nil, nil, nil, NewParserError(str[verr.Index:verr.Index+verr.Size], "invalid UTF-8")
|
||||
return nil, nil, nil, NewParserError(highlight, "invalid UTF-8")
|
||||
}
|
||||
|
||||
var builder bytes.Buffer
|
||||
@@ -744,7 +765,7 @@ func (p *Parser) parseMultilineBasicString(b []byte) ([]byte, []byte, []byte, er
|
||||
i += j
|
||||
for ; i < len(token)-3; i++ {
|
||||
c := token[i]
|
||||
if !(c == '\n' || c == '\r' || c == ' ' || c == '\t') {
|
||||
if c != '\n' && c != '\r' && c != ' ' && c != '\t' {
|
||||
i--
|
||||
break
|
||||
}
|
||||
@@ -820,7 +841,7 @@ func (p *Parser) parseKey(b []byte) (reference, []byte, error) {
|
||||
|
||||
ref := p.builder.Push(Node{
|
||||
Kind: Key,
|
||||
Raw: p.Range(raw),
|
||||
Raw: p.rangeOfToken(raw, b),
|
||||
Data: key,
|
||||
})
|
||||
|
||||
@@ -836,7 +857,7 @@ func (p *Parser) parseKey(b []byte) (reference, []byte, error) {
|
||||
|
||||
p.builder.PushAndChain(Node{
|
||||
Kind: Key,
|
||||
Raw: p.Range(raw),
|
||||
Raw: p.rangeOfToken(raw, b),
|
||||
Data: key,
|
||||
})
|
||||
} else {
|
||||
@@ -897,11 +918,11 @@ func (p *Parser) parseBasicString(b []byte) ([]byte, []byte, []byte, error) {
|
||||
// validate the string and return a direct reference to the buffer.
|
||||
if !escaped {
|
||||
str := token[startIdx:endIdx]
|
||||
verr := characters.Utf8TomlValidAlreadyEscaped(str)
|
||||
if verr.Zero() {
|
||||
highlight := characters.Utf8TomlValidAlreadyEscaped(str)
|
||||
if len(highlight) == 0 {
|
||||
return token, str, rest, nil
|
||||
}
|
||||
return nil, nil, nil, NewParserError(str[verr.Index:verr.Index+verr.Size], "invalid UTF-8")
|
||||
return nil, nil, nil, NewParserError(highlight, "invalid UTF-8")
|
||||
}
|
||||
|
||||
i := startIdx
|
||||
@@ -972,7 +993,7 @@ func hexToRune(b []byte, length int) (rune, error) {
|
||||
|
||||
var r uint32
|
||||
for i, c := range b {
|
||||
d := uint32(0)
|
||||
var d uint32
|
||||
switch {
|
||||
case '0' <= c && c <= '9':
|
||||
d = uint32(c - '0')
|
||||
@@ -1013,7 +1034,7 @@ func (p *Parser) parseIntOrFloatOrDateTime(b []byte) (reference, []byte, error)
|
||||
return p.builder.Push(Node{
|
||||
Kind: Float,
|
||||
Data: b[:3],
|
||||
Raw: p.Range(b[:3]),
|
||||
Raw: p.rangeOfToken(b[:3], b[3:]),
|
||||
}), b[3:], nil
|
||||
case 'n':
|
||||
if !scanFollowsNan(b) {
|
||||
@@ -1023,7 +1044,7 @@ func (p *Parser) parseIntOrFloatOrDateTime(b []byte) (reference, []byte, error)
|
||||
return p.builder.Push(Node{
|
||||
Kind: Float,
|
||||
Data: b[:3],
|
||||
Raw: p.Range(b[:3]),
|
||||
Raw: p.rangeOfToken(b[:3], b[3:]),
|
||||
}), b[3:], nil
|
||||
case '+', '-':
|
||||
return p.scanIntOrFloat(b)
|
||||
@@ -1076,7 +1097,7 @@ byteLoop:
|
||||
}
|
||||
case c == 'T' || c == 't' || c == ':' || c == '.':
|
||||
hasTime = true
|
||||
case c == '+' || c == '-' || c == 'Z' || c == 'z':
|
||||
case c == '+' || c == 'Z' || c == 'z':
|
||||
hasTz = true
|
||||
case c == ' ':
|
||||
if !seenSpace && i+1 < len(b) && isDigit(b[i+1]) {
|
||||
@@ -1148,7 +1169,7 @@ func (p *Parser) scanIntOrFloat(b []byte) (reference, []byte, error) {
|
||||
return p.builder.Push(Node{
|
||||
Kind: Integer,
|
||||
Data: b[:i],
|
||||
Raw: p.Range(b[:i]),
|
||||
Raw: p.rangeOfToken(b[:i], b[i:]),
|
||||
}), b[i:], nil
|
||||
}
|
||||
|
||||
@@ -1172,7 +1193,7 @@ func (p *Parser) scanIntOrFloat(b []byte) (reference, []byte, error) {
|
||||
return p.builder.Push(Node{
|
||||
Kind: Float,
|
||||
Data: b[:i+3],
|
||||
Raw: p.Range(b[:i+3]),
|
||||
Raw: p.rangeOfToken(b[:i+3], b[i+3:]),
|
||||
}), b[i+3:], nil
|
||||
}
|
||||
|
||||
@@ -1184,7 +1205,7 @@ func (p *Parser) scanIntOrFloat(b []byte) (reference, []byte, error) {
|
||||
return p.builder.Push(Node{
|
||||
Kind: Float,
|
||||
Data: b[:i+3],
|
||||
Raw: p.Range(b[:i+3]),
|
||||
Raw: p.rangeOfToken(b[:i+3], b[i+3:]),
|
||||
}), b[i+3:], nil
|
||||
}
|
||||
|
||||
@@ -1207,7 +1228,7 @@ func (p *Parser) scanIntOrFloat(b []byte) (reference, []byte, error) {
|
||||
return p.builder.Push(Node{
|
||||
Kind: kind,
|
||||
Data: b[:i],
|
||||
Raw: p.Range(b[:i]),
|
||||
Raw: p.rangeOfToken(b[:i], b[i:]),
|
||||
}), b[i:], nil
|
||||
}
|
||||
|
||||
|
||||
31
vendor/github.com/pelletier/go-toml/v2/unstable/unmarshaler.go
generated
vendored
31
vendor/github.com/pelletier/go-toml/v2/unstable/unmarshaler.go
generated
vendored
@@ -1,7 +1,32 @@
|
||||
package unstable
|
||||
|
||||
// The Unmarshaler interface may be implemented by types to customize their
|
||||
// behavior when being unmarshaled from a TOML document.
|
||||
// Unmarshaler is implemented by types that can unmarshal a TOML
|
||||
// description of themselves. The input is a valid TOML document
|
||||
// containing the relevant portion of the parsed document.
|
||||
//
|
||||
// For tables (including split tables defined in multiple places),
|
||||
// the data contains the raw key-value bytes from the original document
|
||||
// with adjusted table headers to be relative to the unmarshaling target.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalTOML(value *Node) error
|
||||
UnmarshalTOML(data []byte) error
|
||||
}
|
||||
|
||||
// RawMessage is a raw encoded TOML value. It implements Unmarshaler
|
||||
// and can be used to delay TOML decoding or capture raw content.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// type Config struct {
|
||||
// Plugin RawMessage `toml:"plugin"`
|
||||
// }
|
||||
//
|
||||
// var cfg Config
|
||||
// toml.NewDecoder(r).EnableUnmarshalerInterface().Decode(&cfg)
|
||||
// // cfg.Plugin now contains the raw TOML bytes for [plugin]
|
||||
type RawMessage []byte
|
||||
|
||||
// UnmarshalTOML implements Unmarshaler.
|
||||
func (m *RawMessage) UnmarshalTOML(data []byte) error {
|
||||
*m = append((*m)[0:0], data...)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user