mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[chore] Update all but bun libraries (#526)
* update all but bun libraries Signed-off-by: kim <grufwub@gmail.com> * remove my personal build script changes Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
20
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
20
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
@ -7,9 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.5.4] - 2022-04-25
|
||||
|
||||
* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447)
|
||||
* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444)
|
||||
* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443)
|
||||
|
||||
## [1.5.3] - 2022-04-22
|
||||
|
||||
* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445)
|
||||
|
||||
## [1.5.2] - 2022-04-21
|
||||
|
||||
* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374)
|
||||
* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361)
|
||||
* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424)
|
||||
* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406)
|
||||
* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416)
|
||||
|
||||
## [1.5.1] - 2021-08-24
|
||||
|
||||
* Revert Add AddRaw to not follow symlinks
|
||||
* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394)
|
||||
|
||||
## [1.5.0] - 2021-08-20
|
||||
|
||||
|
17
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
17
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
@ -48,18 +48,6 @@ fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Win
|
||||
|
||||
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
|
||||
|
||||
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
|
||||
|
||||
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
|
||||
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
|
||||
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
|
||||
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
|
||||
* When you're done, you will want to halt or destroy the Vagrant boxes.
|
||||
|
||||
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
|
||||
|
||||
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
|
||||
|
||||
### Maintainers
|
||||
|
||||
Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
@ -67,11 +55,6 @@ Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
* Submit a pull request and sign the CLA as above.
|
||||
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||
|
||||
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
|
||||
|
||||
All code changes should be internal pull requests.
|
||||
|
||||
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||
|
||||
[hub]: https://github.com/github/hub
|
||||
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
||||
|
24
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
24
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
@ -1,12 +1,8 @@
|
||||
# File system notifications for Go
|
||||
|
||||
[](https://godoc.org/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
|
||||
[](https://pkg.go.dev/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [](https://github.com/fsnotify/fsnotify/issues/413)
|
||||
|
||||
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
|
||||
|
||||
```console
|
||||
go get -u golang.org/x/sys/...
|
||||
```
|
||||
fsnotify utilizes [`golang.org/x/sys`](https://pkg.go.dev/golang.org/x/sys) rather than [`syscall`](https://pkg.go.dev/syscall) from the standard library.
|
||||
|
||||
Cross platform: Windows, Linux, BSD and macOS.
|
||||
|
||||
@ -16,22 +12,20 @@ Cross platform: Windows, Linux, BSD and macOS.
|
||||
| kqueue | BSD, macOS, iOS\* | Supported |
|
||||
| ReadDirectoryChangesW | Windows | Supported |
|
||||
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
|
||||
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) |
|
||||
| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) |
|
||||
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) |
|
||||
| fanotify | Linux 2.6.37+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) |
|
||||
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
|
||||
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
|
||||
|
||||
\* Android and iOS are untested.
|
||||
|
||||
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||
Please see [the documentation](https://pkg.go.dev/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||
|
||||
## API stability
|
||||
|
||||
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||
fsnotify is a fork of [howeyc/fsnotify](https://github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||
|
||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
|
||||
|
||||
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Usage
|
||||
|
||||
@ -84,10 +78,6 @@ func main() {
|
||||
|
||||
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||
|
||||
## Example
|
||||
|
||||
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
|
||||
|
||||
## FAQ
|
||||
|
||||
**When a file is moved to another directory is it still being watched?**
|
||||
|
36
vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go
generated
vendored
Normal file
36
vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows
|
||||
// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct{}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
return nil
|
||||
}
|
13
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
13
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
@ -163,6 +163,19 @@ func (w *Watcher) Remove(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WatchList returns the directories and files that are being monitered.
|
||||
func (w *Watcher) WatchList() []string {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
entries := make([]string, 0, len(w.watches))
|
||||
for pathname := range w.watches {
|
||||
entries = append(entries, pathname)
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
|
1
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
1
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
@ -38,7 +38,6 @@ func newFdPoller(fd int) (*fdPoller, error) {
|
||||
poller.close()
|
||||
}
|
||||
}()
|
||||
poller.fd = fd
|
||||
|
||||
// Create epoll fd
|
||||
poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
||||
|
13
vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
13
vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
@ -148,6 +148,19 @@ func (w *Watcher) Remove(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WatchList returns the directories and files that are being monitered.
|
||||
func (w *Watcher) WatchList() []string {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
entries := make([]string, 0, len(w.watches))
|
||||
for pathname := range w.watches {
|
||||
entries = append(entries, pathname)
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
|
||||
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
|
||||
|
||||
|
28
vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
28
vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
@ -96,6 +97,21 @@ func (w *Watcher) Remove(name string) error {
|
||||
return <-in.reply
|
||||
}
|
||||
|
||||
// WatchList returns the directories and files that are being monitered.
|
||||
func (w *Watcher) WatchList() []string {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
entries := make([]string, 0, len(w.watches))
|
||||
for _, entry := range w.watches {
|
||||
for _, watchEntry := range entry {
|
||||
entries = append(entries, watchEntry.path)
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
const (
|
||||
// Options for AddWatch
|
||||
sysFSONESHOT = 0x80000000
|
||||
@ -452,8 +468,16 @@ func (w *Watcher) readEvents() {
|
||||
|
||||
// Point "raw" to the event in the buffer
|
||||
raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
|
||||
buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
|
||||
name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
|
||||
// TODO: Consider using unsafe.Slice that is available from go1.17
|
||||
// https://stackoverflow.com/questions/51187973/how-to-create-an-array-or-a-slice-from-an-array-unsafe-pointer-in-golang
|
||||
// instead of using a fixed syscall.MAX_PATH buf, we create a buf that is the size of the path name
|
||||
size := int(raw.FileNameLength / 2)
|
||||
var buf []uint16
|
||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
|
||||
sh.Data = uintptr(unsafe.Pointer(&raw.FileName))
|
||||
sh.Len = size
|
||||
sh.Cap = size
|
||||
name := syscall.UTF16ToString(buf)
|
||||
fullname := filepath.Join(watch.path, name)
|
||||
|
||||
var mask uint64
|
||||
|
2
vendor/github.com/gin-contrib/sessions/.gitignore
generated
vendored
2
vendor/github.com/gin-contrib/sessions/.gitignore
generated
vendored
@ -1,3 +1,5 @@
|
||||
coverage.out
|
||||
vendor/*
|
||||
!/vendor/vendor.json
|
||||
/gorm/test.db
|
||||
.idea
|
||||
|
57
vendor/github.com/gin-contrib/sessions/.goreleaser.yaml
generated
vendored
Normal file
57
vendor/github.com/gin-contrib/sessions/.goreleaser.yaml
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
project_name: queue
|
||||
|
||||
builds:
|
||||
-
|
||||
# If true, skip the build.
|
||||
# Useful for library projects.
|
||||
# Default is false
|
||||
skip: true
|
||||
|
||||
changelog:
|
||||
# Set it to true if you wish to skip the changelog generation.
|
||||
# This may result in an empty release notes on GitHub/GitLab/Gitea.
|
||||
skip: false
|
||||
|
||||
# Changelog generation implementation to use.
|
||||
#
|
||||
# Valid options are:
|
||||
# - `git`: uses `git log`;
|
||||
# - `github`: uses the compare GitHub API, appending the author login to the changelog.
|
||||
# - `gitlab`: uses the compare GitLab API, appending the author name and email to the changelog.
|
||||
# - `github-native`: uses the GitHub release notes generation API, disables the groups feature.
|
||||
#
|
||||
# Defaults to `git`.
|
||||
use: git
|
||||
|
||||
# Sorts the changelog by the commit's messages.
|
||||
# Could either be asc, desc or empty
|
||||
# Default is empty
|
||||
sort: asc
|
||||
|
||||
# Group commits messages by given regex and title.
|
||||
# Order value defines the order of the groups.
|
||||
# Proving no regex means all commits will be grouped under the default group.
|
||||
# Groups are disabled when using github-native, as it already groups things by itself.
|
||||
#
|
||||
# Default is no groups.
|
||||
groups:
|
||||
- title: Features
|
||||
regexp: "^.*feat[(\\w)]*:+.*$"
|
||||
order: 0
|
||||
- title: 'Bug fixes'
|
||||
regexp: "^.*fix[(\\w)]*:+.*$"
|
||||
order: 1
|
||||
- title: 'Enhancements'
|
||||
regexp: "^.*chore[(\\w)]*:+.*$"
|
||||
order: 2
|
||||
- title: Others
|
||||
order: 999
|
||||
|
||||
filters:
|
||||
# Commit messages matching the regexp listed here will be removed from
|
||||
# the changelog
|
||||
# Default is empty
|
||||
exclude:
|
||||
- '^docs'
|
||||
- 'CICD'
|
||||
- typo
|
153
vendor/github.com/gin-contrib/sessions/README.md
generated
vendored
153
vendor/github.com/gin-contrib/sessions/README.md
generated
vendored
@ -13,6 +13,7 @@ Gin middleware for session management with multi-backend support:
|
||||
- [Redis](#redis)
|
||||
- [memcached](#memcached)
|
||||
- [MongoDB](#mongodb)
|
||||
- [GoRM](#gorm)
|
||||
- [memstore](#memstore)
|
||||
- [PostgreSQL](#postgresql)
|
||||
|
||||
@ -249,12 +250,13 @@ func main() {
|
||||
|
||||
### MongoDB
|
||||
|
||||
#### mgo
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/mongo"
|
||||
"github.com/gin-contrib/sessions/mongo/mongomgo"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/globalsign/mgo"
|
||||
)
|
||||
@ -267,7 +269,54 @@ func main() {
|
||||
}
|
||||
|
||||
c := session.DB("").C("sessions")
|
||||
store := mongo.NewStore(c, 3600, true, []byte("secret"))
|
||||
store := mongomgo.NewStore(c, 3600, true, []byte("secret"))
|
||||
r.Use(sessions.Sessions("mysession", store))
|
||||
|
||||
r.GET("/incr", func(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
var count int
|
||||
v := session.Get("count")
|
||||
if v == nil {
|
||||
count = 0
|
||||
} else {
|
||||
count = v.(int)
|
||||
count++
|
||||
}
|
||||
session.Set("count", count)
|
||||
session.Save()
|
||||
c.JSON(200, gin.H{"count": count})
|
||||
})
|
||||
r.Run(":8000")
|
||||
}
|
||||
```
|
||||
|
||||
#### mongo-driver
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/mongo/mongodriver"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
mongoOptions := options.Client().ApplyURI("mongodb://localhost:27017")
|
||||
client, err := mongo.NewClient(mongoOptions)
|
||||
if err != nil {
|
||||
// handle err
|
||||
}
|
||||
|
||||
if err := client.Connect(context.Background()); err != nil {
|
||||
// handle err
|
||||
}
|
||||
|
||||
c := client.Database("test").Collection("sessions")
|
||||
store := mongodriver.NewStore(c, 3600, true, []byte("secret"))
|
||||
r.Use(sessions.Sessions("mysession", store))
|
||||
|
||||
r.GET("/incr", func(c *gin.Context) {
|
||||
@ -322,46 +371,88 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### GoRM
|
||||
|
||||
[embedmd]:# (_example/gorm/main.go go)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-contrib/sessions"
|
||||
gormsessions "github.com/gin-contrib/sessions/gorm"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
store := gormsessions.NewStore(db, true, []byte("secret"))
|
||||
|
||||
r := gin.Default()
|
||||
r.Use(sessions.Sessions("mysession", store))
|
||||
|
||||
r.GET("/incr", func(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
var count int
|
||||
v := session.Get("count")
|
||||
if v == nil {
|
||||
count = 0
|
||||
} else {
|
||||
count = v.(int)
|
||||
count++
|
||||
}
|
||||
session.Set("count", count)
|
||||
session.Save()
|
||||
c.JSON(200, gin.H{"count": count})
|
||||
})
|
||||
r.Run(":8000")
|
||||
}
|
||||
```
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/postgres"
|
||||
"github.com/gin-gonic/gin"
|
||||
"database/sql"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/postgres"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
db, err := sql.Open("postgres", "postgresql://username:password@localhost:5432/database")
|
||||
if err != nil {
|
||||
// handle err
|
||||
}
|
||||
r := gin.Default()
|
||||
db, err := sql.Open("postgres", "postgresql://username:password@localhost:5432/database")
|
||||
if err != nil {
|
||||
// handle err
|
||||
}
|
||||
|
||||
store, err := postgres.NewStore(db, []byte("secret"))
|
||||
if err != nil {
|
||||
// handle err
|
||||
}
|
||||
store, err := postgres.NewStore(db, []byte("secret"))
|
||||
if err != nil {
|
||||
// handle err
|
||||
}
|
||||
|
||||
r.Use(sessions.Sessions("mysession", store))
|
||||
r.Use(sessions.Sessions("mysession", store))
|
||||
|
||||
r.GET("/incr", func(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
var count int
|
||||
v := session.Get("count")
|
||||
if v == nil {
|
||||
count = 0
|
||||
} else {
|
||||
count = v.(int)
|
||||
count++
|
||||
}
|
||||
session.Set("count", count)
|
||||
session.Save()
|
||||
c.JSON(200, gin.H{"count": count})
|
||||
})
|
||||
r.Run(":8000")
|
||||
r.GET("/incr", func(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
var count int
|
||||
v := session.Get("count")
|
||||
if v == nil {
|
||||
count = 0
|
||||
} else {
|
||||
count = v.(int)
|
||||
count++
|
||||
}
|
||||
session.Set("count", count)
|
||||
session.Save()
|
||||
c.JSON(200, gin.H{"count": count})
|
||||
})
|
||||
r.Run(":8000")
|
||||
}
|
||||
```
|
||||
|
1
vendor/github.com/gin-contrib/sessions/sessions.go
generated
vendored
1
vendor/github.com/gin-contrib/sessions/sessions.go
generated
vendored
@ -111,6 +111,7 @@ func (s *session) Flashes(vars ...string) []interface{} {
|
||||
}
|
||||
|
||||
func (s *session) Options(options Options) {
|
||||
s.written = true
|
||||
s.Session().Options = options.ToGorillaOptions()
|
||||
}
|
||||
|
||||
|
19
vendor/github.com/go-playground/validator/v10/README.md
generated
vendored
19
vendor/github.com/go-playground/validator/v10/README.md
generated
vendored
@ -1,7 +1,7 @@
|
||||
Package validator
|
||||
=================
|
||||
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||

|
||||

|
||||
[](https://travis-ci.org/go-playground/validator)
|
||||
[](https://coveralls.io/github/go-playground/validator?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/go-playground/validator)
|
||||
@ -130,7 +130,7 @@ Baked-in Validations
|
||||
| contains | Contains |
|
||||
| containsany | Contains Any |
|
||||
| containsrune | Contains Rune |
|
||||
| endsnotwith | Ends With |
|
||||
| endsnotwith | Ends Not With |
|
||||
| endswith | Ends With |
|
||||
| excludes | Excludes |
|
||||
| excludesall | Excludes All |
|
||||
@ -153,6 +153,7 @@ Baked-in Validations
|
||||
| bcp47_language_tag | Language tag (BCP 47) |
|
||||
| btc_addr | Bitcoin Address |
|
||||
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
|
||||
| credit_card | Credit Card Number |
|
||||
| datetime | Datetime |
|
||||
| e164 | e164 formatted phone number |
|
||||
| email | E-mail String
|
||||
@ -189,6 +190,18 @@ Baked-in Validations
|
||||
| uuid5 | Universally Unique Identifier UUID v5 |
|
||||
| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 |
|
||||
| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 |
|
||||
| md4 | MD4 hash |
|
||||
| md5 | MD5 hash |
|
||||
| sha256 | SHA256 hash |
|
||||
| sha384 | SHA384 hash |
|
||||
| sha512 | SHA512 hash |
|
||||
| ripemd128 | RIPEMD-128 hash |
|
||||
| ripemd128 | RIPEMD-160 hash |
|
||||
| tiger128 | TIGER128 hash |
|
||||
| tiger160 | TIGER160 hash |
|
||||
| tiger192 | TIGER192 hash |
|
||||
| semver | Semantic Versioning 2.0.0 |
|
||||
| ulid | Universally Unique Lexicographically Sortable Identifier ULID |
|
||||
|
||||
### Comparisons:
|
||||
| Tag | Description |
|
||||
@ -217,6 +230,8 @@ Baked-in Validations
|
||||
| required_with_all | Required With All |
|
||||
| required_without | Required Without |
|
||||
| required_without_all | Required Without All |
|
||||
| excluded_if | Excluded If |
|
||||
| excluded_unless | Excluded Unless |
|
||||
| excluded_with | Excluded With |
|
||||
| excluded_with_all | Excluded With All |
|
||||
| excluded_without | Excluded Without |
|
||||
|
420
vendor/github.com/go-playground/validator/v10/baked_in.go
generated
vendored
420
vendor/github.com/go-playground/validator/v10/baked_in.go
generated
vendored
@ -75,6 +75,8 @@ var (
|
||||
"required_with_all": requiredWithAll,
|
||||
"required_without": requiredWithout,
|
||||
"required_without_all": requiredWithoutAll,
|
||||
"excluded_if": excludedIf,
|
||||
"excluded_unless": excludedUnless,
|
||||
"excluded_with": excludedWith,
|
||||
"excluded_with_all": excludedWithAll,
|
||||
"excluded_without": excludedWithout,
|
||||
@ -148,6 +150,17 @@ var (
|
||||
"uuid3_rfc4122": isUUID3RFC4122,
|
||||
"uuid4_rfc4122": isUUID4RFC4122,
|
||||
"uuid5_rfc4122": isUUID5RFC4122,
|
||||
"ulid": isULID,
|
||||
"md4": isMD4,
|
||||
"md5": isMD5,
|
||||
"sha256": isSHA256,
|
||||
"sha384": isSHA384,
|
||||
"sha512": isSHA512,
|
||||
"ripemd128": isRIPEMD128,
|
||||
"ripemd160": isRIPEMD160,
|
||||
"tiger128": isTIGER128,
|
||||
"tiger160": isTIGER160,
|
||||
"tiger192": isTIGER192,
|
||||
"ascii": isASCII,
|
||||
"printascii": isPrintableASCII,
|
||||
"multibyte": hasMultiByteCharacter,
|
||||
@ -198,11 +211,16 @@ var (
|
||||
"postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2,
|
||||
"postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field,
|
||||
"bic": isIsoBicFormat,
|
||||
"semver": isSemverFormat,
|
||||
"dns_rfc1035_label": isDnsRFC1035LabelFormat,
|
||||
"credit_card": isCreditCard,
|
||||
}
|
||||
)
|
||||
|
||||
var oneofValsCache = map[string][]string{}
|
||||
var oneofValsCacheRWLock = sync.RWMutex{}
|
||||
var (
|
||||
oneofValsCache = map[string][]string{}
|
||||
oneofValsCacheRWLock = sync.RWMutex{}
|
||||
)
|
||||
|
||||
func parseOneOfParam2(s string) []string {
|
||||
oneofValsCacheRWLock.RLock()
|
||||
@ -258,7 +276,6 @@ func isOneOf(fl FieldLevel) bool {
|
||||
|
||||
// isUnique is the validation function for validating if each array|slice|map value is unique
|
||||
func isUnique(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
param := fl.Param()
|
||||
v := reflect.ValueOf(struct{}{})
|
||||
@ -308,7 +325,6 @@ func isUnique(fl FieldLevel) bool {
|
||||
|
||||
// isMAC is the validation function for validating if the field's value is a valid MAC address.
|
||||
func isMAC(fl FieldLevel) bool {
|
||||
|
||||
_, err := net.ParseMAC(fl.Field().String())
|
||||
|
||||
return err == nil
|
||||
@ -316,7 +332,6 @@ func isMAC(fl FieldLevel) bool {
|
||||
|
||||
// isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
|
||||
func isCIDRv4(fl FieldLevel) bool {
|
||||
|
||||
ip, _, err := net.ParseCIDR(fl.Field().String())
|
||||
|
||||
return err == nil && ip.To4() != nil
|
||||
@ -324,7 +339,6 @@ func isCIDRv4(fl FieldLevel) bool {
|
||||
|
||||
// isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
|
||||
func isCIDRv6(fl FieldLevel) bool {
|
||||
|
||||
ip, _, err := net.ParseCIDR(fl.Field().String())
|
||||
|
||||
return err == nil && ip.To4() == nil
|
||||
@ -332,7 +346,6 @@ func isCIDRv6(fl FieldLevel) bool {
|
||||
|
||||
// isCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
|
||||
func isCIDR(fl FieldLevel) bool {
|
||||
|
||||
_, _, err := net.ParseCIDR(fl.Field().String())
|
||||
|
||||
return err == nil
|
||||
@ -340,7 +353,6 @@ func isCIDR(fl FieldLevel) bool {
|
||||
|
||||
// isIPv4 is the validation function for validating if a value is a valid v4 IP address.
|
||||
func isIPv4(fl FieldLevel) bool {
|
||||
|
||||
ip := net.ParseIP(fl.Field().String())
|
||||
|
||||
return ip != nil && ip.To4() != nil
|
||||
@ -348,7 +360,6 @@ func isIPv4(fl FieldLevel) bool {
|
||||
|
||||
// isIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
|
||||
func isIPv6(fl FieldLevel) bool {
|
||||
|
||||
ip := net.ParseIP(fl.Field().String())
|
||||
|
||||
return ip != nil && ip.To4() == nil
|
||||
@ -356,7 +367,6 @@ func isIPv6(fl FieldLevel) bool {
|
||||
|
||||
// isIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
|
||||
func isIP(fl FieldLevel) bool {
|
||||
|
||||
ip := net.ParseIP(fl.Field().String())
|
||||
|
||||
return ip != nil
|
||||
@ -364,7 +374,6 @@ func isIP(fl FieldLevel) bool {
|
||||
|
||||
// isSSN is the validation function for validating if the field's value is a valid SSN.
|
||||
func isSSN(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
|
||||
if field.Len() != 11 {
|
||||
@ -422,7 +431,6 @@ func isLatitude(fl FieldLevel) bool {
|
||||
|
||||
// isDataURI is the validation function for validating if the field's value is a valid data URI.
|
||||
func isDataURI(fl FieldLevel) bool {
|
||||
|
||||
uri := strings.SplitN(fl.Field().String(), ",", 2)
|
||||
|
||||
if len(uri) != 2 {
|
||||
@ -438,7 +446,6 @@ func isDataURI(fl FieldLevel) bool {
|
||||
|
||||
// hasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
|
||||
func hasMultiByteCharacter(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
|
||||
if field.Len() == 0 {
|
||||
@ -498,6 +505,61 @@ func isUUIDRFC4122(fl FieldLevel) bool {
|
||||
return uUIDRFC4122Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isULID is the validation function for validating if the field's value is a valid ULID.
|
||||
func isULID(fl FieldLevel) bool {
|
||||
return uLIDRegex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isMD4 is the validation function for validating if the field's value is a valid MD4.
|
||||
func isMD4(fl FieldLevel) bool {
|
||||
return md4Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isMD5 is the validation function for validating if the field's value is a valid MD5.
|
||||
func isMD5(fl FieldLevel) bool {
|
||||
return md5Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isSHA256 is the validation function for validating if the field's value is a valid SHA256.
|
||||
func isSHA256(fl FieldLevel) bool {
|
||||
return sha256Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isSHA384 is the validation function for validating if the field's value is a valid SHA384.
|
||||
func isSHA384(fl FieldLevel) bool {
|
||||
return sha384Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isSHA512 is the validation function for validating if the field's value is a valid SHA512.
|
||||
func isSHA512(fl FieldLevel) bool {
|
||||
return sha512Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isRIPEMD128 is the validation function for validating if the field's value is a valid PIPEMD128.
|
||||
func isRIPEMD128(fl FieldLevel) bool {
|
||||
return ripemd128Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isRIPEMD160 is the validation function for validating if the field's value is a valid PIPEMD160.
|
||||
func isRIPEMD160(fl FieldLevel) bool {
|
||||
return ripemd160Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isTIGER128 is the validation function for validating if the field's value is a valid TIGER128.
|
||||
func isTIGER128(fl FieldLevel) bool {
|
||||
return tiger128Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isTIGER160 is the validation function for validating if the field's value is a valid TIGER160.
|
||||
func isTIGER160(fl FieldLevel) bool {
|
||||
return tiger160Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isTIGER192 is the validation function for validating if the field's value is a valid isTIGER192.
|
||||
func isTIGER192(fl FieldLevel) bool {
|
||||
return tiger192Regex.MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
// isISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
|
||||
func isISBN(fl FieldLevel) bool {
|
||||
return isISBN10(fl) || isISBN13(fl)
|
||||
@ -505,7 +567,6 @@ func isISBN(fl FieldLevel) bool {
|
||||
|
||||
// isISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
|
||||
func isISBN13(fl FieldLevel) bool {
|
||||
|
||||
s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4)
|
||||
|
||||
if !iSBN13Regex.MatchString(s) {
|
||||
@ -526,7 +587,6 @@ func isISBN13(fl FieldLevel) bool {
|
||||
|
||||
// isISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
|
||||
func isISBN10(fl FieldLevel) bool {
|
||||
|
||||
s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3)
|
||||
|
||||
if !iSBN10Regex.MatchString(s) {
|
||||
@ -714,7 +774,6 @@ func excludes(fl FieldLevel) bool {
|
||||
|
||||
// containsRune is the validation function for validating that the field's value contains the rune specified within the param.
|
||||
func containsRune(fl FieldLevel) bool {
|
||||
|
||||
r, _ := utf8.DecodeRuneInString(fl.Param())
|
||||
|
||||
return strings.ContainsRune(fl.Field().String(), r)
|
||||
@ -777,7 +836,6 @@ func fieldExcludes(fl FieldLevel) bool {
|
||||
|
||||
// isNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
|
||||
func isNeField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -808,12 +866,7 @@ func isNeField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != currentField.Type() {
|
||||
return true
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
t := currentField.Interface().(time.Time)
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
@ -821,6 +874,10 @@ func isNeField(fl FieldLevel) bool {
|
||||
return !fieldTime.Equal(t)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != currentField.Type() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String:
|
||||
@ -834,7 +891,6 @@ func isNe(fl FieldLevel) bool {
|
||||
|
||||
// isLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
|
||||
func isLteCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -861,18 +917,18 @@ func isLteCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
topTime := topField.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != topField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
topTime := topField.Interface().(time.Time)
|
||||
|
||||
return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String:
|
||||
@ -882,7 +938,6 @@ func isLteCrossStructField(fl FieldLevel) bool {
|
||||
// isLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
|
||||
// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
|
||||
func isLtCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -909,18 +964,18 @@ func isLtCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
topTime := topField.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.Before(topTime)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != topField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
topTime := topField.Interface().(time.Time)
|
||||
|
||||
return fieldTime.Before(topTime)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String:
|
||||
@ -929,7 +984,6 @@ func isLtCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
// isGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
|
||||
func isGteCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -956,18 +1010,18 @@ func isGteCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
topTime := topField.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.After(topTime) || fieldTime.Equal(topTime)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != topField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
topTime := topField.Interface().(time.Time)
|
||||
|
||||
return fieldTime.After(topTime) || fieldTime.Equal(topTime)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String:
|
||||
@ -976,7 +1030,6 @@ func isGteCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
// isGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
|
||||
func isGtCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -1003,18 +1056,18 @@ func isGtCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
topTime := topField.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.After(topTime)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != topField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
topTime := topField.Interface().(time.Time)
|
||||
|
||||
return fieldTime.After(topTime)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String:
|
||||
@ -1023,7 +1076,6 @@ func isGtCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
// isNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
|
||||
func isNeCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -1053,18 +1105,18 @@ func isNeCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
t := field.Convert(timeType).Interface().(time.Time)
|
||||
fieldTime := topField.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return !fieldTime.Equal(t)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != topField.Type() {
|
||||
return true
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
t := field.Interface().(time.Time)
|
||||
fieldTime := topField.Interface().(time.Time)
|
||||
|
||||
return !fieldTime.Equal(t)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String:
|
||||
@ -1073,7 +1125,6 @@ func isNeCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
// isEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
|
||||
func isEqCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -1103,18 +1154,18 @@ func isEqCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
t := field.Convert(timeType).Interface().(time.Time)
|
||||
fieldTime := topField.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.Equal(t)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != topField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
t := field.Interface().(time.Time)
|
||||
fieldTime := topField.Interface().(time.Time)
|
||||
|
||||
return fieldTime.Equal(t)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String:
|
||||
@ -1123,7 +1174,6 @@ func isEqCrossStructField(fl FieldLevel) bool {
|
||||
|
||||
// isEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
|
||||
func isEqField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -1153,19 +1203,18 @@ func isEqField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != currentField.Type() {
|
||||
return false
|
||||
}
|
||||
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
t := currentField.Interface().(time.Time)
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
t := currentField.Convert(timeType).Interface().(time.Time)
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.Equal(t)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != currentField.Type() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String:
|
||||
@ -1174,7 +1223,6 @@ func isEqField(fl FieldLevel) bool {
|
||||
|
||||
// isEq is the validation function for validating if the current field's value is equal to the param's value.
|
||||
func isEq(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
param := fl.Param()
|
||||
|
||||
@ -1226,7 +1274,7 @@ func isPostcodeByIso3166Alpha2(fl FieldLevel) bool {
|
||||
return reg.MatchString(field.String())
|
||||
}
|
||||
|
||||
// isPostcodeByIso3166Alpha2 validates by field which represents for a value of country code in iso 3166 alpha 2
|
||||
// isPostcodeByIso3166Alpha2Field validates by field which represents for a value of country code in iso 3166 alpha 2
|
||||
// example: `postcode_iso3166_alpha2_field=CountryCode`
|
||||
func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool {
|
||||
field := fl.Field()
|
||||
@ -1265,11 +1313,9 @@ func isBase64URL(fl FieldLevel) bool {
|
||||
|
||||
// isURI is the validation function for validating if the current field's value is a valid URI.
|
||||
func isURI(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
|
||||
switch field.Kind() {
|
||||
|
||||
case reflect.String:
|
||||
|
||||
s := field.String()
|
||||
@ -1294,11 +1340,9 @@ func isURI(fl FieldLevel) bool {
|
||||
|
||||
// isURL is the validation function for validating if the current field's value is a valid URL.
|
||||
func isURL(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
|
||||
switch field.Kind() {
|
||||
|
||||
case reflect.String:
|
||||
|
||||
var i int
|
||||
@ -1331,7 +1375,6 @@ func isUrnRFC2141(fl FieldLevel) bool {
|
||||
field := fl.Field()
|
||||
|
||||
switch field.Kind() {
|
||||
|
||||
case reflect.String:
|
||||
|
||||
str := field.String()
|
||||
@ -1534,6 +1577,22 @@ func requiredIf(fl FieldLevel) bool {
|
||||
return hasValue(fl)
|
||||
}
|
||||
|
||||
// excludedIf is the validation function
|
||||
// The field under validation must not be present or is empty only if all the other specified fields are equal to the value following with the specified field.
|
||||
func excludedIf(fl FieldLevel) bool {
|
||||
params := parseOneOfParam2(fl.Param())
|
||||
if len(params)%2 != 0 {
|
||||
panic(fmt.Sprintf("Bad param number for excluded_if %s", fl.FieldName()))
|
||||
}
|
||||
|
||||
for i := 0; i < len(params); i += 2 {
|
||||
if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// requiredUnless is the validation function
|
||||
// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field.
|
||||
func requiredUnless(fl FieldLevel) bool {
|
||||
@ -1550,6 +1609,21 @@ func requiredUnless(fl FieldLevel) bool {
|
||||
return hasValue(fl)
|
||||
}
|
||||
|
||||
// excludedUnless is the validation function
|
||||
// The field under validation must not be present or is empty unless all the other specified fields are equal to the value following with the specified field.
|
||||
func excludedUnless(fl FieldLevel) bool {
|
||||
params := parseOneOfParam2(fl.Param())
|
||||
if len(params)%2 != 0 {
|
||||
panic(fmt.Sprintf("Bad param number for excluded_unless %s", fl.FieldName()))
|
||||
}
|
||||
for i := 0; i < len(params); i += 2 {
|
||||
if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return !hasValue(fl)
|
||||
}
|
||||
|
||||
// excludedWith is the validation function
|
||||
// The field under validation must not be present or is empty if any of the other specified fields are present.
|
||||
func excludedWith(fl FieldLevel) bool {
|
||||
@ -1642,7 +1716,6 @@ func requiredWithoutAll(fl FieldLevel) bool {
|
||||
|
||||
// isGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
|
||||
func isGteField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -1669,18 +1742,18 @@ func isGteField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
t := currentField.Convert(timeType).Interface().(time.Time)
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.After(t) || fieldTime.Equal(t)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != currentField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
t := currentField.Interface().(time.Time)
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
|
||||
return fieldTime.After(t) || fieldTime.Equal(t)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String
|
||||
@ -1689,7 +1762,6 @@ func isGteField(fl FieldLevel) bool {
|
||||
|
||||
// isGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
|
||||
func isGtField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -1716,18 +1788,18 @@ func isGtField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
t := currentField.Convert(timeType).Interface().(time.Time)
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.After(t)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != currentField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
t := currentField.Interface().(time.Time)
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
|
||||
return fieldTime.After(t)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String
|
||||
@ -1736,7 +1808,6 @@ func isGtField(fl FieldLevel) bool {
|
||||
|
||||
// isGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
|
||||
func isGte(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
param := fl.Param()
|
||||
|
||||
@ -1769,10 +1840,10 @@ func isGte(fl FieldLevel) bool {
|
||||
|
||||
case reflect.Struct:
|
||||
|
||||
if field.Type() == timeType {
|
||||
if field.Type().ConvertibleTo(timeType) {
|
||||
|
||||
now := time.Now().UTC()
|
||||
t := field.Interface().(time.Time)
|
||||
t := field.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return t.After(now) || t.Equal(now)
|
||||
}
|
||||
@ -1783,7 +1854,6 @@ func isGte(fl FieldLevel) bool {
|
||||
|
||||
// isGt is the validation function for validating if the current field's value is greater than the param's value.
|
||||
func isGt(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
param := fl.Param()
|
||||
|
||||
@ -1815,9 +1885,9 @@ func isGt(fl FieldLevel) bool {
|
||||
return field.Float() > p
|
||||
case reflect.Struct:
|
||||
|
||||
if field.Type() == timeType {
|
||||
if field.Type().ConvertibleTo(timeType) {
|
||||
|
||||
return field.Interface().(time.Time).After(time.Now().UTC())
|
||||
return field.Convert(timeType).Interface().(time.Time).After(time.Now().UTC())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1826,7 +1896,6 @@ func isGt(fl FieldLevel) bool {
|
||||
|
||||
// hasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
|
||||
func hasLengthOf(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
param := fl.Param()
|
||||
|
||||
@ -1868,7 +1937,6 @@ func hasMinOf(fl FieldLevel) bool {
|
||||
|
||||
// isLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
|
||||
func isLteField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -1895,18 +1963,18 @@ func isLteField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
t := currentField.Convert(timeType).Interface().(time.Time)
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.Before(t) || fieldTime.Equal(t)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != currentField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
t := currentField.Interface().(time.Time)
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
|
||||
return fieldTime.Before(t) || fieldTime.Equal(t)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String
|
||||
@ -1915,7 +1983,6 @@ func isLteField(fl FieldLevel) bool {
|
||||
|
||||
// isLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
|
||||
func isLtField(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
kind := field.Kind()
|
||||
|
||||
@ -1942,18 +2009,18 @@ func isLtField(fl FieldLevel) bool {
|
||||
|
||||
fieldType := field.Type()
|
||||
|
||||
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
|
||||
|
||||
t := currentField.Convert(timeType).Interface().(time.Time)
|
||||
fieldTime := field.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return fieldTime.Before(t)
|
||||
}
|
||||
|
||||
// Not Same underlying type i.e. struct and time
|
||||
if fieldType != currentField.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldType == timeType {
|
||||
|
||||
t := currentField.Interface().(time.Time)
|
||||
fieldTime := field.Interface().(time.Time)
|
||||
|
||||
return fieldTime.Before(t)
|
||||
}
|
||||
}
|
||||
|
||||
// default reflect.String
|
||||
@ -1962,7 +2029,6 @@ func isLtField(fl FieldLevel) bool {
|
||||
|
||||
// isLte is the validation function for validating if the current field's value is less than or equal to the param's value.
|
||||
func isLte(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
param := fl.Param()
|
||||
|
||||
@ -1995,10 +2061,10 @@ func isLte(fl FieldLevel) bool {
|
||||
|
||||
case reflect.Struct:
|
||||
|
||||
if field.Type() == timeType {
|
||||
if field.Type().ConvertibleTo(timeType) {
|
||||
|
||||
now := time.Now().UTC()
|
||||
t := field.Interface().(time.Time)
|
||||
t := field.Convert(timeType).Interface().(time.Time)
|
||||
|
||||
return t.Before(now) || t.Equal(now)
|
||||
}
|
||||
@ -2009,7 +2075,6 @@ func isLte(fl FieldLevel) bool {
|
||||
|
||||
// isLt is the validation function for validating if the current field's value is less than the param's value.
|
||||
func isLt(fl FieldLevel) bool {
|
||||
|
||||
field := fl.Field()
|
||||
param := fl.Param()
|
||||
|
||||
@ -2042,9 +2107,9 @@ func isLt(fl FieldLevel) bool {
|
||||
|
||||
case reflect.Struct:
|
||||
|
||||
if field.Type() == timeType {
|
||||
if field.Type().ConvertibleTo(timeType) {
|
||||
|
||||
return field.Interface().(time.Time).Before(time.Now().UTC())
|
||||
return field.Convert(timeType).Interface().(time.Time).Before(time.Now().UTC())
|
||||
}
|
||||
}
|
||||
|
||||
@ -2058,7 +2123,6 @@ func hasMaxOf(fl FieldLevel) bool {
|
||||
|
||||
// isTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
|
||||
func isTCP4AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIP4Addr(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2069,7 +2133,6 @@ func isTCP4AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
|
||||
func isTCP6AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIP6Addr(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2081,7 +2144,6 @@ func isTCP6AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
|
||||
func isTCPAddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIP4Addr(fl) && !isIP6Addr(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2093,7 +2155,6 @@ func isTCPAddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
|
||||
func isUDP4AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIP4Addr(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2105,7 +2166,6 @@ func isUDP4AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
|
||||
func isUDP6AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIP6Addr(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2117,7 +2177,6 @@ func isUDP6AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
|
||||
func isUDPAddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIP4Addr(fl) && !isIP6Addr(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2129,7 +2188,6 @@ func isUDPAddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
|
||||
func isIP4AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIPv4(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2141,7 +2199,6 @@ func isIP4AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
|
||||
func isIP6AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIPv6(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2153,7 +2210,6 @@ func isIP6AddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
|
||||
func isIPAddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
if !isIP(fl) {
|
||||
return false
|
||||
}
|
||||
@ -2165,14 +2221,12 @@ func isIPAddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
// isUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
|
||||
func isUnixAddrResolvable(fl FieldLevel) bool {
|
||||
|
||||
_, err := net.ResolveUnixAddr("unix", fl.Field().String())
|
||||
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func isIP4Addr(fl FieldLevel) bool {
|
||||
|
||||
val := fl.Field().String()
|
||||
|
||||
if idx := strings.LastIndex(val, ":"); idx != -1 {
|
||||
@ -2185,7 +2239,6 @@ func isIP4Addr(fl FieldLevel) bool {
|
||||
}
|
||||
|
||||
func isIP6Addr(fl FieldLevel) bool {
|
||||
|
||||
val := fl.Field().String()
|
||||
|
||||
if idx := strings.LastIndex(val, ":"); idx != -1 {
|
||||
@ -2351,6 +2404,12 @@ func isIso3166AlphaNumeric(fl FieldLevel) bool {
|
||||
|
||||
var code int
|
||||
switch field.Kind() {
|
||||
case reflect.String:
|
||||
i, err := strconv.Atoi(field.String())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
code = i % 1000
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
code = int(field.Int() % 1000)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
@ -2407,3 +2466,56 @@ func isIsoBicFormat(fl FieldLevel) bool {
|
||||
|
||||
return bicRegex.MatchString(bicString)
|
||||
}
|
||||
|
||||
// isSemverFormat is the validation function for validating if the current field's value is a valid semver version, defined in Semantic Versioning 2.0.0
|
||||
func isSemverFormat(fl FieldLevel) bool {
|
||||
semverString := fl.Field().String()
|
||||
|
||||
return semverRegex.MatchString(semverString)
|
||||
}
|
||||
|
||||
// isDnsRFC1035LabelFormat is the validation function
|
||||
// for validating if the current field's value is
|
||||
// a valid dns RFC 1035 label, defined in RFC 1035.
|
||||
func isDnsRFC1035LabelFormat(fl FieldLevel) bool {
|
||||
val := fl.Field().String()
|
||||
return dnsRegexRFC1035Label.MatchString(val)
|
||||
}
|
||||
|
||||
// isCreditCard is the validation function for validating if the current field's value is a valid credit card number
|
||||
func isCreditCard(fl FieldLevel) bool {
|
||||
val := fl.Field().String()
|
||||
var creditCard bytes.Buffer
|
||||
segments := strings.Split(val, " ")
|
||||
for _, segment := range segments {
|
||||
if len(segment) < 3 {
|
||||
return false
|
||||
}
|
||||
creditCard.WriteString(segment)
|
||||
}
|
||||
|
||||
ccDigits := strings.Split(creditCard.String(), "")
|
||||
size := len(ccDigits)
|
||||
if size < 12 || size > 19 {
|
||||
return false
|
||||
}
|
||||
|
||||
sum := 0
|
||||
for i, digit := range ccDigits {
|
||||
value, err := strconv.Atoi(digit)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 {
|
||||
v := value * 2
|
||||
if v >= 10 {
|
||||
sum += 1 + (v % 10)
|
||||
} else {
|
||||
sum += v
|
||||
}
|
||||
} else {
|
||||
sum += value
|
||||
}
|
||||
}
|
||||
return (sum % 10) == 0
|
||||
}
|
||||
|
9
vendor/github.com/go-playground/validator/v10/cache.go
generated
vendored
9
vendor/github.com/go-playground/validator/v10/cache.go
generated
vendored
@ -114,12 +114,13 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
|
||||
cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]}
|
||||
|
||||
numFields := current.NumField()
|
||||
rules := v.rules[typ]
|
||||
|
||||
var ctag *cTag
|
||||
var fld reflect.StructField
|
||||
var tag string
|
||||
var customName string
|
||||
|
||||
|
||||
for i := 0; i < numFields; i++ {
|
||||
|
||||
fld = typ.Field(i)
|
||||
@ -128,7 +129,11 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
|
||||
continue
|
||||
}
|
||||
|
||||
tag = fld.Tag.Get(v.tagName)
|
||||
if rtag, ok := rules[fld.Name]; ok {
|
||||
tag = rtag
|
||||
} else {
|
||||
tag = fld.Tag.Get(v.tagName)
|
||||
}
|
||||
|
||||
if tag == skipValidationTag {
|
||||
continue
|
||||
|
59
vendor/github.com/go-playground/validator/v10/doc.go
generated
vendored
59
vendor/github.com/go-playground/validator/v10/doc.go
generated
vendored
@ -349,6 +349,40 @@ Example:
|
||||
// require the field if the Field1 and Field2 is not present:
|
||||
Usage: required_without_all=Field1 Field2
|
||||
|
||||
Excluded If
|
||||
|
||||
The field under validation must not be present or not empty only if all
|
||||
the other specified fields are equal to the value following the specified
|
||||
field. For strings ensures value is not "". For slices, maps, pointers,
|
||||
interfaces, channels and functions ensures the value is not nil.
|
||||
|
||||
Usage: excluded_if
|
||||
|
||||
Examples:
|
||||
|
||||
// exclude the field if the Field1 is equal to the parameter given:
|
||||
Usage: excluded_if=Field1 foobar
|
||||
|
||||
// exclude the field if the Field1 and Field2 is equal to the value respectively:
|
||||
Usage: excluded_if=Field1 foo Field2 bar
|
||||
|
||||
Excluded Unless
|
||||
|
||||
The field under validation must not be present or empty unless all
|
||||
the other specified fields are equal to the value following the specified
|
||||
field. For strings ensures value is not "". For slices, maps, pointers,
|
||||
interfaces, channels and functions ensures the value is not nil.
|
||||
|
||||
Usage: excluded_unless
|
||||
|
||||
Examples:
|
||||
|
||||
// exclude the field unless the Field1 is equal to the parameter given:
|
||||
Usage: excluded_unless=Field1 foobar
|
||||
|
||||
// exclude the field unless the Field1 and Field2 is equal to the value respectively:
|
||||
Usage: excluded_unless=Field1 foo Field2 bar
|
||||
|
||||
Is Default
|
||||
|
||||
This validates that the value is the default value and is almost the
|
||||
@ -1007,6 +1041,12 @@ This validates that a string value contains a valid version 5 UUID. Uppercase U
|
||||
|
||||
Usage: uuid5
|
||||
|
||||
Universally Unique Lexicographically Sortable Identifier ULID
|
||||
|
||||
This validates that a string value contains a valid ULID value.
|
||||
|
||||
Usage: ulid
|
||||
|
||||
ASCII
|
||||
|
||||
This validates that a string value contains only ASCII characters.
|
||||
@ -1255,6 +1295,13 @@ More information on https://www.iso.org/standard/60390.html
|
||||
|
||||
Usage: bic
|
||||
|
||||
RFC 1035 label
|
||||
|
||||
This validates that a string value is a valid dns RFC 1035 label, defined in RFC 1035.
|
||||
More information on https://datatracker.ietf.org/doc/html/rfc1035
|
||||
|
||||
Usage: dns_rfc1035_label
|
||||
|
||||
TimeZone
|
||||
|
||||
This validates that a string value is a valid time zone based on the time zone database present on the system.
|
||||
@ -1263,6 +1310,18 @@ More information on https://golang.org/pkg/time/#LoadLocation
|
||||
|
||||
Usage: timezone
|
||||
|
||||
Semantic Version
|
||||
|
||||
This validates that a string value is a valid semver version, defined in Semantic Versioning 2.0.0.
|
||||
More information on https://semver.org/
|
||||
|
||||
Usage: semver
|
||||
|
||||
Credit Card
|
||||
|
||||
This validates that a string value contains a valid credit card number using Luhn algoritm.
|
||||
|
||||
Usage: credit_card
|
||||
|
||||
Alias Validators and Tags
|
||||
|
||||
|
40
vendor/github.com/go-playground/validator/v10/regexes.go
generated
vendored
40
vendor/github.com/go-playground/validator/v10/regexes.go
generated
vendored
@ -10,7 +10,7 @@ const (
|
||||
numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
|
||||
numberRegexString = "^[0-9]+$"
|
||||
hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$"
|
||||
hexColorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
|
||||
hexColorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
|
||||
rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$"
|
||||
rgbaRegexString = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
|
||||
hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$"
|
||||
@ -29,6 +29,17 @@ const (
|
||||
uUID4RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
|
||||
uUID5RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
|
||||
uUIDRFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
|
||||
uLIDRegexString = "^[A-HJKMNP-TV-Z0-9]{26}$"
|
||||
md4RegexString = "^[0-9a-f]{32}$"
|
||||
md5RegexString = "^[0-9a-f]{32}$"
|
||||
sha256RegexString = "^[0-9a-f]{64}$"
|
||||
sha384RegexString = "^[0-9a-f]{96}$"
|
||||
sha512RegexString = "^[0-9a-f]{128}$"
|
||||
ripemd128RegexString = "^[0-9a-f]{32}$"
|
||||
ripemd160RegexString = "^[0-9a-f]{40}$"
|
||||
tiger128RegexString = "^[0-9a-f]{32}$"
|
||||
tiger160RegexString = "^[0-9a-f]{40}$"
|
||||
tiger192RegexString = "^[0-9a-f]{48}$"
|
||||
aSCIIRegexString = "^[\x00-\x7F]*$"
|
||||
printableASCIIRegexString = "^[\x20-\x7E]*$"
|
||||
multibyteRegexString = "[^\x00-\x7F]"
|
||||
@ -36,12 +47,12 @@ const (
|
||||
latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
|
||||
longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
|
||||
sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$`
|
||||
hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952
|
||||
hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
|
||||
fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62})(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.')
|
||||
btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address
|
||||
btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
|
||||
btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
|
||||
hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952
|
||||
hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62}){1}(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
|
||||
fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.')
|
||||
btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address
|
||||
btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
|
||||
btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
|
||||
ethAddressRegexString = `^0x[0-9a-fA-F]{40}$`
|
||||
ethAddressUpperRegexString = `^0x[0-9A-F]{40}$`
|
||||
ethAddressLowerRegexString = `^0x[0-9a-f]{40}$`
|
||||
@ -51,6 +62,8 @@ const (
|
||||
jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$"
|
||||
splitParamsRegexString = `'[^']*'|\S+`
|
||||
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
|
||||
semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/
|
||||
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -80,6 +93,17 @@ var (
|
||||
uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString)
|
||||
uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString)
|
||||
uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString)
|
||||
uLIDRegex = regexp.MustCompile(uLIDRegexString)
|
||||
md4Regex = regexp.MustCompile(md4RegexString)
|
||||
md5Regex = regexp.MustCompile(md5RegexString)
|
||||
sha256Regex = regexp.MustCompile(sha256RegexString)
|
||||
sha384Regex = regexp.MustCompile(sha384RegexString)
|
||||
sha512Regex = regexp.MustCompile(sha512RegexString)
|
||||
ripemd128Regex = regexp.MustCompile(ripemd128RegexString)
|
||||
ripemd160Regex = regexp.MustCompile(ripemd160RegexString)
|
||||
tiger128Regex = regexp.MustCompile(tiger128RegexString)
|
||||
tiger160Regex = regexp.MustCompile(tiger160RegexString)
|
||||
tiger192Regex = regexp.MustCompile(tiger192RegexString)
|
||||
aSCIIRegex = regexp.MustCompile(aSCIIRegexString)
|
||||
printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString)
|
||||
multibyteRegex = regexp.MustCompile(multibyteRegexString)
|
||||
@ -102,4 +126,6 @@ var (
|
||||
jWTRegex = regexp.MustCompile(jWTRegexString)
|
||||
splitParamsRegex = regexp.MustCompile(splitParamsRegexString)
|
||||
bicRegex = regexp.MustCompile(bicRegexString)
|
||||
semverRegex = regexp.MustCompile(semverRegexString)
|
||||
dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label)
|
||||
)
|
||||
|
2
vendor/github.com/go-playground/validator/v10/util.go
generated
vendored
2
vendor/github.com/go-playground/validator/v10/util.go
generated
vendored
@ -82,7 +82,7 @@ BEGIN:
|
||||
fld := namespace
|
||||
var ns string
|
||||
|
||||
if typ != timeType {
|
||||
if !typ.ConvertibleTo(timeType) {
|
||||
|
||||
idx := strings.Index(namespace, namespaceSeparator)
|
||||
|
||||
|
11
vendor/github.com/go-playground/validator/v10/validator.go
generated
vendored
11
vendor/github.com/go-playground/validator/v10/validator.go
generated
vendored
@ -164,7 +164,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
|
||||
|
||||
typ = current.Type()
|
||||
|
||||
if typ != timeType {
|
||||
if !typ.ConvertibleTo(timeType) {
|
||||
|
||||
if ct != nil {
|
||||
|
||||
@ -355,6 +355,10 @@ OUTER:
|
||||
v.ct = ct
|
||||
|
||||
if ct.fn(ctx, v) {
|
||||
if ct.isBlockEnd {
|
||||
ct = ct.next
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
// drain rest of the 'or' values, then continue or leave
|
||||
for {
|
||||
@ -368,6 +372,11 @@ OUTER:
|
||||
if ct.typeof != typeOr {
|
||||
continue OUTER
|
||||
}
|
||||
|
||||
if ct.isBlockEnd {
|
||||
ct = ct.next
|
||||
continue OUTER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
69
vendor/github.com/go-playground/validator/v10/validator_instance.go
generated
vendored
69
vendor/github.com/go-playground/validator/v10/validator_instance.go
generated
vendored
@ -33,6 +33,8 @@ const (
|
||||
excludedWithoutTag = "excluded_without"
|
||||
excludedWithTag = "excluded_with"
|
||||
excludedWithAllTag = "excluded_with_all"
|
||||
excludedIfTag = "excluded_if"
|
||||
excludedUnlessTag = "excluded_unless"
|
||||
skipValidationTag = "-"
|
||||
diveTag = "dive"
|
||||
keysTag = "keys"
|
||||
@ -84,6 +86,7 @@ type Validate struct {
|
||||
aliases map[string]string
|
||||
validations map[string]internalValidationFuncWrapper
|
||||
transTagFunc map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
|
||||
rules map[reflect.Type]map[string]string
|
||||
tagCache *tagCache
|
||||
structCache *structCache
|
||||
}
|
||||
@ -120,7 +123,7 @@ func New() *Validate {
|
||||
switch k {
|
||||
// these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour
|
||||
case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag,
|
||||
excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
|
||||
excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
|
||||
_ = v.registerValidation(k, wrapFunc(val), true, true)
|
||||
default:
|
||||
// no need to error check here, baked in will always be valid
|
||||
@ -152,15 +155,24 @@ func (v *Validate) SetTagName(name string) {
|
||||
func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
|
||||
errs := make(map[string]interface{})
|
||||
for field, rule := range rules {
|
||||
if reflect.ValueOf(rule).Kind() == reflect.Map && reflect.ValueOf(data[field]).Kind() == reflect.Map {
|
||||
err := v.ValidateMapCtx(ctx, data[field].(map[string]interface{}), rule.(map[string]interface{}))
|
||||
if len(err) > 0 {
|
||||
errs[field] = err
|
||||
if ruleObj, ok := rule.(map[string]interface{}); ok {
|
||||
if dataObj, ok := data[field].(map[string]interface{}); ok {
|
||||
err := v.ValidateMapCtx(ctx, dataObj, ruleObj)
|
||||
if len(err) > 0 {
|
||||
errs[field] = err
|
||||
}
|
||||
} else if dataObjs, ok := data[field].([]map[string]interface{}); ok {
|
||||
for _, obj := range dataObjs {
|
||||
err := v.ValidateMapCtx(ctx, obj, ruleObj)
|
||||
if len(err) > 0 {
|
||||
errs[field] = err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
|
||||
}
|
||||
} else if reflect.ValueOf(rule).Kind() == reflect.Map {
|
||||
errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
|
||||
} else {
|
||||
err := v.VarCtx(ctx, data[field], rule.(string))
|
||||
} else if ruleStr, ok := rule.(string); ok {
|
||||
err := v.VarCtx(ctx, data[field], ruleStr)
|
||||
if err != nil {
|
||||
errs[field] = err
|
||||
}
|
||||
@ -169,7 +181,7 @@ func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{
|
||||
return errs
|
||||
}
|
||||
|
||||
// ValidateMap validates map data form a map of tags
|
||||
// ValidateMap validates map data from a map of tags
|
||||
func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
|
||||
return v.ValidateMapCtx(context.Background(), data, rules)
|
||||
}
|
||||
@ -180,6 +192,7 @@ func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]int
|
||||
//
|
||||
// validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
||||
// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
|
||||
// // skip if tag key says it should be ignored
|
||||
// if name == "-" {
|
||||
// return ""
|
||||
// }
|
||||
@ -271,6 +284,34 @@ func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...i
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterStructValidationMapRules registers validate map rules.
|
||||
// Be aware that map validation rules supersede those defined on a/the struct if present.
|
||||
//
|
||||
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
|
||||
func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) {
|
||||
if v.rules == nil {
|
||||
v.rules = make(map[reflect.Type]map[string]string)
|
||||
}
|
||||
|
||||
deepCopyRules := make(map[string]string)
|
||||
for i, rule := range rules {
|
||||
deepCopyRules[i] = rule
|
||||
}
|
||||
|
||||
for _, t := range types {
|
||||
typ := reflect.TypeOf(t)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
|
||||
if typ.Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
v.rules[typ] = deepCopyRules
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
|
||||
//
|
||||
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
|
||||
@ -331,7 +372,7 @@ func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct || val.Type() == timeType {
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
|
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)}
|
||||
}
|
||||
|
||||
@ -376,7 +417,7 @@ func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn Filt
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct || val.Type() == timeType {
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
|
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)}
|
||||
}
|
||||
|
||||
@ -424,7 +465,7 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields .
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct || val.Type() == timeType {
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
|
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)}
|
||||
}
|
||||
|
||||
@ -514,7 +555,7 @@ func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ..
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if val.Kind() != reflect.Struct || val.Type() == timeType {
|
||||
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
|
||||
return &InvalidValidationError{Type: reflect.TypeOf(s)}
|
||||
}
|
||||
|
||||
|
39
vendor/github.com/gorilla/websocket/README.md
generated
vendored
39
vendor/github.com/gorilla/websocket/README.md
generated
vendored
@ -6,6 +6,13 @@
|
||||
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
|
||||
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
|
||||
|
||||
|
||||
---
|
||||
|
||||
⚠️ **[The Gorilla WebSocket Package is looking for a new maintainer](https://github.com/gorilla/websocket/issues/370)**
|
||||
|
||||
---
|
||||
|
||||
### Documentation
|
||||
|
||||
* [API Reference](https://pkg.go.dev/github.com/gorilla/websocket?tab=doc)
|
||||
@ -30,35 +37,3 @@ The Gorilla WebSocket package passes the server tests in the [Autobahn Test
|
||||
Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [examples/autobahn
|
||||
subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn).
|
||||
|
||||
### Gorilla WebSocket compared with other packages
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><a href="http://godoc.org/github.com/gorilla/websocket">github.com/gorilla</a></th>
|
||||
<th><a href="http://godoc.org/golang.org/x/net/websocket">golang.org/x/net</a></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr>
|
||||
<tr><td>Passes <a href="https://github.com/crossbario/autobahn-testsuite">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr>
|
||||
<tr><td>Receive <a href="https://tools.ietf.org/html/rfc6455#section-5.4">fragmented</a> message<td>Yes</td><td><a href="https://code.google.com/p/go/issues/detail?id=7632">No</a>, see note 1</td></tr>
|
||||
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close</a> message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=4588">No</a></td></tr>
|
||||
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr>
|
||||
<tr><td>Get the <a href="https://tools.ietf.org/html/rfc6455#section-5.6">type</a> of a received data message</td><td>Yes</td><td>Yes, see note 2</td></tr>
|
||||
<tr><td colspan="3">Other Features</tr></td>
|
||||
<tr><td><a href="https://tools.ietf.org/html/rfc7692">Compression Extensions</a></td><td>Experimental</td><td>No</td></tr>
|
||||
<tr><td>Read message using io.Reader</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextReader">Yes</a></td><td>No, see note 3</td></tr>
|
||||
<tr><td>Write message using io.WriteCloser</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextWriter">Yes</a></td><td>No, see note 3</td></tr>
|
||||
</table>
|
||||
|
||||
Notes:
|
||||
|
||||
1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
|
||||
2. The application can get the type of a received data message by implementing
|
||||
a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal)
|
||||
function.
|
||||
3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
|
||||
Read returns when the input buffer is full or a frame boundary is
|
||||
encountered. Each call to Write sends a single frame message. The Gorilla
|
||||
io.Reader and io.WriteCloser operate on a single WebSocket message.
|
||||
|
||||
|
77
vendor/github.com/gorilla/websocket/client.go
generated
vendored
77
vendor/github.com/gorilla/websocket/client.go
generated
vendored
@ -48,15 +48,23 @@ func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufS
|
||||
}
|
||||
|
||||
// A Dialer contains options for connecting to WebSocket server.
|
||||
//
|
||||
// It is safe to call Dialer's methods concurrently.
|
||||
type Dialer struct {
|
||||
// NetDial specifies the dial function for creating TCP connections. If
|
||||
// NetDial is nil, net.Dial is used.
|
||||
NetDial func(network, addr string) (net.Conn, error)
|
||||
|
||||
// NetDialContext specifies the dial function for creating TCP connections. If
|
||||
// NetDialContext is nil, net.DialContext is used.
|
||||
// NetDialContext is nil, NetDial is used.
|
||||
NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
|
||||
// NetDialTLSContext specifies the dial function for creating TLS/TCP connections. If
|
||||
// NetDialTLSContext is nil, NetDialContext is used.
|
||||
// If NetDialTLSContext is set, Dial assumes the TLS handshake is done there and
|
||||
// TLSClientConfig is ignored.
|
||||
NetDialTLSContext func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
|
||||
// Proxy specifies a function to return a proxy for a given
|
||||
// Request. If the function returns a non-nil error, the
|
||||
// request is aborted with the provided error.
|
||||
@ -65,6 +73,8 @@ type Dialer struct {
|
||||
|
||||
// TLSClientConfig specifies the TLS configuration to use with tls.Client.
|
||||
// If nil, the default configuration is used.
|
||||
// If either NetDialTLS or NetDialTLSContext are set, Dial assumes the TLS handshake
|
||||
// is done there and TLSClientConfig is ignored.
|
||||
TLSClientConfig *tls.Config
|
||||
|
||||
// HandshakeTimeout specifies the duration for the handshake to complete.
|
||||
@ -176,7 +186,7 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
|
||||
}
|
||||
|
||||
req := &http.Request{
|
||||
Method: "GET",
|
||||
Method: http.MethodGet,
|
||||
URL: u,
|
||||
Proto: "HTTP/1.1",
|
||||
ProtoMajor: 1,
|
||||
@ -237,13 +247,32 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
|
||||
// Get network dial function.
|
||||
var netDial func(network, add string) (net.Conn, error)
|
||||
|
||||
if d.NetDialContext != nil {
|
||||
netDial = func(network, addr string) (net.Conn, error) {
|
||||
return d.NetDialContext(ctx, network, addr)
|
||||
switch u.Scheme {
|
||||
case "http":
|
||||
if d.NetDialContext != nil {
|
||||
netDial = func(network, addr string) (net.Conn, error) {
|
||||
return d.NetDialContext(ctx, network, addr)
|
||||
}
|
||||
} else if d.NetDial != nil {
|
||||
netDial = d.NetDial
|
||||
}
|
||||
} else if d.NetDial != nil {
|
||||
netDial = d.NetDial
|
||||
} else {
|
||||
case "https":
|
||||
if d.NetDialTLSContext != nil {
|
||||
netDial = func(network, addr string) (net.Conn, error) {
|
||||
return d.NetDialTLSContext(ctx, network, addr)
|
||||
}
|
||||
} else if d.NetDialContext != nil {
|
||||
netDial = func(network, addr string) (net.Conn, error) {
|
||||
return d.NetDialContext(ctx, network, addr)
|
||||
}
|
||||
} else if d.NetDial != nil {
|
||||
netDial = d.NetDial
|
||||
}
|
||||
default:
|
||||
return nil, nil, errMalformedURL
|
||||
}
|
||||
|
||||
if netDial == nil {
|
||||
netDialer := &net.Dialer{}
|
||||
netDial = func(network, addr string) (net.Conn, error) {
|
||||
return netDialer.DialContext(ctx, network, addr)
|
||||
@ -304,7 +333,9 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
|
||||
}
|
||||
}()
|
||||
|
||||
if u.Scheme == "https" {
|
||||
if u.Scheme == "https" && d.NetDialTLSContext == nil {
|
||||
// If NetDialTLSContext is set, assume that the TLS handshake has already been done
|
||||
|
||||
cfg := cloneTLSConfig(d.TLSClientConfig)
|
||||
if cfg.ServerName == "" {
|
||||
cfg.ServerName = hostNoPort
|
||||
@ -312,11 +343,12 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
|
||||
tlsConn := tls.Client(netConn, cfg)
|
||||
netConn = tlsConn
|
||||
|
||||
var err error
|
||||
if trace != nil {
|
||||
err = doHandshakeWithTrace(trace, tlsConn, cfg)
|
||||
} else {
|
||||
err = doHandshake(tlsConn, cfg)
|
||||
if trace != nil && trace.TLSHandshakeStart != nil {
|
||||
trace.TLSHandshakeStart()
|
||||
}
|
||||
err := doHandshake(ctx, tlsConn, cfg)
|
||||
if trace != nil && trace.TLSHandshakeDone != nil {
|
||||
trace.TLSHandshakeDone(tlsConn.ConnectionState(), err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -348,8 +380,8 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
|
||||
}
|
||||
|
||||
if resp.StatusCode != 101 ||
|
||||
!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
|
||||
!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
|
||||
!tokenListContainsValue(resp.Header, "Upgrade", "websocket") ||
|
||||
!tokenListContainsValue(resp.Header, "Connection", "upgrade") ||
|
||||
resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) {
|
||||
// Before closing the network connection on return from this
|
||||
// function, slurp up some of the response to aid application
|
||||
@ -382,14 +414,9 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h
|
||||
return conn, resp, nil
|
||||
}
|
||||
|
||||
func doHandshake(tlsConn *tls.Conn, cfg *tls.Config) error {
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return err
|
||||
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
|
||||
if cfg == nil {
|
||||
return &tls.Config{}
|
||||
}
|
||||
if !cfg.InsecureSkipVerify {
|
||||
if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return cfg.Clone()
|
||||
}
|
||||
|
16
vendor/github.com/gorilla/websocket/client_clone.go
generated
vendored
16
vendor/github.com/gorilla/websocket/client_clone.go
generated
vendored
@ -1,16 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package websocket
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
|
||||
if cfg == nil {
|
||||
return &tls.Config{}
|
||||
}
|
||||
return cfg.Clone()
|
||||
}
|
38
vendor/github.com/gorilla/websocket/client_clone_legacy.go
generated
vendored
38
vendor/github.com/gorilla/websocket/client_clone_legacy.go
generated
vendored
@ -1,38 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.8
|
||||
|
||||
package websocket
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
// cloneTLSConfig clones all public fields except the fields
|
||||
// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
|
||||
// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
|
||||
// config in active use.
|
||||
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
|
||||
if cfg == nil {
|
||||
return &tls.Config{}
|
||||
}
|
||||
return &tls.Config{
|
||||
Rand: cfg.Rand,
|
||||
Time: cfg.Time,
|
||||
Certificates: cfg.Certificates,
|
||||
NameToCertificate: cfg.NameToCertificate,
|
||||
GetCertificate: cfg.GetCertificate,
|
||||
RootCAs: cfg.RootCAs,
|
||||
NextProtos: cfg.NextProtos,
|
||||
ServerName: cfg.ServerName,
|
||||
ClientAuth: cfg.ClientAuth,
|
||||
ClientCAs: cfg.ClientCAs,
|
||||
InsecureSkipVerify: cfg.InsecureSkipVerify,
|
||||
CipherSuites: cfg.CipherSuites,
|
||||
PreferServerCipherSuites: cfg.PreferServerCipherSuites,
|
||||
ClientSessionCache: cfg.ClientSessionCache,
|
||||
MinVersion: cfg.MinVersion,
|
||||
MaxVersion: cfg.MaxVersion,
|
||||
CurvePreferences: cfg.CurvePreferences,
|
||||
}
|
||||
}
|
63
vendor/github.com/gorilla/websocket/conn.go
generated
vendored
63
vendor/github.com/gorilla/websocket/conn.go
generated
vendored
@ -13,6 +13,7 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
@ -401,6 +402,12 @@ func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) writeBufs(bufs ...[]byte) error {
|
||||
b := net.Buffers(bufs)
|
||||
_, err := b.WriteTo(c.conn)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteControl writes a control message with the given deadline. The allowed
|
||||
// message types are CloseMessage, PingMessage and PongMessage.
|
||||
func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error {
|
||||
@ -794,47 +801,69 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||
}
|
||||
|
||||
// 2. Read and parse first two bytes of frame header.
|
||||
// To aid debugging, collect and report all errors in the first two bytes
|
||||
// of the header.
|
||||
|
||||
var errors []string
|
||||
|
||||
p, err := c.read(2)
|
||||
if err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
|
||||
final := p[0]&finalBit != 0
|
||||
frameType := int(p[0] & 0xf)
|
||||
final := p[0]&finalBit != 0
|
||||
rsv1 := p[0]&rsv1Bit != 0
|
||||
rsv2 := p[0]&rsv2Bit != 0
|
||||
rsv3 := p[0]&rsv3Bit != 0
|
||||
mask := p[1]&maskBit != 0
|
||||
c.setReadRemaining(int64(p[1] & 0x7f))
|
||||
|
||||
c.readDecompress = false
|
||||
if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 {
|
||||
c.readDecompress = true
|
||||
p[0] &^= rsv1Bit
|
||||
if rsv1 {
|
||||
if c.newDecompressionReader != nil {
|
||||
c.readDecompress = true
|
||||
} else {
|
||||
errors = append(errors, "RSV1 set")
|
||||
}
|
||||
}
|
||||
|
||||
if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 {
|
||||
return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16))
|
||||
if rsv2 {
|
||||
errors = append(errors, "RSV2 set")
|
||||
}
|
||||
|
||||
if rsv3 {
|
||||
errors = append(errors, "RSV3 set")
|
||||
}
|
||||
|
||||
switch frameType {
|
||||
case CloseMessage, PingMessage, PongMessage:
|
||||
if c.readRemaining > maxControlFramePayloadSize {
|
||||
return noFrame, c.handleProtocolError("control frame length > 125")
|
||||
errors = append(errors, "len > 125 for control")
|
||||
}
|
||||
if !final {
|
||||
return noFrame, c.handleProtocolError("control frame not final")
|
||||
errors = append(errors, "FIN not set on control")
|
||||
}
|
||||
case TextMessage, BinaryMessage:
|
||||
if !c.readFinal {
|
||||
return noFrame, c.handleProtocolError("message start before final message frame")
|
||||
errors = append(errors, "data before FIN")
|
||||
}
|
||||
c.readFinal = final
|
||||
case continuationFrame:
|
||||
if c.readFinal {
|
||||
return noFrame, c.handleProtocolError("continuation after final message frame")
|
||||
errors = append(errors, "continuation after FIN")
|
||||
}
|
||||
c.readFinal = final
|
||||
default:
|
||||
return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType))
|
||||
errors = append(errors, "bad opcode "+strconv.Itoa(frameType))
|
||||
}
|
||||
|
||||
if mask != c.isServer {
|
||||
errors = append(errors, "bad MASK")
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return noFrame, c.handleProtocolError(strings.Join(errors, ", "))
|
||||
}
|
||||
|
||||
// 3. Read and parse frame length as per
|
||||
@ -872,10 +901,6 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||
|
||||
// 4. Handle frame masking.
|
||||
|
||||
if mask != c.isServer {
|
||||
return noFrame, c.handleProtocolError("incorrect mask flag")
|
||||
}
|
||||
|
||||
if mask {
|
||||
c.readMaskPos = 0
|
||||
p, err := c.read(len(c.readMaskKey))
|
||||
@ -935,7 +960,7 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||
if len(payload) >= 2 {
|
||||
closeCode = int(binary.BigEndian.Uint16(payload))
|
||||
if !isValidReceivedCloseCode(closeCode) {
|
||||
return noFrame, c.handleProtocolError("invalid close code")
|
||||
return noFrame, c.handleProtocolError("bad close code " + strconv.Itoa(closeCode))
|
||||
}
|
||||
closeText = string(payload[2:])
|
||||
if !utf8.ValidString(closeText) {
|
||||
@ -952,7 +977,11 @@ func (c *Conn) advanceFrame() (int, error) {
|
||||
}
|
||||
|
||||
func (c *Conn) handleProtocolError(message string) error {
|
||||
c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait))
|
||||
data := FormatCloseMessage(CloseProtocolError, message)
|
||||
if len(data) > maxControlFramePayloadSize {
|
||||
data = data[:maxControlFramePayloadSize]
|
||||
}
|
||||
c.WriteControl(CloseMessage, data, time.Now().Add(writeWait))
|
||||
return errors.New("websocket: " + message)
|
||||
}
|
||||
|
||||
|
15
vendor/github.com/gorilla/websocket/conn_write.go
generated
vendored
15
vendor/github.com/gorilla/websocket/conn_write.go
generated
vendored
@ -1,15 +0,0 @@
|
||||
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package websocket
|
||||
|
||||
import "net"
|
||||
|
||||
func (c *Conn) writeBufs(bufs ...[]byte) error {
|
||||
b := net.Buffers(bufs)
|
||||
_, err := b.WriteTo(c.conn)
|
||||
return err
|
||||
}
|
18
vendor/github.com/gorilla/websocket/conn_write_legacy.go
generated
vendored
18
vendor/github.com/gorilla/websocket/conn_write_legacy.go
generated
vendored
@ -1,18 +0,0 @@
|
||||
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.8
|
||||
|
||||
package websocket
|
||||
|
||||
func (c *Conn) writeBufs(bufs ...[]byte) error {
|
||||
for _, buf := range bufs {
|
||||
if len(buf) > 0 {
|
||||
if _, err := c.conn.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
1
vendor/github.com/gorilla/websocket/mask.go
generated
vendored
1
vendor/github.com/gorilla/websocket/mask.go
generated
vendored
@ -2,6 +2,7 @@
|
||||
// this source code is governed by a BSD-style license that can be found in the
|
||||
// LICENSE file.
|
||||
|
||||
//go:build !appengine
|
||||
// +build !appengine
|
||||
|
||||
package websocket
|
||||
|
1
vendor/github.com/gorilla/websocket/mask_safe.go
generated
vendored
1
vendor/github.com/gorilla/websocket/mask_safe.go
generated
vendored
@ -2,6 +2,7 @@
|
||||
// this source code is governed by a BSD-style license that can be found in the
|
||||
// LICENSE file.
|
||||
|
||||
//go:build appengine
|
||||
// +build appengine
|
||||
|
||||
package websocket
|
||||
|
2
vendor/github.com/gorilla/websocket/proxy.go
generated
vendored
2
vendor/github.com/gorilla/websocket/proxy.go
generated
vendored
@ -48,7 +48,7 @@ func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error)
|
||||
}
|
||||
|
||||
connectReq := &http.Request{
|
||||
Method: "CONNECT",
|
||||
Method: http.MethodConnect,
|
||||
URL: &url.URL{Opaque: addr},
|
||||
Host: addr,
|
||||
Header: connectHeader,
|
||||
|
8
vendor/github.com/gorilla/websocket/server.go
generated
vendored
8
vendor/github.com/gorilla/websocket/server.go
generated
vendored
@ -23,6 +23,8 @@ func (e HandshakeError) Error() string { return e.message }
|
||||
|
||||
// Upgrader specifies parameters for upgrading an HTTP connection to a
|
||||
// WebSocket connection.
|
||||
//
|
||||
// It is safe to call Upgrader's methods concurrently.
|
||||
type Upgrader struct {
|
||||
// HandshakeTimeout specifies the duration for the handshake to complete.
|
||||
HandshakeTimeout time.Duration
|
||||
@ -115,8 +117,8 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header
|
||||
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
|
||||
//
|
||||
// The responseHeader is included in the response to the client's upgrade
|
||||
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
|
||||
// application negotiated subprotocol (Sec-WebSocket-Protocol).
|
||||
// request. Use the responseHeader to specify cookies (Set-Cookie). To specify
|
||||
// subprotocols supported by the server, set Upgrader.Subprotocols directly.
|
||||
//
|
||||
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
|
||||
// response.
|
||||
@ -131,7 +133,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
|
||||
return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header")
|
||||
}
|
||||
|
||||
if r.Method != "GET" {
|
||||
if r.Method != http.MethodGet {
|
||||
return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")
|
||||
}
|
||||
|
||||
|
21
vendor/github.com/gorilla/websocket/tls_handshake.go
generated
vendored
Normal file
21
vendor/github.com/gorilla/websocket/tls_handshake.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
//go:build go1.17
|
||||
// +build go1.17
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
)
|
||||
|
||||
func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config) error {
|
||||
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if !cfg.InsecureSkipVerify {
|
||||
if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
21
vendor/github.com/gorilla/websocket/tls_handshake_116.go
generated
vendored
Normal file
21
vendor/github.com/gorilla/websocket/tls_handshake_116.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
//go:build !go1.17
|
||||
// +build !go1.17
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
)
|
||||
|
||||
func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config) error {
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !cfg.InsecureSkipVerify {
|
||||
if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
19
vendor/github.com/gorilla/websocket/trace.go
generated
vendored
19
vendor/github.com/gorilla/websocket/trace.go
generated
vendored
@ -1,19 +0,0 @@
|
||||
// +build go1.8
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http/httptrace"
|
||||
)
|
||||
|
||||
func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
|
||||
if trace.TLSHandshakeStart != nil {
|
||||
trace.TLSHandshakeStart()
|
||||
}
|
||||
err := doHandshake(tlsConn, cfg)
|
||||
if trace.TLSHandshakeDone != nil {
|
||||
trace.TLSHandshakeDone(tlsConn.ConnectionState(), err)
|
||||
}
|
||||
return err
|
||||
}
|
12
vendor/github.com/gorilla/websocket/trace_17.go
generated
vendored
12
vendor/github.com/gorilla/websocket/trace_17.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
// +build !go1.8
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http/httptrace"
|
||||
)
|
||||
|
||||
func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
|
||||
return doHandshake(tlsConn, cfg)
|
||||
}
|
12
vendor/github.com/magiconair/properties/lex.go
generated
vendored
12
vendor/github.com/magiconair/properties/lex.go
generated
vendored
@ -128,18 +128,6 @@ func (l *lexer) acceptRun(valid string) {
|
||||
l.backup()
|
||||
}
|
||||
|
||||
// acceptRunUntil consumes a run of runes up to a terminator.
|
||||
func (l *lexer) acceptRunUntil(term rune) {
|
||||
for term != l.next() {
|
||||
}
|
||||
l.backup()
|
||||
}
|
||||
|
||||
// hasText returns true if the current parsed text is not empty.
|
||||
func (l *lexer) isNotEmpty() bool {
|
||||
return l.pos > l.start
|
||||
}
|
||||
|
||||
// lineNumber reports which line we're on, based on the position of
|
||||
// the previous item returned by nextItem. Doing it this way
|
||||
// means we don't have to worry about peek double counting.
|
||||
|
9
vendor/github.com/magiconair/properties/parser.go
generated
vendored
9
vendor/github.com/magiconair/properties/parser.go
generated
vendored
@ -59,14 +59,6 @@ func (p *parser) errorf(format string, args ...interface{}) {
|
||||
panic(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
func (p *parser) expect(expected itemType) (token item) {
|
||||
token = p.lex.nextItem()
|
||||
if token.typ != expected {
|
||||
p.unexpected(token)
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
func (p *parser) expectOneOf(expected ...itemType) (token item) {
|
||||
token = p.lex.nextItem()
|
||||
for _, v := range expected {
|
||||
@ -91,5 +83,4 @@ func (p *parser) recover(errp *error) {
|
||||
}
|
||||
*errp = e.(error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
1
vendor/github.com/magiconair/properties/properties.go
generated
vendored
1
vendor/github.com/magiconair/properties/properties.go
generated
vendored
@ -786,7 +786,6 @@ func expand(s string, keys []string, prefix, postfix string, values map[string]s
|
||||
}
|
||||
s = s[:start] + new_val + s[end+1:]
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters.
|
||||
|
6
vendor/github.com/microcosm-cc/bluemonday/helpers.go
generated
vendored
6
vendor/github.com/microcosm-cc/bluemonday/helpers.go
generated
vendored
@ -295,3 +295,9 @@ func (p *Policy) AllowTables() {
|
||||
CellVerticalAlign,
|
||||
).OnElements("tbody", "tfoot")
|
||||
}
|
||||
|
||||
func (p *Policy) AllowIFrames(vals ...SandboxValue) {
|
||||
p.AllowAttrs("sandbox").OnElements("iframe")
|
||||
|
||||
p.RequireSandboxOnIFrame(vals...)
|
||||
}
|
||||
|
74
vendor/github.com/microcosm-cc/bluemonday/policy.go
generated
vendored
74
vendor/github.com/microcosm-cc/bluemonday/policy.go
generated
vendored
@ -74,6 +74,9 @@ type Policy struct {
|
||||
// When true, add crossorigin="anonymous" to HTML audio, img, link, script, and video tags
|
||||
requireCrossOriginAnonymous bool
|
||||
|
||||
// When true, add and filter sandbox attribute on iframe tags
|
||||
requireSandboxOnIFrame map[string]bool
|
||||
|
||||
// When true add target="_blank" to fully qualified links
|
||||
// Will add for href="http://foo"
|
||||
// Will skip for href="/foo" or href="foo"
|
||||
@ -189,6 +192,25 @@ type stylePolicyBuilder struct {
|
||||
|
||||
type urlPolicy func(url *url.URL) (allowUrl bool)
|
||||
|
||||
type SandboxValue int64
|
||||
|
||||
const (
|
||||
SandboxAllowDownloads SandboxValue = iota
|
||||
SandboxAllowDownloadsWithoutUserActivation
|
||||
SandboxAllowForms
|
||||
SandboxAllowModals
|
||||
SandboxAllowOrientationLock
|
||||
SandboxAllowPointerLock
|
||||
SandboxAllowPopups
|
||||
SandboxAllowPopupsToEscapeSandbox
|
||||
SandboxAllowPresentation
|
||||
SandboxAllowSameOrigin
|
||||
SandboxAllowScripts
|
||||
SandboxAllowStorageAccessByUserActivation
|
||||
SandboxAllowTopNavigation
|
||||
SandboxAllowTopNavigationByUserActivation
|
||||
)
|
||||
|
||||
// init initializes the maps if this has not been done already
|
||||
func (p *Policy) init() {
|
||||
if !p.initialized {
|
||||
@ -680,6 +702,58 @@ func (p *Policy) AllowURLSchemeWithCustomPolicy(
|
||||
return p
|
||||
}
|
||||
|
||||
// RequireSandboxOnIFrame will result in all iframe tags having a sandbox="" tag
|
||||
// Any sandbox values not specified here will be filtered from the generated HTML
|
||||
func (p *Policy) RequireSandboxOnIFrame(vals ...SandboxValue) {
|
||||
p.requireSandboxOnIFrame = make(map[string]bool)
|
||||
|
||||
for _, val := range vals {
|
||||
switch SandboxValue(val) {
|
||||
case SandboxAllowDownloads:
|
||||
p.requireSandboxOnIFrame["allow-downloads"] = true
|
||||
|
||||
case SandboxAllowDownloadsWithoutUserActivation:
|
||||
p.requireSandboxOnIFrame["allow-downloads-without-user-activation"] = true
|
||||
|
||||
case SandboxAllowForms:
|
||||
p.requireSandboxOnIFrame["allow-forms"] = true
|
||||
|
||||
case SandboxAllowModals:
|
||||
p.requireSandboxOnIFrame["allow-modals"] = true
|
||||
|
||||
case SandboxAllowOrientationLock:
|
||||
p.requireSandboxOnIFrame["allow-orientation-lock"] = true
|
||||
|
||||
case SandboxAllowPointerLock:
|
||||
p.requireSandboxOnIFrame["allow-pointer-lock"] = true
|
||||
|
||||
case SandboxAllowPopups:
|
||||
p.requireSandboxOnIFrame["allow-popups"] = true
|
||||
|
||||
case SandboxAllowPopupsToEscapeSandbox:
|
||||
p.requireSandboxOnIFrame["allow-popups-to-escape-sandbox"] = true
|
||||
|
||||
case SandboxAllowPresentation:
|
||||
p.requireSandboxOnIFrame["allow-presentation"] = true
|
||||
|
||||
case SandboxAllowSameOrigin:
|
||||
p.requireSandboxOnIFrame["allow-same-origin"] = true
|
||||
|
||||
case SandboxAllowScripts:
|
||||
p.requireSandboxOnIFrame["allow-scripts"] = true
|
||||
|
||||
case SandboxAllowStorageAccessByUserActivation:
|
||||
p.requireSandboxOnIFrame["allow-storage-access-by-user-activation"] = true
|
||||
|
||||
case SandboxAllowTopNavigation:
|
||||
p.requireSandboxOnIFrame["allow-top-navigation"] = true
|
||||
|
||||
case SandboxAllowTopNavigationByUserActivation:
|
||||
p.requireSandboxOnIFrame["allow-top-navigation-by-user-activation"] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddSpaceWhenStrippingTag states whether to add a single space " " when
|
||||
// removing tags that are not allowed by the policy.
|
||||
//
|
||||
|
29
vendor/github.com/microcosm-cc/bluemonday/sanitize.go
generated
vendored
29
vendor/github.com/microcosm-cc/bluemonday/sanitize.go
generated
vendored
@ -240,7 +240,7 @@ func (p *Policy) sanitize(r io.Reader, w io.Writer) error {
|
||||
// rather than:
|
||||
// p := bluemonday.NewPolicy()
|
||||
// If this is the case, and if they haven't yet triggered an action that
|
||||
// would initiliaze the maps, then we need to do that.
|
||||
// would initialize the maps, then we need to do that.
|
||||
p.init()
|
||||
|
||||
buff, ok := w.(stringWriterWriter)
|
||||
@ -809,6 +809,33 @@ attrsLoop:
|
||||
}
|
||||
}
|
||||
|
||||
if p.requireSandboxOnIFrame != nil && elementName == "iframe" {
|
||||
var sandboxFound bool
|
||||
for i, htmlAttr := range cleanAttrs {
|
||||
if htmlAttr.Key == "sandbox" {
|
||||
sandboxFound = true
|
||||
var cleanVals []string
|
||||
cleanValsSet := make(map[string]bool)
|
||||
for _, val := range strings.Fields(htmlAttr.Val) {
|
||||
if p.requireSandboxOnIFrame[val] {
|
||||
if !cleanValsSet[val] {
|
||||
cleanVals = append(cleanVals, val)
|
||||
cleanValsSet[val] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanAttrs[i].Val = strings.Join(cleanVals, " ")
|
||||
}
|
||||
}
|
||||
|
||||
if !sandboxFound {
|
||||
sandbox := html.Attribute{}
|
||||
sandbox.Key = "sandbox"
|
||||
sandbox.Val = ""
|
||||
cleanAttrs = append(cleanAttrs, sandbox)
|
||||
}
|
||||
}
|
||||
|
||||
return cleanAttrs
|
||||
}
|
||||
|
||||
|
13
vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
generated
vendored
13
vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
generated
vendored
@ -1,3 +1,16 @@
|
||||
## 1.5.0
|
||||
|
||||
* New option `IgnoreUntaggedFields` to ignore decoding to any fields
|
||||
without `mapstructure` (or the configured tag name) set [GH-277]
|
||||
* New option `ErrorUnset` which makes it an error if any fields
|
||||
in a target struct are not set by the decoding process. [GH-225]
|
||||
* New function `OrComposeDecodeHookFunc` to help compose decode hooks. [GH-240]
|
||||
* Decoding to slice from array no longer crashes [GH-265]
|
||||
* Decode nested struct pointers to map [GH-271]
|
||||
* Fix issue where `,squash` was ignored if `Squash` option was set. [GH-280]
|
||||
* Fix issue where fields with `,omitempty` would sometimes decode
|
||||
into a map with an empty string key [GH-281]
|
||||
|
||||
## 1.4.3
|
||||
|
||||
* Fix cases where `json.Number` didn't decode properly [GH-261]
|
||||
|
22
vendor/github.com/mitchellh/mapstructure/decode_hooks.go
generated
vendored
22
vendor/github.com/mitchellh/mapstructure/decode_hooks.go
generated
vendored
@ -77,6 +77,28 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
|
||||
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
|
||||
func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
|
||||
return func(a, b reflect.Value) (interface{}, error) {
|
||||
var allErrs string
|
||||
var out interface{}
|
||||
var err error
|
||||
|
||||
for _, f := range ff {
|
||||
out, err = DecodeHookExec(f, a, b)
|
||||
if err != nil {
|
||||
allErrs += err.Error() + "\n"
|
||||
continue
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
return nil, errors.New(allErrs)
|
||||
}
|
||||
}
|
||||
|
||||
// StringToSliceHookFunc returns a DecodeHookFunc that converts
|
||||
// string to []string by splitting on the given sep.
|
||||
func StringToSliceHookFunc(sep string) DecodeHookFunc {
|
||||
|
83
vendor/github.com/mitchellh/mapstructure/mapstructure.go
generated
vendored
83
vendor/github.com/mitchellh/mapstructure/mapstructure.go
generated
vendored
@ -122,7 +122,7 @@
|
||||
// field value is zero and a numeric type, the field is empty, and it won't
|
||||
// be encoded into the destination type.
|
||||
//
|
||||
// type Source {
|
||||
// type Source struct {
|
||||
// Age int `mapstructure:",omitempty"`
|
||||
// }
|
||||
//
|
||||
@ -215,6 +215,12 @@ type DecoderConfig struct {
|
||||
// (extra keys).
|
||||
ErrorUnused bool
|
||||
|
||||
// If ErrorUnset is true, then it is an error for there to exist
|
||||
// fields in the result that were not set in the decoding process
|
||||
// (extra fields). This only applies to decoding to a struct. This
|
||||
// will affect all nested structs as well.
|
||||
ErrorUnset bool
|
||||
|
||||
// ZeroFields, if set to true, will zero fields before writing them.
|
||||
// For example, a map will be emptied before decoded values are put in
|
||||
// it. If this is false, a map will be merged.
|
||||
@ -259,6 +265,10 @@ type DecoderConfig struct {
|
||||
// defaults to "mapstructure"
|
||||
TagName string
|
||||
|
||||
// IgnoreUntaggedFields ignores all struct fields without explicit
|
||||
// TagName, comparable to `mapstructure:"-"` as default behaviour.
|
||||
IgnoreUntaggedFields bool
|
||||
|
||||
// MatchName is the function used to match the map key to the struct
|
||||
// field name or tag. Defaults to `strings.EqualFold`. This can be used
|
||||
// to implement case-sensitive tag values, support snake casing, etc.
|
||||
@ -284,6 +294,11 @@ type Metadata struct {
|
||||
// Unused is a slice of keys that were found in the raw value but
|
||||
// weren't decoded since there was no matching field in the result interface
|
||||
Unused []string
|
||||
|
||||
// Unset is a slice of field names that were found in the result interface
|
||||
// but weren't set in the decoding process since there was no matching value
|
||||
// in the input
|
||||
Unset []string
|
||||
}
|
||||
|
||||
// Decode takes an input structure and uses reflection to translate it to
|
||||
@ -375,6 +390,10 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
|
||||
if config.Metadata.Unused == nil {
|
||||
config.Metadata.Unused = make([]string, 0)
|
||||
}
|
||||
|
||||
if config.Metadata.Unset == nil {
|
||||
config.Metadata.Unset = make([]string, 0)
|
||||
}
|
||||
}
|
||||
|
||||
if config.TagName == "" {
|
||||
@ -906,9 +925,15 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
tagValue := f.Tag.Get(d.config.TagName)
|
||||
keyName := f.Name
|
||||
|
||||
if tagValue == "" && d.config.IgnoreUntaggedFields {
|
||||
continue
|
||||
}
|
||||
|
||||
// If Squash is set in the config, we squash the field down.
|
||||
squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
|
||||
|
||||
v = dereferencePtrToStructIfNeeded(v, d.config.TagName)
|
||||
|
||||
// Determine the name of the key in the map
|
||||
if index := strings.Index(tagValue, ","); index != -1 {
|
||||
if tagValue[:index] == "-" {
|
||||
@ -920,7 +945,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
}
|
||||
|
||||
// If "squash" is specified in the tag, we squash the field down.
|
||||
squash = !squash && strings.Index(tagValue[index+1:], "squash") != -1
|
||||
squash = squash || strings.Index(tagValue[index+1:], "squash") != -1
|
||||
if squash {
|
||||
// When squashing, the embedded type can be a pointer to a struct.
|
||||
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
|
||||
@ -932,7 +957,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||
return fmt.Errorf("cannot squash non-struct type '%s'", v.Type())
|
||||
}
|
||||
}
|
||||
keyName = tagValue[:index]
|
||||
if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" {
|
||||
keyName = keyNameTagValue
|
||||
}
|
||||
} else if len(tagValue) > 0 {
|
||||
if tagValue == "-" {
|
||||
continue
|
||||
@ -1088,7 +1115,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
|
||||
}
|
||||
|
||||
// If the input value is nil, then don't allocate since empty != nil
|
||||
if dataVal.IsNil() {
|
||||
if dataValKind != reflect.Array && dataVal.IsNil() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1250,6 +1277,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
dataValKeysUnused[dataValKey.Interface()] = struct{}{}
|
||||
}
|
||||
|
||||
targetValKeysUnused := make(map[interface{}]struct{})
|
||||
errors := make([]string, 0)
|
||||
|
||||
// This slice will keep track of all the structs we'll be decoding.
|
||||
@ -1354,7 +1382,8 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
|
||||
if !rawMapVal.IsValid() {
|
||||
// There was no matching key in the map for the value in
|
||||
// the struct. Just ignore.
|
||||
// the struct. Remember it for potential errors and metadata.
|
||||
targetValKeysUnused[fieldName] = struct{}{}
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -1414,6 +1443,17 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
errors = appendErrors(errors, err)
|
||||
}
|
||||
|
||||
if d.config.ErrorUnset && len(targetValKeysUnused) > 0 {
|
||||
keys := make([]string, 0, len(targetValKeysUnused))
|
||||
for rawKey := range targetValKeysUnused {
|
||||
keys = append(keys, rawKey.(string))
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
err := fmt.Errorf("'%s' has unset fields: %s", name, strings.Join(keys, ", "))
|
||||
errors = appendErrors(errors, err)
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return &Error{errors}
|
||||
}
|
||||
@ -1428,6 +1468,14 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
|
||||
d.config.Metadata.Unused = append(d.config.Metadata.Unused, key)
|
||||
}
|
||||
for rawKey := range targetValKeysUnused {
|
||||
key := rawKey.(string)
|
||||
if name != "" {
|
||||
key = name + "." + key
|
||||
}
|
||||
|
||||
d.config.Metadata.Unset = append(d.config.Metadata.Unset, key)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -1465,3 +1513,28 @@ func getKind(val reflect.Value) reflect.Kind {
|
||||
return kind
|
||||
}
|
||||
}
|
||||
|
||||
func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool, tagName string) bool {
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
f := typ.Field(i)
|
||||
if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields
|
||||
return true
|
||||
}
|
||||
if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value {
|
||||
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
|
||||
return v
|
||||
}
|
||||
deref := v.Elem()
|
||||
derefT := deref.Type()
|
||||
if isStructTypeConvertibleToMap(derefT, true, tagName) {
|
||||
return deref
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
6
vendor/github.com/pelletier/go-toml/README.md
generated
vendored
6
vendor/github.com/pelletier/go-toml/README.md
generated
vendored
@ -25,9 +25,9 @@ and [much faster][v2-bench]. If you only need reading and writing TOML documents
|
||||
(majority of cases), those features are implemented and the API unlikely to
|
||||
change.
|
||||
|
||||
The remaining features (Document structure editing and tooling) will be added
|
||||
shortly. While pull-requests are welcome on v1, no active development is
|
||||
expected on it. When v2.0.0 is released, v1 will be deprecated.
|
||||
The remaining features will be added shortly. While pull-requests are welcome on
|
||||
v1, no active development is expected on it. When v2.0.0 is released, v1 will be
|
||||
deprecated.
|
||||
|
||||
👉 [go-toml v2][v2]
|
||||
|
||||
|
19
vendor/github.com/pelletier/go-toml/SECURITY.md
generated
vendored
Normal file
19
vendor/github.com/pelletier/go-toml/SECURITY.md
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ---------- | ------------------ |
|
||||
| Latest 2.x | :white_check_mark: |
|
||||
| All 1.x | :x: |
|
||||
| All 0.x | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Email a vulnerability report to `security@pelletier.codes`. Make sure to include
|
||||
as many details as possible to reproduce the vulnerability. This is a
|
||||
side-project: I will try to get back to you as quickly as possible, time
|
||||
permitting in my personal life. Providing a working patch helps very much!
|
2
vendor/github.com/pelletier/go-toml/marshal.go
generated
vendored
2
vendor/github.com/pelletier/go-toml/marshal.go
generated
vendored
@ -1113,7 +1113,7 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *ref
|
||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
|
||||
}
|
||||
|
||||
if val.Convert(reflect.TypeOf(int(1))).Int() < 0 {
|
||||
if val.Type().Kind() != reflect.Uint64 && val.Convert(reflect.TypeOf(int(1))).Int() < 0 {
|
||||
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String())
|
||||
}
|
||||
if reflect.Indirect(reflect.New(mtype)).OverflowUint(val.Convert(reflect.TypeOf(uint64(0))).Uint()) {
|
||||
|
47
vendor/github.com/pelletier/go-toml/parser.go
generated
vendored
47
vendor/github.com/pelletier/go-toml/parser.go
generated
vendored
@ -293,42 +293,41 @@ func (p *tomlParser) parseRvalue() interface{} {
|
||||
return math.NaN()
|
||||
case tokenInteger:
|
||||
cleanedVal := cleanupNumberToken(tok.val)
|
||||
var err error
|
||||
var val int64
|
||||
base := 10
|
||||
s := cleanedVal
|
||||
checkInvalidUnderscore := numberContainsInvalidUnderscore
|
||||
if len(cleanedVal) >= 3 && cleanedVal[0] == '0' {
|
||||
switch cleanedVal[1] {
|
||||
case 'x':
|
||||
err = hexNumberContainsInvalidUnderscore(tok.val)
|
||||
if err != nil {
|
||||
p.raiseError(tok, "%s", err)
|
||||
}
|
||||
val, err = strconv.ParseInt(cleanedVal[2:], 16, 64)
|
||||
checkInvalidUnderscore = hexNumberContainsInvalidUnderscore
|
||||
base = 16
|
||||
case 'o':
|
||||
err = numberContainsInvalidUnderscore(tok.val)
|
||||
if err != nil {
|
||||
p.raiseError(tok, "%s", err)
|
||||
}
|
||||
val, err = strconv.ParseInt(cleanedVal[2:], 8, 64)
|
||||
base = 8
|
||||
case 'b':
|
||||
err = numberContainsInvalidUnderscore(tok.val)
|
||||
if err != nil {
|
||||
p.raiseError(tok, "%s", err)
|
||||
}
|
||||
val, err = strconv.ParseInt(cleanedVal[2:], 2, 64)
|
||||
base = 2
|
||||
default:
|
||||
panic("invalid base") // the lexer should catch this first
|
||||
}
|
||||
} else {
|
||||
err = numberContainsInvalidUnderscore(tok.val)
|
||||
if err != nil {
|
||||
p.raiseError(tok, "%s", err)
|
||||
}
|
||||
val, err = strconv.ParseInt(cleanedVal, 10, 64)
|
||||
s = cleanedVal[2:]
|
||||
}
|
||||
|
||||
err := checkInvalidUnderscore(tok.val)
|
||||
if err != nil {
|
||||
p.raiseError(tok, "%s", err)
|
||||
}
|
||||
return val
|
||||
|
||||
var val interface{}
|
||||
val, err = strconv.ParseInt(s, base, 64)
|
||||
if err == nil {
|
||||
return val
|
||||
}
|
||||
|
||||
if s[0] != '-' {
|
||||
if val, err = strconv.ParseUint(s, base, 64); err == nil {
|
||||
return val
|
||||
}
|
||||
}
|
||||
p.raiseError(tok, "%s", err)
|
||||
case tokenFloat:
|
||||
err := numberContainsInvalidUnderscore(tok.val)
|
||||
if err != nil {
|
||||
|
2
vendor/github.com/pelletier/go-toml/toml.go
generated
vendored
2
vendor/github.com/pelletier/go-toml/toml.go
generated
vendored
@ -471,7 +471,7 @@ func LoadBytes(b []byte) (tree *Tree, err error) {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
}
|
||||
err = errors.New(r.(string))
|
||||
err = fmt.Errorf("%s", r)
|
||||
}
|
||||
}()
|
||||
|
||||
|
2
vendor/github.com/pelletier/go-toml/v2/.dockerignore
generated
vendored
Normal file
2
vendor/github.com/pelletier/go-toml/v2/.dockerignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
cmd/tomll/tomll
|
||||
cmd/tomljson/tomljson
|
4
vendor/github.com/pelletier/go-toml/v2/.gitattributes
generated
vendored
Normal file
4
vendor/github.com/pelletier/go-toml/v2/.gitattributes
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
* text=auto
|
||||
|
||||
benchmark/benchmark.toml text eol=lf
|
||||
testdata/** text eol=lf
|
6
vendor/github.com/pelletier/go-toml/v2/.gitignore
generated
vendored
Normal file
6
vendor/github.com/pelletier/go-toml/v2/.gitignore
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
test_program/test_program_bin
|
||||
fuzz/
|
||||
cmd/tomll/tomll
|
||||
cmd/tomljson/tomljson
|
||||
cmd/tomltestgen/tomltestgen
|
||||
dist
|
84
vendor/github.com/pelletier/go-toml/v2/.golangci.toml
generated
vendored
Normal file
84
vendor/github.com/pelletier/go-toml/v2/.golangci.toml
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
[service]
|
||||
golangci-lint-version = "1.39.0"
|
||||
|
||||
[linters-settings.wsl]
|
||||
allow-assign-and-anything = true
|
||||
|
||||
[linters-settings.exhaustive]
|
||||
default-signifies-exhaustive = true
|
||||
|
||||
[linters]
|
||||
disable-all = true
|
||||
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",
|
||||
"goheader",
|
||||
"goimports",
|
||||
"golint",
|
||||
"gomnd",
|
||||
# "gomoddirectives",
|
||||
"gomodguard",
|
||||
"goprintffuncname",
|
||||
"gosec",
|
||||
"gosimple",
|
||||
"govet",
|
||||
# "ifshort",
|
||||
"importas",
|
||||
"ineffassign",
|
||||
"lll",
|
||||
"makezero",
|
||||
"misspell",
|
||||
"nakedret",
|
||||
"nestif",
|
||||
"nilerr",
|
||||
# "nlreturn",
|
||||
"noctx",
|
||||
"nolintlint",
|
||||
#"paralleltest",
|
||||
"prealloc",
|
||||
"predeclared",
|
||||
"revive",
|
||||
"rowserrcheck",
|
||||
"sqlclosecheck",
|
||||
"staticcheck",
|
||||
"structcheck",
|
||||
"stylecheck",
|
||||
# "testpackage",
|
||||
"thelper",
|
||||
"tparallel",
|
||||
"typecheck",
|
||||
"unconvert",
|
||||
"unparam",
|
||||
"unused",
|
||||
"varcheck",
|
||||
"wastedassign",
|
||||
"whitespace",
|
||||
# "wrapcheck",
|
||||
# "wsl"
|
||||
]
|
111
vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml
generated
vendored
Normal file
111
vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
- go fmt ./...
|
||||
- go test ./...
|
||||
builds:
|
||||
- id: tomll
|
||||
main: ./cmd/tomll
|
||||
binary: tomll
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}}
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
targets:
|
||||
- linux_amd64
|
||||
- windows_amd64
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
- id: tomljson
|
||||
main: ./cmd/tomljson
|
||||
binary: tomljson
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}}
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
targets:
|
||||
- linux_amd64
|
||||
- windows_amd64
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
- id: jsontoml
|
||||
main: ./cmd/jsontoml
|
||||
binary: jsontoml
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}}
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
targets:
|
||||
- linux_amd64
|
||||
- windows_amd64
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
universal_binaries:
|
||||
- id: tomll
|
||||
replace: true
|
||||
name_template: tomll
|
||||
- id: tomljson
|
||||
replace: true
|
||||
name_template: tomljson
|
||||
- id: jsontoml
|
||||
replace: true
|
||||
name_template: jsontoml
|
||||
archives:
|
||||
- id: jsontoml
|
||||
format: tar.xz
|
||||
builds:
|
||||
- jsontoml
|
||||
files:
|
||||
- none*
|
||||
name_template: "{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}"
|
||||
- id: tomljson
|
||||
format: tar.xz
|
||||
builds:
|
||||
- tomljson
|
||||
files:
|
||||
- none*
|
||||
name_template: "{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}"
|
||||
- id: tomll
|
||||
format: tar.xz
|
||||
builds:
|
||||
- tomll
|
||||
files:
|
||||
- none*
|
||||
name_template: "{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}"
|
||||
dockers:
|
||||
- id: tools
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
ids:
|
||||
- jsontoml
|
||||
- tomljson
|
||||
- tomll
|
||||
image_templates:
|
||||
- "ghcr.io/pelletier/go-toml:latest"
|
||||
- "ghcr.io/pelletier/go-toml:{{ .Tag }}"
|
||||
- "ghcr.io/pelletier/go-toml:v{{ .Major }}"
|
||||
skip_push: false
|
||||
checksum:
|
||||
name_template: 'sha256sums.txt'
|
||||
snapshot:
|
||||
name_template: "{{ incpatch .Version }}-next"
|
||||
release:
|
||||
github:
|
||||
owner: pelletier
|
||||
name: go-toml
|
||||
draft: true
|
||||
prerelease: auto
|
||||
mode: replace
|
||||
changelog:
|
||||
use: github-native
|
||||
announce:
|
||||
skip: true
|
196
vendor/github.com/pelletier/go-toml/v2/CONTRIBUTING.md
generated
vendored
Normal file
196
vendor/github.com/pelletier/go-toml/v2/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
# Contributing
|
||||
|
||||
Thank you for your interest in go-toml! We appreciate you considering
|
||||
contributing to go-toml!
|
||||
|
||||
The main goal is the project is to provide an easy-to-use and efficient TOML
|
||||
implementation for Go that gets the job done and gets out of your way – dealing
|
||||
with TOML is probably not the central piece of your project.
|
||||
|
||||
As the single maintainer of go-toml, time is scarce. All help, big or small, is
|
||||
more than welcomed!
|
||||
|
||||
## Ask questions
|
||||
|
||||
Any question you may have, somebody else might have it too. Always feel free to
|
||||
ask them on the [discussion board][discussions]. We will try to answer them as
|
||||
clearly and quickly as possible, time permitting.
|
||||
|
||||
Asking questions also helps us identify areas where the documentation needs
|
||||
improvement, or new features that weren't envisioned before. Sometimes, a
|
||||
seemingly innocent question leads to the fix of a bug. Don't hesitate and ask
|
||||
away!
|
||||
|
||||
[discussions]: https://github.com/pelletier/go-toml/discussions
|
||||
|
||||
## Improve the documentation
|
||||
|
||||
The best way to share your knowledge and experience with go-toml is to improve
|
||||
the documentation. Fix a typo, clarify an interface, add an example, anything
|
||||
goes!
|
||||
|
||||
The documentation is present in the [README][readme] and thorough the source
|
||||
code. On release, it gets updated on [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
|
||||
file. Unless it's a trivial change (for example a typo), provide a little bit of
|
||||
context in your pull request description or commit message.
|
||||
|
||||
## Report a bug
|
||||
|
||||
Found a bug! Sorry to hear that :(. Help us and other track them down and fix by
|
||||
reporting it. [File a new bug report][bug-report] on the [issues
|
||||
tracker][issues-tracker]. The template should provide enough guidance on what to
|
||||
include. When in doubt: add more details! By reducing ambiguity and providing
|
||||
more information, it decreases back and forth and saves everyone time.
|
||||
|
||||
## Code changes
|
||||
|
||||
Want to contribute a patch? Very happy to hear that!
|
||||
|
||||
First, some high-level rules:
|
||||
|
||||
- A short proposal with some POC code is better than a lengthy piece of text
|
||||
with no code. Code speaks louder than words. That being said, bigger changes
|
||||
should probably start with a [discussion][discussions].
|
||||
- No backward-incompatible patch will be accepted unless discussed. Sometimes
|
||||
it's hard, but we try not to break people's programs unless we absolutely have
|
||||
to.
|
||||
- If you are writing a new feature or extending an existing one, make sure to
|
||||
write some documentation.
|
||||
- Bug fixes need to be accompanied with regression tests.
|
||||
- New code needs to be tested.
|
||||
- Your commit messages need to explain why the change is needed, even if already
|
||||
included in the PR description.
|
||||
|
||||
It does sound like a lot, but those best practices are here to save time overall
|
||||
and continuously improve the quality of the project, which is something everyone
|
||||
benefits from.
|
||||
|
||||
### Get started
|
||||
|
||||
The fairly standard code contribution process looks like that:
|
||||
|
||||
1. [Fork the project][fork].
|
||||
2. Make your changes, commit on any branch you like.
|
||||
3. [Open up a pull request][pull-request]
|
||||
4. Review, potential ask for changes.
|
||||
5. Merge.
|
||||
|
||||
Feel free to ask for help! You can create draft pull requests to gather
|
||||
some early feedback!
|
||||
|
||||
### Run the tests
|
||||
|
||||
You can run tests for go-toml using Go's test tool: `go test -race ./...`.
|
||||
|
||||
During the pull request process, all tests will be ran on Linux, Windows, and
|
||||
MacOS on the last two versions of Go.
|
||||
|
||||
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.
|
||||
|
||||
### Check coverage
|
||||
|
||||
We use `go tool cover` to compute test coverage. Most code editors have a way to
|
||||
run and display code coverage, but at the end of the day, we do this:
|
||||
|
||||
```
|
||||
go test -covermode=atomic -coverprofile=coverage.out
|
||||
go tool cover -func=coverage.out
|
||||
```
|
||||
|
||||
and verify that the overall percentage of tested code does not go down. This is
|
||||
a requirement. As a rule of thumb, all lines of code touched by your changes
|
||||
should be covered. On Unix you can use `./ci.sh coverage -d v2` to check if your
|
||||
code lowers the coverage.
|
||||
|
||||
### Verify performance
|
||||
|
||||
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
|
||||
responsible for checking that your changes do not incur a performance penalty.
|
||||
You can run their following to execute benchmarks:
|
||||
|
||||
```
|
||||
go test ./... -bench=. -count=10
|
||||
```
|
||||
|
||||
Benchmark results should be compared against each other with
|
||||
[benchstat][benchstat]. Typical flow looks like this:
|
||||
|
||||
1. On the `v2` branch, run `go test ./... -bench=. -count 10` and save output to
|
||||
a file (for example `old.txt`).
|
||||
2. Make some code changes.
|
||||
3. Run `go test ....` again, and save the output to an other file (for example
|
||||
`new.txt`).
|
||||
4. Run `benchstat old.txt new.txt` to check that time/op does not go up in any
|
||||
test.
|
||||
|
||||
On Unix you can use `./ci.sh benchmark -d v2` to verify how your code impacts
|
||||
performance.
|
||||
|
||||
It is highly encouraged to add the benchstat results to your pull request
|
||||
description. Pull requests that lower performance will receive more scrutiny.
|
||||
|
||||
[benchstat]: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat
|
||||
|
||||
### Style
|
||||
|
||||
Try to look around and follow the same format and structure as the rest of the
|
||||
code. We enforce using `go fmt` on the whole code base.
|
||||
|
||||
---
|
||||
|
||||
## Maintainers-only
|
||||
|
||||
### Merge pull request
|
||||
|
||||
Checklist:
|
||||
|
||||
- Passing CI.
|
||||
- Does not introduce backward-incompatible changes (unless discussed).
|
||||
- Has relevant doc changes.
|
||||
- Benchstat does not show performance regression.
|
||||
- Pull request is [labeled appropriately][pr-labels].
|
||||
- Title will be understandable in the changelog.
|
||||
|
||||
1. Merge using "squash and merge".
|
||||
2. Make sure to edit the commit message to keep all the useful information
|
||||
nice and clean.
|
||||
3. Make sure the commit title is clear and contains the PR number (#123).
|
||||
|
||||
### New release
|
||||
|
||||
1. Decide on the next version number. Use semver.
|
||||
2. Generate release notes using [`gh`][gh]. Example:
|
||||
```
|
||||
$ gh api -X POST \
|
||||
-F tag_name='v2.0.0-beta.5' \
|
||||
-F target_commitish='v2' \
|
||||
-F previous_tag_name='v2.0.0-beta.4' \
|
||||
--jq '.body' \
|
||||
repos/pelletier/go-toml/releases/generate-notes
|
||||
```
|
||||
3. 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.
|
||||
4. [Draft new release][new-release].
|
||||
5. Fill tag and target with the same value used to generate the changelog.
|
||||
6. Set title to the new tag value.
|
||||
7. Paste the generated changelog.
|
||||
8. Check "create discussion", in the "Releases" category.
|
||||
9. Check pre-release if new version is an alpha or beta.
|
||||
|
||||
[issues-tracker]: https://github.com/pelletier/go-toml/issues
|
||||
[bug-report]: https://github.com/pelletier/go-toml/issues/new?template=bug_report.md
|
||||
[pkg.go.dev]: https://pkg.go.dev/github.com/pelletier/go-toml
|
||||
[readme]: ./README.md
|
||||
[fork]: https://help.github.com/articles/fork-a-repo
|
||||
[pull-request]: https://help.github.com/en/articles/creating-a-pull-request
|
||||
[new-release]: https://github.com/pelletier/go-toml/releases/new
|
||||
[gh]: https://github.com/cli/cli
|
||||
[pr-labels]: https://github.com/pelletier/go-toml/blob/v2/.github/release.yml
|
5
vendor/github.com/pelletier/go-toml/v2/Dockerfile
generated
vendored
Normal file
5
vendor/github.com/pelletier/go-toml/v2/Dockerfile
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
FROM scratch
|
||||
ENV PATH "$PATH:/bin"
|
||||
COPY tomll /bin/tomll
|
||||
COPY tomljson /bin/tomljson
|
||||
COPY jsontoml /bin/jsontoml
|
21
vendor/github.com/pelletier/go-toml/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/pelletier/go-toml/v2/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 - 2022 Thomas Pelletier, Eric Anderton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
545
vendor/github.com/pelletier/go-toml/v2/README.md
generated
vendored
Normal file
545
vendor/github.com/pelletier/go-toml/v2/README.md
generated
vendored
Normal file
@ -0,0 +1,545 @@
|
||||
# go-toml v2
|
||||
|
||||
Go library for the [TOML](https://toml.io/en/) format.
|
||||
|
||||
This library supports [TOML v1.0.0](https://toml.io/en/v1.0.0).
|
||||
|
||||
[🐞 Bug Reports](https://github.com/pelletier/go-toml/issues)
|
||||
|
||||
[💬 Anything else](https://github.com/pelletier/go-toml/discussions)
|
||||
|
||||
## Documentation
|
||||
|
||||
Full API, examples, and implementation notes are available in the Go
|
||||
documentation.
|
||||
|
||||
[](https://pkg.go.dev/github.com/pelletier/go-toml/v2)
|
||||
|
||||
## Import
|
||||
|
||||
```go
|
||||
import "github.com/pelletier/go-toml/v2"
|
||||
```
|
||||
|
||||
See [Modules](#Modules).
|
||||
|
||||
## Features
|
||||
|
||||
### Stdlib behavior
|
||||
|
||||
As much as possible, this library is designed to behave similarly as the
|
||||
standard library's `encoding/json`.
|
||||
|
||||
### Performance
|
||||
|
||||
While go-toml favors usability, it is written with performance in mind. Most
|
||||
operations should not be shockingly slow. See [benchmarks](#benchmarks).
|
||||
|
||||
### Strict mode
|
||||
|
||||
`Decoder` can be set to "strict mode", which makes it error when some parts of
|
||||
the TOML document was not prevent in the target structure. This is a great way
|
||||
to check for typos. [See example in the documentation][strict].
|
||||
|
||||
[strict]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#example-Decoder.DisallowUnknownFields
|
||||
|
||||
### Contextualized errors
|
||||
|
||||
When most decoding errors occur, go-toml returns [`DecodeError`][decode-err]),
|
||||
which contains a human readable contextualized version of the error. For
|
||||
example:
|
||||
|
||||
```
|
||||
2| key1 = "value1"
|
||||
3| key2 = "missing2"
|
||||
| ~~~~ missing field
|
||||
4| key3 = "missing3"
|
||||
5| key4 = "value4"
|
||||
```
|
||||
|
||||
[decode-err]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#DecodeError
|
||||
|
||||
### Local date and time support
|
||||
|
||||
TOML supports native [local date/times][ldt]. It allows to represent a given
|
||||
date, time, or date-time without relation to a timezone or offset. To support
|
||||
this use-case, go-toml provides [`LocalDate`][tld], [`LocalTime`][tlt], and
|
||||
[`LocalDateTime`][tldt]. Those types can be transformed to and from `time.Time`,
|
||||
making them convenient yet unambiguous structures for their respective TOML
|
||||
representation.
|
||||
|
||||
[ldt]: https://toml.io/en/v1.0.0#local-date-time
|
||||
[tld]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalDate
|
||||
[tlt]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalTime
|
||||
[tldt]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalDateTime
|
||||
|
||||
## Getting started
|
||||
|
||||
Given the following struct, let's see how to read it and write it as TOML:
|
||||
|
||||
```go
|
||||
type MyConfig struct {
|
||||
Version int
|
||||
Name string
|
||||
Tags []string
|
||||
}
|
||||
```
|
||||
|
||||
### Unmarshaling
|
||||
|
||||
[`Unmarshal`][unmarshal] reads a TOML document and fills a Go structure with its
|
||||
content. For example:
|
||||
|
||||
```go
|
||||
doc := `
|
||||
version = 2
|
||||
name = "go-toml"
|
||||
tags = ["go", "toml"]
|
||||
`
|
||||
|
||||
var cfg MyConfig
|
||||
err := toml.Unmarshal([]byte(doc), &cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("version:", cfg.Version)
|
||||
fmt.Println("name:", cfg.Name)
|
||||
fmt.Println("tags:", cfg.Tags)
|
||||
|
||||
// Output:
|
||||
// version: 2
|
||||
// name: go-toml
|
||||
// tags: [go toml]
|
||||
```
|
||||
|
||||
[unmarshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Unmarshal
|
||||
|
||||
### Marshaling
|
||||
|
||||
[`Marshal`][marshal] is the opposite of Unmarshal: it represents a Go structure
|
||||
as a TOML document:
|
||||
|
||||
```go
|
||||
cfg := MyConfig{
|
||||
Version: 2,
|
||||
Name: "go-toml",
|
||||
Tags: []string{"go", "toml"},
|
||||
}
|
||||
|
||||
b, err := toml.Marshal(cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
|
||||
// Output:
|
||||
// Version = 2
|
||||
// Name = 'go-toml'
|
||||
// Tags = ['go', 'toml']
|
||||
```
|
||||
|
||||
[marshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Marshal
|
||||
|
||||
## Benchmarks
|
||||
|
||||
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>1.9x</td></tr>
|
||||
<tr><td>Marshal/ReferenceFile/map-2</td><td>1.7x</td><td>1.8x</td></tr>
|
||||
<tr><td>Marshal/ReferenceFile/struct-2</td><td>2.2x</td><td>2.5x</td></tr>
|
||||
<tr><td>Unmarshal/HugoFrontMatter-2</td><td>2.9x</td><td>2.9x</td></tr>
|
||||
<tr><td>Unmarshal/ReferenceFile/map-2</td><td>2.6x</td><td>2.9x</td></tr>
|
||||
<tr><td>Unmarshal/ReferenceFile/struct-2</td><td>4.4x</td><td>5.3x</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
|
||||
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.9x</td></tr>
|
||||
<tr><td>Marshal/SimpleDocument/struct-2</td><td>2.7x</td><td>4.2x</td></tr>
|
||||
<tr><td>Unmarshal/SimpleDocument/map-2</td><td>4.5x</td><td>3.1x</td></tr>
|
||||
<tr><td>Unmarshal/SimpleDocument/struct-2</td><td>6.2x</td><td>3.9x</td></tr>
|
||||
<tr><td>UnmarshalDataset/example-2</td><td>3.1x</td><td>3.5x</td></tr>
|
||||
<tr><td>UnmarshalDataset/code-2</td><td>2.3x</td><td>3.1x</td></tr>
|
||||
<tr><td>UnmarshalDataset/twitter-2</td><td>2.5x</td><td>2.6x</td></tr>
|
||||
<tr><td>UnmarshalDataset/citm_catalog-2</td><td>2.1x</td><td>2.2x</td></tr>
|
||||
<tr><td>UnmarshalDataset/canada-2</td><td>1.6x</td><td>1.3x</td></tr>
|
||||
<tr><td>UnmarshalDataset/config-2</td><td>4.3x</td><td>3.2x</td></tr>
|
||||
<tr><td>[Geo mean]</td><td>2.7x</td><td>2.8x</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>This table can be generated with <code>./ci.sh benchmark -a -html</code>.</p>
|
||||
</details>
|
||||
|
||||
## Modules
|
||||
|
||||
go-toml uses Go's standard modules system.
|
||||
|
||||
Installation instructions:
|
||||
|
||||
- Go ≥ 1.16: Nothing to do. Use the import in your code. The `go` command deals
|
||||
with it automatically.
|
||||
- Go ≥ 1.13: `GO111MODULE=on go get github.com/pelletier/go-toml/v2`.
|
||||
|
||||
In case of trouble: [Go Modules FAQ][mod-faq].
|
||||
|
||||
[mod-faq]: https://github.com/golang/go/wiki/Modules#why-does-installing-a-tool-via-go-get-fail-with-error-cannot-find-main-module
|
||||
|
||||
## Tools
|
||||
|
||||
Go-toml provides three handy command line tools:
|
||||
|
||||
* `tomljson`: Reads a TOML file and outputs its JSON representation.
|
||||
|
||||
```
|
||||
$ go install github.com/pelletier/go-toml/v2/cmd/tomljson@latest
|
||||
$ tomljson --help
|
||||
```
|
||||
|
||||
* `jsontoml`: Reads a JSON file and outputs a TOML representation.
|
||||
|
||||
```
|
||||
$ go install github.com/pelletier/go-toml/v2/cmd/jsontoml@latest
|
||||
$ jsontoml --help
|
||||
```
|
||||
|
||||
* `tomll`: Lints and reformats a TOML file.
|
||||
|
||||
```
|
||||
$ go install github.com/pelletier/go-toml/v2/cmd/tomll@latest
|
||||
$ tomll --help
|
||||
```
|
||||
|
||||
### Docker image
|
||||
|
||||
Those tools are also available as a [Docker image][docker]. For example, to use
|
||||
`tomljson`:
|
||||
|
||||
```
|
||||
docker run -i ghcr.io/pelletier/go-toml:v2 tomljson < example.toml
|
||||
```
|
||||
|
||||
Multiple versions are availble on [ghcr.io][docker].
|
||||
|
||||
[docker]: https://github.com/pelletier/go-toml/pkgs/container/go-toml
|
||||
|
||||
## Migrating from v1
|
||||
|
||||
This section describes the differences between v1 and v2, with some pointers on
|
||||
how to get the original behavior when possible.
|
||||
|
||||
### Decoding / Unmarshal
|
||||
|
||||
#### Automatic field name guessing
|
||||
|
||||
When unmarshaling to a struct, if a key in the TOML document does not exactly
|
||||
match the name of a struct field or any of the `toml`-tagged field, v1 tries
|
||||
multiple variations of the key ([code][v1-keys]).
|
||||
|
||||
V2 instead does a case-insensitive matching, like `encoding/json`.
|
||||
|
||||
This could impact you if you are relying on casing to differentiate two fields,
|
||||
and one of them is a not using the `toml` struct tag. The recommended solution
|
||||
is to be specific about tag names for those fields using the `toml` struct tag.
|
||||
|
||||
[v1-keys]: https://github.com/pelletier/go-toml/blob/a2e52561804c6cd9392ebf0048ca64fe4af67a43/marshal.go#L775-L781
|
||||
|
||||
#### Ignore preexisting value in interface
|
||||
|
||||
When decoding into a non-nil `interface{}`, go-toml v1 uses the type of the
|
||||
element in the interface to decode the object. For example:
|
||||
|
||||
```go
|
||||
type inner struct {
|
||||
B interface{}
|
||||
}
|
||||
type doc struct {
|
||||
A interface{}
|
||||
}
|
||||
|
||||
d := doc{
|
||||
A: inner{
|
||||
B: "Before",
|
||||
},
|
||||
}
|
||||
|
||||
data := `
|
||||
[A]
|
||||
B = "After"
|
||||
`
|
||||
|
||||
toml.Unmarshal([]byte(data), &d)
|
||||
fmt.Printf("toml v1: %#v\n", d)
|
||||
|
||||
// toml v1: main.doc{A:main.inner{B:"After"}}
|
||||
```
|
||||
|
||||
In this case, field `A` is of type `interface{}`, containing a `inner` struct.
|
||||
V1 sees that type and uses it when decoding the object.
|
||||
|
||||
When decoding an object into an `interface{}`, V2 instead disregards whatever
|
||||
value the `interface{}` may contain and replaces it with a
|
||||
`map[string]interface{}`. With the same data structure as above, here is what
|
||||
the result looks like:
|
||||
|
||||
```go
|
||||
toml.Unmarshal([]byte(data), &d)
|
||||
fmt.Printf("toml v2: %#v\n", d)
|
||||
|
||||
// toml v2: main.doc{A:map[string]interface {}{"B":"After"}}
|
||||
```
|
||||
|
||||
This is to match `encoding/json`'s behavior. There is no way to make the v2
|
||||
decoder behave like v1.
|
||||
|
||||
#### Values out of array bounds ignored
|
||||
|
||||
When decoding into an array, v1 returns an error when the number of elements
|
||||
contained in the doc is superior to the capacity of the array. For example:
|
||||
|
||||
```go
|
||||
type doc struct {
|
||||
A [2]string
|
||||
}
|
||||
d := doc{}
|
||||
err := toml.Unmarshal([]byte(`A = ["one", "two", "many"]`), &d)
|
||||
fmt.Println(err)
|
||||
|
||||
// (1, 1): unmarshal: TOML array length (3) exceeds destination array length (2)
|
||||
```
|
||||
|
||||
In the same situation, v2 ignores the last value:
|
||||
|
||||
```go
|
||||
err := toml.Unmarshal([]byte(`A = ["one", "two", "many"]`), &d)
|
||||
fmt.Println("err:", err, "d:", d)
|
||||
// err: <nil> d: {[one two]}
|
||||
```
|
||||
|
||||
This is to match `encoding/json`'s behavior. There is no way to make the v2
|
||||
decoder behave like v1.
|
||||
|
||||
#### Support for `toml.Unmarshaler` has been dropped
|
||||
|
||||
This method was not widely used, poorly defined, and added a lot of complexity.
|
||||
A similar effect can be achieved by implementing the `encoding.TextUnmarshaler`
|
||||
interface and use strings.
|
||||
|
||||
#### Support for `default` struct tag has been dropped
|
||||
|
||||
This feature adds complexity and a poorly defined API for an effect that can be
|
||||
accomplished outside of the library.
|
||||
|
||||
It does not seem like other format parsers in Go support that feature (the
|
||||
project referenced in the original ticket #202 has not been updated since 2017).
|
||||
Given that go-toml v2 should not touch values not in the document, the same
|
||||
effect can be achieved by pre-filling the struct with defaults (libraries like
|
||||
[go-defaults][go-defaults] can help). Also, string representation is not well
|
||||
defined for all types: it creates issues like #278.
|
||||
|
||||
The recommended replacement is pre-filling the struct before unmarshaling.
|
||||
|
||||
[go-defaults]: https://github.com/mcuadros/go-defaults
|
||||
|
||||
#### `toml.Tree` replacement
|
||||
|
||||
This structure was the initial attempt at providing a document model for
|
||||
go-toml. It allows manipulating the structure of any document, encoding and
|
||||
decoding from their TOML representation. While a more robust feature was
|
||||
initially planned in go-toml v2, this has been ultimately [removed from
|
||||
scope][nodoc] of this library, with no plan to add it back at the moment. The
|
||||
closest equivalent at the moment would be to unmarshal into an `interface{}` and
|
||||
use type assertions and/or reflection to manipulate the arbitrary
|
||||
structure. However this would fall short of providing all of the TOML features
|
||||
such as adding comments and be specific about whitespace.
|
||||
|
||||
|
||||
#### `toml.Position` are not retrievable anymore
|
||||
|
||||
The API for retrieving the position (line, column) of a specific TOML element do
|
||||
not exist anymore. This was done to minimize the amount of concepts introduced
|
||||
by the library (query path), and avoid the performance hit related to storing
|
||||
positions in the absence of a document model, for a feature that seemed to have
|
||||
little use. Errors however have gained more detailed position
|
||||
information. Position retrieval seems better fitted for a document model, which
|
||||
has been [removed from the scope][nodoc] of go-toml v2 at the moment.
|
||||
|
||||
### Encoding / Marshal
|
||||
|
||||
#### Default struct fields order
|
||||
|
||||
V1 emits struct fields order alphabetically by default. V2 struct fields are
|
||||
emitted in order they are defined. For example:
|
||||
|
||||
```go
|
||||
type S struct {
|
||||
B string
|
||||
A string
|
||||
}
|
||||
|
||||
data := S{
|
||||
B: "B",
|
||||
A: "A",
|
||||
}
|
||||
|
||||
b, _ := tomlv1.Marshal(data)
|
||||
fmt.Println("v1:\n" + string(b))
|
||||
|
||||
b, _ = tomlv2.Marshal(data)
|
||||
fmt.Println("v2:\n" + string(b))
|
||||
|
||||
// Output:
|
||||
// v1:
|
||||
// A = "A"
|
||||
// B = "B"
|
||||
|
||||
// v2:
|
||||
// B = 'B'
|
||||
// A = 'A'
|
||||
```
|
||||
|
||||
There is no way to make v2 encoder behave like v1. A workaround could be to
|
||||
manually sort the fields alphabetically in the struct definition, or generate
|
||||
struct types using `reflect.StructOf`.
|
||||
|
||||
#### No indentation by default
|
||||
|
||||
V1 automatically indents content of tables by default. V2 does not. However the
|
||||
same behavior can be obtained using [`Encoder.SetIndentTables`][sit]. For example:
|
||||
|
||||
```go
|
||||
data := map[string]interface{}{
|
||||
"table": map[string]string{
|
||||
"key": "value",
|
||||
},
|
||||
}
|
||||
|
||||
b, _ := tomlv1.Marshal(data)
|
||||
fmt.Println("v1:\n" + string(b))
|
||||
|
||||
b, _ = tomlv2.Marshal(data)
|
||||
fmt.Println("v2:\n" + string(b))
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
enc := tomlv2.NewEncoder(&buf)
|
||||
enc.SetIndentTables(true)
|
||||
enc.Encode(data)
|
||||
fmt.Println("v2 Encoder:\n" + string(buf.Bytes()))
|
||||
|
||||
// Output:
|
||||
// v1:
|
||||
//
|
||||
// [table]
|
||||
// key = "value"
|
||||
//
|
||||
// v2:
|
||||
// [table]
|
||||
// key = 'value'
|
||||
//
|
||||
//
|
||||
// v2 Encoder:
|
||||
// [table]
|
||||
// key = 'value'
|
||||
```
|
||||
|
||||
[sit]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Encoder.SetIndentTables
|
||||
|
||||
#### Keys and strings are single quoted
|
||||
|
||||
V1 always uses double quotes (`"`) around strings and keys that cannot be
|
||||
represented bare (unquoted). V2 uses single quotes instead by default (`'`),
|
||||
unless a character cannot be represented, then falls back to double quotes. As a
|
||||
result of this change, `Encoder.QuoteMapKeys` has been removed, as it is not
|
||||
useful anymore.
|
||||
|
||||
There is no way to make v2 encoder behave like v1.
|
||||
|
||||
#### `TextMarshaler` emits as a string, not TOML
|
||||
|
||||
Types that implement [`encoding.TextMarshaler`][tm] can emit arbitrary TOML in
|
||||
v1. The encoder would append the result to the output directly. In v2 the result
|
||||
is wrapped in a string. As a result, this interface cannot be implemented by the
|
||||
root object.
|
||||
|
||||
There is no way to make v2 encoder behave like v1.
|
||||
|
||||
[tm]: https://golang.org/pkg/encoding/#TextMarshaler
|
||||
|
||||
#### `Encoder.CompactComments` has been removed
|
||||
|
||||
Emitting compact comments is now the default behavior of go-toml. This option
|
||||
is not necessary anymore.
|
||||
|
||||
#### Struct tags have been merged
|
||||
|
||||
V1 used to provide multiple struct tags: `comment`, `commented`, `multiline`,
|
||||
`toml`, and `omitempty`. To behave more like the standard library, v2 has merged
|
||||
`toml`, `multiline`, and `omitempty`. For example:
|
||||
|
||||
```go
|
||||
type doc struct {
|
||||
// v1
|
||||
F string `toml:"field" multiline:"true" omitempty:"true"`
|
||||
// v2
|
||||
F string `toml:"field,multiline,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
Has a result, the `Encoder.SetTag*` methods have been removed, as there is just
|
||||
one tag now.
|
||||
|
||||
|
||||
#### `commented` tag has been removed
|
||||
|
||||
There is no replacement for the `commented` tag. This feature would be better
|
||||
suited in a proper document model for go-toml v2, which has been [cut from
|
||||
scope][nodoc] at the moment.
|
||||
|
||||
#### `Encoder.ArraysWithOneElementPerLine` has been renamed
|
||||
|
||||
The new name is `Encoder.SetArraysMultiline`. The behavior should be the same.
|
||||
|
||||
#### `Encoder.Indentation` has been renamed
|
||||
|
||||
The new name is `Encoder.SetIndentSymbol`. The behavior should be the same.
|
||||
|
||||
|
||||
#### Embedded structs behave like stdlib
|
||||
|
||||
V1 defaults to merging embedded struct fields into the embedding struct. This
|
||||
behavior was unexpected because it does not follow the standard library. To
|
||||
avoid breaking backward compatibility, the `Encoder.PromoteAnonymous` method was
|
||||
added to make the encoder behave correctly. Given backward compatibility is not
|
||||
a problem anymore, v2 does the right thing by default: it follows the behavior
|
||||
of `encoding/json`. `Encoder.PromoteAnonymous` has been removed.
|
||||
|
||||
[nodoc]: https://github.com/pelletier/go-toml/discussions/506#discussioncomment-1526038
|
||||
|
||||
### `query`
|
||||
|
||||
go-toml v1 provided the [`go-toml/query`][query] package. It allowed to run
|
||||
JSONPath-style queries on TOML files. This feature is not available in v2. For a
|
||||
replacement, check out [dasel][dasel].
|
||||
|
||||
This package has been removed because it was essentially not supported anymore
|
||||
(last commit May 2020), increased the complexity of the code base, and more
|
||||
complete solutions exist out there.
|
||||
|
||||
[query]: https://github.com/pelletier/go-toml/tree/f99d6bbca119636aeafcf351ee52b3d202782627/query
|
||||
[dasel]: https://github.com/TomWright/dasel
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT). Read [LICENSE](LICENSE).
|
19
vendor/github.com/pelletier/go-toml/v2/SECURITY.md
generated
vendored
Normal file
19
vendor/github.com/pelletier/go-toml/v2/SECURITY.md
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ---------- | ------------------ |
|
||||
| Latest 2.x | :white_check_mark: |
|
||||
| All 1.x | :x: |
|
||||
| All 0.x | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Email a vulnerability report to `security@pelletier.codes`. Make sure to include
|
||||
as many details as possible to reproduce the vulnerability. This is a
|
||||
side-project: I will try to get back to you as quickly as possible, time
|
||||
permitting in my personal life. Providing a working patch helps very much!
|
279
vendor/github.com/pelletier/go-toml/v2/ci.sh
generated
vendored
Normal file
279
vendor/github.com/pelletier/go-toml/v2/ci.sh
generated
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
|
||||
stderr() {
|
||||
echo "$@" 1>&2
|
||||
}
|
||||
|
||||
usage() {
|
||||
b=$(basename "$0")
|
||||
echo $b: ERROR: "$@" 1>&2
|
||||
|
||||
cat 1>&2 <<EOF
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
$(basename "$0") is the script to run continuous integration commands for
|
||||
go-toml on unix.
|
||||
|
||||
Requires Go and Git to be available in the PATH. Expects to be ran from the
|
||||
root of go-toml's Git repository.
|
||||
|
||||
USAGE
|
||||
|
||||
$b COMMAND [OPTIONS...]
|
||||
|
||||
COMMANDS
|
||||
|
||||
benchmark [OPTIONS...] [BRANCH]
|
||||
|
||||
Run benchmarks.
|
||||
|
||||
ARGUMENTS
|
||||
|
||||
BRANCH Optional. Defines which Git branch to use when running
|
||||
benchmarks.
|
||||
|
||||
OPTIONS
|
||||
|
||||
-d Compare benchmarks of HEAD with BRANCH using benchstats. In
|
||||
this form the BRANCH argument is required.
|
||||
|
||||
-a Compare benchmarks of HEAD against go-toml v1 and
|
||||
BurntSushi/toml.
|
||||
|
||||
-html When used with -a, emits the output as HTML, ready to be
|
||||
embedded in the README.
|
||||
|
||||
coverage [OPTIONS...] [BRANCH]
|
||||
|
||||
Generates code coverage.
|
||||
|
||||
ARGUMENTS
|
||||
|
||||
BRANCH Optional. Defines which Git branch to use when reporting
|
||||
coverage. Defaults to HEAD.
|
||||
|
||||
OPTIONS
|
||||
|
||||
-d Compare coverage of HEAD with the one of BRANCH. In this form,
|
||||
the BRANCH argument is required. Exit code is non-zero when
|
||||
coverage percentage decreased.
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
cover() {
|
||||
branch="${1}"
|
||||
dir="$(mktemp -d)"
|
||||
|
||||
stderr "Executing coverage for ${branch} at ${dir}"
|
||||
|
||||
if [ "${branch}" = "HEAD" ]; then
|
||||
cp -r . "${dir}/"
|
||||
else
|
||||
git worktree add "$dir" "$branch"
|
||||
fi
|
||||
|
||||
pushd "$dir"
|
||||
go test -covermode=atomic -coverpkg=./... -coverprofile=coverage.out.tmp ./...
|
||||
cat coverage.out.tmp | grep -v testsuite | grep -v tomltestgen | grep -v gotoml-test-decoder > coverage.out
|
||||
go tool cover -func=coverage.out
|
||||
popd
|
||||
|
||||
if [ "${branch}" != "HEAD" ]; then
|
||||
git worktree remove --force "$dir"
|
||||
fi
|
||||
}
|
||||
|
||||
coverage() {
|
||||
case "$1" in
|
||||
-d)
|
||||
shift
|
||||
target="${1?Need to provide a target branch argument}"
|
||||
|
||||
output_dir="$(mktemp -d)"
|
||||
target_out="${output_dir}/target.txt"
|
||||
head_out="${output_dir}/head.txt"
|
||||
|
||||
cover "${target}" > "${target_out}"
|
||||
cover "HEAD" > "${head_out}"
|
||||
|
||||
cat "${target_out}"
|
||||
cat "${head_out}"
|
||||
|
||||
echo ""
|
||||
|
||||
target_pct="$(tail -n2 ${target_out} | head -n1 | sed -E 's/.*total.*\t([0-9.]+)%.*/\1/')"
|
||||
head_pct="$(tail -n2 ${head_out} | head -n1 | sed -E 's/.*total.*\t([0-9.]+)%/\1/')"
|
||||
echo "Results: ${target} ${target_pct}% HEAD ${head_pct}%"
|
||||
|
||||
delta_pct=$(echo "$head_pct - $target_pct" | bc -l)
|
||||
echo "Delta: ${delta_pct}"
|
||||
|
||||
if [[ $delta_pct = \-* ]]; then
|
||||
echo "Regression!";
|
||||
|
||||
target_diff="${output_dir}/target.diff.txt"
|
||||
head_diff="${output_dir}/head.diff.txt"
|
||||
cat "${target_out}" | grep -E '^github.com/pelletier/go-toml' | tr -s "\t " | cut -f 2,3 | sort > "${target_diff}"
|
||||
cat "${head_out}" | grep -E '^github.com/pelletier/go-toml' | tr -s "\t " | cut -f 2,3 | sort > "${head_diff}"
|
||||
|
||||
diff --side-by-side --suppress-common-lines "${target_diff}" "${head_diff}"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
cover "${1-HEAD}"
|
||||
}
|
||||
|
||||
bench() {
|
||||
branch="${1}"
|
||||
out="${2}"
|
||||
replace="${3}"
|
||||
dir="$(mktemp -d)"
|
||||
|
||||
stderr "Executing benchmark for ${branch} at ${dir}"
|
||||
|
||||
if [ "${branch}" = "HEAD" ]; then
|
||||
cp -r . "${dir}/"
|
||||
else
|
||||
git worktree add "$dir" "$branch"
|
||||
fi
|
||||
|
||||
pushd "$dir"
|
||||
|
||||
if [ "${replace}" != "" ]; then
|
||||
find ./benchmark/ -iname '*.go' -exec sed -i -E "s|github.com/pelletier/go-toml/v2|${replace}|g" {} \;
|
||||
go get "${replace}"
|
||||
fi
|
||||
|
||||
export GOMAXPROCS=2
|
||||
nice -n -19 taskset --cpu-list 0,1 go test '-bench=^Benchmark(Un)?[mM]arshal' -count=5 -run=Nothing ./... | tee "${out}"
|
||||
popd
|
||||
|
||||
if [ "${branch}" != "HEAD" ]; then
|
||||
git worktree remove --force "$dir"
|
||||
fi
|
||||
}
|
||||
|
||||
fmktemp() {
|
||||
if mktemp --version|grep GNU >/dev/null; then
|
||||
mktemp --suffix=-$1;
|
||||
else
|
||||
mktemp -t $1;
|
||||
fi
|
||||
}
|
||||
|
||||
benchstathtml() {
|
||||
python3 - $1 <<'EOF'
|
||||
import sys
|
||||
|
||||
lines = []
|
||||
stop = False
|
||||
|
||||
with open(sys.argv[1]) as f:
|
||||
for line in f.readlines():
|
||||
line = line.strip()
|
||||
if line == "":
|
||||
stop = True
|
||||
if not stop:
|
||||
lines.append(line.split(','))
|
||||
|
||||
results = []
|
||||
for line in reversed(lines[1:]):
|
||||
v2 = float(line[1])
|
||||
results.append([
|
||||
line[0].replace("-32", ""),
|
||||
"%.1fx" % (float(line[3])/v2), # v1
|
||||
"%.1fx" % (float(line[5])/v2), # bs
|
||||
])
|
||||
# move geomean to the end
|
||||
results.append(results[0])
|
||||
del results[0]
|
||||
|
||||
|
||||
def printtable(data):
|
||||
print("""
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Benchmark</th><th>go-toml v1</th><th>BurntSushi/toml</th></tr>
|
||||
</thead>
|
||||
<tbody>""")
|
||||
|
||||
for r in data:
|
||||
print(" <tr><td>{}</td><td>{}</td><td>{}</td></tr>".format(*r))
|
||||
|
||||
print(""" </tbody>
|
||||
</table>""")
|
||||
|
||||
|
||||
def match(x):
|
||||
return "ReferenceFile" in x[0] or "HugoFrontMatter" in x[0]
|
||||
|
||||
above = [x for x in results if match(x)]
|
||||
below = [x for x in results if not match(x)]
|
||||
|
||||
printtable(above)
|
||||
print("<details><summary>See more</summary>")
|
||||
print("""<p>The table above has the results of the most common use-cases. The table below
|
||||
contains the results of all benchmarks, including unrealistic ones. It is
|
||||
provided for completeness.</p>""")
|
||||
printtable(below)
|
||||
print('<p>This table can be generated with <code>./ci.sh benchmark -a -html</code>.</p>')
|
||||
print("</details>")
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
benchmark() {
|
||||
case "$1" in
|
||||
-d)
|
||||
shift
|
||||
target="${1?Need to provide a target branch argument}"
|
||||
|
||||
old=`fmktemp ${target}`
|
||||
bench "${target}" "${old}"
|
||||
|
||||
new=`fmktemp HEAD`
|
||||
bench HEAD "${new}"
|
||||
|
||||
benchstat "${old}" "${new}"
|
||||
return 0
|
||||
;;
|
||||
-a)
|
||||
shift
|
||||
|
||||
v2stats=`fmktemp go-toml-v2`
|
||||
bench HEAD "${v2stats}" "github.com/pelletier/go-toml/v2"
|
||||
v1stats=`fmktemp go-toml-v1`
|
||||
bench HEAD "${v1stats}" "github.com/pelletier/go-toml"
|
||||
bsstats=`fmktemp bs-toml`
|
||||
bench HEAD "${bsstats}" "github.com/BurntSushi/toml"
|
||||
|
||||
cp "${v2stats}" go-toml-v2.txt
|
||||
cp "${v1stats}" go-toml-v1.txt
|
||||
cp "${bsstats}" bs-toml.txt
|
||||
|
||||
if [ "$1" = "-html" ]; then
|
||||
tmpcsv=`fmktemp csv`
|
||||
benchstat -csv -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt > $tmpcsv
|
||||
benchstathtml $tmpcsv
|
||||
else
|
||||
benchstat -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt
|
||||
fi
|
||||
|
||||
rm -f go-toml-v2.txt go-toml-v1.txt bs-toml.txt
|
||||
return $?
|
||||
esac
|
||||
|
||||
bench "${1-HEAD}" `mktemp`
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
coverage) shift; coverage $@;;
|
||||
benchmark) shift; benchmark $@;;
|
||||
*) usage "bad argument $1";;
|
||||
esac
|
544
vendor/github.com/pelletier/go-toml/v2/decode.go
generated
vendored
Normal file
544
vendor/github.com/pelletier/go-toml/v2/decode.go
generated
vendored
Normal file
@ -0,0 +1,544 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func parseInteger(b []byte) (int64, error) {
|
||||
if len(b) > 2 && b[0] == '0' {
|
||||
switch b[1] {
|
||||
case 'x':
|
||||
return parseIntHex(b)
|
||||
case 'b':
|
||||
return parseIntBin(b)
|
||||
case 'o':
|
||||
return parseIntOct(b)
|
||||
default:
|
||||
panic(fmt.Errorf("invalid base '%c', should have been checked by scanIntOrFloat", b[1]))
|
||||
}
|
||||
}
|
||||
|
||||
return parseIntDec(b)
|
||||
}
|
||||
|
||||
func parseLocalDate(b []byte) (LocalDate, error) {
|
||||
// full-date = date-fullyear "-" date-month "-" date-mday
|
||||
// date-fullyear = 4DIGIT
|
||||
// date-month = 2DIGIT ; 01-12
|
||||
// date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
||||
var date LocalDate
|
||||
|
||||
if len(b) != 10 || b[4] != '-' || b[7] != '-' {
|
||||
return date, newDecodeError(b, "dates are expected to have the format YYYY-MM-DD")
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
date.Year, err = parseDecimalDigits(b[0:4])
|
||||
if err != nil {
|
||||
return LocalDate{}, err
|
||||
}
|
||||
|
||||
date.Month, err = parseDecimalDigits(b[5:7])
|
||||
if err != nil {
|
||||
return LocalDate{}, err
|
||||
}
|
||||
|
||||
date.Day, err = parseDecimalDigits(b[8:10])
|
||||
if err != nil {
|
||||
return LocalDate{}, err
|
||||
}
|
||||
|
||||
if !isValidDate(date.Year, date.Month, date.Day) {
|
||||
return LocalDate{}, newDecodeError(b, "impossible date")
|
||||
}
|
||||
|
||||
return date, nil
|
||||
}
|
||||
|
||||
func parseDecimalDigits(b []byte) (int, error) {
|
||||
v := 0
|
||||
|
||||
for i, c := range b {
|
||||
if c < '0' || c > '9' {
|
||||
return 0, newDecodeError(b[i:i+1], "expected digit (0-9)")
|
||||
}
|
||||
v *= 10
|
||||
v += int(c - '0')
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func parseDateTime(b []byte) (time.Time, error) {
|
||||
// offset-date-time = full-date time-delim full-time
|
||||
// full-time = partial-time time-offset
|
||||
// time-offset = "Z" / time-numoffset
|
||||
// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
|
||||
|
||||
dt, b, err := parseLocalDateTime(b)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
var zone *time.Location
|
||||
|
||||
if len(b) == 0 {
|
||||
// parser should have checked that when assigning the date time node
|
||||
panic("date time should have a timezone")
|
||||
}
|
||||
|
||||
if b[0] == 'Z' || b[0] == 'z' {
|
||||
b = b[1:]
|
||||
zone = time.UTC
|
||||
} else {
|
||||
const dateTimeByteLen = 6
|
||||
if len(b) != dateTimeByteLen {
|
||||
return time.Time{}, newDecodeError(b, "invalid date-time timezone")
|
||||
}
|
||||
var direction int
|
||||
switch b[0] {
|
||||
case '-':
|
||||
direction = -1
|
||||
case '+':
|
||||
direction = +1
|
||||
default:
|
||||
return time.Time{}, newDecodeError(b[:1], "invalid timezone offset character")
|
||||
}
|
||||
|
||||
if b[3] != ':' {
|
||||
return time.Time{}, newDecodeError(b[3:4], "expected a : separator")
|
||||
}
|
||||
|
||||
hours, err := parseDecimalDigits(b[1:3])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if hours > 23 {
|
||||
return time.Time{}, newDecodeError(b[:1], "invalid timezone offset hours")
|
||||
}
|
||||
|
||||
minutes, err := parseDecimalDigits(b[4:6])
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if minutes > 59 {
|
||||
return time.Time{}, newDecodeError(b[:1], "invalid timezone offset minutes")
|
||||
}
|
||||
|
||||
seconds := direction * (hours*3600 + minutes*60)
|
||||
if seconds == 0 {
|
||||
zone = time.UTC
|
||||
} else {
|
||||
zone = time.FixedZone("", seconds)
|
||||
}
|
||||
b = b[dateTimeByteLen:]
|
||||
}
|
||||
|
||||
if len(b) > 0 {
|
||||
return time.Time{}, newDecodeError(b, "extra bytes at the end of the timezone")
|
||||
}
|
||||
|
||||
t := time.Date(
|
||||
dt.Year,
|
||||
time.Month(dt.Month),
|
||||
dt.Day,
|
||||
dt.Hour,
|
||||
dt.Minute,
|
||||
dt.Second,
|
||||
dt.Nanosecond,
|
||||
zone)
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
|
||||
var dt LocalDateTime
|
||||
|
||||
const localDateTimeByteMinLen = 11
|
||||
if len(b) < localDateTimeByteMinLen {
|
||||
return dt, nil, newDecodeError(b, "local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNNNNN]")
|
||||
}
|
||||
|
||||
date, err := parseLocalDate(b[:10])
|
||||
if err != nil {
|
||||
return dt, nil, err
|
||||
}
|
||||
dt.LocalDate = date
|
||||
|
||||
sep := b[10]
|
||||
if sep != 'T' && sep != ' ' && sep != 't' {
|
||||
return dt, nil, newDecodeError(b[10:11], "datetime separator is expected to be T or a space")
|
||||
}
|
||||
|
||||
t, rest, err := parseLocalTime(b[11:])
|
||||
if err != nil {
|
||||
return dt, nil, err
|
||||
}
|
||||
dt.LocalTime = t
|
||||
|
||||
return dt, rest, nil
|
||||
}
|
||||
|
||||
// parseLocalTime is a bit different because it also returns the remaining
|
||||
// []byte that is didn't need. This is to allow parseDateTime to parse those
|
||||
// remaining bytes as a timezone.
|
||||
func parseLocalTime(b []byte) (LocalTime, []byte, error) {
|
||||
var (
|
||||
nspow = [10]int{0, 1e8, 1e7, 1e6, 1e5, 1e4, 1e3, 1e2, 1e1, 1e0}
|
||||
t LocalTime
|
||||
)
|
||||
|
||||
// check if b matches to have expected format HH:MM:SS[.NNNNNN]
|
||||
const localTimeByteLen = 8
|
||||
if len(b) < localTimeByteLen {
|
||||
return t, nil, newDecodeError(b, "times are expected to have the format HH:MM:SS[.NNNNNN]")
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
t.Hour, err = parseDecimalDigits(b[0:2])
|
||||
if err != nil {
|
||||
return t, nil, err
|
||||
}
|
||||
|
||||
if t.Hour > 23 {
|
||||
return t, nil, newDecodeError(b[0:2], "hour cannot be greater 23")
|
||||
}
|
||||
if b[2] != ':' {
|
||||
return t, nil, newDecodeError(b[2:3], "expecting colon between hours and minutes")
|
||||
}
|
||||
|
||||
t.Minute, err = parseDecimalDigits(b[3:5])
|
||||
if err != nil {
|
||||
return t, nil, err
|
||||
}
|
||||
if t.Minute > 59 {
|
||||
return t, nil, newDecodeError(b[3:5], "minutes cannot be greater 59")
|
||||
}
|
||||
if b[5] != ':' {
|
||||
return t, nil, newDecodeError(b[5:6], "expecting colon between minutes and seconds")
|
||||
}
|
||||
|
||||
t.Second, err = parseDecimalDigits(b[6:8])
|
||||
if err != nil {
|
||||
return t, nil, err
|
||||
}
|
||||
|
||||
if t.Second > 60 {
|
||||
return t, nil, newDecodeError(b[6:8], "seconds cannot be greater 60")
|
||||
}
|
||||
|
||||
b = b[8:]
|
||||
|
||||
if len(b) >= 1 && b[0] == '.' {
|
||||
frac := 0
|
||||
precision := 0
|
||||
digits := 0
|
||||
|
||||
for i, c := range b[1:] {
|
||||
if !isDigit(c) {
|
||||
if i == 0 {
|
||||
return t, nil, newDecodeError(b[0:1], "need at least one digit after fraction point")
|
||||
}
|
||||
break
|
||||
}
|
||||
digits++
|
||||
|
||||
const maxFracPrecision = 9
|
||||
if i >= maxFracPrecision {
|
||||
// go-toml allows decoding fractional seconds
|
||||
// beyond the supported precision of 9
|
||||
// digits. It truncates the fractional component
|
||||
// to the supported precision and ignores the
|
||||
// remaining digits.
|
||||
//
|
||||
// https://github.com/pelletier/go-toml/discussions/707
|
||||
continue
|
||||
}
|
||||
|
||||
frac *= 10
|
||||
frac += int(c - '0')
|
||||
precision++
|
||||
}
|
||||
|
||||
if precision == 0 {
|
||||
return t, nil, newDecodeError(b[:1], "nanoseconds need at least one digit")
|
||||
}
|
||||
|
||||
t.Nanosecond = frac * nspow[precision]
|
||||
t.Precision = precision
|
||||
|
||||
return t, b[1+digits:], nil
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
cleaned, err := checkAndRemoveUnderscoresFloats(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if cleaned[0] == '.' {
|
||||
return 0, newDecodeError(b, "float cannot start with a dot")
|
||||
}
|
||||
|
||||
if cleaned[len(cleaned)-1] == '.' {
|
||||
return 0, newDecodeError(b, "float cannot end with a dot")
|
||||
}
|
||||
|
||||
dotAlreadySeen := false
|
||||
for i, c := range cleaned {
|
||||
if c == '.' {
|
||||
if dotAlreadySeen {
|
||||
return 0, newDecodeError(b[i:i+1], "float can have at most one decimal point")
|
||||
}
|
||||
if !isDigit(cleaned[i-1]) {
|
||||
return 0, newDecodeError(b[i-1:i+1], "float decimal point must be preceded by a digit")
|
||||
}
|
||||
if !isDigit(cleaned[i+1]) {
|
||||
return 0, newDecodeError(b[i:i+2], "float decimal point must be followed by a digit")
|
||||
}
|
||||
dotAlreadySeen = true
|
||||
}
|
||||
}
|
||||
|
||||
start := 0
|
||||
if cleaned[0] == '+' || cleaned[0] == '-' {
|
||||
start = 1
|
||||
}
|
||||
if cleaned[start] == '0' && isDigit(cleaned[start+1]) {
|
||||
return 0, newDecodeError(b, "float integer part cannot have leading zeroes")
|
||||
}
|
||||
|
||||
f, err := strconv.ParseFloat(string(cleaned), 64)
|
||||
if err != nil {
|
||||
return 0, newDecodeError(b, "unable to parse float: %w", err)
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func parseIntHex(b []byte) (int64, error) {
|
||||
cleaned, err := checkAndRemoveUnderscoresIntegers(b[2:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(string(cleaned), 16, 64)
|
||||
if err != nil {
|
||||
return 0, newDecodeError(b, "couldn't parse hexadecimal number: %w", err)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func parseIntOct(b []byte) (int64, error) {
|
||||
cleaned, err := checkAndRemoveUnderscoresIntegers(b[2:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(string(cleaned), 8, 64)
|
||||
if err != nil {
|
||||
return 0, newDecodeError(b, "couldn't parse octal number: %w", err)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func parseIntBin(b []byte) (int64, error) {
|
||||
cleaned, err := checkAndRemoveUnderscoresIntegers(b[2:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(string(cleaned), 2, 64)
|
||||
if err != nil {
|
||||
return 0, newDecodeError(b, "couldn't parse binary number: %w", err)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func isSign(b byte) bool {
|
||||
return b == '+' || b == '-'
|
||||
}
|
||||
|
||||
func parseIntDec(b []byte) (int64, error) {
|
||||
cleaned, err := checkAndRemoveUnderscoresIntegers(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
startIdx := 0
|
||||
|
||||
if isSign(cleaned[0]) {
|
||||
startIdx++
|
||||
}
|
||||
|
||||
if len(cleaned) > startIdx+1 && cleaned[startIdx] == '0' {
|
||||
return 0, newDecodeError(b, "leading zero not allowed on decimal number")
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(string(cleaned), 10, 64)
|
||||
if err != nil {
|
||||
return 0, newDecodeError(b, "couldn't parse decimal number: %w", err)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func checkAndRemoveUnderscoresIntegers(b []byte) ([]byte, error) {
|
||||
start := 0
|
||||
if b[start] == '+' || b[start] == '-' {
|
||||
start++
|
||||
}
|
||||
|
||||
if len(b) == start {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
if b[start] == '_' {
|
||||
return nil, newDecodeError(b[start:start+1], "number cannot start with underscore")
|
||||
}
|
||||
|
||||
if b[len(b)-1] == '_' {
|
||||
return nil, newDecodeError(b[len(b)-1:], "number cannot end with underscore")
|
||||
}
|
||||
|
||||
// fast path
|
||||
i := 0
|
||||
for ; i < len(b); i++ {
|
||||
if b[i] == '_' {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(b) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
before := false
|
||||
cleaned := make([]byte, i, len(b))
|
||||
copy(cleaned, b)
|
||||
|
||||
for i++; i < len(b); i++ {
|
||||
c := b[i]
|
||||
if c == '_' {
|
||||
if !before {
|
||||
return nil, newDecodeError(b[i-1:i+1], "number must have at least one digit between underscores")
|
||||
}
|
||||
before = false
|
||||
} else {
|
||||
before = true
|
||||
cleaned = append(cleaned, c)
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned, nil
|
||||
}
|
||||
|
||||
func checkAndRemoveUnderscoresFloats(b []byte) ([]byte, error) {
|
||||
if b[0] == '_' {
|
||||
return nil, newDecodeError(b[0:1], "number cannot start with underscore")
|
||||
}
|
||||
|
||||
if b[len(b)-1] == '_' {
|
||||
return nil, newDecodeError(b[len(b)-1:], "number cannot end with underscore")
|
||||
}
|
||||
|
||||
// fast path
|
||||
i := 0
|
||||
for ; i < len(b); i++ {
|
||||
if b[i] == '_' {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(b) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
before := false
|
||||
cleaned := make([]byte, 0, len(b))
|
||||
|
||||
for i := 0; i < len(b); i++ {
|
||||
c := b[i]
|
||||
|
||||
switch c {
|
||||
case '_':
|
||||
if !before {
|
||||
return nil, newDecodeError(b[i-1:i+1], "number must have at least one digit between underscores")
|
||||
}
|
||||
if i < len(b)-1 && (b[i+1] == 'e' || b[i+1] == 'E') {
|
||||
return nil, newDecodeError(b[i+1:i+2], "cannot have underscore before exponent")
|
||||
}
|
||||
before = false
|
||||
case '+', '-':
|
||||
// signed exponents
|
||||
cleaned = append(cleaned, c)
|
||||
before = false
|
||||
case 'e', 'E':
|
||||
if i < len(b)-1 && b[i+1] == '_' {
|
||||
return nil, newDecodeError(b[i+1:i+2], "cannot have underscore after exponent")
|
||||
}
|
||||
cleaned = append(cleaned, c)
|
||||
case '.':
|
||||
if i < len(b)-1 && b[i+1] == '_' {
|
||||
return nil, newDecodeError(b[i+1:i+2], "cannot have underscore after decimal point")
|
||||
}
|
||||
if i > 0 && b[i-1] == '_' {
|
||||
return nil, newDecodeError(b[i-1:i], "cannot have underscore before decimal point")
|
||||
}
|
||||
cleaned = append(cleaned, c)
|
||||
default:
|
||||
before = true
|
||||
cleaned = append(cleaned, c)
|
||||
}
|
||||
}
|
||||
|
||||
return cleaned, nil
|
||||
}
|
||||
|
||||
// isValidDate checks if a provided date is a date that exists.
|
||||
func isValidDate(year int, month int, day int) bool {
|
||||
return month > 0 && month < 13 && day > 0 && day <= daysIn(month, year)
|
||||
}
|
||||
|
||||
// daysBefore[m] counts the number of days in a non-leap year
|
||||
// before month m begins. There is an entry for m=12, counting
|
||||
// the number of days before January of next year (365).
|
||||
var daysBefore = [...]int32{
|
||||
0,
|
||||
31,
|
||||
31 + 28,
|
||||
31 + 28 + 31,
|
||||
31 + 28 + 31 + 30,
|
||||
31 + 28 + 31 + 30 + 31,
|
||||
31 + 28 + 31 + 30 + 31 + 30,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
|
||||
}
|
||||
|
||||
func daysIn(m int, year int) int {
|
||||
if m == 2 && isLeap(year) {
|
||||
return 29
|
||||
}
|
||||
return int(daysBefore[m] - daysBefore[m-1])
|
||||
}
|
||||
|
||||
func isLeap(year int) bool {
|
||||
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
|
||||
}
|
2
vendor/github.com/pelletier/go-toml/v2/doc.go
generated
vendored
Normal file
2
vendor/github.com/pelletier/go-toml/v2/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package toml is a library to read and write TOML documents.
|
||||
package toml
|
269
vendor/github.com/pelletier/go-toml/v2/errors.go
generated
vendored
Normal file
269
vendor/github.com/pelletier/go-toml/v2/errors.go
generated
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||
)
|
||||
|
||||
// DecodeError represents an error encountered during the parsing or decoding
|
||||
// of a TOML document.
|
||||
//
|
||||
// In addition to the error message, it contains the position in the document
|
||||
// where it happened, as well as a human-readable representation that shows
|
||||
// where the error occurred in the document.
|
||||
type DecodeError struct {
|
||||
message string
|
||||
line int
|
||||
column int
|
||||
key Key
|
||||
|
||||
human string
|
||||
}
|
||||
|
||||
// StrictMissingError occurs in a TOML document that does not have a
|
||||
// corresponding field in the target value. It contains all the missing fields
|
||||
// in Errors.
|
||||
//
|
||||
// Emitted by Decoder when DisallowUnknownFields() was called.
|
||||
type StrictMissingError struct {
|
||||
// One error per field that could not be found.
|
||||
Errors []DecodeError
|
||||
}
|
||||
|
||||
// Error returns the canonical string for this error.
|
||||
func (s *StrictMissingError) Error() string {
|
||||
return "strict mode: fields in the document are missing in the target struct"
|
||||
}
|
||||
|
||||
// String returns a human readable description of all errors.
|
||||
func (s *StrictMissingError) String() string {
|
||||
var buf strings.Builder
|
||||
|
||||
for i, e := range s.Errors {
|
||||
if i > 0 {
|
||||
buf.WriteString("\n---\n")
|
||||
}
|
||||
|
||||
buf.WriteString(e.String())
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type Key []string
|
||||
|
||||
// internal version of DecodeError that is used as the base to create a
|
||||
// DecodeError with full context.
|
||||
type decodeError struct {
|
||||
highlight []byte
|
||||
message string
|
||||
key Key // optional
|
||||
}
|
||||
|
||||
func (de *decodeError) Error() string {
|
||||
return de.message
|
||||
}
|
||||
|
||||
func newDecodeError(highlight []byte, format string, args ...interface{}) error {
|
||||
return &decodeError{
|
||||
highlight: highlight,
|
||||
message: fmt.Errorf(format, args...).Error(),
|
||||
}
|
||||
}
|
||||
|
||||
// Error returns the error message contained in the DecodeError.
|
||||
func (e *DecodeError) Error() string {
|
||||
return "toml: " + e.message
|
||||
}
|
||||
|
||||
// String returns the human-readable contextualized error. This string is multi-line.
|
||||
func (e *DecodeError) String() string {
|
||||
return e.human
|
||||
}
|
||||
|
||||
// Position returns the (line, column) pair indicating where the error
|
||||
// occurred in the document. Positions are 1-indexed.
|
||||
func (e *DecodeError) Position() (row int, column int) {
|
||||
return e.line, e.column
|
||||
}
|
||||
|
||||
// Key that was being processed when the error occurred. The key is present only
|
||||
// if this DecodeError is part of a StrictMissingError.
|
||||
func (e *DecodeError) Key() Key {
|
||||
return e.key
|
||||
}
|
||||
|
||||
// decodeErrorFromHighlight creates a DecodeError referencing a highlighted
|
||||
// range of bytes from document.
|
||||
//
|
||||
// highlight needs to be a sub-slice of document, or this function panics.
|
||||
//
|
||||
// The function copies all bytes used in DecodeError, so that document and
|
||||
// highlight can be freely deallocated.
|
||||
//nolint:funlen
|
||||
func wrapDecodeError(document []byte, de *decodeError) *DecodeError {
|
||||
offset := danger.SubsliceOffset(document, de.highlight)
|
||||
|
||||
errMessage := de.Error()
|
||||
errLine, errColumn := positionAtEnd(document[:offset])
|
||||
before, after := linesOfContext(document, de.highlight, offset, 3)
|
||||
|
||||
var buf strings.Builder
|
||||
|
||||
maxLine := errLine + len(after) - 1
|
||||
lineColumnWidth := len(strconv.Itoa(maxLine))
|
||||
|
||||
// Write the lines of context strictly before the error.
|
||||
for i := len(before) - 1; i > 0; i-- {
|
||||
line := errLine - i
|
||||
buf.WriteString(formatLineNumber(line, lineColumnWidth))
|
||||
buf.WriteString("|")
|
||||
|
||||
if len(before[i]) > 0 {
|
||||
buf.WriteString(" ")
|
||||
buf.Write(before[i])
|
||||
}
|
||||
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
|
||||
// Write the document line that contains the error.
|
||||
|
||||
buf.WriteString(formatLineNumber(errLine, lineColumnWidth))
|
||||
buf.WriteString("| ")
|
||||
|
||||
if len(before) > 0 {
|
||||
buf.Write(before[0])
|
||||
}
|
||||
|
||||
buf.Write(de.highlight)
|
||||
|
||||
if len(after) > 0 {
|
||||
buf.Write(after[0])
|
||||
}
|
||||
|
||||
buf.WriteRune('\n')
|
||||
|
||||
// Write the line with the error message itself (so it does not have a line
|
||||
// number).
|
||||
|
||||
buf.WriteString(strings.Repeat(" ", lineColumnWidth))
|
||||
buf.WriteString("| ")
|
||||
|
||||
if len(before) > 0 {
|
||||
buf.WriteString(strings.Repeat(" ", len(before[0])))
|
||||
}
|
||||
|
||||
buf.WriteString(strings.Repeat("~", len(de.highlight)))
|
||||
|
||||
if len(errMessage) > 0 {
|
||||
buf.WriteString(" ")
|
||||
buf.WriteString(errMessage)
|
||||
}
|
||||
|
||||
// Write the lines of context strictly after the error.
|
||||
|
||||
for i := 1; i < len(after); i++ {
|
||||
buf.WriteRune('\n')
|
||||
line := errLine + i
|
||||
buf.WriteString(formatLineNumber(line, lineColumnWidth))
|
||||
buf.WriteString("|")
|
||||
|
||||
if len(after[i]) > 0 {
|
||||
buf.WriteString(" ")
|
||||
buf.Write(after[i])
|
||||
}
|
||||
}
|
||||
|
||||
return &DecodeError{
|
||||
message: errMessage,
|
||||
line: errLine,
|
||||
column: errColumn,
|
||||
key: de.key,
|
||||
human: buf.String(),
|
||||
}
|
||||
}
|
||||
|
||||
func formatLineNumber(line int, width int) string {
|
||||
format := "%" + strconv.Itoa(width) + "d"
|
||||
|
||||
return fmt.Sprintf(format, line)
|
||||
}
|
||||
|
||||
func linesOfContext(document []byte, highlight []byte, offset int, linesAround int) ([][]byte, [][]byte) {
|
||||
return beforeLines(document, offset, linesAround), afterLines(document, highlight, offset, linesAround)
|
||||
}
|
||||
|
||||
func beforeLines(document []byte, offset int, linesAround int) [][]byte {
|
||||
var beforeLines [][]byte
|
||||
|
||||
// Walk the document backward from the highlight to find previous lines
|
||||
// of context.
|
||||
rest := document[:offset]
|
||||
backward:
|
||||
for o := len(rest) - 1; o >= 0 && len(beforeLines) <= linesAround && len(rest) > 0; {
|
||||
switch {
|
||||
case rest[o] == '\n':
|
||||
// handle individual lines
|
||||
beforeLines = append(beforeLines, rest[o+1:])
|
||||
rest = rest[:o]
|
||||
o = len(rest) - 1
|
||||
case o == 0:
|
||||
// add the first line only if it's non-empty
|
||||
beforeLines = append(beforeLines, rest)
|
||||
|
||||
break backward
|
||||
default:
|
||||
o--
|
||||
}
|
||||
}
|
||||
|
||||
return beforeLines
|
||||
}
|
||||
|
||||
func afterLines(document []byte, highlight []byte, offset int, linesAround int) [][]byte {
|
||||
var afterLines [][]byte
|
||||
|
||||
// Walk the document forward from the highlight to find the following
|
||||
// lines of context.
|
||||
rest := document[offset+len(highlight):]
|
||||
forward:
|
||||
for o := 0; o < len(rest) && len(afterLines) <= linesAround; {
|
||||
switch {
|
||||
case rest[o] == '\n':
|
||||
// handle individual lines
|
||||
afterLines = append(afterLines, rest[:o])
|
||||
rest = rest[o+1:]
|
||||
o = 0
|
||||
|
||||
case o == len(rest)-1:
|
||||
// add last line only if it's non-empty
|
||||
afterLines = append(afterLines, rest)
|
||||
|
||||
break forward
|
||||
default:
|
||||
o++
|
||||
}
|
||||
}
|
||||
|
||||
return afterLines
|
||||
}
|
||||
|
||||
func positionAtEnd(b []byte) (row int, column int) {
|
||||
row = 1
|
||||
column = 1
|
||||
|
||||
for _, c := range b {
|
||||
if c == '\n' {
|
||||
row++
|
||||
column = 1
|
||||
} else {
|
||||
column++
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
144
vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go
generated
vendored
Normal file
144
vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||
)
|
||||
|
||||
// Iterator starts uninitialized, you need to call Next() first.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// it := n.Children()
|
||||
// for it.Next() {
|
||||
// it.Node()
|
||||
// }
|
||||
type Iterator struct {
|
||||
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.started {
|
||||
c.started = true
|
||||
} else if c.node.Valid() {
|
||||
c.node = c.node.Next()
|
||||
}
|
||||
return c.node.Valid()
|
||||
}
|
||||
|
||||
// IsLast returns true if the current node of the iterator is the last
|
||||
// one. Subsequent call to Next() will return false.
|
||||
func (c *Iterator) IsLast() bool {
|
||||
return c.node.next == 0
|
||||
}
|
||||
|
||||
// Node returns a copy of the node pointed at by the iterator.
|
||||
func (c *Iterator) Node() *Node {
|
||||
return c.node
|
||||
}
|
||||
|
||||
// Root contains a full AST.
|
||||
//
|
||||
// It is immutable once constructed with Builder.
|
||||
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]
|
||||
}
|
||||
|
||||
// Arrays have one child per element in the array. InlineTables have
|
||||
// one child per key-value pair in the table. KeyValues have at least
|
||||
// two children. The first one is the value. The rest make a
|
||||
// potentially dotted key. Table and Array table have one child per
|
||||
// element of the key they represent (same as KeyValue, but without
|
||||
// the last node being the value).
|
||||
type Node struct {
|
||||
Kind Kind
|
||||
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
|
||||
}
|
||||
|
||||
type Range struct {
|
||||
Offset uint32
|
||||
Length uint32
|
||||
}
|
||||
|
||||
// Next returns a copy of the next node, or an invalid Node if there
|
||||
// is no next node.
|
||||
func (n *Node) Next() *Node {
|
||||
if n.next == 0 {
|
||||
return nil
|
||||
}
|
||||
ptr := unsafe.Pointer(n)
|
||||
size := unsafe.Sizeof(Node{})
|
||||
return (*Node)(danger.Stride(ptr, size, n.next))
|
||||
}
|
||||
|
||||
// Child returns a copy of the first child node of this node. Other
|
||||
// children can be accessed calling Next on the first child. Returns
|
||||
// an invalid Node if there is none.
|
||||
func (n *Node) Child() *Node {
|
||||
if n.child == 0 {
|
||||
return nil
|
||||
}
|
||||
ptr := unsafe.Pointer(n)
|
||||
size := unsafe.Sizeof(Node{})
|
||||
return (*Node)(danger.Stride(ptr, size, n.child))
|
||||
}
|
||||
|
||||
// Valid returns true if the node's kind is set (not to Invalid).
|
||||
func (n *Node) Valid() bool {
|
||||
return n != nil
|
||||
}
|
||||
|
||||
// Key returns the child nodes making the Key on a supported
|
||||
// node. Panics otherwise. They are guaranteed to be all be of the
|
||||
// Kind Key. A simple key would return just one element.
|
||||
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"))
|
||||
}
|
||||
return Iterator{node: value.Next()}
|
||||
case Table, ArrayTable:
|
||||
return Iterator{node: n.Child()}
|
||||
default:
|
||||
panic(fmt.Errorf("Key() is not supported on a %s", n.Kind))
|
||||
}
|
||||
}
|
||||
|
||||
// Value returns a pointer to the value node of a KeyValue.
|
||||
// Guaranteed to be non-nil. Panics if not called on a KeyValue node,
|
||||
// or if the Children are malformed.
|
||||
func (n *Node) Value() *Node {
|
||||
return n.Child()
|
||||
}
|
||||
|
||||
// Children returns an iterator over a node's children.
|
||||
func (n *Node) Children() Iterator {
|
||||
return Iterator{node: n.Child()}
|
||||
}
|
51
vendor/github.com/pelletier/go-toml/v2/internal/ast/builder.go
generated
vendored
Normal file
51
vendor/github.com/pelletier/go-toml/v2/internal/ast/builder.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
package ast
|
||||
|
||||
type Reference int
|
||||
|
||||
const InvalidReference Reference = -1
|
||||
|
||||
func (r Reference) Valid() bool {
|
||||
return r != InvalidReference
|
||||
}
|
||||
|
||||
type Builder struct {
|
||||
tree Root
|
||||
lastIdx int
|
||||
}
|
||||
|
||||
func (b *Builder) Tree() *Root {
|
||||
return &b.tree
|
||||
}
|
||||
|
||||
func (b *Builder) NodeAt(ref Reference) *Node {
|
||||
return b.tree.at(ref)
|
||||
}
|
||||
|
||||
func (b *Builder) Reset() {
|
||||
b.tree.nodes = b.tree.nodes[:0]
|
||||
b.lastIdx = 0
|
||||
}
|
||||
|
||||
func (b *Builder) Push(n Node) Reference {
|
||||
b.lastIdx = len(b.tree.nodes)
|
||||
b.tree.nodes = append(b.tree.nodes, n)
|
||||
return Reference(b.lastIdx)
|
||||
}
|
||||
|
||||
func (b *Builder) PushAndChain(n Node) Reference {
|
||||
newIdx := len(b.tree.nodes)
|
||||
b.tree.nodes = append(b.tree.nodes, n)
|
||||
if b.lastIdx >= 0 {
|
||||
b.tree.nodes[b.lastIdx].next = newIdx - b.lastIdx
|
||||
}
|
||||
b.lastIdx = newIdx
|
||||
return Reference(b.lastIdx)
|
||||
}
|
||||
|
||||
func (b *Builder) AttachChild(parent Reference, child Reference) {
|
||||
b.tree.nodes[parent].child = int(child) - int(parent)
|
||||
}
|
||||
|
||||
func (b *Builder) Chain(from Reference, to Reference) {
|
||||
b.tree.nodes[from].next = int(to) - int(from)
|
||||
}
|
69
vendor/github.com/pelletier/go-toml/v2/internal/ast/kind.go
generated
vendored
Normal file
69
vendor/github.com/pelletier/go-toml/v2/internal/ast/kind.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package ast
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Kind int
|
||||
|
||||
const (
|
||||
// meta
|
||||
Invalid Kind = iota
|
||||
Comment
|
||||
Key
|
||||
|
||||
// top level structures
|
||||
Table
|
||||
ArrayTable
|
||||
KeyValue
|
||||
|
||||
// containers values
|
||||
Array
|
||||
InlineTable
|
||||
|
||||
// values
|
||||
String
|
||||
Bool
|
||||
Float
|
||||
Integer
|
||||
LocalDate
|
||||
LocalTime
|
||||
LocalDateTime
|
||||
DateTime
|
||||
)
|
||||
|
||||
func (k Kind) String() string {
|
||||
switch k {
|
||||
case Invalid:
|
||||
return "Invalid"
|
||||
case Comment:
|
||||
return "Comment"
|
||||
case Key:
|
||||
return "Key"
|
||||
case Table:
|
||||
return "Table"
|
||||
case ArrayTable:
|
||||
return "ArrayTable"
|
||||
case KeyValue:
|
||||
return "KeyValue"
|
||||
case Array:
|
||||
return "Array"
|
||||
case InlineTable:
|
||||
return "InlineTable"
|
||||
case String:
|
||||
return "String"
|
||||
case Bool:
|
||||
return "Bool"
|
||||
case Float:
|
||||
return "Float"
|
||||
case Integer:
|
||||
return "Integer"
|
||||
case LocalDate:
|
||||
return "LocalDate"
|
||||
case LocalTime:
|
||||
return "LocalTime"
|
||||
case LocalDateTime:
|
||||
return "LocalDateTime"
|
||||
case DateTime:
|
||||
return "DateTime"
|
||||
}
|
||||
panic(fmt.Errorf("Kind.String() not implemented for '%d'", k))
|
||||
}
|
65
vendor/github.com/pelletier/go-toml/v2/internal/danger/danger.go
generated
vendored
Normal file
65
vendor/github.com/pelletier/go-toml/v2/internal/danger/danger.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
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
Normal file
23
vendor/github.com/pelletier/go-toml/v2/internal/danger/typeid.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
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])
|
||||
}
|
50
vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
generated
vendored
Normal file
50
vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
package tracker
|
||||
|
||||
import (
|
||||
"github.com/pelletier/go-toml/v2/internal/ast"
|
||||
)
|
||||
|
||||
// KeyTracker is a tracker that keeps track of the current Key as the AST is
|
||||
// walked.
|
||||
type KeyTracker struct {
|
||||
k []string
|
||||
}
|
||||
|
||||
// UpdateTable sets the state of the tracker with the AST table node.
|
||||
func (t *KeyTracker) UpdateTable(node *ast.Node) {
|
||||
t.reset()
|
||||
t.Push(node)
|
||||
}
|
||||
|
||||
// UpdateArrayTable sets the state of the tracker with the AST array table node.
|
||||
func (t *KeyTracker) UpdateArrayTable(node *ast.Node) {
|
||||
t.reset()
|
||||
t.Push(node)
|
||||
}
|
||||
|
||||
// Push the given key on the stack.
|
||||
func (t *KeyTracker) Push(node *ast.Node) {
|
||||
it := node.Key()
|
||||
for it.Next() {
|
||||
t.k = append(t.k, string(it.Node().Data))
|
||||
}
|
||||
}
|
||||
|
||||
// Pop key from stack.
|
||||
func (t *KeyTracker) Pop(node *ast.Node) {
|
||||
it := node.Key()
|
||||
for it.Next() {
|
||||
t.k = t.k[:len(t.k)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns the current key
|
||||
func (t *KeyTracker) Key() []string {
|
||||
k := make([]string, len(t.k))
|
||||
copy(k, t.k)
|
||||
return k
|
||||
}
|
||||
|
||||
func (t *KeyTracker) reset() {
|
||||
t.k = t.k[:0]
|
||||
}
|
356
vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
generated
vendored
Normal file
356
vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
generated
vendored
Normal file
@ -0,0 +1,356 @@
|
||||
package tracker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/pelletier/go-toml/v2/internal/ast"
|
||||
)
|
||||
|
||||
type keyKind uint8
|
||||
|
||||
const (
|
||||
invalidKind keyKind = iota
|
||||
valueKind
|
||||
tableKind
|
||||
arrayTableKind
|
||||
)
|
||||
|
||||
func (k keyKind) String() string {
|
||||
switch k {
|
||||
case invalidKind:
|
||||
return "invalid"
|
||||
case valueKind:
|
||||
return "value"
|
||||
case tableKind:
|
||||
return "table"
|
||||
case arrayTableKind:
|
||||
return "array table"
|
||||
}
|
||||
panic("missing keyKind string mapping")
|
||||
}
|
||||
|
||||
// SeenTracker tracks which keys have been seen with which TOML type to flag
|
||||
// duplicates and mismatches according to the spec.
|
||||
//
|
||||
// Each node in the visited tree is represented by an entry. Each entry has an
|
||||
// identifier, which is provided by a counter. Entries are stored in the array
|
||||
// entries. As new nodes are discovered (referenced for the first time in the
|
||||
// TOML document), entries are created and appended to the array. An entry
|
||||
// points to its parent using its id.
|
||||
//
|
||||
// To find whether a given key (sequence of []byte) has already been visited,
|
||||
// the entries are linearly searched, looking for one with the right name and
|
||||
// parent id.
|
||||
//
|
||||
// Given that all keys appear in the document after their parent, it is
|
||||
// guaranteed that all descendants of a node are stored after the node, this
|
||||
// speeds up the search process.
|
||||
//
|
||||
// When encountering [[array tables]], the descendants of that node are removed
|
||||
// to allow that branch of the tree to be "rediscovered". To maintain the
|
||||
// invariant above, the deletion process needs to keep the order of entries.
|
||||
// This results in more copies in that case.
|
||||
type SeenTracker struct {
|
||||
entries []entry
|
||||
currentIdx int
|
||||
}
|
||||
|
||||
var pool sync.Pool
|
||||
|
||||
func (s *SeenTracker) reset() {
|
||||
// Always contains a root element at index 0.
|
||||
s.currentIdx = 0
|
||||
if len(s.entries) == 0 {
|
||||
s.entries = make([]entry, 1, 2)
|
||||
} else {
|
||||
s.entries = s.entries[:1]
|
||||
}
|
||||
s.entries[0].child = -1
|
||||
s.entries[0].next = -1
|
||||
}
|
||||
|
||||
type entry struct {
|
||||
// Use -1 to indicate no child or no sibling.
|
||||
child int
|
||||
next int
|
||||
|
||||
name []byte
|
||||
kind keyKind
|
||||
explicit bool
|
||||
kv bool
|
||||
}
|
||||
|
||||
// Find the index of the child of parentIdx with key k. Returns -1 if
|
||||
// it does not exist.
|
||||
func (s *SeenTracker) find(parentIdx int, k []byte) int {
|
||||
for i := s.entries[parentIdx].child; i >= 0; i = s.entries[i].next {
|
||||
if bytes.Equal(s.entries[i].name, k) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Remove all descendants of node at position idx.
|
||||
func (s *SeenTracker) clear(idx int) {
|
||||
if idx >= len(s.entries) {
|
||||
return
|
||||
}
|
||||
|
||||
for i := s.entries[idx].child; i >= 0; {
|
||||
next := s.entries[i].next
|
||||
n := s.entries[0].next
|
||||
s.entries[0].next = i
|
||||
s.entries[i].next = n
|
||||
s.entries[i].name = nil
|
||||
s.clear(i)
|
||||
i = next
|
||||
}
|
||||
|
||||
s.entries[idx].child = -1
|
||||
}
|
||||
|
||||
func (s *SeenTracker) create(parentIdx int, name []byte, kind keyKind, explicit bool, kv bool) int {
|
||||
e := entry{
|
||||
child: -1,
|
||||
next: s.entries[parentIdx].child,
|
||||
|
||||
name: name,
|
||||
kind: kind,
|
||||
explicit: explicit,
|
||||
kv: kv,
|
||||
}
|
||||
var idx int
|
||||
if s.entries[0].next >= 0 {
|
||||
idx = s.entries[0].next
|
||||
s.entries[0].next = s.entries[idx].next
|
||||
s.entries[idx] = e
|
||||
} else {
|
||||
idx = len(s.entries)
|
||||
s.entries = append(s.entries, e)
|
||||
}
|
||||
|
||||
s.entries[parentIdx].child = idx
|
||||
|
||||
return idx
|
||||
}
|
||||
|
||||
func (s *SeenTracker) setExplicitFlag(parentIdx int) {
|
||||
for i := s.entries[parentIdx].child; i >= 0; i = s.entries[i].next {
|
||||
if s.entries[i].kv {
|
||||
s.entries[i].explicit = true
|
||||
s.entries[i].kv = false
|
||||
}
|
||||
s.setExplicitFlag(i)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckExpression takes a top-level node and checks that it does not contain
|
||||
// keys that have been seen in previous calls, and validates that types are
|
||||
// consistent.
|
||||
func (s *SeenTracker) CheckExpression(node *ast.Node) error {
|
||||
if s.entries == nil {
|
||||
s.reset()
|
||||
}
|
||||
switch node.Kind {
|
||||
case ast.KeyValue:
|
||||
return s.checkKeyValue(node)
|
||||
case ast.Table:
|
||||
return s.checkTable(node)
|
||||
case ast.ArrayTable:
|
||||
return s.checkArrayTable(node)
|
||||
default:
|
||||
panic(fmt.Errorf("this should not be a top level node type: %s", node.Kind))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SeenTracker) checkTable(node *ast.Node) error {
|
||||
if s.currentIdx >= 0 {
|
||||
s.setExplicitFlag(s.currentIdx)
|
||||
}
|
||||
|
||||
it := node.Key()
|
||||
|
||||
parentIdx := 0
|
||||
|
||||
// This code is duplicated in checkArrayTable. This is because factoring
|
||||
// it in a function requires to copy the iterator, or allocate it to the
|
||||
// heap, which is not cheap.
|
||||
for it.Next() {
|
||||
if it.IsLast() {
|
||||
break
|
||||
}
|
||||
|
||||
k := it.Node().Data
|
||||
|
||||
idx := s.find(parentIdx, k)
|
||||
|
||||
if idx < 0 {
|
||||
idx = s.create(parentIdx, k, tableKind, false, false)
|
||||
} else {
|
||||
entry := s.entries[idx]
|
||||
if entry.kind == valueKind {
|
||||
return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
|
||||
}
|
||||
}
|
||||
parentIdx = idx
|
||||
}
|
||||
|
||||
k := it.Node().Data
|
||||
idx := s.find(parentIdx, k)
|
||||
|
||||
if idx >= 0 {
|
||||
kind := s.entries[idx].kind
|
||||
if kind != tableKind {
|
||||
return fmt.Errorf("toml: key %s should be a table, not a %s", string(k), kind)
|
||||
}
|
||||
if s.entries[idx].explicit {
|
||||
return fmt.Errorf("toml: table %s already exists", string(k))
|
||||
}
|
||||
s.entries[idx].explicit = true
|
||||
} else {
|
||||
idx = s.create(parentIdx, k, tableKind, true, false)
|
||||
}
|
||||
|
||||
s.currentIdx = idx
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SeenTracker) checkArrayTable(node *ast.Node) error {
|
||||
if s.currentIdx >= 0 {
|
||||
s.setExplicitFlag(s.currentIdx)
|
||||
}
|
||||
|
||||
it := node.Key()
|
||||
|
||||
parentIdx := 0
|
||||
|
||||
for it.Next() {
|
||||
if it.IsLast() {
|
||||
break
|
||||
}
|
||||
|
||||
k := it.Node().Data
|
||||
|
||||
idx := s.find(parentIdx, k)
|
||||
|
||||
if idx < 0 {
|
||||
idx = s.create(parentIdx, k, tableKind, false, false)
|
||||
} else {
|
||||
entry := s.entries[idx]
|
||||
if entry.kind == valueKind {
|
||||
return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
|
||||
}
|
||||
}
|
||||
|
||||
parentIdx = idx
|
||||
}
|
||||
|
||||
k := it.Node().Data
|
||||
idx := s.find(parentIdx, k)
|
||||
|
||||
if idx >= 0 {
|
||||
kind := s.entries[idx].kind
|
||||
if kind != arrayTableKind {
|
||||
return fmt.Errorf("toml: key %s already exists as a %s, but should be an array table", kind, string(k))
|
||||
}
|
||||
s.clear(idx)
|
||||
} else {
|
||||
idx = s.create(parentIdx, k, arrayTableKind, true, false)
|
||||
}
|
||||
|
||||
s.currentIdx = idx
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SeenTracker) checkKeyValue(node *ast.Node) error {
|
||||
parentIdx := s.currentIdx
|
||||
it := node.Key()
|
||||
|
||||
for it.Next() {
|
||||
k := it.Node().Data
|
||||
|
||||
idx := s.find(parentIdx, k)
|
||||
|
||||
if idx < 0 {
|
||||
idx = s.create(parentIdx, k, tableKind, false, true)
|
||||
} else {
|
||||
entry := s.entries[idx]
|
||||
if it.IsLast() {
|
||||
return fmt.Errorf("toml: key %s is already defined", string(k))
|
||||
} else if entry.kind != tableKind {
|
||||
return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
|
||||
} else if entry.explicit {
|
||||
return fmt.Errorf("toml: cannot redefine table %s that has already been explicitly defined", string(k))
|
||||
}
|
||||
}
|
||||
|
||||
parentIdx = idx
|
||||
}
|
||||
|
||||
s.entries[parentIdx].kind = valueKind
|
||||
|
||||
value := node.Value()
|
||||
|
||||
switch value.Kind {
|
||||
case ast.InlineTable:
|
||||
return s.checkInlineTable(value)
|
||||
case ast.Array:
|
||||
return s.checkArray(value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SeenTracker) checkArray(node *ast.Node) error {
|
||||
it := node.Children()
|
||||
for it.Next() {
|
||||
n := it.Node()
|
||||
switch n.Kind {
|
||||
case ast.InlineTable:
|
||||
err := s.checkInlineTable(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case ast.Array:
|
||||
err := s.checkArray(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SeenTracker) checkInlineTable(node *ast.Node) error {
|
||||
if pool.New == nil {
|
||||
pool.New = func() interface{} {
|
||||
return &SeenTracker{}
|
||||
}
|
||||
}
|
||||
|
||||
s = pool.Get().(*SeenTracker)
|
||||
s.reset()
|
||||
|
||||
it := node.Children()
|
||||
for it.Next() {
|
||||
n := it.Node()
|
||||
err := s.checkKeyValue(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// As inline tables are self-contained, the tracker does not
|
||||
// need to retain the details of what they contain. The
|
||||
// keyValue element that creates the inline table is kept to
|
||||
// mark the presence of the inline table and prevent
|
||||
// redefinition of its keys: check* functions cannot walk into
|
||||
// a value.
|
||||
pool.Put(s)
|
||||
return nil
|
||||
}
|
1
vendor/github.com/pelletier/go-toml/v2/internal/tracker/tracker.go
generated
vendored
Normal file
1
vendor/github.com/pelletier/go-toml/v2/internal/tracker/tracker.go
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
package tracker
|
120
vendor/github.com/pelletier/go-toml/v2/localtime.go
generated
vendored
Normal file
120
vendor/github.com/pelletier/go-toml/v2/localtime.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LocalDate represents a calendar day in no specific timezone.
|
||||
type LocalDate struct {
|
||||
Year int
|
||||
Month int
|
||||
Day int
|
||||
}
|
||||
|
||||
// AsTime converts d into a specific time instance at midnight in zone.
|
||||
func (d LocalDate) AsTime(zone *time.Location) time.Time {
|
||||
return time.Date(d.Year, time.Month(d.Month), d.Day, 0, 0, 0, 0, zone)
|
||||
}
|
||||
|
||||
// String returns RFC 3339 representation of d.
|
||||
func (d LocalDate) String() string {
|
||||
return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
|
||||
}
|
||||
|
||||
// MarshalText returns RFC 3339 representation of d.
|
||||
func (d LocalDate) MarshalText() ([]byte, error) {
|
||||
return []byte(d.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText parses b using RFC 3339 to fill d.
|
||||
func (d *LocalDate) UnmarshalText(b []byte) error {
|
||||
res, err := parseLocalDate(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalTime represents a time of day of no specific day in no specific
|
||||
// timezone.
|
||||
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[
|
||||
Nanosecond int // Nanoseconds within the second: [0, 1000000000[
|
||||
Precision int // Number of digits to display for Nanosecond.
|
||||
}
|
||||
|
||||
// String returns RFC 3339 representation of d.
|
||||
// If d.Nanosecond and d.Precision are zero, the time won't have a nanosecond
|
||||
// component. If d.Nanosecond > 0 but d.Precision = 0, then the minimum number
|
||||
// of digits for nanoseconds is provided.
|
||||
func (d LocalTime) String() string {
|
||||
s := fmt.Sprintf("%02d:%02d:%02d", d.Hour, d.Minute, d.Second)
|
||||
|
||||
if d.Precision > 0 {
|
||||
s += fmt.Sprintf(".%09d", d.Nanosecond)[:d.Precision+1]
|
||||
} else if d.Nanosecond > 0 {
|
||||
// Nanoseconds are specified, but precision is not provided. Use the
|
||||
// minimum.
|
||||
s += strings.Trim(fmt.Sprintf(".%09d", d.Nanosecond), "0")
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// MarshalText returns RFC 3339 representation of d.
|
||||
func (d LocalTime) MarshalText() ([]byte, error) {
|
||||
return []byte(d.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText parses b using RFC 3339 to fill d.
|
||||
func (d *LocalTime) UnmarshalText(b []byte) error {
|
||||
res, left, err := parseLocalTime(b)
|
||||
if err == nil && len(left) != 0 {
|
||||
err = newDecodeError(left, "extra characters")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalDateTime represents a time of a specific day in no specific timezone.
|
||||
type LocalDateTime struct {
|
||||
LocalDate
|
||||
LocalTime
|
||||
}
|
||||
|
||||
// AsTime converts d into a specific time instance in zone.
|
||||
func (d LocalDateTime) AsTime(zone *time.Location) time.Time {
|
||||
return time.Date(d.Year, time.Month(d.Month), d.Day, d.Hour, d.Minute, d.Second, d.Nanosecond, zone)
|
||||
}
|
||||
|
||||
// String returns RFC 3339 representation of d.
|
||||
func (d LocalDateTime) String() string {
|
||||
return d.LocalDate.String() + "T" + d.LocalTime.String()
|
||||
}
|
||||
|
||||
// MarshalText returns RFC 3339 representation of d.
|
||||
func (d LocalDateTime) MarshalText() ([]byte, error) {
|
||||
return []byte(d.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText parses b using RFC 3339 to fill d.
|
||||
func (d *LocalDateTime) UnmarshalText(data []byte) error {
|
||||
res, left, err := parseLocalDateTime(data)
|
||||
if err == nil && len(left) != 0 {
|
||||
err = newDecodeError(left, "extra characters")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*d = res
|
||||
return nil
|
||||
}
|
950
vendor/github.com/pelletier/go-toml/v2/marshaler.go
generated
vendored
Normal file
950
vendor/github.com/pelletier/go-toml/v2/marshaler.go
generated
vendored
Normal file
@ -0,0 +1,950 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Marshal serializes a Go value as a TOML document.
|
||||
//
|
||||
// It is a shortcut for Encoder.Encode() with the default options.
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
enc := NewEncoder(&buf)
|
||||
|
||||
err := enc.Encode(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Encoder writes a TOML document to an output stream.
|
||||
type Encoder struct {
|
||||
// output
|
||||
w io.Writer
|
||||
|
||||
// global settings
|
||||
tablesInline bool
|
||||
arraysMultiline bool
|
||||
indentSymbol string
|
||||
indentTables bool
|
||||
}
|
||||
|
||||
// NewEncoder returns a new Encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{
|
||||
w: w,
|
||||
indentSymbol: " ",
|
||||
}
|
||||
}
|
||||
|
||||
// SetTablesInline forces the encoder to emit all tables inline.
|
||||
//
|
||||
// This behavior can be controlled on an individual struct field basis with the
|
||||
// inline tag:
|
||||
//
|
||||
// MyField `inline:"true"`
|
||||
func (enc *Encoder) SetTablesInline(inline bool) *Encoder {
|
||||
enc.tablesInline = inline
|
||||
return enc
|
||||
}
|
||||
|
||||
// SetArraysMultiline forces the encoder to emit all arrays with one element per
|
||||
// line.
|
||||
//
|
||||
// This behavior can be controlled on an individual struct field basis with the multiline tag:
|
||||
//
|
||||
// MyField `multiline:"true"`
|
||||
func (enc *Encoder) SetArraysMultiline(multiline bool) *Encoder {
|
||||
enc.arraysMultiline = multiline
|
||||
return enc
|
||||
}
|
||||
|
||||
// SetIndentSymbol defines the string that should be used for indentation. The
|
||||
// provided string is repeated for each indentation level. Defaults to two
|
||||
// spaces.
|
||||
func (enc *Encoder) SetIndentSymbol(s string) *Encoder {
|
||||
enc.indentSymbol = s
|
||||
return enc
|
||||
}
|
||||
|
||||
// SetIndentTables forces the encoder to intent tables and array tables.
|
||||
func (enc *Encoder) SetIndentTables(indent bool) *Encoder {
|
||||
enc.indentTables = indent
|
||||
return enc
|
||||
}
|
||||
|
||||
// Encode writes a TOML representation of v to the stream.
|
||||
//
|
||||
// If v cannot be represented to TOML it returns an error.
|
||||
//
|
||||
// Encoding rules
|
||||
//
|
||||
// A top level slice containing only maps or structs is encoded as [[table
|
||||
// array]].
|
||||
//
|
||||
// All slices not matching rule 1 are encoded as [array]. As a result, any map
|
||||
// or struct they contain is encoded as an {inline table}.
|
||||
//
|
||||
// Nil interfaces and nil pointers are not supported.
|
||||
//
|
||||
// Keys in key-values always have one part.
|
||||
//
|
||||
// Intermediate tables are always printed.
|
||||
//
|
||||
// By default, strings are encoded as literal string, unless they contain either
|
||||
// a newline character or a single quote. In that case they are emitted as
|
||||
// quoted strings.
|
||||
//
|
||||
// When encoding structs, fields are encoded in order of definition, with their
|
||||
// exact name.
|
||||
//
|
||||
// Struct tags
|
||||
//
|
||||
// The encoding of each public struct field can be customized by the format
|
||||
// string in the "toml" key of the struct field's tag. This follows
|
||||
// encoding/json's convention. The format string starts with the name of the
|
||||
// field, optionally followed by a comma-separated list of options. The name may
|
||||
// be empty in order to provide options without overriding the default name.
|
||||
//
|
||||
// The "multiline" option emits strings as quoted multi-line TOML strings. It
|
||||
// has no effect on fields that would not be encoded as strings.
|
||||
//
|
||||
// The "inline" option turns fields that would be emitted as tables into inline
|
||||
// tables instead. It has no effect on other fields.
|
||||
//
|
||||
// The "omitempty" option prevents empty values or groups from being emitted.
|
||||
//
|
||||
// In addition to the "toml" tag struct tag, a "comment" tag can be used to emit
|
||||
// a TOML comment before the value being annotated. Comments are ignored inside
|
||||
// inline tables.
|
||||
func (enc *Encoder) Encode(v interface{}) error {
|
||||
var (
|
||||
b []byte
|
||||
ctx encoderCtx
|
||||
)
|
||||
|
||||
ctx.inline = enc.tablesInline
|
||||
|
||||
if v == nil {
|
||||
return fmt.Errorf("toml: cannot encode a nil interface")
|
||||
}
|
||||
|
||||
b, err := enc.encode(b, ctx, reflect.ValueOf(v))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = enc.w.Write(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("toml: cannot write: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type valueOptions struct {
|
||||
multiline bool
|
||||
omitempty bool
|
||||
comment string
|
||||
}
|
||||
|
||||
type encoderCtx struct {
|
||||
// Current top-level key.
|
||||
parentKey []string
|
||||
|
||||
// Key that should be used for a KV.
|
||||
key string
|
||||
// Extra flag to account for the empty string
|
||||
hasKey bool
|
||||
|
||||
// Set to true to indicate that the encoder is inside a KV, so that all
|
||||
// tables need to be inlined.
|
||||
insideKv bool
|
||||
|
||||
// Set to true to skip the first table header in an array table.
|
||||
skipTableHeader bool
|
||||
|
||||
// Should the next table be encoded as inline
|
||||
inline bool
|
||||
|
||||
// Indentation level
|
||||
indent int
|
||||
|
||||
// Options coming from struct tags
|
||||
options valueOptions
|
||||
}
|
||||
|
||||
func (ctx *encoderCtx) shiftKey() {
|
||||
if ctx.hasKey {
|
||||
ctx.parentKey = append(ctx.parentKey, ctx.key)
|
||||
ctx.clearKey()
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *encoderCtx) setKey(k string) {
|
||||
ctx.key = k
|
||||
ctx.hasKey = true
|
||||
}
|
||||
|
||||
func (ctx *encoderCtx) clearKey() {
|
||||
ctx.key = ""
|
||||
ctx.hasKey = false
|
||||
}
|
||||
|
||||
func (ctx *encoderCtx) isRoot() bool {
|
||||
return len(ctx.parentKey) == 0 && !ctx.hasKey
|
||||
}
|
||||
|
||||
func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
|
||||
i := v.Interface()
|
||||
|
||||
switch x := i.(type) {
|
||||
case time.Time:
|
||||
if x.Nanosecond() > 0 {
|
||||
return x.AppendFormat(b, time.RFC3339Nano), nil
|
||||
}
|
||||
return x.AppendFormat(b, time.RFC3339), nil
|
||||
case LocalTime:
|
||||
return append(b, x.String()...), nil
|
||||
case LocalDate:
|
||||
return append(b, x.String()...), nil
|
||||
case LocalDateTime:
|
||||
return append(b, x.String()...), nil
|
||||
}
|
||||
|
||||
hasTextMarshaler := v.Type().Implements(textMarshalerType)
|
||||
if hasTextMarshaler || (v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
|
||||
if !hasTextMarshaler {
|
||||
v = v.Addr()
|
||||
}
|
||||
|
||||
if ctx.isRoot() {
|
||||
return nil, fmt.Errorf("toml: type %s implementing the TextMarshaler interface cannot be a root element", v.Type())
|
||||
}
|
||||
|
||||
text, err := v.Interface().(encoding.TextMarshaler).MarshalText()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = enc.encodeString(b, string(text), ctx.options)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
// containers
|
||||
case reflect.Map:
|
||||
return enc.encodeMap(b, ctx, v)
|
||||
case reflect.Struct:
|
||||
return enc.encodeStruct(b, ctx, v)
|
||||
case reflect.Slice:
|
||||
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 enc.encode(b, ctx, v.Elem())
|
||||
case reflect.Ptr:
|
||||
if v.IsNil() {
|
||||
return enc.encode(b, ctx, reflect.Zero(v.Type().Elem()))
|
||||
}
|
||||
|
||||
return enc.encode(b, ctx, v.Elem())
|
||||
|
||||
// values
|
||||
case reflect.String:
|
||||
b = enc.encodeString(b, v.String(), ctx.options)
|
||||
case reflect.Float32:
|
||||
f := v.Float()
|
||||
|
||||
if math.IsNaN(f) {
|
||||
b = append(b, "nan"...)
|
||||
} else if f > math.MaxFloat32 {
|
||||
b = append(b, "inf"...)
|
||||
} else if f < -math.MaxFloat32 {
|
||||
b = append(b, "-inf"...)
|
||||
} else if math.Trunc(f) == f {
|
||||
b = strconv.AppendFloat(b, f, 'f', 1, 32)
|
||||
} else {
|
||||
b = strconv.AppendFloat(b, f, 'f', -1, 32)
|
||||
}
|
||||
case reflect.Float64:
|
||||
f := v.Float()
|
||||
if math.IsNaN(f) {
|
||||
b = append(b, "nan"...)
|
||||
} else if f > math.MaxFloat64 {
|
||||
b = append(b, "inf"...)
|
||||
} else if f < -math.MaxFloat64 {
|
||||
b = append(b, "-inf"...)
|
||||
} else if math.Trunc(f) == f {
|
||||
b = strconv.AppendFloat(b, f, 'f', 1, 64)
|
||||
} else {
|
||||
b = strconv.AppendFloat(b, f, 'f', -1, 64)
|
||||
}
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
b = append(b, "true"...)
|
||||
} else {
|
||||
b = append(b, "false"...)
|
||||
}
|
||||
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
|
||||
b = strconv.AppendUint(b, v.Uint(), 10)
|
||||
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
|
||||
b = strconv.AppendInt(b, v.Int(), 10)
|
||||
default:
|
||||
return nil, fmt.Errorf("toml: cannot encode value of type %s", v.Kind())
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func isNil(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr, reflect.Interface, reflect.Map:
|
||||
return v.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v reflect.Value) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
if (ctx.options.omitempty || options.omitempty) && isEmptyValue(v) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
if !ctx.inline {
|
||||
b = enc.encodeComment(ctx.indent, options.comment, b)
|
||||
}
|
||||
|
||||
b = enc.indent(ctx.indent, b)
|
||||
b = enc.encodeKey(b, ctx.key)
|
||||
b = append(b, " = "...)
|
||||
|
||||
// create a copy of the context because the value of a KV shouldn't
|
||||
// modify the global context.
|
||||
subctx := ctx
|
||||
subctx.insideKv = true
|
||||
subctx.shiftKey()
|
||||
subctx.options = options
|
||||
|
||||
b, err = enc.encode(b, subctx, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const literalQuote = '\''
|
||||
|
||||
func (enc *Encoder) encodeString(b []byte, v string, options valueOptions) []byte {
|
||||
if needsQuoting(v) {
|
||||
return enc.encodeQuotedString(options.multiline, b, v)
|
||||
}
|
||||
|
||||
return enc.encodeLiteralString(b, v)
|
||||
}
|
||||
|
||||
func needsQuoting(v string) bool {
|
||||
// TODO: vectorize
|
||||
for _, b := range []byte(v) {
|
||||
if b == '\'' || b == '\r' || b == '\n' || invalidAscii(b) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// caller should have checked that the string does not contain new lines or ' .
|
||||
func (enc *Encoder) encodeLiteralString(b []byte, v string) []byte {
|
||||
b = append(b, literalQuote)
|
||||
b = append(b, v...)
|
||||
b = append(b, literalQuote)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
//nolint:cyclop
|
||||
func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byte {
|
||||
stringQuote := `"`
|
||||
|
||||
if multiline {
|
||||
stringQuote = `"""`
|
||||
}
|
||||
|
||||
b = append(b, stringQuote...)
|
||||
if multiline {
|
||||
b = append(b, '\n')
|
||||
}
|
||||
|
||||
const (
|
||||
hextable = "0123456789ABCDEF"
|
||||
// U+0000 to U+0008, U+000A to U+001F, U+007F
|
||||
nul = 0x0
|
||||
bs = 0x8
|
||||
lf = 0xa
|
||||
us = 0x1f
|
||||
del = 0x7f
|
||||
)
|
||||
|
||||
for _, r := range []byte(v) {
|
||||
switch r {
|
||||
case '\\':
|
||||
b = append(b, `\\`...)
|
||||
case '"':
|
||||
b = append(b, `\"`...)
|
||||
case '\b':
|
||||
b = append(b, `\b`...)
|
||||
case '\f':
|
||||
b = append(b, `\f`...)
|
||||
case '\n':
|
||||
if multiline {
|
||||
b = append(b, r)
|
||||
} else {
|
||||
b = append(b, `\n`...)
|
||||
}
|
||||
case '\r':
|
||||
b = append(b, `\r`...)
|
||||
case '\t':
|
||||
b = append(b, `\t`...)
|
||||
default:
|
||||
switch {
|
||||
case r >= nul && r <= bs, r >= lf && r <= us, r == del:
|
||||
b = append(b, `\u00`...)
|
||||
b = append(b, hextable[r>>4])
|
||||
b = append(b, hextable[r&0x0f])
|
||||
default:
|
||||
b = append(b, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b = append(b, stringQuote...)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// caller should have checked that the string is in A-Z / a-z / 0-9 / - / _ .
|
||||
func (enc *Encoder) encodeUnquotedKey(b []byte, v string) []byte {
|
||||
return append(b, v...)
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeTableHeader(ctx encoderCtx, b []byte) ([]byte, error) {
|
||||
if len(ctx.parentKey) == 0 {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
|
||||
|
||||
b = enc.indent(ctx.indent, b)
|
||||
|
||||
b = append(b, '[')
|
||||
|
||||
b = enc.encodeKey(b, ctx.parentKey[0])
|
||||
|
||||
for _, k := range ctx.parentKey[1:] {
|
||||
b = append(b, '.')
|
||||
b = enc.encodeKey(b, k)
|
||||
}
|
||||
|
||||
b = append(b, "]\n"...)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
//nolint:cyclop
|
||||
func (enc *Encoder) encodeKey(b []byte, k string) []byte {
|
||||
needsQuotation := false
|
||||
cannotUseLiteral := false
|
||||
|
||||
if len(k) == 0 {
|
||||
return append(b, "''"...)
|
||||
}
|
||||
|
||||
for _, c := range k {
|
||||
if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' {
|
||||
continue
|
||||
}
|
||||
|
||||
if c == literalQuote {
|
||||
cannotUseLiteral = true
|
||||
}
|
||||
|
||||
needsQuotation = true
|
||||
}
|
||||
|
||||
if needsQuotation && needsQuoting(k) {
|
||||
cannotUseLiteral = true
|
||||
}
|
||||
|
||||
switch {
|
||||
case cannotUseLiteral:
|
||||
return enc.encodeQuotedString(false, b, k)
|
||||
case needsQuotation:
|
||||
return enc.encodeLiteralString(b, k)
|
||||
default:
|
||||
return enc.encodeUnquotedKey(b, k)
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
|
||||
if v.Type().Key().Kind() != reflect.String {
|
||||
return nil, fmt.Errorf("toml: type %s is not supported as a map key", v.Type().Key().Kind())
|
||||
}
|
||||
|
||||
var (
|
||||
t table
|
||||
emptyValueOptions valueOptions
|
||||
)
|
||||
|
||||
iter := v.MapRange()
|
||||
for iter.Next() {
|
||||
k := iter.Key().String()
|
||||
v := iter.Value()
|
||||
|
||||
if isNil(v) {
|
||||
continue
|
||||
}
|
||||
|
||||
if willConvertToTableOrArrayTable(ctx, v) {
|
||||
t.pushTable(k, v, emptyValueOptions)
|
||||
} else {
|
||||
t.pushKV(k, v, emptyValueOptions)
|
||||
}
|
||||
}
|
||||
|
||||
sortEntriesByKey(t.kvs)
|
||||
sortEntriesByKey(t.tables)
|
||||
|
||||
return enc.encodeTable(b, ctx, t)
|
||||
}
|
||||
|
||||
func sortEntriesByKey(e []entry) {
|
||||
sort.Slice(e, func(i, j int) bool {
|
||||
return e[i].Key < e[j].Key
|
||||
})
|
||||
}
|
||||
|
||||
type entry struct {
|
||||
Key string
|
||||
Value reflect.Value
|
||||
Options valueOptions
|
||||
}
|
||||
|
||||
type table struct {
|
||||
kvs []entry
|
||||
tables []entry
|
||||
}
|
||||
|
||||
func (t *table) pushKV(k string, v reflect.Value, options valueOptions) {
|
||||
for _, e := range t.kvs {
|
||||
if e.Key == k {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.kvs = append(t.kvs, entry{Key: k, Value: v, Options: options})
|
||||
}
|
||||
|
||||
func (t *table) pushTable(k string, v reflect.Value, options valueOptions) {
|
||||
for _, e := range t.tables {
|
||||
if e.Key == k {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.tables = append(t.tables, entry{Key: k, Value: v, Options: options})
|
||||
}
|
||||
|
||||
func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
|
||||
// TODO: cache this
|
||||
typ := v.Type()
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
fieldType := typ.Field(i)
|
||||
|
||||
// only consider exported fields
|
||||
if fieldType.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
tag := fieldType.Tag.Get("toml")
|
||||
|
||||
// special field name to skip field
|
||||
if tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
k, opts := parseTag(tag)
|
||||
if !isValidName(k) {
|
||||
k = ""
|
||||
}
|
||||
|
||||
f := v.Field(i)
|
||||
|
||||
if k == "" {
|
||||
if fieldType.Anonymous {
|
||||
if fieldType.Type.Kind() == reflect.Struct {
|
||||
walkStruct(ctx, t, f)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
k = fieldType.Name
|
||||
}
|
||||
}
|
||||
|
||||
if isNil(f) {
|
||||
continue
|
||||
}
|
||||
|
||||
options := valueOptions{
|
||||
multiline: opts.multiline,
|
||||
omitempty: opts.omitempty,
|
||||
comment: fieldType.Tag.Get("comment"),
|
||||
}
|
||||
|
||||
if opts.inline || !willConvertToTableOrArrayTable(ctx, f) {
|
||||
t.pushKV(k, f, options)
|
||||
} else {
|
||||
t.pushTable(k, f, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeStruct(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
|
||||
var t table
|
||||
|
||||
walkStruct(ctx, &t, v)
|
||||
|
||||
return enc.encodeTable(b, ctx, t)
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeComment(indent int, comment string, b []byte) []byte {
|
||||
if comment != "" {
|
||||
b = enc.indent(indent, b)
|
||||
b = append(b, "# "...)
|
||||
b = append(b, comment...)
|
||||
b = append(b, '\n')
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func isValidName(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
for _, c := range s {
|
||||
switch {
|
||||
case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
|
||||
// Backslash and quote chars are reserved, but
|
||||
// otherwise any punctuation chars are allowed
|
||||
// in a tag name.
|
||||
case !unicode.IsLetter(c) && !unicode.IsDigit(c):
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type tagOptions struct {
|
||||
multiline bool
|
||||
inline bool
|
||||
omitempty bool
|
||||
}
|
||||
|
||||
func parseTag(tag string) (string, tagOptions) {
|
||||
opts := tagOptions{}
|
||||
|
||||
idx := strings.Index(tag, ",")
|
||||
if idx == -1 {
|
||||
return tag, opts
|
||||
}
|
||||
|
||||
raw := tag[idx+1:]
|
||||
tag = string(tag[:idx])
|
||||
for raw != "" {
|
||||
var o string
|
||||
i := strings.Index(raw, ",")
|
||||
if i >= 0 {
|
||||
o, raw = raw[:i], raw[i+1:]
|
||||
} else {
|
||||
o, raw = raw, ""
|
||||
}
|
||||
switch o {
|
||||
case "multiline":
|
||||
opts.multiline = true
|
||||
case "inline":
|
||||
opts.inline = true
|
||||
case "omitempty":
|
||||
opts.omitempty = true
|
||||
}
|
||||
}
|
||||
|
||||
return tag, opts
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
ctx.shiftKey()
|
||||
|
||||
if ctx.insideKv || (ctx.inline && !ctx.isRoot()) {
|
||||
return enc.encodeTableInline(b, ctx, t)
|
||||
}
|
||||
|
||||
if !ctx.skipTableHeader {
|
||||
b, err = enc.encodeTableHeader(ctx, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if enc.indentTables && len(ctx.parentKey) > 0 {
|
||||
ctx.indent++
|
||||
}
|
||||
}
|
||||
ctx.skipTableHeader = false
|
||||
|
||||
for _, kv := range t.kvs {
|
||||
ctx.setKey(kv.Key)
|
||||
|
||||
b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = append(b, '\n')
|
||||
}
|
||||
|
||||
for _, table := range t.tables {
|
||||
ctx.setKey(table.Key)
|
||||
|
||||
ctx.options = table.Options
|
||||
|
||||
b, err = enc.encode(b, ctx, table.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = append(b, '\n')
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
b = append(b, '{')
|
||||
|
||||
first := true
|
||||
for _, kv := range t.kvs {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
b = append(b, `, `...)
|
||||
}
|
||||
|
||||
ctx.setKey(kv.Key)
|
||||
|
||||
b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(t.tables) > 0 {
|
||||
panic("inline table cannot contain nested tables, online key-values")
|
||||
}
|
||||
|
||||
b = append(b, "}"...)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
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.PtrTo(v.Type()).Implements(textMarshalerType)) {
|
||||
return false
|
||||
}
|
||||
|
||||
t := v.Type()
|
||||
switch t.Kind() {
|
||||
case reflect.Map, reflect.Struct:
|
||||
return !ctx.inline
|
||||
case reflect.Interface:
|
||||
return willConvertToTable(ctx, v.Elem())
|
||||
case reflect.Ptr:
|
||||
if v.IsNil() {
|
||||
return false
|
||||
}
|
||||
|
||||
return willConvertToTable(ctx, v.Elem())
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func willConvertToTableOrArrayTable(ctx encoderCtx, v reflect.Value) bool {
|
||||
if ctx.insideKv {
|
||||
return false
|
||||
}
|
||||
t := v.Type()
|
||||
|
||||
if t.Kind() == reflect.Interface {
|
||||
return willConvertToTableOrArrayTable(ctx, v.Elem())
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Slice {
|
||||
if v.Len() == 0 {
|
||||
// An empty slice should be a kv = [].
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
t := willConvertToTable(ctx, v.Index(i))
|
||||
|
||||
if !t {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return willConvertToTable(ctx, v)
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeSlice(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
|
||||
if v.Len() == 0 {
|
||||
b = append(b, "[]"...)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
if willConvertToTableOrArrayTable(ctx, v) {
|
||||
return enc.encodeSliceAsArrayTable(b, ctx, v)
|
||||
}
|
||||
|
||||
return enc.encodeSliceAsArray(b, ctx, v)
|
||||
}
|
||||
|
||||
// caller should have checked that v is a slice that only contains values that
|
||||
// encode into tables.
|
||||
func (enc *Encoder) encodeSliceAsArrayTable(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
|
||||
ctx.shiftKey()
|
||||
|
||||
scratch := make([]byte, 0, 64)
|
||||
scratch = append(scratch, "[["...)
|
||||
|
||||
for i, k := range ctx.parentKey {
|
||||
if i > 0 {
|
||||
scratch = append(scratch, '.')
|
||||
}
|
||||
|
||||
scratch = enc.encodeKey(scratch, k)
|
||||
}
|
||||
|
||||
scratch = append(scratch, "]]\n"...)
|
||||
ctx.skipTableHeader = true
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
b = append(b, scratch...)
|
||||
|
||||
var err error
|
||||
b, err = enc.encode(b, ctx, v.Index(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) encodeSliceAsArray(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
|
||||
multiline := ctx.options.multiline || enc.arraysMultiline
|
||||
separator := ", "
|
||||
|
||||
b = append(b, '[')
|
||||
|
||||
subCtx := ctx
|
||||
subCtx.options = valueOptions{}
|
||||
|
||||
if multiline {
|
||||
separator = ",\n"
|
||||
|
||||
b = append(b, '\n')
|
||||
|
||||
subCtx.indent++
|
||||
}
|
||||
|
||||
var err error
|
||||
first := true
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
b = append(b, separator...)
|
||||
}
|
||||
|
||||
if multiline {
|
||||
b = enc.indent(subCtx.indent, b)
|
||||
}
|
||||
|
||||
b, err = enc.encode(b, subCtx, v.Index(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if multiline {
|
||||
b = append(b, '\n')
|
||||
b = enc.indent(ctx.indent, b)
|
||||
}
|
||||
|
||||
b = append(b, ']')
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) indent(level int, b []byte) []byte {
|
||||
for i := 0; i < level; i++ {
|
||||
b = append(b, enc.indentSymbol...)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
1086
vendor/github.com/pelletier/go-toml/v2/parser.go
generated
vendored
Normal file
1086
vendor/github.com/pelletier/go-toml/v2/parser.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
269
vendor/github.com/pelletier/go-toml/v2/scanner.go
generated
vendored
Normal file
269
vendor/github.com/pelletier/go-toml/v2/scanner.go
generated
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
package toml
|
||||
|
||||
func scanFollows(b []byte, pattern string) bool {
|
||||
n := len(pattern)
|
||||
|
||||
return len(b) >= n && string(b[:n]) == pattern
|
||||
}
|
||||
|
||||
func scanFollowsMultilineBasicStringDelimiter(b []byte) bool {
|
||||
return scanFollows(b, `"""`)
|
||||
}
|
||||
|
||||
func scanFollowsMultilineLiteralStringDelimiter(b []byte) bool {
|
||||
return scanFollows(b, `'''`)
|
||||
}
|
||||
|
||||
func scanFollowsTrue(b []byte) bool {
|
||||
return scanFollows(b, `true`)
|
||||
}
|
||||
|
||||
func scanFollowsFalse(b []byte) bool {
|
||||
return scanFollows(b, `false`)
|
||||
}
|
||||
|
||||
func scanFollowsInf(b []byte) bool {
|
||||
return scanFollows(b, `inf`)
|
||||
}
|
||||
|
||||
func scanFollowsNan(b []byte) bool {
|
||||
return scanFollows(b, `nan`)
|
||||
}
|
||||
|
||||
func scanUnquotedKey(b []byte) ([]byte, []byte) {
|
||||
// unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _
|
||||
for i := 0; i < len(b); i++ {
|
||||
if !isUnquotedKeyChar(b[i]) {
|
||||
return b[:i], b[i:]
|
||||
}
|
||||
}
|
||||
|
||||
return b, b[len(b):]
|
||||
}
|
||||
|
||||
func isUnquotedKeyChar(r byte) bool {
|
||||
return (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' || r == '_'
|
||||
}
|
||||
|
||||
func scanLiteralString(b []byte) ([]byte, []byte, error) {
|
||||
// literal-string = apostrophe *literal-char apostrophe
|
||||
// apostrophe = %x27 ; ' apostrophe
|
||||
// literal-char = %x09 / %x20-26 / %x28-7E / non-ascii
|
||||
for i := 1; i < len(b); {
|
||||
switch b[i] {
|
||||
case '\'':
|
||||
return b[:i+1], b[i+1:], nil
|
||||
case '\n', '\r':
|
||||
return nil, nil, newDecodeError(b[i:i+1], "literal strings cannot have new lines")
|
||||
}
|
||||
size := utf8ValidNext(b[i:])
|
||||
if size == 0 {
|
||||
return nil, nil, newDecodeError(b[i:i+1], "invalid character")
|
||||
}
|
||||
i += size
|
||||
}
|
||||
|
||||
return nil, nil, newDecodeError(b[len(b):], "unterminated literal string")
|
||||
}
|
||||
|
||||
func scanMultilineLiteralString(b []byte) ([]byte, []byte, error) {
|
||||
// ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body
|
||||
// ml-literal-string-delim
|
||||
// ml-literal-string-delim = 3apostrophe
|
||||
// ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ]
|
||||
//
|
||||
// mll-content = mll-char / newline
|
||||
// mll-char = %x09 / %x20-26 / %x28-7E / non-ascii
|
||||
// mll-quotes = 1*2apostrophe
|
||||
for i := 3; i < len(b); {
|
||||
switch b[i] {
|
||||
case '\'':
|
||||
if scanFollowsMultilineLiteralStringDelimiter(b[i:]) {
|
||||
i += 3
|
||||
|
||||
// At that point we found 3 apostrophe, and i is the
|
||||
// index of the byte after the third one. The scanner
|
||||
// needs to be eager, because there can be an extra 2
|
||||
// apostrophe that can be accepted at the end of the
|
||||
// string.
|
||||
|
||||
if i >= len(b) || b[i] != '\'' {
|
||||
return b[:i], b[i:], nil
|
||||
}
|
||||
i++
|
||||
|
||||
if i >= len(b) || b[i] != '\'' {
|
||||
return b[:i], b[i:], nil
|
||||
}
|
||||
i++
|
||||
|
||||
if i < len(b) && b[i] == '\'' {
|
||||
return nil, nil, newDecodeError(b[i-3:i+1], "''' not allowed in multiline literal string")
|
||||
}
|
||||
|
||||
return b[:i], b[i:], nil
|
||||
}
|
||||
case '\r':
|
||||
if len(b) < i+2 {
|
||||
return nil, nil, newDecodeError(b[len(b):], `need a \n after \r`)
|
||||
}
|
||||
if b[i+1] != '\n' {
|
||||
return nil, nil, newDecodeError(b[i:i+2], `need a \n after \r`)
|
||||
}
|
||||
i += 2 // skip the \n
|
||||
continue
|
||||
}
|
||||
size := utf8ValidNext(b[i:])
|
||||
if size == 0 {
|
||||
return nil, nil, newDecodeError(b[i:i+1], "invalid character")
|
||||
}
|
||||
i += size
|
||||
}
|
||||
|
||||
return nil, nil, newDecodeError(b[len(b):], `multiline literal string not terminated by '''`)
|
||||
}
|
||||
|
||||
func scanWindowsNewline(b []byte) ([]byte, []byte, error) {
|
||||
const lenCRLF = 2
|
||||
if len(b) < lenCRLF {
|
||||
return nil, nil, newDecodeError(b, "windows new line expected")
|
||||
}
|
||||
|
||||
if b[1] != '\n' {
|
||||
return nil, nil, newDecodeError(b, `windows new line should be \r\n`)
|
||||
}
|
||||
|
||||
return b[:lenCRLF], b[lenCRLF:], nil
|
||||
}
|
||||
|
||||
func scanWhitespace(b []byte) ([]byte, []byte) {
|
||||
for i := 0; i < len(b); i++ {
|
||||
switch b[i] {
|
||||
case ' ', '\t':
|
||||
continue
|
||||
default:
|
||||
return b[:i], b[i:]
|
||||
}
|
||||
}
|
||||
|
||||
return b, b[len(b):]
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func scanComment(b []byte) ([]byte, []byte, error) {
|
||||
// comment-start-symbol = %x23 ; #
|
||||
// non-ascii = %x80-D7FF / %xE000-10FFFF
|
||||
// non-eol = %x09 / %x20-7F / non-ascii
|
||||
//
|
||||
// comment = comment-start-symbol *non-eol
|
||||
|
||||
for i := 1; i < len(b); {
|
||||
if b[i] == '\n' {
|
||||
return b[:i], b[i:], nil
|
||||
}
|
||||
if b[i] == '\r' {
|
||||
if i+1 < len(b) && b[i+1] == '\n' {
|
||||
return b[:i+1], b[i+1:], nil
|
||||
}
|
||||
return nil, nil, newDecodeError(b[i:i+1], "invalid character in comment")
|
||||
}
|
||||
size := utf8ValidNext(b[i:])
|
||||
if size == 0 {
|
||||
return nil, nil, newDecodeError(b[i:i+1], "invalid character in comment")
|
||||
}
|
||||
|
||||
i += size
|
||||
}
|
||||
|
||||
return b, b[len(b):], nil
|
||||
}
|
||||
|
||||
func scanBasicString(b []byte) ([]byte, bool, []byte, error) {
|
||||
// basic-string = quotation-mark *basic-char quotation-mark
|
||||
// quotation-mark = %x22 ; "
|
||||
// basic-char = basic-unescaped / escaped
|
||||
// basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
|
||||
// escaped = escape escape-seq-char
|
||||
escaped := false
|
||||
i := 1
|
||||
|
||||
for ; i < len(b); i++ {
|
||||
switch b[i] {
|
||||
case '"':
|
||||
return b[:i+1], escaped, b[i+1:], nil
|
||||
case '\n', '\r':
|
||||
return nil, escaped, nil, newDecodeError(b[i:i+1], "basic strings cannot have new lines")
|
||||
case '\\':
|
||||
if len(b) < i+2 {
|
||||
return nil, escaped, nil, newDecodeError(b[i:i+1], "need a character after \\")
|
||||
}
|
||||
escaped = true
|
||||
i++ // skip the next character
|
||||
}
|
||||
}
|
||||
|
||||
return nil, escaped, nil, newDecodeError(b[len(b):], `basic string not terminated by "`)
|
||||
}
|
||||
|
||||
func scanMultilineBasicString(b []byte) ([]byte, bool, []byte, error) {
|
||||
// ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
|
||||
// ml-basic-string-delim
|
||||
// ml-basic-string-delim = 3quotation-mark
|
||||
// ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ]
|
||||
//
|
||||
// mlb-content = mlb-char / newline / mlb-escaped-nl
|
||||
// mlb-char = mlb-unescaped / escaped
|
||||
// mlb-quotes = 1*2quotation-mark
|
||||
// mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
|
||||
// mlb-escaped-nl = escape ws newline *( wschar / newline )
|
||||
|
||||
escaped := false
|
||||
i := 3
|
||||
|
||||
for ; i < len(b); i++ {
|
||||
switch b[i] {
|
||||
case '"':
|
||||
if scanFollowsMultilineBasicStringDelimiter(b[i:]) {
|
||||
i += 3
|
||||
|
||||
// At that point we found 3 apostrophe, and i is the
|
||||
// index of the byte after the third one. The scanner
|
||||
// needs to be eager, because there can be an extra 2
|
||||
// apostrophe that can be accepted at the end of the
|
||||
// string.
|
||||
|
||||
if i >= len(b) || b[i] != '"' {
|
||||
return b[:i], escaped, b[i:], nil
|
||||
}
|
||||
i++
|
||||
|
||||
if i >= len(b) || b[i] != '"' {
|
||||
return b[:i], escaped, b[i:], nil
|
||||
}
|
||||
i++
|
||||
|
||||
if i < len(b) && b[i] == '"' {
|
||||
return nil, escaped, nil, newDecodeError(b[i-3:i+1], `""" not allowed in multiline basic string`)
|
||||
}
|
||||
|
||||
return b[:i], escaped, b[i:], nil
|
||||
}
|
||||
case '\\':
|
||||
if len(b) < i+2 {
|
||||
return nil, escaped, nil, newDecodeError(b[len(b):], "need a character after \\")
|
||||
}
|
||||
escaped = true
|
||||
i++ // skip the next character
|
||||
case '\r':
|
||||
if len(b) < i+2 {
|
||||
return nil, escaped, nil, newDecodeError(b[len(b):], `need a \n after \r`)
|
||||
}
|
||||
if b[i+1] != '\n' {
|
||||
return nil, escaped, nil, newDecodeError(b[i:i+2], `need a \n after \r`)
|
||||
}
|
||||
i++ // skip the \n
|
||||
}
|
||||
}
|
||||
|
||||
return nil, escaped, nil, newDecodeError(b[len(b):], `multiline basic string not terminated by """`)
|
||||
}
|
107
vendor/github.com/pelletier/go-toml/v2/strict.go
generated
vendored
Normal file
107
vendor/github.com/pelletier/go-toml/v2/strict.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"github.com/pelletier/go-toml/v2/internal/ast"
|
||||
"github.com/pelletier/go-toml/v2/internal/danger"
|
||||
"github.com/pelletier/go-toml/v2/internal/tracker"
|
||||
)
|
||||
|
||||
type strict struct {
|
||||
Enabled bool
|
||||
|
||||
// Tracks the current key being processed.
|
||||
key tracker.KeyTracker
|
||||
|
||||
missing []decodeError
|
||||
}
|
||||
|
||||
func (s *strict) EnterTable(node *ast.Node) {
|
||||
if !s.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
s.key.UpdateTable(node)
|
||||
}
|
||||
|
||||
func (s *strict) EnterArrayTable(node *ast.Node) {
|
||||
if !s.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
s.key.UpdateArrayTable(node)
|
||||
}
|
||||
|
||||
func (s *strict) EnterKeyValue(node *ast.Node) {
|
||||
if !s.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
s.key.Push(node)
|
||||
}
|
||||
|
||||
func (s *strict) ExitKeyValue(node *ast.Node) {
|
||||
if !s.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
s.key.Pop(node)
|
||||
}
|
||||
|
||||
func (s *strict) MissingTable(node *ast.Node) {
|
||||
if !s.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
s.missing = append(s.missing, decodeError{
|
||||
highlight: keyLocation(node),
|
||||
message: "missing table",
|
||||
key: s.key.Key(),
|
||||
})
|
||||
}
|
||||
|
||||
func (s *strict) MissingField(node *ast.Node) {
|
||||
if !s.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
s.missing = append(s.missing, decodeError{
|
||||
highlight: keyLocation(node),
|
||||
message: "missing field",
|
||||
key: s.key.Key(),
|
||||
})
|
||||
}
|
||||
|
||||
func (s *strict) Error(doc []byte) error {
|
||||
if !s.Enabled || len(s.missing) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := &StrictMissingError{
|
||||
Errors: make([]DecodeError, 0, len(s.missing)),
|
||||
}
|
||||
|
||||
for _, derr := range s.missing {
|
||||
derr := derr
|
||||
err.Errors = append(err.Errors, *wrapDecodeError(doc, &derr))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func keyLocation(node *ast.Node) []byte {
|
||||
k := node.Key()
|
||||
|
||||
hasOne := k.Next()
|
||||
if !hasOne {
|
||||
panic("should not be called with empty key")
|
||||
}
|
||||
|
||||
start := k.Node().Data
|
||||
end := k.Node().Data
|
||||
|
||||
for k.Next() {
|
||||
end = k.Node().Data
|
||||
}
|
||||
|
||||
return danger.BytesRange(start, end)
|
||||
}
|
243
vendor/github.com/pelletier/go-toml/v2/toml.abnf
generated
vendored
Normal file
243
vendor/github.com/pelletier/go-toml/v2/toml.abnf
generated
vendored
Normal file
@ -0,0 +1,243 @@
|
||||
;; This document describes TOML's syntax, using the ABNF format (defined in
|
||||
;; RFC 5234 -- https://www.ietf.org/rfc/rfc5234.txt).
|
||||
;;
|
||||
;; All valid TOML documents will match this description, however certain
|
||||
;; invalid documents would need to be rejected as per the semantics described
|
||||
;; in the supporting text description.
|
||||
|
||||
;; It is possible to try this grammar interactively, using instaparse.
|
||||
;; http://instaparse.mojombo.com/
|
||||
;;
|
||||
;; To do so, in the lower right, click on Options and change `:input-format` to
|
||||
;; ':abnf'. Then paste this entire ABNF document into the grammar entry box
|
||||
;; (above the options). Then you can type or paste a sample TOML document into
|
||||
;; the beige box on the left. Tada!
|
||||
|
||||
;; Overall Structure
|
||||
|
||||
toml = expression *( newline expression )
|
||||
|
||||
expression = ws [ comment ]
|
||||
expression =/ ws keyval ws [ comment ]
|
||||
expression =/ ws table ws [ comment ]
|
||||
|
||||
;; Whitespace
|
||||
|
||||
ws = *wschar
|
||||
wschar = %x20 ; Space
|
||||
wschar =/ %x09 ; Horizontal tab
|
||||
|
||||
;; Newline
|
||||
|
||||
newline = %x0A ; LF
|
||||
newline =/ %x0D.0A ; CRLF
|
||||
|
||||
;; Comment
|
||||
|
||||
comment-start-symbol = %x23 ; #
|
||||
non-ascii = %x80-D7FF / %xE000-10FFFF
|
||||
non-eol = %x09 / %x20-7F / non-ascii
|
||||
|
||||
comment = comment-start-symbol *non-eol
|
||||
|
||||
;; Key-Value pairs
|
||||
|
||||
keyval = key keyval-sep val
|
||||
|
||||
key = simple-key / dotted-key
|
||||
simple-key = quoted-key / unquoted-key
|
||||
|
||||
unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _
|
||||
quoted-key = basic-string / literal-string
|
||||
dotted-key = simple-key 1*( dot-sep simple-key )
|
||||
|
||||
dot-sep = ws %x2E ws ; . Period
|
||||
keyval-sep = ws %x3D ws ; =
|
||||
|
||||
val = string / boolean / array / inline-table / date-time / float / integer
|
||||
|
||||
;; String
|
||||
|
||||
string = ml-basic-string / basic-string / ml-literal-string / literal-string
|
||||
|
||||
;; Basic String
|
||||
|
||||
basic-string = quotation-mark *basic-char quotation-mark
|
||||
|
||||
quotation-mark = %x22 ; "
|
||||
|
||||
basic-char = basic-unescaped / escaped
|
||||
basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
|
||||
escaped = escape escape-seq-char
|
||||
|
||||
escape = %x5C ; \
|
||||
escape-seq-char = %x22 ; " quotation mark U+0022
|
||||
escape-seq-char =/ %x5C ; \ reverse solidus U+005C
|
||||
escape-seq-char =/ %x62 ; b backspace U+0008
|
||||
escape-seq-char =/ %x66 ; f form feed U+000C
|
||||
escape-seq-char =/ %x6E ; n line feed U+000A
|
||||
escape-seq-char =/ %x72 ; r carriage return U+000D
|
||||
escape-seq-char =/ %x74 ; t tab U+0009
|
||||
escape-seq-char =/ %x75 4HEXDIG ; uXXXX U+XXXX
|
||||
escape-seq-char =/ %x55 8HEXDIG ; UXXXXXXXX U+XXXXXXXX
|
||||
|
||||
;; Multiline Basic String
|
||||
|
||||
ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
|
||||
ml-basic-string-delim
|
||||
ml-basic-string-delim = 3quotation-mark
|
||||
ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ]
|
||||
|
||||
mlb-content = mlb-char / newline / mlb-escaped-nl
|
||||
mlb-char = mlb-unescaped / escaped
|
||||
mlb-quotes = 1*2quotation-mark
|
||||
mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
|
||||
mlb-escaped-nl = escape ws newline *( wschar / newline )
|
||||
|
||||
;; Literal String
|
||||
|
||||
literal-string = apostrophe *literal-char apostrophe
|
||||
|
||||
apostrophe = %x27 ; ' apostrophe
|
||||
|
||||
literal-char = %x09 / %x20-26 / %x28-7E / non-ascii
|
||||
|
||||
;; Multiline Literal String
|
||||
|
||||
ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body
|
||||
ml-literal-string-delim
|
||||
ml-literal-string-delim = 3apostrophe
|
||||
ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ]
|
||||
|
||||
mll-content = mll-char / newline
|
||||
mll-char = %x09 / %x20-26 / %x28-7E / non-ascii
|
||||
mll-quotes = 1*2apostrophe
|
||||
|
||||
;; Integer
|
||||
|
||||
integer = dec-int / hex-int / oct-int / bin-int
|
||||
|
||||
minus = %x2D ; -
|
||||
plus = %x2B ; +
|
||||
underscore = %x5F ; _
|
||||
digit1-9 = %x31-39 ; 1-9
|
||||
digit0-7 = %x30-37 ; 0-7
|
||||
digit0-1 = %x30-31 ; 0-1
|
||||
|
||||
hex-prefix = %x30.78 ; 0x
|
||||
oct-prefix = %x30.6F ; 0o
|
||||
bin-prefix = %x30.62 ; 0b
|
||||
|
||||
dec-int = [ minus / plus ] unsigned-dec-int
|
||||
unsigned-dec-int = DIGIT / digit1-9 1*( DIGIT / underscore DIGIT )
|
||||
|
||||
hex-int = hex-prefix HEXDIG *( HEXDIG / underscore HEXDIG )
|
||||
oct-int = oct-prefix digit0-7 *( digit0-7 / underscore digit0-7 )
|
||||
bin-int = bin-prefix digit0-1 *( digit0-1 / underscore digit0-1 )
|
||||
|
||||
;; Float
|
||||
|
||||
float = float-int-part ( exp / frac [ exp ] )
|
||||
float =/ special-float
|
||||
|
||||
float-int-part = dec-int
|
||||
frac = decimal-point zero-prefixable-int
|
||||
decimal-point = %x2E ; .
|
||||
zero-prefixable-int = DIGIT *( DIGIT / underscore DIGIT )
|
||||
|
||||
exp = "e" float-exp-part
|
||||
float-exp-part = [ minus / plus ] zero-prefixable-int
|
||||
|
||||
special-float = [ minus / plus ] ( inf / nan )
|
||||
inf = %x69.6e.66 ; inf
|
||||
nan = %x6e.61.6e ; nan
|
||||
|
||||
;; Boolean
|
||||
|
||||
boolean = true / false
|
||||
|
||||
true = %x74.72.75.65 ; true
|
||||
false = %x66.61.6C.73.65 ; false
|
||||
|
||||
;; Date and Time (as defined in RFC 3339)
|
||||
|
||||
date-time = offset-date-time / local-date-time / local-date / local-time
|
||||
|
||||
date-fullyear = 4DIGIT
|
||||
date-month = 2DIGIT ; 01-12
|
||||
date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
||||
time-delim = "T" / %x20 ; T, t, or space
|
||||
time-hour = 2DIGIT ; 00-23
|
||||
time-minute = 2DIGIT ; 00-59
|
||||
time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules
|
||||
time-secfrac = "." 1*DIGIT
|
||||
time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
|
||||
time-offset = "Z" / time-numoffset
|
||||
|
||||
partial-time = time-hour ":" time-minute ":" time-second [ time-secfrac ]
|
||||
full-date = date-fullyear "-" date-month "-" date-mday
|
||||
full-time = partial-time time-offset
|
||||
|
||||
;; Offset Date-Time
|
||||
|
||||
offset-date-time = full-date time-delim full-time
|
||||
|
||||
;; Local Date-Time
|
||||
|
||||
local-date-time = full-date time-delim partial-time
|
||||
|
||||
;; Local Date
|
||||
|
||||
local-date = full-date
|
||||
|
||||
;; Local Time
|
||||
|
||||
local-time = partial-time
|
||||
|
||||
;; Array
|
||||
|
||||
array = array-open [ array-values ] ws-comment-newline array-close
|
||||
|
||||
array-open = %x5B ; [
|
||||
array-close = %x5D ; ]
|
||||
|
||||
array-values = ws-comment-newline val ws-comment-newline array-sep array-values
|
||||
array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ]
|
||||
|
||||
array-sep = %x2C ; , Comma
|
||||
|
||||
ws-comment-newline = *( wschar / [ comment ] newline )
|
||||
|
||||
;; Table
|
||||
|
||||
table = std-table / array-table
|
||||
|
||||
;; Standard Table
|
||||
|
||||
std-table = std-table-open key std-table-close
|
||||
|
||||
std-table-open = %x5B ws ; [ Left square bracket
|
||||
std-table-close = ws %x5D ; ] Right square bracket
|
||||
|
||||
;; Inline Table
|
||||
|
||||
inline-table = inline-table-open [ inline-table-keyvals ] inline-table-close
|
||||
|
||||
inline-table-open = %x7B ws ; {
|
||||
inline-table-close = ws %x7D ; }
|
||||
inline-table-sep = ws %x2C ws ; , Comma
|
||||
|
||||
inline-table-keyvals = keyval [ inline-table-sep inline-table-keyvals ]
|
||||
|
||||
;; Array Table
|
||||
|
||||
array-table = array-table-open key array-table-close
|
||||
|
||||
array-table-open = %x5B.5B ws ; [[ Double left square bracket
|
||||
array-table-close = ws %x5D.5D ; ]] Double right square bracket
|
||||
|
||||
;; Built-in ABNF terms, reproduced here for clarity
|
||||
|
||||
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
|
||||
DIGIT = %x30-39 ; 0-9
|
||||
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
|
14
vendor/github.com/pelletier/go-toml/v2/types.go
generated
vendored
Normal file
14
vendor/github.com/pelletier/go-toml/v2/types.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var timeType = reflect.TypeOf(time.Time{})
|
||||
var textMarshalerType = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()
|
||||
var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
|
||||
var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{})
|
||||
var sliceInterfaceType = reflect.TypeOf([]interface{}{})
|
||||
var stringType = reflect.TypeOf("")
|
1189
vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
generated
vendored
Normal file
1189
vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
240
vendor/github.com/pelletier/go-toml/v2/utf8.go
generated
vendored
Normal file
240
vendor/github.com/pelletier/go-toml/v2/utf8.go
generated
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
package toml
|
||||
|
||||
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:
|
||||
//
|
||||
// Any Unicode character may be used except those that must be escaped:
|
||||
// quotation mark, backslash, and the control characters other than tab (U+0000
|
||||
// to U+0008, U+000A to U+001F, U+007F).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// quotation mark => already checked
|
||||
// backslash => already checked
|
||||
// 0-0x8 => invalid
|
||||
// 0x9 => tab, ok
|
||||
// 0xA - 0x1F => invalid
|
||||
// 0x7F => invalid
|
||||
func utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
|
||||
// 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.
|
||||
// The compiler can generate a 32bit load for first32 and second32
|
||||
// on many platforms. See test/codegen/memcombine.go.
|
||||
first32 := uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
|
||||
second32 := uint32(p[4]) | uint32(p[5])<<8 | uint32(p[6])<<16 | uint32(p[7])<<24
|
||||
if (first32|second32)&0x80808080 != 0 {
|
||||
// Found a non ASCII byte (>= RuneSelf).
|
||||
break
|
||||
}
|
||||
|
||||
for i, b := range p[:8] {
|
||||
if invalidAscii(b) {
|
||||
err.Index = offset + i
|
||||
err.Size = 1
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
i++
|
||||
continue
|
||||
}
|
||||
x := first[pi]
|
||||
if x == xx {
|
||||
// Illegal starter byte.
|
||||
err.Index = offset + i
|
||||
err.Size = 1
|
||||
return
|
||||
}
|
||||
size := int(x & 7)
|
||||
if i+size > n {
|
||||
// Short or invalid.
|
||||
err.Index = offset + i
|
||||
err.Size = n - i
|
||||
return
|
||||
}
|
||||
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 {
|
||||
} else if c := p[i+2]; c < locb || hicb < c {
|
||||
err.Index = offset + i
|
||||
err.Size = 3
|
||||
return
|
||||
} else if size == 3 {
|
||||
} else if c := p[i+3]; c < locb || hicb < c {
|
||||
err.Index = offset + i
|
||||
err.Size = 4
|
||||
return
|
||||
}
|
||||
i += size
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Return 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) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
x := first[c]
|
||||
if x == xx {
|
||||
// Illegal starter byte.
|
||||
return 0
|
||||
}
|
||||
size := int(x & 7)
|
||||
if size > len(p) {
|
||||
// Short or invalid.
|
||||
return 0
|
||||
}
|
||||
accept := acceptRanges[x>>4]
|
||||
if c := p[1]; c < accept.lo || accept.hi < c {
|
||||
return 0
|
||||
} else if size == 2 {
|
||||
} else if c := p[2]; c < locb || hicb < c {
|
||||
return 0
|
||||
} else if size == 3 {
|
||||
} else if c := p[3]; c < locb || hicb < c {
|
||||
return 0
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
var invalidAsciiTable = [256]bool{
|
||||
0x00: true,
|
||||
0x01: true,
|
||||
0x02: true,
|
||||
0x03: true,
|
||||
0x04: true,
|
||||
0x05: true,
|
||||
0x06: true,
|
||||
0x07: true,
|
||||
0x08: true,
|
||||
// 0x09 TAB
|
||||
// 0x0A LF
|
||||
0x0B: true,
|
||||
0x0C: true,
|
||||
// 0x0D CR
|
||||
0x0E: true,
|
||||
0x0F: true,
|
||||
0x10: true,
|
||||
0x11: true,
|
||||
0x12: true,
|
||||
0x13: true,
|
||||
0x14: true,
|
||||
0x15: true,
|
||||
0x16: true,
|
||||
0x17: true,
|
||||
0x18: true,
|
||||
0x19: true,
|
||||
0x1A: true,
|
||||
0x1B: true,
|
||||
0x1C: true,
|
||||
0x1D: true,
|
||||
0x1E: true,
|
||||
0x1F: true,
|
||||
// 0x20 - 0x7E Printable ASCII characters
|
||||
0x7F: true,
|
||||
}
|
||||
|
||||
func invalidAscii(b byte) bool {
|
||||
return invalidAsciiTable[b]
|
||||
}
|
||||
|
||||
// acceptRange gives the range of valid values for the second byte in a UTF-8
|
||||
// sequence.
|
||||
type acceptRange struct {
|
||||
lo uint8 // lowest value for second byte.
|
||||
hi uint8 // highest value for second byte.
|
||||
}
|
||||
|
||||
// acceptRanges has size 16 to avoid bounds checks in the code that uses it.
|
||||
var acceptRanges = [16]acceptRange{
|
||||
0: {locb, hicb},
|
||||
1: {0xA0, hicb},
|
||||
2: {locb, 0x9F},
|
||||
3: {0x90, hicb},
|
||||
4: {locb, 0x8F},
|
||||
}
|
||||
|
||||
// first is information about the first byte in a UTF-8 sequence.
|
||||
var first = [256]uint8{
|
||||
// 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F
|
||||
// 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F
|
||||
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F
|
||||
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF
|
||||
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF
|
||||
xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF
|
||||
s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF
|
||||
s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF
|
||||
s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF
|
||||
}
|
||||
|
||||
const (
|
||||
// The default lowest and highest continuation byte.
|
||||
locb = 0b10000000
|
||||
hicb = 0b10111111
|
||||
|
||||
// These names of these constants are chosen to give nice alignment in the
|
||||
// table below. The first nibble is an index into acceptRanges or F for
|
||||
// special one-byte cases. The second nibble is the Rune length or the
|
||||
// Status for the special one-byte case.
|
||||
xx = 0xF1 // invalid: size 1
|
||||
as = 0xF0 // ASCII: size 1
|
||||
s1 = 0x02 // accept 0, size 2
|
||||
s2 = 0x13 // accept 1, size 3
|
||||
s3 = 0x03 // accept 0, size 3
|
||||
s4 = 0x23 // accept 2, size 3
|
||||
s5 = 0x34 // accept 3, size 4
|
||||
s6 = 0x04 // accept 0, size 4
|
||||
s7 = 0x44 // accept 4, size 4
|
||||
)
|
16
vendor/github.com/spf13/afero/README.md
generated
vendored
16
vendor/github.com/spf13/afero/README.md
generated
vendored
@ -79,11 +79,11 @@ would.
|
||||
|
||||
So if my application before had:
|
||||
```go
|
||||
os.Open('/tmp/foo')
|
||||
os.Open("/tmp/foo")
|
||||
```
|
||||
We would replace it with:
|
||||
```go
|
||||
AppFs.Open('/tmp/foo')
|
||||
AppFs.Open("/tmp/foo")
|
||||
```
|
||||
|
||||
`AppFs` being the variable we defined above.
|
||||
@ -259,6 +259,18 @@ system using InMemoryFile.
|
||||
Afero has experimental support for secure file transfer protocol (sftp). Which can
|
||||
be used to perform file operations over a encrypted channel.
|
||||
|
||||
### GCSFs
|
||||
|
||||
Afero has experimental support for Google Cloud Storage (GCS). You can either set the
|
||||
`GOOGLE_APPLICATION_CREDENTIALS_JSON` env variable to your JSON credentials or use `opts` in
|
||||
`NewGcsFS` to configure access to your GCS bucket.
|
||||
|
||||
Some known limitations of the existing implementation:
|
||||
* No Chmod support - The GCS ACL could probably be mapped to *nix style permissions but that would add another level of complexity and is ignored in this version.
|
||||
* No Chtimes support - Could be simulated with attributes (gcs a/m-times are set implicitly) but that's is left for another version.
|
||||
* Not thread safe - Also assumes all file operations are done through the same instance of the GcsFs. File operations between different GcsFs instances are not guaranteed to be consistent.
|
||||
|
||||
|
||||
## Filtering Backends
|
||||
|
||||
### BasePathFs
|
||||
|
6
vendor/github.com/spf13/afero/cacheOnReadFs.go
generated
vendored
6
vendor/github.com/spf13/afero/cacheOnReadFs.go
generated
vendored
@ -75,6 +75,10 @@ func (u *CacheOnReadFs) copyToLayer(name string) error {
|
||||
return copyToLayer(u.base, u.layer, name)
|
||||
}
|
||||
|
||||
func (u *CacheOnReadFs) copyFileToLayer(name string, flag int, perm os.FileMode) error {
|
||||
return copyFileToLayer(u.base, u.layer, name, flag, perm)
|
||||
}
|
||||
|
||||
func (u *CacheOnReadFs) Chtimes(name string, atime, mtime time.Time) error {
|
||||
st, _, err := u.cacheStatus(name)
|
||||
if err != nil {
|
||||
@ -212,7 +216,7 @@ func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File,
|
||||
switch st {
|
||||
case cacheLocal, cacheHit:
|
||||
default:
|
||||
if err := u.copyToLayer(name); err != nil {
|
||||
if err := u.copyFileToLayer(name, flag, perm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
2
vendor/github.com/spf13/afero/mem/file.go
generated
vendored
2
vendor/github.com/spf13/afero/mem/file.go
generated
vendored
@ -71,7 +71,7 @@ func CreateFile(name string) *FileData {
|
||||
}
|
||||
|
||||
func CreateDir(name string) *FileData {
|
||||
return &FileData{name: name, memDir: &DirMap{}, dir: true}
|
||||
return &FileData{name: name, memDir: &DirMap{}, dir: true, modtime: time.Now()}
|
||||
}
|
||||
|
||||
func ChangeFileName(f *FileData, newname string) {
|
||||
|
2
vendor/github.com/spf13/afero/memmap.go
generated
vendored
2
vendor/github.com/spf13/afero/memmap.go
generated
vendored
@ -279,7 +279,7 @@ func (m *MemMapFs) RemoveAll(path string) error {
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
for p := range m.getData() {
|
||||
if strings.HasPrefix(p, path) {
|
||||
if p == path || strings.HasPrefix(p, path+FilePathSeparator) {
|
||||
m.mu.RUnlock()
|
||||
m.mu.Lock()
|
||||
delete(m.getData(), p)
|
||||
|
28
vendor/github.com/spf13/afero/unionFile.go
generated
vendored
28
vendor/github.com/spf13/afero/unionFile.go
generated
vendored
@ -268,13 +268,7 @@ func (f *UnionFile) WriteString(s string) (n int, err error) {
|
||||
return 0, BADFD
|
||||
}
|
||||
|
||||
func copyToLayer(base Fs, layer Fs, name string) error {
|
||||
bfh, err := base.Open(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer bfh.Close()
|
||||
|
||||
func copyFile(base Fs, layer Fs, name string, bfh File) error {
|
||||
// First make sure the directory exists
|
||||
exists, err := Exists(layer, filepath.Dir(name))
|
||||
if err != nil {
|
||||
@ -315,3 +309,23 @@ func copyToLayer(base Fs, layer Fs, name string) error {
|
||||
}
|
||||
return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime())
|
||||
}
|
||||
|
||||
func copyToLayer(base Fs, layer Fs, name string) error {
|
||||
bfh, err := base.Open(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer bfh.Close()
|
||||
|
||||
return copyFile(base, layer, name, bfh)
|
||||
}
|
||||
|
||||
func copyFileToLayer(base Fs, layer Fs, name string, flag int, perm os.FileMode) error {
|
||||
bfh, err := base.OpenFile(name, flag, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer bfh.Close()
|
||||
|
||||
return copyFile(base, layer, name, bfh)
|
||||
}
|
||||
|
13
vendor/github.com/spf13/cobra/MAINTAINERS
generated
vendored
Normal file
13
vendor/github.com/spf13/cobra/MAINTAINERS
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
maintainers:
|
||||
- spf13
|
||||
- johnSchnake
|
||||
- jpmcb
|
||||
- marckhouzam
|
||||
inactive:
|
||||
- anthonyfok
|
||||
- bep
|
||||
- bogem
|
||||
- broady
|
||||
- eparis
|
||||
- jharshman
|
||||
- wfernandes
|
11
vendor/github.com/spf13/cobra/Makefile
generated
vendored
11
vendor/github.com/spf13/cobra/Makefile
generated
vendored
@ -9,11 +9,11 @@ ifeq (, $(shell which richgo))
|
||||
$(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo")
|
||||
endif
|
||||
|
||||
.PHONY: fmt lint test cobra_generator install_deps clean
|
||||
.PHONY: fmt lint test install_deps clean
|
||||
|
||||
default: all
|
||||
|
||||
all: fmt test cobra_generator
|
||||
all: fmt test
|
||||
|
||||
fmt:
|
||||
$(info ******************** checking formatting ********************)
|
||||
@ -23,15 +23,10 @@ lint:
|
||||
$(info ******************** running lint tools ********************)
|
||||
golangci-lint run -v
|
||||
|
||||
test: install_deps lint
|
||||
test: install_deps
|
||||
$(info ******************** running tests ********************)
|
||||
richgo test -v ./...
|
||||
|
||||
cobra_generator: install_deps
|
||||
$(info ******************** building generator ********************)
|
||||
mkdir -p $(BIN)
|
||||
make -C cobra all
|
||||
|
||||
install_deps:
|
||||
$(info ******************** downloading dependencies ********************)
|
||||
go get -v ./...
|
||||
|
54
vendor/github.com/spf13/cobra/README.md
generated
vendored
54
vendor/github.com/spf13/cobra/README.md
generated
vendored
@ -1,52 +1,26 @@
|
||||

|
||||
|
||||
Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files.
|
||||
Cobra is a library for creating powerful modern CLI applications.
|
||||
|
||||
Cobra is used in many Go projects such as [Kubernetes](http://kubernetes.io/),
|
||||
[Hugo](https://gohugo.io), and [Github CLI](https://github.com/cli/cli) to
|
||||
name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra.
|
||||
|
||||
[](https://github.com/spf13/cobra/actions?query=workflow%3ATest)
|
||||
[](https://godoc.org/github.com/spf13/cobra)
|
||||
[](https://pkg.go.dev/github.com/spf13/cobra)
|
||||
[](https://goreportcard.com/report/github.com/spf13/cobra)
|
||||
[](https://gophers.slack.com/archives/CD3LP1199)
|
||||
|
||||
# Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Concepts](#concepts)
|
||||
* [Commands](#commands)
|
||||
* [Flags](#flags)
|
||||
- [Installing](#installing)
|
||||
- [Usage](#usage)
|
||||
* [Using the Cobra Generator](user_guide.md#using-the-cobra-generator)
|
||||
* [Using the Cobra Library](user_guide.md#using-the-cobra-library)
|
||||
* [Working with Flags](user_guide.md#working-with-flags)
|
||||
* [Positional and Custom Arguments](user_guide.md#positional-and-custom-arguments)
|
||||
* [Example](user_guide.md#example)
|
||||
* [Help Command](user_guide.md#help-command)
|
||||
* [Usage Message](user_guide.md#usage-message)
|
||||
* [PreRun and PostRun Hooks](user_guide.md#prerun-and-postrun-hooks)
|
||||
* [Suggestions when "unknown command" happens](user_guide.md#suggestions-when-unknown-command-happens)
|
||||
* [Generating documentation for your command](user_guide.md#generating-documentation-for-your-command)
|
||||
* [Generating shell completions](user_guide.md#generating-shell-completions)
|
||||
- [Contributing](CONTRIBUTING.md)
|
||||
- [License](#license)
|
||||
|
||||
# Overview
|
||||
|
||||
Cobra is a library providing a simple interface to create powerful modern CLI
|
||||
interfaces similar to git & go tools.
|
||||
|
||||
Cobra is also an application that will generate your application scaffolding to rapidly
|
||||
develop a Cobra-based application.
|
||||
|
||||
Cobra provides:
|
||||
* Easy subcommand-based CLIs: `app server`, `app fetch`, etc.
|
||||
* Fully POSIX-compliant flags (including short & long versions)
|
||||
* Nested subcommands
|
||||
* Global, local and cascading flags
|
||||
* Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname`
|
||||
* Intelligent suggestions (`app srver`... did you mean `app server`?)
|
||||
* Automatic help generation for commands and flags
|
||||
* Automatic help flag recognition of `-h`, `--help`, etc.
|
||||
@ -54,7 +28,7 @@ Cobra provides:
|
||||
* Automatically generated man pages for your application
|
||||
* Command aliases so you can change things without breaking them
|
||||
* The flexibility to define your own help, usage, etc.
|
||||
* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps
|
||||
* Optional seamless integration with [viper](http://github.com/spf13/viper) for 12-factor apps
|
||||
|
||||
# Concepts
|
||||
|
||||
@ -88,7 +62,7 @@ have children commands and optionally run an action.
|
||||
|
||||
In the example above, 'server' is the command.
|
||||
|
||||
[More about cobra.Command](https://godoc.org/github.com/spf13/cobra#Command)
|
||||
[More about cobra.Command](https://pkg.go.dev/github.com/spf13/cobra#Command)
|
||||
|
||||
## Flags
|
||||
|
||||
@ -105,10 +79,11 @@ which maintains the same interface while adding POSIX compliance.
|
||||
|
||||
# Installing
|
||||
Using Cobra is easy. First, use `go get` to install the latest version
|
||||
of the library. This command will install the `cobra` generator executable
|
||||
along with the library and its dependencies:
|
||||
of the library.
|
||||
|
||||
go get -u github.com/spf13/cobra
|
||||
```
|
||||
go get -u github.com/spf13/cobra@latest
|
||||
```
|
||||
|
||||
Next, include Cobra in your application:
|
||||
|
||||
@ -117,8 +92,19 @@ import "github.com/spf13/cobra"
|
||||
```
|
||||
|
||||
# Usage
|
||||
`cobra-cli` is a command line program to generate cobra applications and command files.
|
||||
It will bootstrap your application scaffolding to rapidly
|
||||
develop a Cobra-based application. It is the easiest way to incorporate Cobra into your application.
|
||||
|
||||
See [User Guide](user_guide.md).
|
||||
It can be installed by running:
|
||||
|
||||
```
|
||||
go install github.com/spf13/cobra-cli@latest
|
||||
```
|
||||
|
||||
For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/master/README.md)
|
||||
|
||||
For complete details on using the Cobra library, please read the [The Cobra User Guide](user_guide.md).
|
||||
|
||||
# License
|
||||
|
||||
|
12
vendor/github.com/spf13/cobra/args.go
generated
vendored
12
vendor/github.com/spf13/cobra/args.go
generated
vendored
@ -107,3 +107,15 @@ func RangeArgs(min int, max int) PositionalArgs {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MatchAll allows combining several PositionalArgs to work in concert.
|
||||
func MatchAll(pargs ...PositionalArgs) PositionalArgs {
|
||||
return func(cmd *Command, args []string) error {
|
||||
for _, parg := range pargs {
|
||||
if err := parg(cmd, args); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
48
vendor/github.com/spf13/cobra/bash_completions.go
generated
vendored
48
vendor/github.com/spf13/cobra/bash_completions.go
generated
vendored
@ -24,7 +24,7 @@ func writePreamble(buf io.StringWriter, name string) {
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`
|
||||
__%[1]s_debug()
|
||||
{
|
||||
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
|
||||
if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then
|
||||
echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
|
||||
fi
|
||||
}
|
||||
@ -134,7 +134,7 @@ __%[1]s_handle_go_custom_completion()
|
||||
$filteringCmd
|
||||
elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
|
||||
# File completion for directories only
|
||||
local subDir
|
||||
local subdir
|
||||
# Use printf to strip any trailing newline
|
||||
subdir=$(printf "%%s" "${out[0]}")
|
||||
if [ -n "$subdir" ]; then
|
||||
@ -187,13 +187,19 @@ __%[1]s_handle_reply()
|
||||
PREFIX=""
|
||||
cur="${cur#*=}"
|
||||
${flags_completion[${index}]}
|
||||
if [ -n "${ZSH_VERSION}" ]; then
|
||||
if [ -n "${ZSH_VERSION:-}" ]; then
|
||||
# zsh completion needs --flag= prefix
|
||||
eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return 0;
|
||||
|
||||
if [[ -z "${flag_parsing_disabled}" ]]; then
|
||||
# If flag parsing is enabled, we have completed the flags and can return.
|
||||
# If flag parsing is disabled, we may not know all (or any) of the flags, so we fallthrough
|
||||
# to possibly call handle_go_custom_completion.
|
||||
return 0;
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -232,13 +238,13 @@ __%[1]s_handle_reply()
|
||||
fi
|
||||
|
||||
if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
|
||||
if declare -F __%[1]s_custom_func >/dev/null; then
|
||||
# try command name qualified custom func
|
||||
__%[1]s_custom_func
|
||||
else
|
||||
# otherwise fall back to unqualified for compatibility
|
||||
declare -F __custom_func >/dev/null && __custom_func
|
||||
fi
|
||||
if declare -F __%[1]s_custom_func >/dev/null; then
|
||||
# try command name qualified custom func
|
||||
__%[1]s_custom_func
|
||||
else
|
||||
# otherwise fall back to unqualified for compatibility
|
||||
declare -F __custom_func >/dev/null && __custom_func
|
||||
fi
|
||||
fi
|
||||
|
||||
# available in bash-completion >= 2, not always present on macOS
|
||||
@ -272,7 +278,7 @@ __%[1]s_handle_flag()
|
||||
|
||||
# if a command required a flag, and we found it, unset must_have_one_flag()
|
||||
local flagname=${words[c]}
|
||||
local flagvalue
|
||||
local flagvalue=""
|
||||
# if the word contained an =
|
||||
if [[ ${words[c]} == *"="* ]]; then
|
||||
flagvalue=${flagname#*=} # take in as flagvalue after the =
|
||||
@ -291,7 +297,7 @@ __%[1]s_handle_flag()
|
||||
|
||||
# keep flag value with flagname as flaghash
|
||||
# flaghash variable is an associative array which is only supported in bash > 3.
|
||||
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
|
||||
if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then
|
||||
if [ -n "${flagvalue}" ] ; then
|
||||
flaghash[${flagname}]=${flagvalue}
|
||||
elif [ -n "${words[ $((c+1)) ]}" ] ; then
|
||||
@ -303,7 +309,7 @@ __%[1]s_handle_flag()
|
||||
|
||||
# skip the argument to a two word flag
|
||||
if [[ ${words[c]} != *"="* ]] && __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then
|
||||
__%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument"
|
||||
__%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument"
|
||||
c=$((c+1))
|
||||
# if we are looking for a flags value, don't show commands
|
||||
if [[ $c -eq $cword ]]; then
|
||||
@ -363,7 +369,7 @@ __%[1]s_handle_word()
|
||||
__%[1]s_handle_command
|
||||
elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then
|
||||
# aliashash variable is an associative array which is only supported in bash > 3.
|
||||
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
|
||||
if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then
|
||||
words[c]=${aliashash[${words[c]}]}
|
||||
__%[1]s_handle_command
|
||||
else
|
||||
@ -394,6 +400,7 @@ func writePostscript(buf io.StringWriter, name string) {
|
||||
fi
|
||||
|
||||
local c=0
|
||||
local flag_parsing_disabled=
|
||||
local flags=()
|
||||
local two_word_flags=()
|
||||
local local_nonpersistent_flags=()
|
||||
@ -403,8 +410,8 @@ func writePostscript(buf io.StringWriter, name string) {
|
||||
local command_aliases=()
|
||||
local must_have_one_flag=()
|
||||
local must_have_one_noun=()
|
||||
local has_completion_function
|
||||
local last_command
|
||||
local has_completion_function=""
|
||||
local last_command=""
|
||||
local nouns=()
|
||||
local noun_aliases=()
|
||||
|
||||
@ -535,6 +542,11 @@ func writeFlags(buf io.StringWriter, cmd *Command) {
|
||||
flags_completion=()
|
||||
|
||||
`)
|
||||
|
||||
if cmd.DisableFlagParsing {
|
||||
WriteStringAndCheck(buf, " flag_parsing_disabled=1\n")
|
||||
}
|
||||
|
||||
localNonPersistentFlags := cmd.LocalNonPersistentFlags()
|
||||
cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
|
||||
if nonCompletableFlag(flag) {
|
||||
@ -609,7 +621,7 @@ func writeCmdAliases(buf io.StringWriter, cmd *Command) {
|
||||
|
||||
sort.Strings(cmd.Aliases)
|
||||
|
||||
WriteStringAndCheck(buf, fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n"))
|
||||
WriteStringAndCheck(buf, fmt.Sprint(` if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then`, "\n"))
|
||||
for _, value := range cmd.Aliases {
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" command_aliases+=(%q)\n", value))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
|
||||
|
31
vendor/github.com/spf13/cobra/bash_completionsV2.go
generated
vendored
31
vendor/github.com/spf13/cobra/bash_completionsV2.go
generated
vendored
@ -138,13 +138,42 @@ __%[1]s_process_completion_results() {
|
||||
_filedir -d
|
||||
fi
|
||||
else
|
||||
__%[1]s_handle_standard_completion_case
|
||||
__%[1]s_handle_completion_types
|
||||
fi
|
||||
|
||||
__%[1]s_handle_special_char "$cur" :
|
||||
__%[1]s_handle_special_char "$cur" =
|
||||
}
|
||||
|
||||
__%[1]s_handle_completion_types() {
|
||||
__%[1]s_debug "__%[1]s_handle_completion_types: COMP_TYPE is $COMP_TYPE"
|
||||
|
||||
case $COMP_TYPE in
|
||||
37|42)
|
||||
# Type: menu-complete/menu-complete-backward and insert-completions
|
||||
# If the user requested inserting one completion at a time, or all
|
||||
# completions at once on the command-line we must remove the descriptions.
|
||||
# https://github.com/spf13/cobra/issues/1508
|
||||
local tab comp
|
||||
tab=$(printf '\t')
|
||||
while IFS='' read -r comp; do
|
||||
# Strip any description
|
||||
comp=${comp%%%%$tab*}
|
||||
# Only consider the completions that match
|
||||
comp=$(compgen -W "$comp" -- "$cur")
|
||||
if [ -n "$comp" ]; then
|
||||
COMPREPLY+=("$comp")
|
||||
fi
|
||||
done < <(printf "%%s\n" "${out[@]}")
|
||||
;;
|
||||
|
||||
*)
|
||||
# Type: complete (normal completion)
|
||||
__%[1]s_handle_standard_completion_case
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
__%[1]s_handle_standard_completion_case() {
|
||||
local tab comp
|
||||
tab=$(printf '\t')
|
||||
|
1
vendor/github.com/spf13/cobra/command_notwin.go
generated
vendored
1
vendor/github.com/spf13/cobra/command_notwin.go
generated
vendored
@ -1,3 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package cobra
|
||||
|
1
vendor/github.com/spf13/cobra/command_win.go
generated
vendored
1
vendor/github.com/spf13/cobra/command_win.go
generated
vendored
@ -1,3 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cobra
|
||||
|
208
vendor/github.com/spf13/cobra/completions.go
generated
vendored
208
vendor/github.com/spf13/cobra/completions.go
generated
vendored
@ -93,6 +93,8 @@ type CompletionOptions struct {
|
||||
// DisableDescriptions turns off all completion descriptions for shells
|
||||
// that support them
|
||||
DisableDescriptions bool
|
||||
// HiddenDefaultCmd makes the default 'completion' command hidden
|
||||
HiddenDefaultCmd bool
|
||||
}
|
||||
|
||||
// NoFileCompletions can be used to disable file completion for commands that should
|
||||
@ -226,7 +228,17 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
|
||||
if c.Root().TraverseChildren {
|
||||
finalCmd, finalArgs, err = c.Root().Traverse(trimmedArgs)
|
||||
} else {
|
||||
finalCmd, finalArgs, err = c.Root().Find(trimmedArgs)
|
||||
// For Root commands that don't specify any value for their Args fields, when we call
|
||||
// Find(), if those Root commands don't have any sub-commands, they will accept arguments.
|
||||
// However, because we have added the __complete sub-command in the current code path, the
|
||||
// call to Find() -> legacyArgs() will return an error if there are any arguments.
|
||||
// To avoid this, we first remove the __complete command to get back to having no sub-commands.
|
||||
rootCmd := c.Root()
|
||||
if len(rootCmd.Commands()) == 1 {
|
||||
rootCmd.RemoveCommand(c)
|
||||
}
|
||||
|
||||
finalCmd, finalArgs, err = rootCmd.Find(trimmedArgs)
|
||||
}
|
||||
if err != nil {
|
||||
// Unable to find the real command. E.g., <program> someInvalidCmd <TAB>
|
||||
@ -266,6 +278,12 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
|
||||
}
|
||||
}
|
||||
|
||||
// We only remove the flags from the arguments if DisableFlagParsing is not set.
|
||||
// This is important for commands which have requested to do their own flag completion.
|
||||
if !finalCmd.DisableFlagParsing {
|
||||
finalArgs = finalCmd.Flags().Args()
|
||||
}
|
||||
|
||||
if flag != nil && flagCompletion {
|
||||
// Check if we are completing a flag value subject to annotations
|
||||
if validExts, present := flag.Annotations[BashCompFilenameExt]; present {
|
||||
@ -290,12 +308,16 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
|
||||
}
|
||||
}
|
||||
|
||||
var completions []string
|
||||
var directive ShellCompDirective
|
||||
|
||||
// Note that we want to perform flagname completion even if finalCmd.DisableFlagParsing==true;
|
||||
// doing this allows for completion of persistant flag names even for commands that disable flag parsing.
|
||||
//
|
||||
// When doing completion of a flag name, as soon as an argument starts with
|
||||
// a '-' we know it is a flag. We cannot use isFlagArg() here as it requires
|
||||
// the flag name to be complete
|
||||
if flag == nil && len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") && flagCompletion {
|
||||
var completions []string
|
||||
|
||||
// First check for required flags
|
||||
completions = completeRequireFlags(finalCmd, toComplete)
|
||||
|
||||
@ -322,86 +344,86 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
|
||||
})
|
||||
}
|
||||
|
||||
directive := ShellCompDirectiveNoFileComp
|
||||
directive = ShellCompDirectiveNoFileComp
|
||||
if len(completions) == 1 && strings.HasSuffix(completions[0], "=") {
|
||||
// If there is a single completion, the shell usually adds a space
|
||||
// after the completion. We don't want that if the flag ends with an =
|
||||
directive = ShellCompDirectiveNoSpace
|
||||
}
|
||||
return finalCmd, completions, directive, nil
|
||||
}
|
||||
|
||||
// We only remove the flags from the arguments if DisableFlagParsing is not set.
|
||||
// This is important for commands which have requested to do their own flag completion.
|
||||
if !finalCmd.DisableFlagParsing {
|
||||
finalArgs = finalCmd.Flags().Args()
|
||||
}
|
||||
|
||||
var completions []string
|
||||
directive := ShellCompDirectiveDefault
|
||||
if flag == nil {
|
||||
foundLocalNonPersistentFlag := false
|
||||
// If TraverseChildren is true on the root command we don't check for
|
||||
// local flags because we can use a local flag on a parent command
|
||||
if !finalCmd.Root().TraverseChildren {
|
||||
// Check if there are any local, non-persistent flags on the command-line
|
||||
localNonPersistentFlags := finalCmd.LocalNonPersistentFlags()
|
||||
finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
|
||||
if localNonPersistentFlags.Lookup(flag.Name) != nil && flag.Changed {
|
||||
foundLocalNonPersistentFlag = true
|
||||
}
|
||||
})
|
||||
if !finalCmd.DisableFlagParsing {
|
||||
// If DisableFlagParsing==false, we have completed the flags as known by Cobra;
|
||||
// we can return what we found.
|
||||
// If DisableFlagParsing==true, Cobra may not be aware of all flags, so we
|
||||
// let the logic continue to see if ValidArgsFunction needs to be called.
|
||||
return finalCmd, completions, directive, nil
|
||||
}
|
||||
|
||||
// Complete subcommand names, including the help command
|
||||
if len(finalArgs) == 0 && !foundLocalNonPersistentFlag {
|
||||
// We only complete sub-commands if:
|
||||
// - there are no arguments on the command-line and
|
||||
// - there are no local, non-persistent flags on the command-line or TraverseChildren is true
|
||||
for _, subCmd := range finalCmd.Commands() {
|
||||
if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand {
|
||||
if strings.HasPrefix(subCmd.Name(), toComplete) {
|
||||
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
|
||||
} else {
|
||||
directive = ShellCompDirectiveDefault
|
||||
if flag == nil {
|
||||
foundLocalNonPersistentFlag := false
|
||||
// If TraverseChildren is true on the root command we don't check for
|
||||
// local flags because we can use a local flag on a parent command
|
||||
if !finalCmd.Root().TraverseChildren {
|
||||
// Check if there are any local, non-persistent flags on the command-line
|
||||
localNonPersistentFlags := finalCmd.LocalNonPersistentFlags()
|
||||
finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
|
||||
if localNonPersistentFlags.Lookup(flag.Name) != nil && flag.Changed {
|
||||
foundLocalNonPersistentFlag = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Complete subcommand names, including the help command
|
||||
if len(finalArgs) == 0 && !foundLocalNonPersistentFlag {
|
||||
// We only complete sub-commands if:
|
||||
// - there are no arguments on the command-line and
|
||||
// - there are no local, non-persistent flags on the command-line or TraverseChildren is true
|
||||
for _, subCmd := range finalCmd.Commands() {
|
||||
if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand {
|
||||
if strings.HasPrefix(subCmd.Name(), toComplete) {
|
||||
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
|
||||
}
|
||||
directive = ShellCompDirectiveNoFileComp
|
||||
}
|
||||
directive = ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete required flags even without the '-' prefix
|
||||
completions = append(completions, completeRequireFlags(finalCmd, toComplete)...)
|
||||
// Complete required flags even without the '-' prefix
|
||||
completions = append(completions, completeRequireFlags(finalCmd, toComplete)...)
|
||||
|
||||
// Always complete ValidArgs, even if we are completing a subcommand name.
|
||||
// This is for commands that have both subcommands and ValidArgs.
|
||||
if len(finalCmd.ValidArgs) > 0 {
|
||||
if len(finalArgs) == 0 {
|
||||
// ValidArgs are only for the first argument
|
||||
for _, validArg := range finalCmd.ValidArgs {
|
||||
if strings.HasPrefix(validArg, toComplete) {
|
||||
completions = append(completions, validArg)
|
||||
// Always complete ValidArgs, even if we are completing a subcommand name.
|
||||
// This is for commands that have both subcommands and ValidArgs.
|
||||
if len(finalCmd.ValidArgs) > 0 {
|
||||
if len(finalArgs) == 0 {
|
||||
// ValidArgs are only for the first argument
|
||||
for _, validArg := range finalCmd.ValidArgs {
|
||||
if strings.HasPrefix(validArg, toComplete) {
|
||||
completions = append(completions, validArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
directive = ShellCompDirectiveNoFileComp
|
||||
directive = ShellCompDirectiveNoFileComp
|
||||
|
||||
// If no completions were found within commands or ValidArgs,
|
||||
// see if there are any ArgAliases that should be completed.
|
||||
if len(completions) == 0 {
|
||||
for _, argAlias := range finalCmd.ArgAliases {
|
||||
if strings.HasPrefix(argAlias, toComplete) {
|
||||
completions = append(completions, argAlias)
|
||||
// If no completions were found within commands or ValidArgs,
|
||||
// see if there are any ArgAliases that should be completed.
|
||||
if len(completions) == 0 {
|
||||
for _, argAlias := range finalCmd.ArgAliases {
|
||||
if strings.HasPrefix(argAlias, toComplete) {
|
||||
completions = append(completions, argAlias)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there are ValidArgs specified (even if they don't match), we stop completion.
|
||||
// Only one of ValidArgs or ValidArgsFunction can be used for a single command.
|
||||
return finalCmd, completions, directive, nil
|
||||
}
|
||||
|
||||
// If there are ValidArgs specified (even if they don't match), we stop completion.
|
||||
// Only one of ValidArgs or ValidArgsFunction can be used for a single command.
|
||||
return finalCmd, completions, directive, nil
|
||||
// Let the logic continue so as to add any ValidArgsFunction completions,
|
||||
// even if we already found sub-commands.
|
||||
// This is for commands that have subcommands but also specify a ValidArgsFunction.
|
||||
}
|
||||
|
||||
// Let the logic continue so as to add any ValidArgsFunction completions,
|
||||
// even if we already found sub-commands.
|
||||
// This is for commands that have subcommands but also specify a ValidArgsFunction.
|
||||
}
|
||||
|
||||
// Find the completion function for the flag or command
|
||||
@ -589,39 +611,43 @@ func (c *Command) initDefaultCompletionCmd() {
|
||||
|
||||
completionCmd := &Command{
|
||||
Use: compCmdName,
|
||||
Short: "generate the autocompletion script for the specified shell",
|
||||
Long: fmt.Sprintf(`
|
||||
Generate the autocompletion script for %[1]s for the specified shell.
|
||||
Short: "Generate the autocompletion script for the specified shell",
|
||||
Long: fmt.Sprintf(`Generate the autocompletion script for %[1]s for the specified shell.
|
||||
See each sub-command's help for details on how to use the generated script.
|
||||
`, c.Root().Name()),
|
||||
Args: NoArgs,
|
||||
ValidArgsFunction: NoFileCompletions,
|
||||
Hidden: c.CompletionOptions.HiddenDefaultCmd,
|
||||
}
|
||||
c.AddCommand(completionCmd)
|
||||
|
||||
out := c.OutOrStdout()
|
||||
noDesc := c.CompletionOptions.DisableDescriptions
|
||||
shortDesc := "generate the autocompletion script for %s"
|
||||
shortDesc := "Generate the autocompletion script for %s"
|
||||
bash := &Command{
|
||||
Use: "bash",
|
||||
Short: fmt.Sprintf(shortDesc, "bash"),
|
||||
Long: fmt.Sprintf(`
|
||||
Generate the autocompletion script for the bash shell.
|
||||
Long: fmt.Sprintf(`Generate the autocompletion script for the bash shell.
|
||||
|
||||
This script depends on the 'bash-completion' package.
|
||||
If it is not installed already, you can install it via your OS's package manager.
|
||||
|
||||
To load completions in your current shell session:
|
||||
$ source <(%[1]s completion bash)
|
||||
|
||||
source <(%[1]s completion bash)
|
||||
|
||||
To load completions for every new session, execute once:
|
||||
Linux:
|
||||
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
|
||||
MacOS:
|
||||
$ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
|
||||
|
||||
#### Linux:
|
||||
|
||||
%[1]s completion bash > /etc/bash_completion.d/%[1]s
|
||||
|
||||
#### macOS:
|
||||
|
||||
%[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
|
||||
|
||||
You will need to start a new shell for this setup to take effect.
|
||||
`, c.Root().Name()),
|
||||
`, c.Root().Name()),
|
||||
Args: NoArgs,
|
||||
DisableFlagsInUseLine: true,
|
||||
ValidArgsFunction: NoFileCompletions,
|
||||
@ -636,19 +662,22 @@ You will need to start a new shell for this setup to take effect.
|
||||
zsh := &Command{
|
||||
Use: "zsh",
|
||||
Short: fmt.Sprintf(shortDesc, "zsh"),
|
||||
Long: fmt.Sprintf(`
|
||||
Generate the autocompletion script for the zsh shell.
|
||||
Long: fmt.Sprintf(`Generate the autocompletion script for the zsh shell.
|
||||
|
||||
If shell completion is not already enabled in your environment you will need
|
||||
to enable it. You can execute the following once:
|
||||
|
||||
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
|
||||
echo "autoload -U compinit; compinit" >> ~/.zshrc
|
||||
|
||||
To load completions for every new session, execute once:
|
||||
# Linux:
|
||||
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
|
||||
# macOS:
|
||||
$ %[1]s completion zsh > /usr/local/share/zsh/site-functions/_%[1]s
|
||||
|
||||
#### Linux:
|
||||
|
||||
%[1]s completion zsh > "${fpath[1]}/_%[1]s"
|
||||
|
||||
#### macOS:
|
||||
|
||||
%[1]s completion zsh > /usr/local/share/zsh/site-functions/_%[1]s
|
||||
|
||||
You will need to start a new shell for this setup to take effect.
|
||||
`, c.Root().Name()),
|
||||
@ -668,14 +697,15 @@ You will need to start a new shell for this setup to take effect.
|
||||
fish := &Command{
|
||||
Use: "fish",
|
||||
Short: fmt.Sprintf(shortDesc, "fish"),
|
||||
Long: fmt.Sprintf(`
|
||||
Generate the autocompletion script for the fish shell.
|
||||
Long: fmt.Sprintf(`Generate the autocompletion script for the fish shell.
|
||||
|
||||
To load completions in your current shell session:
|
||||
$ %[1]s completion fish | source
|
||||
|
||||
%[1]s completion fish | source
|
||||
|
||||
To load completions for every new session, execute once:
|
||||
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
|
||||
|
||||
%[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
|
||||
|
||||
You will need to start a new shell for this setup to take effect.
|
||||
`, c.Root().Name()),
|
||||
@ -692,11 +722,11 @@ You will need to start a new shell for this setup to take effect.
|
||||
powershell := &Command{
|
||||
Use: "powershell",
|
||||
Short: fmt.Sprintf(shortDesc, "powershell"),
|
||||
Long: fmt.Sprintf(`
|
||||
Generate the autocompletion script for powershell.
|
||||
Long: fmt.Sprintf(`Generate the autocompletion script for powershell.
|
||||
|
||||
To load completions in your current shell session:
|
||||
PS C:\> %[1]s completion powershell | Out-String | Invoke-Expression
|
||||
|
||||
%[1]s completion powershell | Out-String | Invoke-Expression
|
||||
|
||||
To load completions for every new session, add the output of the above command
|
||||
to your powershell profile.
|
||||
|
6
vendor/github.com/spf13/cobra/powershell_completions.go
generated
vendored
6
vendor/github.com/spf13/cobra/powershell_completions.go
generated
vendored
@ -50,7 +50,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
|
||||
if ($Command.Length -gt $CursorPosition) {
|
||||
$Command=$Command.Substring(0,$CursorPosition)
|
||||
}
|
||||
__%[1]s_debug "Truncated command: $Command"
|
||||
__%[1]s_debug "Truncated command: $Command"
|
||||
|
||||
$ShellCompDirectiveError=%[3]d
|
||||
$ShellCompDirectiveNoSpace=%[4]d
|
||||
@ -58,7 +58,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
|
||||
$ShellCompDirectiveFilterFileExt=%[6]d
|
||||
$ShellCompDirectiveFilterDirs=%[7]d
|
||||
|
||||
# Prepare the command to request completions for the program.
|
||||
# Prepare the command to request completions for the program.
|
||||
# Split the command at the first space to separate the program and arguments.
|
||||
$Program,$Arguments = $Command.Split(" ",2)
|
||||
$RequestComp="$Program %[2]s $Arguments"
|
||||
@ -233,7 +233,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
|
||||
Default {
|
||||
# Like MenuComplete but we don't want to add a space here because
|
||||
# the user need to press space anyway to get the completion.
|
||||
# Description will not be shown because thats not possible with TabCompleteNext
|
||||
# Description will not be shown because that's not possible with TabCompleteNext
|
||||
[System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
|
||||
}
|
||||
}
|
||||
|
13
vendor/github.com/spf13/cobra/projects_using_cobra.md
generated
vendored
13
vendor/github.com/spf13/cobra/projects_using_cobra.md
generated
vendored
@ -4,6 +4,7 @@
|
||||
- [Bleve](http://www.blevesearch.com/)
|
||||
- [CockroachDB](http://www.cockroachlabs.com/)
|
||||
- [Cosmos SDK](https://github.com/cosmos/cosmos-sdk)
|
||||
- [Datree](https://github.com/datreeio/datree)
|
||||
- [Delve](https://github.com/derekparker/delve)
|
||||
- [Docker (distribution)](https://github.com/docker/distribution)
|
||||
- [Etcd](https://etcd.io/)
|
||||
@ -14,25 +15,37 @@
|
||||
- [GitHub Labeler](https://github.com/erdaltsksn/gh-label)
|
||||
- [Golangci-lint](https://golangci-lint.run)
|
||||
- [GopherJS](http://www.gopherjs.org/)
|
||||
- [GoReleaser](https://goreleaser.com)
|
||||
- [Helm](https://helm.sh)
|
||||
- [Hugo](https://gohugo.io)
|
||||
- [Infracost](https://github.com/infracost/infracost)
|
||||
- [Istio](https://istio.io)
|
||||
- [Kool](https://github.com/kool-dev/kool)
|
||||
- [Kubernetes](http://kubernetes.io/)
|
||||
- [Linkerd](https://linkerd.io/)
|
||||
- [Mattermost-server](https://github.com/mattermost/mattermost-server)
|
||||
- [Mercure](https://mercure.rocks/)
|
||||
- [Meroxa CLI](https://github.com/meroxa/cli)
|
||||
- [Metal Stack CLI](https://github.com/metal-stack/metalctl)
|
||||
- [Moby (former Docker)](https://github.com/moby/moby)
|
||||
- [Moldy](https://github.com/Moldy-Community/moldy)
|
||||
- [Multi-gitter](https://github.com/lindell/multi-gitter)
|
||||
- [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
|
||||
- [nFPM](https://nfpm.goreleaser.com)
|
||||
- [OpenShift](https://www.openshift.com/)
|
||||
- [Ory Hydra](https://github.com/ory/hydra)
|
||||
- [Ory Kratos](https://github.com/ory/kratos)
|
||||
- [Pixie](https://github.com/pixie-io/pixie)
|
||||
- [Pouch](https://github.com/alibaba/pouch)
|
||||
- [ProjectAtomic (enterprise)](http://www.projectatomic.io/)
|
||||
- [Prototool](https://github.com/uber/prototool)
|
||||
- [QRcp](https://github.com/claudiodangelis/qrcp)
|
||||
- [Random](https://github.com/erdaltsksn/random)
|
||||
- [Rclone](https://rclone.org/)
|
||||
- [Scaleway CLI](https://github.com/scaleway/scaleway-cli)
|
||||
- [Skaffold](https://skaffold.dev/)
|
||||
- [Tendermint](https://github.com/tendermint/tendermint)
|
||||
- [Twitch CLI](https://github.com/twitchdev/twitch-cli)
|
||||
- [UpCloud CLI (`upctl`)](https://github.com/UpCloudLtd/upcloud-cli)
|
||||
- VMware's [Tanzu Community Edition](https://github.com/vmware-tanzu/community-edition) & [Tanzu Framework](https://github.com/vmware-tanzu/tanzu-framework)
|
||||
- [Werf](https://werf.io/)
|
||||
|
26
vendor/github.com/spf13/cobra/shell_completions.md
generated
vendored
26
vendor/github.com/spf13/cobra/shell_completions.md
generated
vendored
@ -16,10 +16,12 @@ If you do not wish to use the default `completion` command, you can choose to
|
||||
provide your own, which will take precedence over the default one. (This also provides
|
||||
backwards-compatibility with programs that already have their own `completion` command.)
|
||||
|
||||
If you are using the generator, you can create a completion command by running
|
||||
If you are using the `cobra-cli` generator,
|
||||
which can be found at [spf13/cobra-cli](https://github.com/spf13/cobra-cli),
|
||||
you can create a completion command by running
|
||||
|
||||
```bash
|
||||
cobra add completion
|
||||
cobra-cli add completion
|
||||
```
|
||||
and then modifying the generated `cmd/completion.go` file to look something like this
|
||||
(writing the shell script to stdout allows the most flexible use):
|
||||
@ -28,17 +30,17 @@ and then modifying the generated `cmd/completion.go` file to look something like
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "completion [bash|zsh|fish|powershell]",
|
||||
Short: "Generate completion script",
|
||||
Long: `To load completions:
|
||||
Long: fmt.Sprintf(`To load completions:
|
||||
|
||||
Bash:
|
||||
|
||||
$ source <(yourprogram completion bash)
|
||||
$ source <(%[1]s completion bash)
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
# Linux:
|
||||
$ yourprogram completion bash > /etc/bash_completion.d/yourprogram
|
||||
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
|
||||
# macOS:
|
||||
$ yourprogram completion bash > /usr/local/etc/bash_completion.d/yourprogram
|
||||
$ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
|
||||
|
||||
Zsh:
|
||||
|
||||
@ -48,25 +50,25 @@ Zsh:
|
||||
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
$ yourprogram completion zsh > "${fpath[1]}/_yourprogram"
|
||||
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
|
||||
|
||||
# You will need to start a new shell for this setup to take effect.
|
||||
|
||||
fish:
|
||||
|
||||
$ yourprogram completion fish | source
|
||||
$ %[1]s completion fish | source
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
$ yourprogram completion fish > ~/.config/fish/completions/yourprogram.fish
|
||||
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
|
||||
|
||||
PowerShell:
|
||||
|
||||
PS> yourprogram completion powershell | Out-String | Invoke-Expression
|
||||
PS> %[1]s completion powershell | Out-String | Invoke-Expression
|
||||
|
||||
# To load completions for every new session, run:
|
||||
PS> yourprogram completion powershell > yourprogram.ps1
|
||||
PS> %[1]s completion powershell > %[1]s.ps1
|
||||
# and source this file from your PowerShell profile.
|
||||
`,
|
||||
`,cmd.Root().Name()),
|
||||
DisableFlagsInUseLine: true,
|
||||
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
|
||||
Args: cobra.ExactValidArgs(1),
|
||||
|
9
vendor/github.com/spf13/cobra/user_guide.md
generated
vendored
9
vendor/github.com/spf13/cobra/user_guide.md
generated
vendored
@ -29,10 +29,10 @@ func main() {
|
||||
|
||||
## Using the Cobra Generator
|
||||
|
||||
Cobra provides its own program that will create your application and add any
|
||||
Cobra-CLI is its own program that will create your application and add any
|
||||
commands you want. It's the easiest way to incorporate Cobra into your application.
|
||||
|
||||
[Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it.
|
||||
For complete details on using the Cobra generator, please refer to [The Cobra-CLI Generator README](https://github.com/spf13/cobra-cli/blob/master/README.md)
|
||||
|
||||
## Using the Cobra Library
|
||||
|
||||
@ -86,7 +86,7 @@ var (
|
||||
userLicense string
|
||||
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "cobra",
|
||||
Use: "cobra-cli",
|
||||
Short: "A generator for Cobra based Applications",
|
||||
Long: `Cobra is a CLI library for Go that empowers applications.
|
||||
This application is a tool to generate the needed files
|
||||
@ -281,7 +281,7 @@ func init() {
|
||||
|
||||
In this example, the persistent flag `author` is bound with `viper`.
|
||||
**Note**: the variable `author` will not be set to the value from config,
|
||||
when the `--author` flag is not provided by user.
|
||||
when the `--author` flag is provided by user.
|
||||
|
||||
More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
|
||||
|
||||
@ -315,6 +315,7 @@ The following validators are built in:
|
||||
- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
|
||||
- `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command`
|
||||
- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
|
||||
- `MatchAll(pargs ...PositionalArgs)` - enables combining existing checks with arbitrary other checks (e.g. you want to check the ExactArgs length along with other qualities).
|
||||
|
||||
An example of setting the custom validator:
|
||||
|
||||
|
4
vendor/github.com/spf13/cobra/zsh_completions.go
generated
vendored
4
vendor/github.com/spf13/cobra/zsh_completions.go
generated
vendored
@ -202,7 +202,7 @@ _%[1]s()
|
||||
_arguments '*:filename:'"$filteringCmd"
|
||||
elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
|
||||
# File completion for directories only
|
||||
local subDir
|
||||
local subdir
|
||||
subdir="${completions[1]}"
|
||||
if [ -n "$subdir" ]; then
|
||||
__%[1]s_debug "Listing directories in $subdir"
|
||||
@ -250,7 +250,7 @@ _%[1]s()
|
||||
|
||||
# don't run the completion function when being source-ed or eval-ed
|
||||
if [ "$funcstack[1]" = "_%[1]s" ]; then
|
||||
_%[1]s
|
||||
_%[1]s
|
||||
fi
|
||||
`, name, compCmd,
|
||||
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
||||
|
5
vendor/github.com/spf13/viper/.golangci.yml
generated
vendored
5
vendor/github.com/spf13/viper/.golangci.yml
generated
vendored
@ -3,7 +3,10 @@ run:
|
||||
|
||||
linters-settings:
|
||||
gci:
|
||||
local-prefixes: github.com/spf13/viper
|
||||
sections:
|
||||
- standard
|
||||
- default
|
||||
- prefix(github.com/spf13/viper)
|
||||
golint:
|
||||
min-confidence: 0
|
||||
goimports:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user