mirror of
https://github.com/go-task/task.git
synced 2026-06-12 18:31:52 +00:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53234b91e0 | ||
|
|
588de5d0dd | ||
|
|
b9d1af315d | ||
|
|
0cc7fae704 | ||
|
|
3e3d8d8181 | ||
|
|
e2ffb6a276 | ||
|
|
c3f3eb5f51 | ||
|
|
3078a3ee68 | ||
|
|
d55eb98477 | ||
|
|
fa936a54c0 | ||
|
|
478d1466d9 | ||
|
|
2f317aa32c | ||
|
|
2e351e1f9b | ||
|
|
ef75d5061d | ||
|
|
5b3c11eabd | ||
|
|
78bf1aeeac | ||
|
|
6636cd38c0 | ||
|
|
f686c7598f | ||
|
|
f9454a3808 | ||
|
|
3291f60fe7 | ||
|
|
2e52e101be | ||
|
|
72528af18a | ||
|
|
6f7b26908f | ||
|
|
4de3abe9e2 | ||
|
|
19f1200314 | ||
|
|
697e5466a5 | ||
|
|
17c3a67be6 | ||
|
|
41df7e19b4 | ||
|
|
91d5fa5fe6 | ||
|
|
6368c2fdb6 | ||
|
|
08ab113b79 | ||
|
|
f4c8997192 | ||
|
|
7db3db48b0 | ||
|
|
fa850d1440 | ||
|
|
3aaf1b2ec1 | ||
|
|
4127ea5afe | ||
|
|
9bffad0f27 | ||
|
|
561c213a92 | ||
|
|
d8f9b0697d | ||
|
|
e6bb0cfc6d | ||
|
|
a9181255b8 | ||
|
|
4ba13e4e8a | ||
|
|
b5fff68351 | ||
|
|
ae8f405ef9 | ||
|
|
2e1d0ab4a6 | ||
|
|
576b18246a | ||
|
|
a9b8e31228 | ||
|
|
b8116015c7 | ||
|
|
f7d119f544 | ||
|
|
6733ef458f | ||
|
|
9abe71e967 | ||
|
|
8619c8d417 | ||
|
|
eb783d04b8 | ||
|
|
67e5c1eaf3 | ||
|
|
c655f23755 | ||
|
|
b9820c5c7d | ||
|
|
0162c2990e | ||
|
|
240589978d | ||
|
|
b325b506c9 | ||
|
|
ea2e86e398 | ||
|
|
2df72fe39a | ||
|
|
cbd4da153a | ||
|
|
f899df2e82 | ||
|
|
131499b66d | ||
|
|
e95e2e8e8a | ||
|
|
adc433f02a | ||
|
|
847f206043 | ||
|
|
1576943702 | ||
|
|
3779f72155 | ||
|
|
36bcc13fdd | ||
|
|
a493591541 | ||
|
|
c7154d4102 | ||
|
|
f3e741889a | ||
|
|
4c06f101f4 | ||
|
|
a9adfbafd4 | ||
|
|
2542713c32 | ||
|
|
27a21eb4cb | ||
|
|
989f2eaa3e | ||
|
|
a53fcf8bba | ||
|
|
61b1aa8559 | ||
|
|
a15cf26842 | ||
|
|
f2843589a9 | ||
|
|
0609380061 |
@@ -9,6 +9,6 @@ trim_trailing_whitespace = true
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
|
||||
[*.{md,yml}]
|
||||
[*.{md,yml,yaml,json,toml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,3 +14,4 @@
|
||||
.glide/
|
||||
|
||||
./task
|
||||
dist/
|
||||
|
||||
189
README.md
189
README.md
@@ -1,3 +1,5 @@
|
||||
[](https://gitter.im/go-task/task?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
# Task - Simple "Make" alternative
|
||||
|
||||
Task is a simple tool that allows you to easily run development and build
|
||||
@@ -6,18 +8,20 @@ It aims to be simpler and easier to use then [GNU Make][make].
|
||||
|
||||
## Installation
|
||||
|
||||
If you have a Go environment setup, you can simply run:
|
||||
If you have a [Go][golang] environment setup, you can simply run:
|
||||
|
||||
```bash
|
||||
go get -u -v github.com/go-task/task/cmd/task
|
||||
```
|
||||
|
||||
Now the `task` executable should be available in your `PATH`.
|
||||
Or you can download from the [releases][releases] page and add to your `PATH`.
|
||||
|
||||
## Usage
|
||||
|
||||
Create a file called `Taskfile.yml`. The `cmds` key should contains the
|
||||
commands of a task:
|
||||
Create a file called `Taskfile.yml` in the root of the project.
|
||||
(`Taskfile.toml` and `Taskfile.json` are also supported, but YAML is used in
|
||||
the documentation). The `cmds` attribute should contains the commands of a
|
||||
task:
|
||||
|
||||
```yml
|
||||
build:
|
||||
@@ -36,12 +40,61 @@ task assets build
|
||||
```
|
||||
|
||||
If Bash is available (Linux and Windows while on Git Bash), the commands will
|
||||
run in Bash, otherwise will run on `cmd` (Windows).
|
||||
run in Bash, otherwise will fallback to `cmd` (on Windows).
|
||||
|
||||
|
||||
### Environment
|
||||
You can specify environment variables that are added when running a command:
|
||||
|
||||
```yml
|
||||
build:
|
||||
cmds:
|
||||
- echo $hallo
|
||||
env:
|
||||
hallo: welt
|
||||
```
|
||||
|
||||
### OS specific task support
|
||||
|
||||
If you add a `Taskfile_{{GOOS}}` you can override or amend your taskfile based on the op;erating system.
|
||||
|
||||
Example:
|
||||
|
||||
Taskfile.yml:
|
||||
|
||||
```yml
|
||||
build:
|
||||
cmds:
|
||||
- echo "default"
|
||||
```
|
||||
|
||||
Taskfile_linux.yml:
|
||||
|
||||
```yml
|
||||
build:
|
||||
cmds:
|
||||
- echo "linux"
|
||||
```
|
||||
|
||||
Will print out `linux` and not default
|
||||
|
||||
### Running task in another dir
|
||||
|
||||
By default, tasks will be executed in the directory where the Taskfile is
|
||||
located. But you can easily make the task run in another folder informing
|
||||
`dir`:
|
||||
|
||||
```yml
|
||||
js:
|
||||
dir: www/public/js
|
||||
cmds:
|
||||
- gulp
|
||||
```
|
||||
|
||||
### Task dependencies
|
||||
|
||||
You may have tasks that depends on others. Just point them on `deps` will run
|
||||
them automatically:
|
||||
You may have tasks that depends on others. Just pointing them on `deps` will
|
||||
make them run automatically before running the parent task:
|
||||
|
||||
```yml
|
||||
build:
|
||||
@@ -72,10 +125,23 @@ css:
|
||||
- npm run buildcss
|
||||
```
|
||||
|
||||
Each task can only be run once. If it is included from another dependend task causing
|
||||
a cyclomatic dependency, execution will be stopped.
|
||||
|
||||
```yml
|
||||
task1:
|
||||
deps: [task2]
|
||||
|
||||
task2:
|
||||
deps: [task1]
|
||||
```
|
||||
|
||||
Will stop at the moment the dependencies of `task2` are executed.
|
||||
|
||||
### Prevent task from running when not necessary
|
||||
|
||||
If a task generates something, you can inform Task the source and generated
|
||||
files, to Task will prevent to run them if not necessary.
|
||||
files, so Task will prevent to run them if not necessary.
|
||||
|
||||
```yml
|
||||
build:
|
||||
@@ -105,4 +171,111 @@ will compare the modification date/time of the files to determine if it's
|
||||
necessary to run the task. If not, it will just print
|
||||
`Task "js" is up to date`.
|
||||
|
||||
You can use `--force` or `-f` if you want to force a task to run even when
|
||||
up-to-date.
|
||||
|
||||
### Variables
|
||||
|
||||
```yml
|
||||
build:
|
||||
deps: [setvar]
|
||||
cmds:
|
||||
- echo "{{.PREFIX}} {{.THEVAR}}"
|
||||
vars:
|
||||
PREFIX: "Path:"
|
||||
|
||||
setvar:
|
||||
cmds:
|
||||
- echo "{{.PATH}}"
|
||||
set: THEVAR
|
||||
```
|
||||
|
||||
The above sample saves the path into a new variable which is then again echoed.
|
||||
|
||||
You can use environment variables, task level variables and a file called
|
||||
`Taskvars.yml` (or `Taskvars.toml` or `Taskvars.json`) as source of variables.
|
||||
|
||||
They are evaluated in the following order:
|
||||
|
||||
Task local variables are overwritten by variables found in `Taskvars` file.
|
||||
Variables found in `Taskvars` file are overwritten with variables from the
|
||||
environment. The output of the last command is stored in the environment. So
|
||||
you can do something like this:
|
||||
|
||||
```yml
|
||||
build:
|
||||
deps: [setvar]
|
||||
cmds:
|
||||
- echo "{{.PREFIX}} '{{.THEVAR}}'"
|
||||
vars:
|
||||
PREFIX: "Result: "
|
||||
|
||||
setvar:
|
||||
cmds:
|
||||
- echo -n "a"
|
||||
- echo -n "{{.THEVAR}}b"
|
||||
- echo -n "{{.THEVAR}}c"
|
||||
set: THEVAR
|
||||
```
|
||||
|
||||
The result of a run of build would be:
|
||||
|
||||
```
|
||||
a
|
||||
ab
|
||||
abc
|
||||
Result: 'abc'
|
||||
```
|
||||
|
||||
#### Dynamic variables
|
||||
|
||||
If you prefix a variable with `$`, then the variable is considered a dynamic
|
||||
variable. The value after the $-symbol will be treated as a command and the
|
||||
output assigned.
|
||||
|
||||
```yml
|
||||
build:
|
||||
cmds:
|
||||
- go build -ldflags="-X main.Version={{.LAST_GIT_COMMIT}}" main.go
|
||||
vars:
|
||||
LAST_GIT_COMMIT: $git log -n 1 --format=%h
|
||||
```
|
||||
|
||||
### Go's template engine
|
||||
|
||||
Task parse commands as [Go's template engine][gotemplate] before executing
|
||||
them. Variables are acessible through dot syntax (`.VARNAME`). The following
|
||||
functions are available:
|
||||
|
||||
- `OS`: return operating system. Possible values are "windows", "linux",
|
||||
"darwin" (macOS) and "freebsd".
|
||||
- `ARCH`: return the architecture Task was compiled to: "386", "amd64", "arm"
|
||||
or "s390x".
|
||||
- `IsSH`: on unix systems this should always return `true`. On Windows, will
|
||||
return `true` if `sh` command was found (Git Bash). In this case commands
|
||||
will run on `sh`. Otherwise, this function will return `false` meaning
|
||||
commands will run on `cmd`.
|
||||
|
||||
Example:
|
||||
|
||||
```yml
|
||||
printos:
|
||||
cmds:
|
||||
- echo '{{OS}} {{ARCH}}'
|
||||
- "echo '{{if eq OS \"windows\"}}windows-command{{else}}unix-command{{end}}'"
|
||||
- echo 'Is SH? {{IsSH}}'
|
||||
```
|
||||
|
||||
## Alternatives
|
||||
|
||||
Similar software:
|
||||
|
||||
- [tj/robo][robo]
|
||||
- [dogtools/dog][dog]
|
||||
|
||||
[make]: https://www.gnu.org/software/make/
|
||||
[releases]: https://github.com/go-task/task/releases
|
||||
[golang]: https://golang.org/
|
||||
[gotemplate]: https://golang.org/pkg/text/template/
|
||||
[robo]: https://github.com/tj/robo
|
||||
[dog]: https://github.com/dogtools/dog
|
||||
|
||||
20
Taskfile.yml
Normal file
20
Taskfile.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
# compiles current source code and make "task" executable available on
|
||||
# $GOPATH/bin/task{.exe}
|
||||
install:
|
||||
cmds:
|
||||
- go install -v ./...
|
||||
|
||||
lint:
|
||||
cmds:
|
||||
- golint .
|
||||
- golint ./cmd/task
|
||||
|
||||
# TODO: have tests
|
||||
test:
|
||||
cmds:
|
||||
- go test -v
|
||||
|
||||
# https://github.com/goreleaser/goreleaser
|
||||
release:
|
||||
cmds:
|
||||
- goreleaser
|
||||
@@ -1,9 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-task/task"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pflag.Usage = func() {
|
||||
fmt.Println(`task [target1 target2 ...]: Runs commands under targets like make.
|
||||
|
||||
Example: 'task hello' with the following 'Taskfile.yml' file will generate
|
||||
an 'output.txt' file.
|
||||
'''
|
||||
hello:
|
||||
cmds:
|
||||
- echo "I am going to write a file named 'output.txt' now."
|
||||
- echo "hello" > output.txt
|
||||
generates:
|
||||
- output.txt
|
||||
'''
|
||||
`)
|
||||
pflag.PrintDefaults()
|
||||
}
|
||||
pflag.BoolVarP(&task.Force, "force", "f", false, "forces execution even when the task is up-to-date")
|
||||
pflag.Parse()
|
||||
task.Run()
|
||||
}
|
||||
|
||||
38
errors.go
Normal file
38
errors.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type taskFileNotFound struct {
|
||||
taskFile string
|
||||
}
|
||||
|
||||
func (err taskFileNotFound) Error() string {
|
||||
return fmt.Sprintf(`task: No task file found (is it named "%s"?)`, err.taskFile)
|
||||
}
|
||||
|
||||
type taskNotFoundError struct {
|
||||
taskName string
|
||||
}
|
||||
|
||||
func (err *taskNotFoundError) Error() string {
|
||||
return fmt.Sprintf(`task: Task "%s" not found`, err.taskName)
|
||||
}
|
||||
|
||||
type taskRunError struct {
|
||||
taskName string
|
||||
err error
|
||||
}
|
||||
|
||||
func (err *taskRunError) Error() string {
|
||||
return fmt.Sprintf(`task: Failed to run task "%s": %v`, err.taskName, err.err)
|
||||
}
|
||||
|
||||
type cyclicDepError struct {
|
||||
taskName string
|
||||
}
|
||||
|
||||
func (err *cyclicDepError) Error() string {
|
||||
return fmt.Sprintf(`task: Cyclic dependency of task "%s" detected`, err.taskName)
|
||||
}
|
||||
11
example/Taskfile.json
Normal file
11
example/Taskfile.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"hello": {
|
||||
"cmds": [
|
||||
"echo \"I am going to write a file named 'output.txt' now.\"",
|
||||
"echo \"hello\" > output.txt"
|
||||
],
|
||||
"generates": [
|
||||
"output.txt"
|
||||
]
|
||||
}
|
||||
}
|
||||
6
example/Taskfile.toml
Normal file
6
example/Taskfile.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[hello]
|
||||
cmds = [
|
||||
"echo \"I am going to write a file named 'output.txt' now.\"",
|
||||
"echo \"hello\" > output.txt"
|
||||
]
|
||||
generates = ["output.txt"]
|
||||
6
example/Taskfile.yml
Normal file
6
example/Taskfile.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
hello:
|
||||
cmds:
|
||||
- echo "I am going to write a file named 'output.txt' now."
|
||||
- echo "hello" > output.txt
|
||||
generates:
|
||||
- output.txt
|
||||
5
file.go
5
file.go
@@ -7,11 +7,6 @@ import (
|
||||
"github.com/mattn/go-zglob"
|
||||
)
|
||||
|
||||
var dirsToSkip = []string{
|
||||
".git",
|
||||
"node_modules",
|
||||
}
|
||||
|
||||
func minTime(a, b time.Time) time.Time {
|
||||
if !a.IsZero() && a.Before(b) {
|
||||
return a
|
||||
|
||||
10
goreleaser.yml
Normal file
10
goreleaser.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
build:
|
||||
binary_name: task
|
||||
main: cmd/task/task.go
|
||||
goos:
|
||||
- windows
|
||||
- darwin
|
||||
- linux
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
58
read_taskfile.go
Normal file
58
read_taskfile.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"runtime"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/imdario/mergo"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func readTaskfile() (map[string]*Task, error) {
|
||||
initialTasks, err := readTaskfileData(TaskFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mergeTasks, err := readTaskfileData(fmt.Sprintf("%s_%s", TaskFilePath, runtime.GOOS))
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
default:
|
||||
return nil, err
|
||||
case taskFileNotFound:
|
||||
return initialTasks, nil
|
||||
}
|
||||
}
|
||||
if err := mergo.MapWithOverwrite(&initialTasks, mergeTasks); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return initialTasks, nil
|
||||
}
|
||||
|
||||
func readTaskfileData(path string) (tasks map[string]*Task, err error) {
|
||||
if b, err := ioutil.ReadFile(path + ".yml"); err == nil {
|
||||
return tasks, yaml.Unmarshal(b, &tasks)
|
||||
}
|
||||
if b, err := ioutil.ReadFile(path + ".json"); err == nil {
|
||||
return tasks, json.Unmarshal(b, &tasks)
|
||||
}
|
||||
if b, err := ioutil.ReadFile(path + ".toml"); err == nil {
|
||||
return tasks, toml.Unmarshal(b, &tasks)
|
||||
}
|
||||
return nil, taskFileNotFound{path}
|
||||
}
|
||||
|
||||
func exists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
133
task.go
133
task.go
@@ -2,20 +2,29 @@ package task
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
TaskFilePath = "Taskfile.yml"
|
||||
ShExists bool
|
||||
ShPath string
|
||||
// TaskFilePath is the default Taskfile
|
||||
TaskFilePath = "Taskfile"
|
||||
// ShExists is true if Bash was found
|
||||
ShExists bool
|
||||
// ShPath constains the Bash path if found
|
||||
ShPath string
|
||||
|
||||
// Force (--force or -f flag) forces a task to run even when it's up-to-date
|
||||
Force bool
|
||||
|
||||
// Tasks constains the tasks parsed from Taskfile
|
||||
Tasks = make(map[string]*Task)
|
||||
|
||||
runnedTasks = make(map[string]struct{})
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -27,47 +36,30 @@ func init() {
|
||||
ShExists = true
|
||||
}
|
||||
|
||||
// Task represents a task
|
||||
type Task struct {
|
||||
Cmds []string
|
||||
Deps []string
|
||||
Sources []string
|
||||
Generates []string
|
||||
Dir string
|
||||
Vars map[string]string
|
||||
Set string
|
||||
Env map[string]string
|
||||
}
|
||||
|
||||
type TaskNotFoundError struct {
|
||||
taskName string
|
||||
}
|
||||
|
||||
func (err *TaskNotFoundError) Error() string {
|
||||
return fmt.Sprintf(`Task "%s" not found`, err.taskName)
|
||||
}
|
||||
|
||||
type TaskRunError struct {
|
||||
taskName string
|
||||
err error
|
||||
}
|
||||
|
||||
func (err *TaskRunError) Error() string {
|
||||
return fmt.Sprintf(`Failed to run task "%s": %v`, err.taskName, err.err)
|
||||
}
|
||||
|
||||
// Run runs Task
|
||||
func Run() {
|
||||
log.SetFlags(0)
|
||||
|
||||
args := os.Args[1:]
|
||||
args := pflag.Args()
|
||||
if len(args) == 0 {
|
||||
log.Fatal("No argument given")
|
||||
log.Fatal("task: No argument given")
|
||||
}
|
||||
|
||||
file, err := ioutil.ReadFile(TaskFilePath)
|
||||
var err error
|
||||
Tasks, err = readTaskfile()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.Fatal("Taskfile.yml not found")
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err = yaml.Unmarshal(file, &Tasks); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -78,32 +70,47 @@ func Run() {
|
||||
}
|
||||
}
|
||||
|
||||
// RunTask runs a task by its name
|
||||
func RunTask(name string) error {
|
||||
if _, found := runnedTasks[name]; found {
|
||||
return &cyclicDepError{name}
|
||||
}
|
||||
runnedTasks[name] = struct{}{}
|
||||
|
||||
t, ok := Tasks[name]
|
||||
if !ok {
|
||||
return &TaskNotFoundError{name}
|
||||
return &taskNotFoundError{name}
|
||||
}
|
||||
|
||||
if isTaskUpToDate(t) {
|
||||
log.Printf(`Task "%s" is up to date`, name)
|
||||
return nil
|
||||
vars, err := t.handleVariables()
|
||||
if err != nil {
|
||||
return &taskRunError{name, err}
|
||||
}
|
||||
|
||||
for _, d := range t.Deps {
|
||||
if err := RunTask(d); err != nil {
|
||||
d, err = ReplaceVariables(d, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = RunTask(d); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range t.Cmds {
|
||||
if err := runCommand(c); err != nil {
|
||||
return &TaskRunError{name, err}
|
||||
if !Force && t.isUpToDate() {
|
||||
log.Printf(`task: Task "%s" is up to date`, name)
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := range t.Cmds {
|
||||
if err = t.runCommand(i); err != nil {
|
||||
return &taskRunError{name, err}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isTaskUpToDate(t *Task) bool {
|
||||
func (t *Task) isUpToDate() bool {
|
||||
if len(t.Sources) == 0 || len(t.Generates) == 0 {
|
||||
return false
|
||||
}
|
||||
@@ -121,16 +128,54 @@ func isTaskUpToDate(t *Task) bool {
|
||||
return generatesMinTime.After(sourcesMaxTime)
|
||||
}
|
||||
|
||||
func runCommand(c string) error {
|
||||
func (t *Task) runCommand(i int) error {
|
||||
vars, err := t.handleVariables()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c, err := ReplaceVariables(t.Cmds[i], vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dir, err := ReplaceVariables(t.Dir, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
if ShExists {
|
||||
cmd = exec.Command(ShPath, "-c", c)
|
||||
} else {
|
||||
cmd = exec.Command("cmd", "/C", c)
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
if dir != "" {
|
||||
cmd.Dir = dir
|
||||
}
|
||||
if t.Env != nil {
|
||||
cmd.Env = os.Environ()
|
||||
for key, value := range t.Env {
|
||||
replacedValue, err := ReplaceVariables(value, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
replacedKey, err := ReplaceVariables(key, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", replacedKey, replacedValue))
|
||||
}
|
||||
}
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
if t.Set != "" {
|
||||
bytes, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.Setenv(t.Set, strings.TrimSpace(string(bytes)))
|
||||
return nil
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
if err = cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
142
variable_handling.go
Normal file
142
variable_handling.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// TaskvarsFilePath file containing additional variables
|
||||
TaskvarsFilePath = "Taskvars"
|
||||
// ErrMultilineResultCmd is returned when a command returns multiline result
|
||||
ErrMultilineResultCmd = errors.New("Got multiline result from command")
|
||||
)
|
||||
|
||||
var varCmds = make(map[string]string)
|
||||
|
||||
func handleDynamicVariableContent(value string) (string, error) {
|
||||
if value == "" || value[0] != '$' {
|
||||
return value, nil
|
||||
}
|
||||
if result, ok := varCmds[value]; ok {
|
||||
return result, nil
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
if ShExists {
|
||||
cmd = exec.Command(ShPath, "-c", value[1:])
|
||||
} else {
|
||||
cmd = exec.Command("cmd", "/C", value[1:])
|
||||
}
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stderr = os.Stderr
|
||||
b, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if b[len(b)-1] == '\n' {
|
||||
b = b[:len(b)-1]
|
||||
}
|
||||
if bytes.ContainsRune(b, '\n') {
|
||||
return "", ErrMultilineResultCmd
|
||||
}
|
||||
result := strings.TrimSpace(string(b))
|
||||
varCmds[value] = result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (t *Task) handleVariables() (map[string]string, error) {
|
||||
localVariables := make(map[string]string)
|
||||
for key, value := range t.Vars {
|
||||
val, err := handleDynamicVariableContent(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localVariables[key] = val
|
||||
}
|
||||
if fileVariables, err := readTaskvarsFile(); err == nil {
|
||||
for key, value := range fileVariables {
|
||||
val, err := handleDynamicVariableContent(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localVariables[key] = val
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
for key, value := range getEnvironmentVariables() {
|
||||
localVariables[key] = value
|
||||
}
|
||||
return localVariables, nil
|
||||
}
|
||||
|
||||
var templateFuncs = template.FuncMap{
|
||||
"OS": func() string { return runtime.GOOS },
|
||||
"ARCH": func() string { return runtime.GOARCH },
|
||||
"IsSH": func() bool { return ShExists },
|
||||
}
|
||||
|
||||
// ReplaceVariables writes vars into initial string
|
||||
func ReplaceVariables(initial string, vars map[string]string) (string, error) {
|
||||
t, err := template.New("").Funcs(templateFuncs).Parse(initial)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
b := bytes.NewBuffer(nil)
|
||||
if err = t.Execute(b, vars); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
// GetEnvironmentVariables returns environment variables as map
|
||||
func getEnvironmentVariables() map[string]string {
|
||||
type getKeyValFunc func(item string) (key, val string)
|
||||
getEnvironment := func(data []string, getKeyVal getKeyValFunc) map[string]string {
|
||||
items := make(map[string]string)
|
||||
for _, item := range data {
|
||||
key, val := getKeyVal(item)
|
||||
items[key] = val
|
||||
}
|
||||
return items
|
||||
}
|
||||
return getEnvironment(os.Environ(), func(item string) (key, val string) {
|
||||
splits := strings.Split(item, "=")
|
||||
key = splits[0]
|
||||
val = splits[1]
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func readTaskvarsFile() (map[string]string, error) {
|
||||
var variables map[string]string
|
||||
if b, err := ioutil.ReadFile(TaskvarsFilePath + ".yml"); err == nil {
|
||||
if err := yaml.Unmarshal(b, &variables); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return variables, nil
|
||||
}
|
||||
if b, err := ioutil.ReadFile(TaskvarsFilePath + ".json"); err == nil {
|
||||
if err := json.Unmarshal(b, &variables); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return variables, nil
|
||||
}
|
||||
if b, err := ioutil.ReadFile(TaskvarsFilePath + ".toml"); err == nil {
|
||||
if err := toml.Unmarshal(b, &variables); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return variables, nil
|
||||
}
|
||||
return variables, nil
|
||||
}
|
||||
3
vendor/github.com/BurntSushi/toml/COMPATIBLE
generated
vendored
Normal file
3
vendor/github.com/BurntSushi/toml/COMPATIBLE
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Compatible with TOML version
|
||||
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
|
||||
|
||||
14
vendor/github.com/BurntSushi/toml/COPYING
generated
vendored
Normal file
14
vendor/github.com/BurntSushi/toml/COPYING
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
19
vendor/github.com/BurntSushi/toml/Makefile
generated
vendored
Normal file
19
vendor/github.com/BurntSushi/toml/Makefile
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
install:
|
||||
go install ./...
|
||||
|
||||
test: install
|
||||
go test -v
|
||||
toml-test toml-test-decoder
|
||||
toml-test -encoder toml-test-encoder
|
||||
|
||||
fmt:
|
||||
gofmt -w *.go */*.go
|
||||
colcheck *.go */*.go
|
||||
|
||||
tags:
|
||||
find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS
|
||||
|
||||
push:
|
||||
git push origin master
|
||||
git push github master
|
||||
|
||||
220
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
Normal file
220
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
## TOML parser and encoder for Go with reflection
|
||||
|
||||
TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
|
||||
reflection interface similar to Go's standard library `json` and `xml`
|
||||
packages. This package also supports the `encoding.TextUnmarshaler` and
|
||||
`encoding.TextMarshaler` interfaces so that you can define custom data
|
||||
representations. (There is an example of this below.)
|
||||
|
||||
Spec: https://github.com/mojombo/toml
|
||||
|
||||
Compatible with TOML version
|
||||
[v0.2.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.2.0.md)
|
||||
|
||||
Documentation: http://godoc.org/github.com/BurntSushi/toml
|
||||
|
||||
Installation:
|
||||
|
||||
```bash
|
||||
go get github.com/BurntSushi/toml
|
||||
```
|
||||
|
||||
Try the toml validator:
|
||||
|
||||
```bash
|
||||
go get github.com/BurntSushi/toml/cmd/tomlv
|
||||
tomlv some-toml-file.toml
|
||||
```
|
||||
|
||||
[](https://travis-ci.org/BurntSushi/toml)
|
||||
|
||||
|
||||
### Testing
|
||||
|
||||
This package passes all tests in
|
||||
[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder
|
||||
and the encoder.
|
||||
|
||||
### Examples
|
||||
|
||||
This package works similarly to how the Go standard library handles `XML`
|
||||
and `JSON`. Namely, data is loaded into Go values via reflection.
|
||||
|
||||
For the simplest example, consider some TOML file as just a list of keys
|
||||
and values:
|
||||
|
||||
```toml
|
||||
Age = 25
|
||||
Cats = [ "Cauchy", "Plato" ]
|
||||
Pi = 3.14
|
||||
Perfection = [ 6, 28, 496, 8128 ]
|
||||
DOB = 1987-07-05T05:45:00Z
|
||||
```
|
||||
|
||||
Which could be defined in Go as:
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Age int
|
||||
Cats []string
|
||||
Pi float64
|
||||
Perfection []int
|
||||
DOB time.Time // requires `import time`
|
||||
}
|
||||
```
|
||||
|
||||
And then decoded with:
|
||||
|
||||
```go
|
||||
var conf Config
|
||||
if _, err := toml.Decode(tomlData, &conf); err != nil {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
You can also use struct tags if your struct field name doesn't map to a TOML
|
||||
key value directly:
|
||||
|
||||
```toml
|
||||
some_key_NAME = "wat"
|
||||
```
|
||||
|
||||
```go
|
||||
type TOML struct {
|
||||
ObscureKey string `toml:"some_key_NAME"`
|
||||
}
|
||||
```
|
||||
|
||||
### Using the `encoding.TextUnmarshaler` interface
|
||||
|
||||
Here's an example that automatically parses duration strings into
|
||||
`time.Duration` values:
|
||||
|
||||
```toml
|
||||
[[song]]
|
||||
name = "Thunder Road"
|
||||
duration = "4m49s"
|
||||
|
||||
[[song]]
|
||||
name = "Stairway to Heaven"
|
||||
duration = "8m03s"
|
||||
```
|
||||
|
||||
Which can be decoded with:
|
||||
|
||||
```go
|
||||
type song struct {
|
||||
Name string
|
||||
Duration duration
|
||||
}
|
||||
type songs struct {
|
||||
Song []song
|
||||
}
|
||||
var favorites songs
|
||||
if _, err := toml.Decode(blob, &favorites); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, s := range favorites.Song {
|
||||
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
|
||||
}
|
||||
```
|
||||
|
||||
And you'll also need a `duration` type that satisfies the
|
||||
`encoding.TextUnmarshaler` interface:
|
||||
|
||||
```go
|
||||
type duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (d *duration) UnmarshalText(text []byte) error {
|
||||
var err error
|
||||
d.Duration, err = time.ParseDuration(string(text))
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### More complex usage
|
||||
|
||||
Here's an example of how to load the example from the official spec page:
|
||||
|
||||
```toml
|
||||
# This is a TOML document. Boom.
|
||||
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Tom Preston-Werner"
|
||||
organization = "GitHub"
|
||||
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
|
||||
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
||||
|
||||
[database]
|
||||
server = "192.168.1.1"
|
||||
ports = [ 8001, 8001, 8002 ]
|
||||
connection_max = 5000
|
||||
enabled = true
|
||||
|
||||
[servers]
|
||||
|
||||
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
dc = "eqdc10"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
dc = "eqdc10"
|
||||
|
||||
[clients]
|
||||
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
||||
|
||||
# Line breaks are OK when inside arrays
|
||||
hosts = [
|
||||
"alpha",
|
||||
"omega"
|
||||
]
|
||||
```
|
||||
|
||||
And the corresponding Go types are:
|
||||
|
||||
```go
|
||||
type tomlConfig struct {
|
||||
Title string
|
||||
Owner ownerInfo
|
||||
DB database `toml:"database"`
|
||||
Servers map[string]server
|
||||
Clients clients
|
||||
}
|
||||
|
||||
type ownerInfo struct {
|
||||
Name string
|
||||
Org string `toml:"organization"`
|
||||
Bio string
|
||||
DOB time.Time
|
||||
}
|
||||
|
||||
type database struct {
|
||||
Server string
|
||||
Ports []int
|
||||
ConnMax int `toml:"connection_max"`
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
type server struct {
|
||||
IP string
|
||||
DC string
|
||||
}
|
||||
|
||||
type clients struct {
|
||||
Data [][]interface{}
|
||||
Hosts []string
|
||||
}
|
||||
```
|
||||
|
||||
Note that a case insensitive match will be tried if an exact match can't be
|
||||
found.
|
||||
|
||||
A working example of the above can be found in `_examples/example.{go,toml}`.
|
||||
|
||||
509
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
Normal file
509
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
Normal file
@@ -0,0 +1,509 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func e(format string, args ...interface{}) error {
|
||||
return fmt.Errorf("toml: "+format, args...)
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface implemented by objects that can unmarshal a
|
||||
// TOML description of themselves.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalTOML(interface{}) error
|
||||
}
|
||||
|
||||
// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`.
|
||||
func Unmarshal(p []byte, v interface{}) error {
|
||||
_, err := Decode(string(p), v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Primitive is a TOML value that hasn't been decoded into a Go value.
|
||||
// When using the various `Decode*` functions, the type `Primitive` may
|
||||
// be given to any value, and its decoding will be delayed.
|
||||
//
|
||||
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
|
||||
//
|
||||
// The underlying representation of a `Primitive` value is subject to change.
|
||||
// Do not rely on it.
|
||||
//
|
||||
// N.B. Primitive values are still parsed, so using them will only avoid
|
||||
// the overhead of reflection. They can be useful when you don't know the
|
||||
// exact type of TOML data until run time.
|
||||
type Primitive struct {
|
||||
undecoded interface{}
|
||||
context Key
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
//
|
||||
// Use MetaData.PrimitiveDecode instead.
|
||||
func PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||
md := MetaData{decoded: make(map[string]bool)}
|
||||
return md.unify(primValue.undecoded, rvalue(v))
|
||||
}
|
||||
|
||||
// PrimitiveDecode is just like the other `Decode*` functions, except it
|
||||
// decodes a TOML value that has already been parsed. Valid primitive values
|
||||
// can *only* be obtained from values filled by the decoder functions,
|
||||
// including this method. (i.e., `v` may contain more `Primitive`
|
||||
// values.)
|
||||
//
|
||||
// Meta data for primitive values is included in the meta data returned by
|
||||
// the `Decode*` functions with one exception: keys returned by the Undecoded
|
||||
// method will only reflect keys that were decoded. Namely, any keys hidden
|
||||
// behind a Primitive will be considered undecoded. Executing this method will
|
||||
// update the undecoded keys in the meta data. (See the example.)
|
||||
func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||
md.context = primValue.context
|
||||
defer func() { md.context = nil }()
|
||||
return md.unify(primValue.undecoded, rvalue(v))
|
||||
}
|
||||
|
||||
// Decode will decode the contents of `data` in TOML format into a pointer
|
||||
// `v`.
|
||||
//
|
||||
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
|
||||
// used interchangeably.)
|
||||
//
|
||||
// TOML arrays of tables correspond to either a slice of structs or a slice
|
||||
// of maps.
|
||||
//
|
||||
// TOML datetimes correspond to Go `time.Time` values.
|
||||
//
|
||||
// All other TOML types (float, string, int, bool and array) correspond
|
||||
// to the obvious Go types.
|
||||
//
|
||||
// An exception to the above rules is if a type implements the
|
||||
// encoding.TextUnmarshaler interface. In this case, any primitive TOML value
|
||||
// (floats, strings, integers, booleans and datetimes) will be converted to
|
||||
// a byte string and given to the value's UnmarshalText method. See the
|
||||
// Unmarshaler example for a demonstration with time duration strings.
|
||||
//
|
||||
// Key mapping
|
||||
//
|
||||
// TOML keys can map to either keys in a Go map or field names in a Go
|
||||
// struct. The special `toml` struct tag may be used to map TOML keys to
|
||||
// struct fields that don't match the key name exactly. (See the example.)
|
||||
// A case insensitive match to struct names will be tried if an exact match
|
||||
// can't be found.
|
||||
//
|
||||
// The mapping between TOML values and Go values is loose. That is, there
|
||||
// may exist TOML values that cannot be placed into your representation, and
|
||||
// there may be parts of your representation that do not correspond to
|
||||
// TOML values. This loose mapping can be made stricter by using the IsDefined
|
||||
// and/or Undecoded methods on the MetaData returned.
|
||||
//
|
||||
// This decoder will not handle cyclic types. If a cyclic type is passed,
|
||||
// `Decode` will not terminate.
|
||||
func Decode(data string, v interface{}) (MetaData, error) {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr {
|
||||
return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
|
||||
}
|
||||
if rv.IsNil() {
|
||||
return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
|
||||
}
|
||||
p, err := parse(data)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
md := MetaData{
|
||||
p.mapping, p.types, p.ordered,
|
||||
make(map[string]bool, len(p.ordered)), nil,
|
||||
}
|
||||
return md, md.unify(p.mapping, indirect(rv))
|
||||
}
|
||||
|
||||
// DecodeFile is just like Decode, except it will automatically read the
|
||||
// contents of the file at `fpath` and decode it for you.
|
||||
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
|
||||
bs, err := ioutil.ReadFile(fpath)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
return Decode(string(bs), v)
|
||||
}
|
||||
|
||||
// DecodeReader is just like Decode, except it will consume all bytes
|
||||
// from the reader and decode it for you.
|
||||
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
|
||||
bs, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
return Decode(string(bs), v)
|
||||
}
|
||||
|
||||
// unify performs a sort of type unification based on the structure of `rv`,
|
||||
// which is the client representation.
|
||||
//
|
||||
// Any type mismatch produces an error. Finding a type that we don't know
|
||||
// how to handle produces an unsupported type error.
|
||||
func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
|
||||
|
||||
// Special case. Look for a `Primitive` value.
|
||||
if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
|
||||
// Save the undecoded data and the key context into the primitive
|
||||
// value.
|
||||
context := make(Key, len(md.context))
|
||||
copy(context, md.context)
|
||||
rv.Set(reflect.ValueOf(Primitive{
|
||||
undecoded: data,
|
||||
context: context,
|
||||
}))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Special case. Unmarshaler Interface support.
|
||||
if rv.CanAddr() {
|
||||
if v, ok := rv.Addr().Interface().(Unmarshaler); ok {
|
||||
return v.UnmarshalTOML(data)
|
||||
}
|
||||
}
|
||||
|
||||
// Special case. Handle time.Time values specifically.
|
||||
// TODO: Remove this code when we decide to drop support for Go 1.1.
|
||||
// This isn't necessary in Go 1.2 because time.Time satisfies the encoding
|
||||
// interfaces.
|
||||
if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
|
||||
return md.unifyDatetime(data, rv)
|
||||
}
|
||||
|
||||
// Special case. Look for a value satisfying the TextUnmarshaler interface.
|
||||
if v, ok := rv.Interface().(TextUnmarshaler); ok {
|
||||
return md.unifyText(data, v)
|
||||
}
|
||||
// BUG(burntsushi)
|
||||
// The behavior here is incorrect whenever a Go type satisfies the
|
||||
// encoding.TextUnmarshaler interface but also corresponds to a TOML
|
||||
// hash or array. In particular, the unmarshaler should only be applied
|
||||
// to primitive TOML values. But at this point, it will be applied to
|
||||
// all kinds of values and produce an incorrect error whenever those values
|
||||
// are hashes or arrays (including arrays of tables).
|
||||
|
||||
k := rv.Kind()
|
||||
|
||||
// laziness
|
||||
if k >= reflect.Int && k <= reflect.Uint64 {
|
||||
return md.unifyInt(data, rv)
|
||||
}
|
||||
switch k {
|
||||
case reflect.Ptr:
|
||||
elem := reflect.New(rv.Type().Elem())
|
||||
err := md.unify(data, reflect.Indirect(elem))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rv.Set(elem)
|
||||
return nil
|
||||
case reflect.Struct:
|
||||
return md.unifyStruct(data, rv)
|
||||
case reflect.Map:
|
||||
return md.unifyMap(data, rv)
|
||||
case reflect.Array:
|
||||
return md.unifyArray(data, rv)
|
||||
case reflect.Slice:
|
||||
return md.unifySlice(data, rv)
|
||||
case reflect.String:
|
||||
return md.unifyString(data, rv)
|
||||
case reflect.Bool:
|
||||
return md.unifyBool(data, rv)
|
||||
case reflect.Interface:
|
||||
// we only support empty interfaces.
|
||||
if rv.NumMethod() > 0 {
|
||||
return e("unsupported type %s", rv.Type())
|
||||
}
|
||||
return md.unifyAnything(data, rv)
|
||||
case reflect.Float32:
|
||||
fallthrough
|
||||
case reflect.Float64:
|
||||
return md.unifyFloat64(data, rv)
|
||||
}
|
||||
return e("unsupported type %s", rv.Kind())
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
|
||||
tmap, ok := mapping.(map[string]interface{})
|
||||
if !ok {
|
||||
if mapping == nil {
|
||||
return nil
|
||||
}
|
||||
return e("type mismatch for %s: expected table but found %T",
|
||||
rv.Type().String(), mapping)
|
||||
}
|
||||
|
||||
for key, datum := range tmap {
|
||||
var f *field
|
||||
fields := cachedTypeFields(rv.Type())
|
||||
for i := range fields {
|
||||
ff := &fields[i]
|
||||
if ff.name == key {
|
||||
f = ff
|
||||
break
|
||||
}
|
||||
if f == nil && strings.EqualFold(ff.name, key) {
|
||||
f = ff
|
||||
}
|
||||
}
|
||||
if f != nil {
|
||||
subv := rv
|
||||
for _, i := range f.index {
|
||||
subv = indirect(subv.Field(i))
|
||||
}
|
||||
if isUnifiable(subv) {
|
||||
md.decoded[md.context.add(key).String()] = true
|
||||
md.context = append(md.context, key)
|
||||
if err := md.unify(datum, subv); err != nil {
|
||||
return err
|
||||
}
|
||||
md.context = md.context[0 : len(md.context)-1]
|
||||
} else if f.name != "" {
|
||||
// Bad user! No soup for you!
|
||||
return e("cannot write unexported field %s.%s",
|
||||
rv.Type().String(), f.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
|
||||
tmap, ok := mapping.(map[string]interface{})
|
||||
if !ok {
|
||||
if tmap == nil {
|
||||
return nil
|
||||
}
|
||||
return badtype("map", mapping)
|
||||
}
|
||||
if rv.IsNil() {
|
||||
rv.Set(reflect.MakeMap(rv.Type()))
|
||||
}
|
||||
for k, v := range tmap {
|
||||
md.decoded[md.context.add(k).String()] = true
|
||||
md.context = append(md.context, k)
|
||||
|
||||
rvkey := indirect(reflect.New(rv.Type().Key()))
|
||||
rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
|
||||
if err := md.unify(v, rvval); err != nil {
|
||||
return err
|
||||
}
|
||||
md.context = md.context[0 : len(md.context)-1]
|
||||
|
||||
rvkey.SetString(k)
|
||||
rv.SetMapIndex(rvkey, rvval)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
|
||||
datav := reflect.ValueOf(data)
|
||||
if datav.Kind() != reflect.Slice {
|
||||
if !datav.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return badtype("slice", data)
|
||||
}
|
||||
sliceLen := datav.Len()
|
||||
if sliceLen != rv.Len() {
|
||||
return e("expected array length %d; got TOML array of length %d",
|
||||
rv.Len(), sliceLen)
|
||||
}
|
||||
return md.unifySliceArray(datav, rv)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
|
||||
datav := reflect.ValueOf(data)
|
||||
if datav.Kind() != reflect.Slice {
|
||||
if !datav.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return badtype("slice", data)
|
||||
}
|
||||
n := datav.Len()
|
||||
if rv.IsNil() || rv.Cap() < n {
|
||||
rv.Set(reflect.MakeSlice(rv.Type(), n, n))
|
||||
}
|
||||
rv.SetLen(n)
|
||||
return md.unifySliceArray(datav, rv)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
|
||||
sliceLen := data.Len()
|
||||
for i := 0; i < sliceLen; i++ {
|
||||
v := data.Index(i).Interface()
|
||||
sliceval := indirect(rv.Index(i))
|
||||
if err := md.unify(v, sliceval); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error {
|
||||
if _, ok := data.(time.Time); ok {
|
||||
rv.Set(reflect.ValueOf(data))
|
||||
return nil
|
||||
}
|
||||
return badtype("time.Time", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
|
||||
if s, ok := data.(string); ok {
|
||||
rv.SetString(s)
|
||||
return nil
|
||||
}
|
||||
return badtype("string", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
|
||||
if num, ok := data.(float64); ok {
|
||||
switch rv.Kind() {
|
||||
case reflect.Float32:
|
||||
fallthrough
|
||||
case reflect.Float64:
|
||||
rv.SetFloat(num)
|
||||
default:
|
||||
panic("bug")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return badtype("float", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
|
||||
if num, ok := data.(int64); ok {
|
||||
if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int64:
|
||||
// No bounds checking necessary.
|
||||
case reflect.Int8:
|
||||
if num < math.MinInt8 || num > math.MaxInt8 {
|
||||
return e("value %d is out of range for int8", num)
|
||||
}
|
||||
case reflect.Int16:
|
||||
if num < math.MinInt16 || num > math.MaxInt16 {
|
||||
return e("value %d is out of range for int16", num)
|
||||
}
|
||||
case reflect.Int32:
|
||||
if num < math.MinInt32 || num > math.MaxInt32 {
|
||||
return e("value %d is out of range for int32", num)
|
||||
}
|
||||
}
|
||||
rv.SetInt(num)
|
||||
} else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 {
|
||||
unum := uint64(num)
|
||||
switch rv.Kind() {
|
||||
case reflect.Uint, reflect.Uint64:
|
||||
// No bounds checking necessary.
|
||||
case reflect.Uint8:
|
||||
if num < 0 || unum > math.MaxUint8 {
|
||||
return e("value %d is out of range for uint8", num)
|
||||
}
|
||||
case reflect.Uint16:
|
||||
if num < 0 || unum > math.MaxUint16 {
|
||||
return e("value %d is out of range for uint16", num)
|
||||
}
|
||||
case reflect.Uint32:
|
||||
if num < 0 || unum > math.MaxUint32 {
|
||||
return e("value %d is out of range for uint32", num)
|
||||
}
|
||||
}
|
||||
rv.SetUint(unum)
|
||||
} else {
|
||||
panic("unreachable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return badtype("integer", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
|
||||
if b, ok := data.(bool); ok {
|
||||
rv.SetBool(b)
|
||||
return nil
|
||||
}
|
||||
return badtype("boolean", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
|
||||
rv.Set(reflect.ValueOf(data))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
|
||||
var s string
|
||||
switch sdata := data.(type) {
|
||||
case TextMarshaler:
|
||||
text, err := sdata.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s = string(text)
|
||||
case fmt.Stringer:
|
||||
s = sdata.String()
|
||||
case string:
|
||||
s = sdata
|
||||
case bool:
|
||||
s = fmt.Sprintf("%v", sdata)
|
||||
case int64:
|
||||
s = fmt.Sprintf("%d", sdata)
|
||||
case float64:
|
||||
s = fmt.Sprintf("%f", sdata)
|
||||
default:
|
||||
return badtype("primitive (string-like)", data)
|
||||
}
|
||||
if err := v.UnmarshalText([]byte(s)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rvalue returns a reflect.Value of `v`. All pointers are resolved.
|
||||
func rvalue(v interface{}) reflect.Value {
|
||||
return indirect(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// indirect returns the value pointed to by a pointer.
|
||||
// Pointers are followed until the value is not a pointer.
|
||||
// New values are allocated for each nil pointer.
|
||||
//
|
||||
// An exception to this rule is if the value satisfies an interface of
|
||||
// interest to us (like encoding.TextUnmarshaler).
|
||||
func indirect(v reflect.Value) reflect.Value {
|
||||
if v.Kind() != reflect.Ptr {
|
||||
if v.CanSet() {
|
||||
pv := v.Addr()
|
||||
if _, ok := pv.Interface().(TextUnmarshaler); ok {
|
||||
return pv
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
return indirect(reflect.Indirect(v))
|
||||
}
|
||||
|
||||
func isUnifiable(rv reflect.Value) bool {
|
||||
if rv.CanSet() {
|
||||
return true
|
||||
}
|
||||
if _, ok := rv.Interface().(TextUnmarshaler); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func badtype(expected string, data interface{}) error {
|
||||
return e("cannot load TOML value of type %T into a Go %s", data, expected)
|
||||
}
|
||||
121
vendor/github.com/BurntSushi/toml/decode_meta.go
generated
vendored
Normal file
121
vendor/github.com/BurntSushi/toml/decode_meta.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
package toml
|
||||
|
||||
import "strings"
|
||||
|
||||
// MetaData allows access to meta information about TOML data that may not
|
||||
// be inferrable via reflection. In particular, whether a key has been defined
|
||||
// and the TOML type of a key.
|
||||
type MetaData struct {
|
||||
mapping map[string]interface{}
|
||||
types map[string]tomlType
|
||||
keys []Key
|
||||
decoded map[string]bool
|
||||
context Key // Used only during decoding.
|
||||
}
|
||||
|
||||
// IsDefined returns true if the key given exists in the TOML data. The key
|
||||
// should be specified hierarchially. e.g.,
|
||||
//
|
||||
// // access the TOML key 'a.b.c'
|
||||
// IsDefined("a", "b", "c")
|
||||
//
|
||||
// IsDefined will return false if an empty key given. Keys are case sensitive.
|
||||
func (md *MetaData) IsDefined(key ...string) bool {
|
||||
if len(key) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var hash map[string]interface{}
|
||||
var ok bool
|
||||
var hashOrVal interface{} = md.mapping
|
||||
for _, k := range key {
|
||||
if hash, ok = hashOrVal.(map[string]interface{}); !ok {
|
||||
return false
|
||||
}
|
||||
if hashOrVal, ok = hash[k]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Type returns a string representation of the type of the key specified.
|
||||
//
|
||||
// Type will return the empty string if given an empty key or a key that
|
||||
// does not exist. Keys are case sensitive.
|
||||
func (md *MetaData) Type(key ...string) string {
|
||||
fullkey := strings.Join(key, ".")
|
||||
if typ, ok := md.types[fullkey]; ok {
|
||||
return typ.typeString()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
|
||||
// to get values of this type.
|
||||
type Key []string
|
||||
|
||||
func (k Key) String() string {
|
||||
return strings.Join(k, ".")
|
||||
}
|
||||
|
||||
func (k Key) maybeQuotedAll() string {
|
||||
var ss []string
|
||||
for i := range k {
|
||||
ss = append(ss, k.maybeQuoted(i))
|
||||
}
|
||||
return strings.Join(ss, ".")
|
||||
}
|
||||
|
||||
func (k Key) maybeQuoted(i int) string {
|
||||
quote := false
|
||||
for _, c := range k[i] {
|
||||
if !isBareKeyChar(c) {
|
||||
quote = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if quote {
|
||||
return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\""
|
||||
}
|
||||
return k[i]
|
||||
}
|
||||
|
||||
func (k Key) add(piece string) Key {
|
||||
newKey := make(Key, len(k)+1)
|
||||
copy(newKey, k)
|
||||
newKey[len(k)] = piece
|
||||
return newKey
|
||||
}
|
||||
|
||||
// Keys returns a slice of every key in the TOML data, including key groups.
|
||||
// Each key is itself a slice, where the first element is the top of the
|
||||
// hierarchy and the last is the most specific.
|
||||
//
|
||||
// The list will have the same order as the keys appeared in the TOML data.
|
||||
//
|
||||
// All keys returned are non-empty.
|
||||
func (md *MetaData) Keys() []Key {
|
||||
return md.keys
|
||||
}
|
||||
|
||||
// Undecoded returns all keys that have not been decoded in the order in which
|
||||
// they appear in the original TOML document.
|
||||
//
|
||||
// This includes keys that haven't been decoded because of a Primitive value.
|
||||
// Once the Primitive value is decoded, the keys will be considered decoded.
|
||||
//
|
||||
// Also note that decoding into an empty interface will result in no decoding,
|
||||
// and so no keys will be considered decoded.
|
||||
//
|
||||
// In this sense, the Undecoded keys correspond to keys in the TOML document
|
||||
// that do not have a concrete type in your representation.
|
||||
func (md *MetaData) Undecoded() []Key {
|
||||
undecoded := make([]Key, 0, len(md.keys))
|
||||
for _, key := range md.keys {
|
||||
if !md.decoded[key.String()] {
|
||||
undecoded = append(undecoded, key)
|
||||
}
|
||||
}
|
||||
return undecoded
|
||||
}
|
||||
27
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
Normal file
27
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Package toml provides facilities for decoding and encoding TOML configuration
|
||||
files via reflection. There is also support for delaying decoding with
|
||||
the Primitive type, and querying the set of keys in a TOML document with the
|
||||
MetaData type.
|
||||
|
||||
The specification implemented: https://github.com/mojombo/toml
|
||||
|
||||
The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
|
||||
whether a file is a valid TOML document. It can also be used to print the
|
||||
type of each key in a TOML document.
|
||||
|
||||
Testing
|
||||
|
||||
There are two important types of tests used for this package. The first is
|
||||
contained inside '*_test.go' files and uses the standard Go unit testing
|
||||
framework. These tests are primarily devoted to holistically testing the
|
||||
decoder and encoder.
|
||||
|
||||
The second type of testing is used to verify the implementation's adherence
|
||||
to the TOML specification. These tests have been factored into their own
|
||||
project: https://github.com/BurntSushi/toml-test
|
||||
|
||||
The reason the tests are in a separate project is so that they can be used by
|
||||
any implementation of TOML. Namely, it is language agnostic.
|
||||
*/
|
||||
package toml
|
||||
568
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
Normal file
568
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
Normal file
@@ -0,0 +1,568 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type tomlEncodeError struct{ error }
|
||||
|
||||
var (
|
||||
errArrayMixedElementTypes = errors.New(
|
||||
"toml: cannot encode array with mixed element types")
|
||||
errArrayNilElement = errors.New(
|
||||
"toml: cannot encode array with nil element")
|
||||
errNonString = errors.New(
|
||||
"toml: cannot encode a map with non-string key type")
|
||||
errAnonNonStruct = errors.New(
|
||||
"toml: cannot encode an anonymous field that is not a struct")
|
||||
errArrayNoTable = errors.New(
|
||||
"toml: TOML array element cannot contain a table")
|
||||
errNoKey = errors.New(
|
||||
"toml: top-level values must be Go maps or structs")
|
||||
errAnything = errors.New("") // used in testing
|
||||
)
|
||||
|
||||
var quotedReplacer = strings.NewReplacer(
|
||||
"\t", "\\t",
|
||||
"\n", "\\n",
|
||||
"\r", "\\r",
|
||||
"\"", "\\\"",
|
||||
"\\", "\\\\",
|
||||
)
|
||||
|
||||
// Encoder controls the encoding of Go values to a TOML document to some
|
||||
// io.Writer.
|
||||
//
|
||||
// The indentation level can be controlled with the Indent field.
|
||||
type Encoder struct {
|
||||
// A single indentation level. By default it is two spaces.
|
||||
Indent string
|
||||
|
||||
// hasWritten is whether we have written any output to w yet.
|
||||
hasWritten bool
|
||||
w *bufio.Writer
|
||||
}
|
||||
|
||||
// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer
|
||||
// given. By default, a single indentation level is 2 spaces.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{
|
||||
w: bufio.NewWriter(w),
|
||||
Indent: " ",
|
||||
}
|
||||
}
|
||||
|
||||
// Encode writes a TOML representation of the Go value to the underlying
|
||||
// io.Writer. If the value given cannot be encoded to a valid TOML document,
|
||||
// then an error is returned.
|
||||
//
|
||||
// The mapping between Go values and TOML values should be precisely the same
|
||||
// as for the Decode* functions. Similarly, the TextMarshaler interface is
|
||||
// supported by encoding the resulting bytes as strings. (If you want to write
|
||||
// arbitrary binary data then you will need to use something like base64 since
|
||||
// TOML does not have any binary types.)
|
||||
//
|
||||
// When encoding TOML hashes (i.e., Go maps or structs), keys without any
|
||||
// sub-hashes are encoded first.
|
||||
//
|
||||
// If a Go map is encoded, then its keys are sorted alphabetically for
|
||||
// deterministic output. More control over this behavior may be provided if
|
||||
// there is demand for it.
|
||||
//
|
||||
// Encoding Go values without a corresponding TOML representation---like map
|
||||
// types with non-string keys---will cause an error to be returned. Similarly
|
||||
// for mixed arrays/slices, arrays/slices with nil elements, embedded
|
||||
// non-struct types and nested slices containing maps or structs.
|
||||
// (e.g., [][]map[string]string is not allowed but []map[string]string is OK
|
||||
// and so is []map[string][]string.)
|
||||
func (enc *Encoder) Encode(v interface{}) error {
|
||||
rv := eindirect(reflect.ValueOf(v))
|
||||
if err := enc.safeEncode(Key([]string{}), rv); err != nil {
|
||||
return err
|
||||
}
|
||||
return enc.w.Flush()
|
||||
}
|
||||
|
||||
func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if terr, ok := r.(tomlEncodeError); ok {
|
||||
err = terr.error
|
||||
return
|
||||
}
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
enc.encode(key, rv)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) encode(key Key, rv reflect.Value) {
|
||||
// Special case. Time needs to be in ISO8601 format.
|
||||
// Special case. If we can marshal the type to text, then we used that.
|
||||
// Basically, this prevents the encoder for handling these types as
|
||||
// generic structs (or whatever the underlying type of a TextMarshaler is).
|
||||
switch rv.Interface().(type) {
|
||||
case time.Time, TextMarshaler:
|
||||
enc.keyEqElement(key, rv)
|
||||
return
|
||||
}
|
||||
|
||||
k := rv.Kind()
|
||||
switch k {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||
reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
|
||||
enc.keyEqElement(key, rv)
|
||||
case reflect.Array, reflect.Slice:
|
||||
if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
|
||||
enc.eArrayOfTables(key, rv)
|
||||
} else {
|
||||
enc.keyEqElement(key, rv)
|
||||
}
|
||||
case reflect.Interface:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.encode(key, rv.Elem())
|
||||
case reflect.Map:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.eTable(key, rv)
|
||||
case reflect.Ptr:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.encode(key, rv.Elem())
|
||||
case reflect.Struct:
|
||||
enc.eTable(key, rv)
|
||||
default:
|
||||
panic(e("unsupported type for key '%s': %s", key, k))
|
||||
}
|
||||
}
|
||||
|
||||
// eElement encodes any value that can be an array element (primitives and
|
||||
// arrays).
|
||||
func (enc *Encoder) eElement(rv reflect.Value) {
|
||||
switch v := rv.Interface().(type) {
|
||||
case time.Time:
|
||||
// Special case time.Time as a primitive. Has to come before
|
||||
// TextMarshaler below because time.Time implements
|
||||
// encoding.TextMarshaler, but we need to always use UTC.
|
||||
enc.wf(v.UTC().Format("2006-01-02T15:04:05Z"))
|
||||
return
|
||||
case TextMarshaler:
|
||||
// Special case. Use text marshaler if it's available for this value.
|
||||
if s, err := v.MarshalText(); err != nil {
|
||||
encPanic(err)
|
||||
} else {
|
||||
enc.writeQuoted(string(s))
|
||||
}
|
||||
return
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
enc.wf(strconv.FormatBool(rv.Bool()))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64:
|
||||
enc.wf(strconv.FormatInt(rv.Int(), 10))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||
reflect.Uint32, reflect.Uint64:
|
||||
enc.wf(strconv.FormatUint(rv.Uint(), 10))
|
||||
case reflect.Float32:
|
||||
enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32)))
|
||||
case reflect.Float64:
|
||||
enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64)))
|
||||
case reflect.Array, reflect.Slice:
|
||||
enc.eArrayOrSliceElement(rv)
|
||||
case reflect.Interface:
|
||||
enc.eElement(rv.Elem())
|
||||
case reflect.String:
|
||||
enc.writeQuoted(rv.String())
|
||||
default:
|
||||
panic(e("unexpected primitive type: %s", rv.Kind()))
|
||||
}
|
||||
}
|
||||
|
||||
// By the TOML spec, all floats must have a decimal with at least one
|
||||
// number on either side.
|
||||
func floatAddDecimal(fstr string) string {
|
||||
if !strings.Contains(fstr, ".") {
|
||||
return fstr + ".0"
|
||||
}
|
||||
return fstr
|
||||
}
|
||||
|
||||
func (enc *Encoder) writeQuoted(s string) {
|
||||
enc.wf("\"%s\"", quotedReplacer.Replace(s))
|
||||
}
|
||||
|
||||
func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
|
||||
length := rv.Len()
|
||||
enc.wf("[")
|
||||
for i := 0; i < length; i++ {
|
||||
elem := rv.Index(i)
|
||||
enc.eElement(elem)
|
||||
if i != length-1 {
|
||||
enc.wf(", ")
|
||||
}
|
||||
}
|
||||
enc.wf("]")
|
||||
}
|
||||
|
||||
func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
|
||||
if len(key) == 0 {
|
||||
encPanic(errNoKey)
|
||||
}
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
trv := rv.Index(i)
|
||||
if isNil(trv) {
|
||||
continue
|
||||
}
|
||||
panicIfInvalidKey(key)
|
||||
enc.newline()
|
||||
enc.wf("%s[[%s]]", enc.indentStr(key), key.maybeQuotedAll())
|
||||
enc.newline()
|
||||
enc.eMapOrStruct(key, trv)
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) eTable(key Key, rv reflect.Value) {
|
||||
panicIfInvalidKey(key)
|
||||
if len(key) == 1 {
|
||||
// Output an extra new line between top-level tables.
|
||||
// (The newline isn't written if nothing else has been written though.)
|
||||
enc.newline()
|
||||
}
|
||||
if len(key) > 0 {
|
||||
enc.wf("%s[%s]", enc.indentStr(key), key.maybeQuotedAll())
|
||||
enc.newline()
|
||||
}
|
||||
enc.eMapOrStruct(key, rv)
|
||||
}
|
||||
|
||||
func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) {
|
||||
switch rv := eindirect(rv); rv.Kind() {
|
||||
case reflect.Map:
|
||||
enc.eMap(key, rv)
|
||||
case reflect.Struct:
|
||||
enc.eStruct(key, rv)
|
||||
default:
|
||||
panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) eMap(key Key, rv reflect.Value) {
|
||||
rt := rv.Type()
|
||||
if rt.Key().Kind() != reflect.String {
|
||||
encPanic(errNonString)
|
||||
}
|
||||
|
||||
// Sort keys so that we have deterministic output. And write keys directly
|
||||
// underneath this key first, before writing sub-structs or sub-maps.
|
||||
var mapKeysDirect, mapKeysSub []string
|
||||
for _, mapKey := range rv.MapKeys() {
|
||||
k := mapKey.String()
|
||||
if typeIsHash(tomlTypeOfGo(rv.MapIndex(mapKey))) {
|
||||
mapKeysSub = append(mapKeysSub, k)
|
||||
} else {
|
||||
mapKeysDirect = append(mapKeysDirect, k)
|
||||
}
|
||||
}
|
||||
|
||||
var writeMapKeys = func(mapKeys []string) {
|
||||
sort.Strings(mapKeys)
|
||||
for _, mapKey := range mapKeys {
|
||||
mrv := rv.MapIndex(reflect.ValueOf(mapKey))
|
||||
if isNil(mrv) {
|
||||
// Don't write anything for nil fields.
|
||||
continue
|
||||
}
|
||||
enc.encode(key.add(mapKey), mrv)
|
||||
}
|
||||
}
|
||||
writeMapKeys(mapKeysDirect)
|
||||
writeMapKeys(mapKeysSub)
|
||||
}
|
||||
|
||||
func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
|
||||
// Write keys for fields directly under this key first, because if we write
|
||||
// a field that creates a new table, then all keys under it will be in that
|
||||
// table (not the one we're writing here).
|
||||
rt := rv.Type()
|
||||
var fieldsDirect, fieldsSub [][]int
|
||||
var addFields func(rt reflect.Type, rv reflect.Value, start []int)
|
||||
addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
|
||||
for i := 0; i < rt.NumField(); i++ {
|
||||
f := rt.Field(i)
|
||||
// skip unexported fields
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
continue
|
||||
}
|
||||
frv := rv.Field(i)
|
||||
if f.Anonymous {
|
||||
t := f.Type
|
||||
switch t.Kind() {
|
||||
case reflect.Struct:
|
||||
// Treat anonymous struct fields with
|
||||
// tag names as though they are not
|
||||
// anonymous, like encoding/json does.
|
||||
if getOptions(f.Tag).name == "" {
|
||||
addFields(t, frv, f.Index)
|
||||
continue
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if t.Elem().Kind() == reflect.Struct &&
|
||||
getOptions(f.Tag).name == "" {
|
||||
if !frv.IsNil() {
|
||||
addFields(t.Elem(), frv.Elem(), f.Index)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Fall through to the normal field encoding logic below
|
||||
// for non-struct anonymous fields.
|
||||
}
|
||||
}
|
||||
|
||||
if typeIsHash(tomlTypeOfGo(frv)) {
|
||||
fieldsSub = append(fieldsSub, append(start, f.Index...))
|
||||
} else {
|
||||
fieldsDirect = append(fieldsDirect, append(start, f.Index...))
|
||||
}
|
||||
}
|
||||
}
|
||||
addFields(rt, rv, nil)
|
||||
|
||||
var writeFields = func(fields [][]int) {
|
||||
for _, fieldIndex := range fields {
|
||||
sft := rt.FieldByIndex(fieldIndex)
|
||||
sf := rv.FieldByIndex(fieldIndex)
|
||||
if isNil(sf) {
|
||||
// Don't write anything for nil fields.
|
||||
continue
|
||||
}
|
||||
|
||||
opts := getOptions(sft.Tag)
|
||||
if opts.skip {
|
||||
continue
|
||||
}
|
||||
keyName := sft.Name
|
||||
if opts.name != "" {
|
||||
keyName = opts.name
|
||||
}
|
||||
if opts.omitempty && isEmpty(sf) {
|
||||
continue
|
||||
}
|
||||
if opts.omitzero && isZero(sf) {
|
||||
continue
|
||||
}
|
||||
|
||||
enc.encode(key.add(keyName), sf)
|
||||
}
|
||||
}
|
||||
writeFields(fieldsDirect)
|
||||
writeFields(fieldsSub)
|
||||
}
|
||||
|
||||
// tomlTypeName returns the TOML type name of the Go value's type. It is
|
||||
// used to determine whether the types of array elements are mixed (which is
|
||||
// forbidden). If the Go value is nil, then it is illegal for it to be an array
|
||||
// element, and valueIsNil is returned as true.
|
||||
|
||||
// Returns the TOML type of a Go value. The type may be `nil`, which means
|
||||
// no concrete TOML type could be found.
|
||||
func tomlTypeOfGo(rv reflect.Value) tomlType {
|
||||
if isNil(rv) || !rv.IsValid() {
|
||||
return nil
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
return tomlBool
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||
reflect.Uint64:
|
||||
return tomlInteger
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return tomlFloat
|
||||
case reflect.Array, reflect.Slice:
|
||||
if typeEqual(tomlHash, tomlArrayType(rv)) {
|
||||
return tomlArrayHash
|
||||
}
|
||||
return tomlArray
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return tomlTypeOfGo(rv.Elem())
|
||||
case reflect.String:
|
||||
return tomlString
|
||||
case reflect.Map:
|
||||
return tomlHash
|
||||
case reflect.Struct:
|
||||
switch rv.Interface().(type) {
|
||||
case time.Time:
|
||||
return tomlDatetime
|
||||
case TextMarshaler:
|
||||
return tomlString
|
||||
default:
|
||||
return tomlHash
|
||||
}
|
||||
default:
|
||||
panic("unexpected reflect.Kind: " + rv.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
// tomlArrayType returns the element type of a TOML array. The type returned
|
||||
// may be nil if it cannot be determined (e.g., a nil slice or a zero length
|
||||
// slize). This function may also panic if it finds a type that cannot be
|
||||
// expressed in TOML (such as nil elements, heterogeneous arrays or directly
|
||||
// nested arrays of tables).
|
||||
func tomlArrayType(rv reflect.Value) tomlType {
|
||||
if isNil(rv) || !rv.IsValid() || rv.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
firstType := tomlTypeOfGo(rv.Index(0))
|
||||
if firstType == nil {
|
||||
encPanic(errArrayNilElement)
|
||||
}
|
||||
|
||||
rvlen := rv.Len()
|
||||
for i := 1; i < rvlen; i++ {
|
||||
elem := rv.Index(i)
|
||||
switch elemType := tomlTypeOfGo(elem); {
|
||||
case elemType == nil:
|
||||
encPanic(errArrayNilElement)
|
||||
case !typeEqual(firstType, elemType):
|
||||
encPanic(errArrayMixedElementTypes)
|
||||
}
|
||||
}
|
||||
// If we have a nested array, then we must make sure that the nested
|
||||
// array contains ONLY primitives.
|
||||
// This checks arbitrarily nested arrays.
|
||||
if typeEqual(firstType, tomlArray) || typeEqual(firstType, tomlArrayHash) {
|
||||
nest := tomlArrayType(eindirect(rv.Index(0)))
|
||||
if typeEqual(nest, tomlHash) || typeEqual(nest, tomlArrayHash) {
|
||||
encPanic(errArrayNoTable)
|
||||
}
|
||||
}
|
||||
return firstType
|
||||
}
|
||||
|
||||
type tagOptions struct {
|
||||
skip bool // "-"
|
||||
name string
|
||||
omitempty bool
|
||||
omitzero bool
|
||||
}
|
||||
|
||||
func getOptions(tag reflect.StructTag) tagOptions {
|
||||
t := tag.Get("toml")
|
||||
if t == "-" {
|
||||
return tagOptions{skip: true}
|
||||
}
|
||||
var opts tagOptions
|
||||
parts := strings.Split(t, ",")
|
||||
opts.name = parts[0]
|
||||
for _, s := range parts[1:] {
|
||||
switch s {
|
||||
case "omitempty":
|
||||
opts.omitempty = true
|
||||
case "omitzero":
|
||||
opts.omitzero = true
|
||||
}
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
func isZero(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return rv.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return rv.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return rv.Float() == 0.0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isEmpty(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
|
||||
return rv.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !rv.Bool()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (enc *Encoder) newline() {
|
||||
if enc.hasWritten {
|
||||
enc.wf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) keyEqElement(key Key, val reflect.Value) {
|
||||
if len(key) == 0 {
|
||||
encPanic(errNoKey)
|
||||
}
|
||||
panicIfInvalidKey(key)
|
||||
enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
|
||||
enc.eElement(val)
|
||||
enc.newline()
|
||||
}
|
||||
|
||||
func (enc *Encoder) wf(format string, v ...interface{}) {
|
||||
if _, err := fmt.Fprintf(enc.w, format, v...); err != nil {
|
||||
encPanic(err)
|
||||
}
|
||||
enc.hasWritten = true
|
||||
}
|
||||
|
||||
func (enc *Encoder) indentStr(key Key) string {
|
||||
return strings.Repeat(enc.Indent, len(key)-1)
|
||||
}
|
||||
|
||||
func encPanic(err error) {
|
||||
panic(tomlEncodeError{err})
|
||||
}
|
||||
|
||||
func eindirect(v reflect.Value) reflect.Value {
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return eindirect(v.Elem())
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func isNil(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
return rv.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func panicIfInvalidKey(key Key) {
|
||||
for _, k := range key {
|
||||
if len(k) == 0 {
|
||||
encPanic(e("Key '%s' is not a valid table name. Key names "+
|
||||
"cannot be empty.", key.maybeQuotedAll()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isValidKeyName(s string) bool {
|
||||
return len(s) != 0
|
||||
}
|
||||
19
vendor/github.com/BurntSushi/toml/encoding_types.go
generated
vendored
Normal file
19
vendor/github.com/BurntSushi/toml/encoding_types.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// +build go1.2
|
||||
|
||||
package toml
|
||||
|
||||
// In order to support Go 1.1, we define our own TextMarshaler and
|
||||
// TextUnmarshaler types. For Go 1.2+, we just alias them with the
|
||||
// standard library interfaces.
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
)
|
||||
|
||||
// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
|
||||
// so that Go 1.1 can be supported.
|
||||
type TextMarshaler encoding.TextMarshaler
|
||||
|
||||
// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
|
||||
// here so that Go 1.1 can be supported.
|
||||
type TextUnmarshaler encoding.TextUnmarshaler
|
||||
18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
generated
vendored
Normal file
18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// +build !go1.2
|
||||
|
||||
package toml
|
||||
|
||||
// These interfaces were introduced in Go 1.2, so we add them manually when
|
||||
// compiling for Go 1.1.
|
||||
|
||||
// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
|
||||
// so that Go 1.1 can be supported.
|
||||
type TextMarshaler interface {
|
||||
MarshalText() (text []byte, err error)
|
||||
}
|
||||
|
||||
// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
|
||||
// here so that Go 1.1 can be supported.
|
||||
type TextUnmarshaler interface {
|
||||
UnmarshalText(text []byte) error
|
||||
}
|
||||
858
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
Normal file
858
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
Normal file
@@ -0,0 +1,858 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type itemType int
|
||||
|
||||
const (
|
||||
itemError itemType = iota
|
||||
itemNIL // used in the parser to indicate no type
|
||||
itemEOF
|
||||
itemText
|
||||
itemString
|
||||
itemRawString
|
||||
itemMultilineString
|
||||
itemRawMultilineString
|
||||
itemBool
|
||||
itemInteger
|
||||
itemFloat
|
||||
itemDatetime
|
||||
itemArray // the start of an array
|
||||
itemArrayEnd
|
||||
itemTableStart
|
||||
itemTableEnd
|
||||
itemArrayTableStart
|
||||
itemArrayTableEnd
|
||||
itemKeyStart
|
||||
itemCommentStart
|
||||
)
|
||||
|
||||
const (
|
||||
eof = 0
|
||||
tableStart = '['
|
||||
tableEnd = ']'
|
||||
arrayTableStart = '['
|
||||
arrayTableEnd = ']'
|
||||
tableSep = '.'
|
||||
keySep = '='
|
||||
arrayStart = '['
|
||||
arrayEnd = ']'
|
||||
arrayValTerm = ','
|
||||
commentStart = '#'
|
||||
stringStart = '"'
|
||||
stringEnd = '"'
|
||||
rawStringStart = '\''
|
||||
rawStringEnd = '\''
|
||||
)
|
||||
|
||||
type stateFn func(lx *lexer) stateFn
|
||||
|
||||
type lexer struct {
|
||||
input string
|
||||
start int
|
||||
pos int
|
||||
width int
|
||||
line int
|
||||
state stateFn
|
||||
items chan item
|
||||
|
||||
// A stack of state functions used to maintain context.
|
||||
// The idea is to reuse parts of the state machine in various places.
|
||||
// For example, values can appear at the top level or within arbitrarily
|
||||
// nested arrays. The last state on the stack is used after a value has
|
||||
// been lexed. Similarly for comments.
|
||||
stack []stateFn
|
||||
}
|
||||
|
||||
type item struct {
|
||||
typ itemType
|
||||
val string
|
||||
line int
|
||||
}
|
||||
|
||||
func (lx *lexer) nextItem() item {
|
||||
for {
|
||||
select {
|
||||
case item := <-lx.items:
|
||||
return item
|
||||
default:
|
||||
lx.state = lx.state(lx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func lex(input string) *lexer {
|
||||
lx := &lexer{
|
||||
input: input + "\n",
|
||||
state: lexTop,
|
||||
line: 1,
|
||||
items: make(chan item, 10),
|
||||
stack: make([]stateFn, 0, 10),
|
||||
}
|
||||
return lx
|
||||
}
|
||||
|
||||
func (lx *lexer) push(state stateFn) {
|
||||
lx.stack = append(lx.stack, state)
|
||||
}
|
||||
|
||||
func (lx *lexer) pop() stateFn {
|
||||
if len(lx.stack) == 0 {
|
||||
return lx.errorf("BUG in lexer: no states to pop.")
|
||||
}
|
||||
last := lx.stack[len(lx.stack)-1]
|
||||
lx.stack = lx.stack[0 : len(lx.stack)-1]
|
||||
return last
|
||||
}
|
||||
|
||||
func (lx *lexer) current() string {
|
||||
return lx.input[lx.start:lx.pos]
|
||||
}
|
||||
|
||||
func (lx *lexer) emit(typ itemType) {
|
||||
lx.items <- item{typ, lx.current(), lx.line}
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
func (lx *lexer) emitTrim(typ itemType) {
|
||||
lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line}
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
func (lx *lexer) next() (r rune) {
|
||||
if lx.pos >= len(lx.input) {
|
||||
lx.width = 0
|
||||
return eof
|
||||
}
|
||||
|
||||
if lx.input[lx.pos] == '\n' {
|
||||
lx.line++
|
||||
}
|
||||
r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:])
|
||||
lx.pos += lx.width
|
||||
return r
|
||||
}
|
||||
|
||||
// ignore skips over the pending input before this point.
|
||||
func (lx *lexer) ignore() {
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
// backup steps back one rune. Can be called only once per call of next.
|
||||
func (lx *lexer) backup() {
|
||||
lx.pos -= lx.width
|
||||
if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
|
||||
lx.line--
|
||||
}
|
||||
}
|
||||
|
||||
// accept consumes the next rune if it's equal to `valid`.
|
||||
func (lx *lexer) accept(valid rune) bool {
|
||||
if lx.next() == valid {
|
||||
return true
|
||||
}
|
||||
lx.backup()
|
||||
return false
|
||||
}
|
||||
|
||||
// peek returns but does not consume the next rune in the input.
|
||||
func (lx *lexer) peek() rune {
|
||||
r := lx.next()
|
||||
lx.backup()
|
||||
return r
|
||||
}
|
||||
|
||||
// skip ignores all input that matches the given predicate.
|
||||
func (lx *lexer) skip(pred func(rune) bool) {
|
||||
for {
|
||||
r := lx.next()
|
||||
if pred(r) {
|
||||
continue
|
||||
}
|
||||
lx.backup()
|
||||
lx.ignore()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// errorf stops all lexing by emitting an error and returning `nil`.
|
||||
// Note that any value that is a character is escaped if it's a special
|
||||
// character (new lines, tabs, etc.).
|
||||
func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
|
||||
lx.items <- item{
|
||||
itemError,
|
||||
fmt.Sprintf(format, values...),
|
||||
lx.line,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// lexTop consumes elements at the top level of TOML data.
|
||||
func lexTop(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isWhitespace(r) || isNL(r) {
|
||||
return lexSkip(lx, lexTop)
|
||||
}
|
||||
|
||||
switch r {
|
||||
case commentStart:
|
||||
lx.push(lexTop)
|
||||
return lexCommentStart
|
||||
case tableStart:
|
||||
return lexTableStart
|
||||
case eof:
|
||||
if lx.pos > lx.start {
|
||||
return lx.errorf("Unexpected EOF.")
|
||||
}
|
||||
lx.emit(itemEOF)
|
||||
return nil
|
||||
}
|
||||
|
||||
// At this point, the only valid item can be a key, so we back up
|
||||
// and let the key lexer do the rest.
|
||||
lx.backup()
|
||||
lx.push(lexTopEnd)
|
||||
return lexKeyStart
|
||||
}
|
||||
|
||||
// lexTopEnd is entered whenever a top-level item has been consumed. (A value
|
||||
// or a table.) It must see only whitespace, and will turn back to lexTop
|
||||
// upon a new line. If it sees EOF, it will quit the lexer successfully.
|
||||
func lexTopEnd(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == commentStart:
|
||||
// a comment will read to a new line for us.
|
||||
lx.push(lexTop)
|
||||
return lexCommentStart
|
||||
case isWhitespace(r):
|
||||
return lexTopEnd
|
||||
case isNL(r):
|
||||
lx.ignore()
|
||||
return lexTop
|
||||
case r == eof:
|
||||
lx.ignore()
|
||||
return lexTop
|
||||
}
|
||||
return lx.errorf("Expected a top-level item to end with a new line, "+
|
||||
"comment or EOF, but got %q instead.", r)
|
||||
}
|
||||
|
||||
// lexTable lexes the beginning of a table. Namely, it makes sure that
|
||||
// it starts with a character other than '.' and ']'.
|
||||
// It assumes that '[' has already been consumed.
|
||||
// It also handles the case that this is an item in an array of tables.
|
||||
// e.g., '[[name]]'.
|
||||
func lexTableStart(lx *lexer) stateFn {
|
||||
if lx.peek() == arrayTableStart {
|
||||
lx.next()
|
||||
lx.emit(itemArrayTableStart)
|
||||
lx.push(lexArrayTableEnd)
|
||||
} else {
|
||||
lx.emit(itemTableStart)
|
||||
lx.push(lexTableEnd)
|
||||
}
|
||||
return lexTableNameStart
|
||||
}
|
||||
|
||||
func lexTableEnd(lx *lexer) stateFn {
|
||||
lx.emit(itemTableEnd)
|
||||
return lexTopEnd
|
||||
}
|
||||
|
||||
func lexArrayTableEnd(lx *lexer) stateFn {
|
||||
if r := lx.next(); r != arrayTableEnd {
|
||||
return lx.errorf("Expected end of table array name delimiter %q, "+
|
||||
"but got %q instead.", arrayTableEnd, r)
|
||||
}
|
||||
lx.emit(itemArrayTableEnd)
|
||||
return lexTopEnd
|
||||
}
|
||||
|
||||
func lexTableNameStart(lx *lexer) stateFn {
|
||||
lx.skip(isWhitespace)
|
||||
switch r := lx.peek(); {
|
||||
case r == tableEnd || r == eof:
|
||||
return lx.errorf("Unexpected end of table name. (Table names cannot " +
|
||||
"be empty.)")
|
||||
case r == tableSep:
|
||||
return lx.errorf("Unexpected table separator. (Table names cannot " +
|
||||
"be empty.)")
|
||||
case r == stringStart || r == rawStringStart:
|
||||
lx.ignore()
|
||||
lx.push(lexTableNameEnd)
|
||||
return lexValue // reuse string lexing
|
||||
default:
|
||||
return lexBareTableName
|
||||
}
|
||||
}
|
||||
|
||||
// lexBareTableName lexes the name of a table. It assumes that at least one
|
||||
// valid character for the table has already been read.
|
||||
func lexBareTableName(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isBareKeyChar(r) {
|
||||
return lexBareTableName
|
||||
}
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexTableNameEnd
|
||||
}
|
||||
|
||||
// lexTableNameEnd reads the end of a piece of a table name, optionally
|
||||
// consuming whitespace.
|
||||
func lexTableNameEnd(lx *lexer) stateFn {
|
||||
lx.skip(isWhitespace)
|
||||
switch r := lx.next(); {
|
||||
case isWhitespace(r):
|
||||
return lexTableNameEnd
|
||||
case r == tableSep:
|
||||
lx.ignore()
|
||||
return lexTableNameStart
|
||||
case r == tableEnd:
|
||||
return lx.pop()
|
||||
default:
|
||||
return lx.errorf("Expected '.' or ']' to end table name, but got %q "+
|
||||
"instead.", r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexKeyStart consumes a key name up until the first non-whitespace character.
|
||||
// lexKeyStart will ignore whitespace.
|
||||
func lexKeyStart(lx *lexer) stateFn {
|
||||
r := lx.peek()
|
||||
switch {
|
||||
case r == keySep:
|
||||
return lx.errorf("Unexpected key separator %q.", keySep)
|
||||
case isWhitespace(r) || isNL(r):
|
||||
lx.next()
|
||||
return lexSkip(lx, lexKeyStart)
|
||||
case r == stringStart || r == rawStringStart:
|
||||
lx.ignore()
|
||||
lx.emit(itemKeyStart)
|
||||
lx.push(lexKeyEnd)
|
||||
return lexValue // reuse string lexing
|
||||
default:
|
||||
lx.ignore()
|
||||
lx.emit(itemKeyStart)
|
||||
return lexBareKey
|
||||
}
|
||||
}
|
||||
|
||||
// lexBareKey consumes the text of a bare key. Assumes that the first character
|
||||
// (which is not whitespace) has not yet been consumed.
|
||||
func lexBareKey(lx *lexer) stateFn {
|
||||
switch r := lx.next(); {
|
||||
case isBareKeyChar(r):
|
||||
return lexBareKey
|
||||
case isWhitespace(r):
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexKeyEnd
|
||||
case r == keySep:
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexKeyEnd
|
||||
default:
|
||||
return lx.errorf("Bare keys cannot contain %q.", r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexKeyEnd consumes the end of a key and trims whitespace (up to the key
|
||||
// separator).
|
||||
func lexKeyEnd(lx *lexer) stateFn {
|
||||
switch r := lx.next(); {
|
||||
case r == keySep:
|
||||
return lexSkip(lx, lexValue)
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexKeyEnd)
|
||||
default:
|
||||
return lx.errorf("Expected key separator %q, but got %q instead.",
|
||||
keySep, r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexValue starts the consumption of a value anywhere a value is expected.
|
||||
// lexValue will ignore whitespace.
|
||||
// After a value is lexed, the last state on the next is popped and returned.
|
||||
func lexValue(lx *lexer) stateFn {
|
||||
// We allow whitespace to precede a value, but NOT new lines.
|
||||
// In array syntax, the array states are responsible for ignoring new
|
||||
// lines.
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexValue)
|
||||
case isDigit(r):
|
||||
lx.backup() // avoid an extra state and use the same as above
|
||||
return lexNumberOrDateStart
|
||||
}
|
||||
switch r {
|
||||
case arrayStart:
|
||||
lx.ignore()
|
||||
lx.emit(itemArray)
|
||||
return lexArrayValue
|
||||
case stringStart:
|
||||
if lx.accept(stringStart) {
|
||||
if lx.accept(stringStart) {
|
||||
lx.ignore() // Ignore """
|
||||
return lexMultilineString
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
lx.ignore() // ignore the '"'
|
||||
return lexString
|
||||
case rawStringStart:
|
||||
if lx.accept(rawStringStart) {
|
||||
if lx.accept(rawStringStart) {
|
||||
lx.ignore() // Ignore """
|
||||
return lexMultilineRawString
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
lx.ignore() // ignore the "'"
|
||||
return lexRawString
|
||||
case '+', '-':
|
||||
return lexNumberStart
|
||||
case '.': // special error case, be kind to users
|
||||
return lx.errorf("Floats must start with a digit, not '.'.")
|
||||
}
|
||||
if unicode.IsLetter(r) {
|
||||
// Be permissive here; lexBool will give a nice error if the
|
||||
// user wrote something like
|
||||
// x = foo
|
||||
// (i.e. not 'true' or 'false' but is something else word-like.)
|
||||
lx.backup()
|
||||
return lexBool
|
||||
}
|
||||
return lx.errorf("Expected value but found %q instead.", r)
|
||||
}
|
||||
|
||||
// lexArrayValue consumes one value in an array. It assumes that '[' or ','
|
||||
// have already been consumed. All whitespace and new lines are ignored.
|
||||
func lexArrayValue(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r) || isNL(r):
|
||||
return lexSkip(lx, lexArrayValue)
|
||||
case r == commentStart:
|
||||
lx.push(lexArrayValue)
|
||||
return lexCommentStart
|
||||
case r == arrayValTerm:
|
||||
return lx.errorf("Unexpected array value terminator %q.",
|
||||
arrayValTerm)
|
||||
case r == arrayEnd:
|
||||
return lexArrayEnd
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.push(lexArrayValueEnd)
|
||||
return lexValue
|
||||
}
|
||||
|
||||
// lexArrayValueEnd consumes the cruft between values of an array. Namely,
|
||||
// it ignores whitespace and expects either a ',' or a ']'.
|
||||
func lexArrayValueEnd(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r) || isNL(r):
|
||||
return lexSkip(lx, lexArrayValueEnd)
|
||||
case r == commentStart:
|
||||
lx.push(lexArrayValueEnd)
|
||||
return lexCommentStart
|
||||
case r == arrayValTerm:
|
||||
lx.ignore()
|
||||
return lexArrayValue // move on to the next value
|
||||
case r == arrayEnd:
|
||||
return lexArrayEnd
|
||||
}
|
||||
return lx.errorf("Expected an array value terminator %q or an array "+
|
||||
"terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r)
|
||||
}
|
||||
|
||||
// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has
|
||||
// just been consumed.
|
||||
func lexArrayEnd(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
lx.emit(itemArrayEnd)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexString consumes the inner contents of a string. It assumes that the
|
||||
// beginning '"' has already been consumed and ignored.
|
||||
func lexString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isNL(r):
|
||||
return lx.errorf("Strings cannot contain new lines.")
|
||||
case r == '\\':
|
||||
lx.push(lexString)
|
||||
return lexStringEscape
|
||||
case r == stringEnd:
|
||||
lx.backup()
|
||||
lx.emit(itemString)
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
return lexString
|
||||
}
|
||||
|
||||
// lexMultilineString consumes the inner contents of a string. It assumes that
|
||||
// the beginning '"""' has already been consumed and ignored.
|
||||
func lexMultilineString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == '\\':
|
||||
return lexMultilineStringEscape
|
||||
case r == stringEnd:
|
||||
if lx.accept(stringEnd) {
|
||||
if lx.accept(stringEnd) {
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.emit(itemMultilineString)
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
}
|
||||
return lexMultilineString
|
||||
}
|
||||
|
||||
// lexRawString consumes a raw string. Nothing can be escaped in such a string.
|
||||
// It assumes that the beginning "'" has already been consumed and ignored.
|
||||
func lexRawString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isNL(r):
|
||||
return lx.errorf("Strings cannot contain new lines.")
|
||||
case r == rawStringEnd:
|
||||
lx.backup()
|
||||
lx.emit(itemRawString)
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
return lexRawString
|
||||
}
|
||||
|
||||
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
|
||||
// a string. It assumes that the beginning "'" has already been consumed and
|
||||
// ignored.
|
||||
func lexMultilineRawString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == rawStringEnd:
|
||||
if lx.accept(rawStringEnd) {
|
||||
if lx.accept(rawStringEnd) {
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.emit(itemRawMultilineString)
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
}
|
||||
return lexMultilineRawString
|
||||
}
|
||||
|
||||
// lexMultilineStringEscape consumes an escaped character. It assumes that the
|
||||
// preceding '\\' has already been consumed.
|
||||
func lexMultilineStringEscape(lx *lexer) stateFn {
|
||||
// Handle the special case first:
|
||||
if isNL(lx.next()) {
|
||||
return lexMultilineString
|
||||
}
|
||||
lx.backup()
|
||||
lx.push(lexMultilineString)
|
||||
return lexStringEscape(lx)
|
||||
}
|
||||
|
||||
func lexStringEscape(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch r {
|
||||
case 'b':
|
||||
fallthrough
|
||||
case 't':
|
||||
fallthrough
|
||||
case 'n':
|
||||
fallthrough
|
||||
case 'f':
|
||||
fallthrough
|
||||
case 'r':
|
||||
fallthrough
|
||||
case '"':
|
||||
fallthrough
|
||||
case '\\':
|
||||
return lx.pop()
|
||||
case 'u':
|
||||
return lexShortUnicodeEscape
|
||||
case 'U':
|
||||
return lexLongUnicodeEscape
|
||||
}
|
||||
return lx.errorf("Invalid escape character %q. Only the following "+
|
||||
"escape characters are allowed: "+
|
||||
"\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, "+
|
||||
"\\uXXXX and \\UXXXXXXXX.", r)
|
||||
}
|
||||
|
||||
func lexShortUnicodeEscape(lx *lexer) stateFn {
|
||||
var r rune
|
||||
for i := 0; i < 4; i++ {
|
||||
r = lx.next()
|
||||
if !isHexadecimal(r) {
|
||||
return lx.errorf("Expected four hexadecimal digits after '\\u', "+
|
||||
"but got '%s' instead.", lx.current())
|
||||
}
|
||||
}
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
func lexLongUnicodeEscape(lx *lexer) stateFn {
|
||||
var r rune
|
||||
for i := 0; i < 8; i++ {
|
||||
r = lx.next()
|
||||
if !isHexadecimal(r) {
|
||||
return lx.errorf("Expected eight hexadecimal digits after '\\U', "+
|
||||
"but got '%s' instead.", lx.current())
|
||||
}
|
||||
}
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexNumberOrDateStart consumes either an integer, a float, or datetime.
|
||||
func lexNumberOrDateStart(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumberOrDate
|
||||
}
|
||||
switch r {
|
||||
case '_':
|
||||
return lexNumber
|
||||
case 'e', 'E':
|
||||
return lexFloat
|
||||
case '.':
|
||||
return lx.errorf("Floats must start with a digit, not '.'.")
|
||||
}
|
||||
return lx.errorf("Expected a digit but got %q.", r)
|
||||
}
|
||||
|
||||
// lexNumberOrDate consumes either an integer, float or datetime.
|
||||
func lexNumberOrDate(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumberOrDate
|
||||
}
|
||||
switch r {
|
||||
case '-':
|
||||
return lexDatetime
|
||||
case '_':
|
||||
return lexNumber
|
||||
case '.', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemInteger)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexDatetime consumes a Datetime, to a first approximation.
|
||||
// The parser validates that it matches one of the accepted formats.
|
||||
func lexDatetime(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexDatetime
|
||||
}
|
||||
switch r {
|
||||
case '-', 'T', ':', '.', 'Z':
|
||||
return lexDatetime
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemDatetime)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexNumberStart consumes either an integer or a float. It assumes that a sign
|
||||
// has already been read, but that *no* digits have been consumed.
|
||||
// lexNumberStart will move to the appropriate integer or float states.
|
||||
func lexNumberStart(lx *lexer) stateFn {
|
||||
// We MUST see a digit. Even floats have to start with a digit.
|
||||
r := lx.next()
|
||||
if !isDigit(r) {
|
||||
if r == '.' {
|
||||
return lx.errorf("Floats must start with a digit, not '.'.")
|
||||
}
|
||||
return lx.errorf("Expected a digit but got %q.", r)
|
||||
}
|
||||
return lexNumber
|
||||
}
|
||||
|
||||
// lexNumber consumes an integer or a float after seeing the first digit.
|
||||
func lexNumber(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumber
|
||||
}
|
||||
switch r {
|
||||
case '_':
|
||||
return lexNumber
|
||||
case '.', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemInteger)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexFloat consumes the elements of a float. It allows any sequence of
|
||||
// float-like characters, so floats emitted by the lexer are only a first
|
||||
// approximation and must be validated by the parser.
|
||||
func lexFloat(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexFloat
|
||||
}
|
||||
switch r {
|
||||
case '_', '.', '-', '+', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemFloat)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexBool consumes a bool string: 'true' or 'false.
|
||||
func lexBool(lx *lexer) stateFn {
|
||||
var rs []rune
|
||||
for {
|
||||
r := lx.next()
|
||||
if r == eof || isWhitespace(r) || isNL(r) {
|
||||
lx.backup()
|
||||
break
|
||||
}
|
||||
rs = append(rs, r)
|
||||
}
|
||||
s := string(rs)
|
||||
switch s {
|
||||
case "true", "false":
|
||||
lx.emit(itemBool)
|
||||
return lx.pop()
|
||||
}
|
||||
return lx.errorf("Expected value but found %q instead.", s)
|
||||
}
|
||||
|
||||
// lexCommentStart begins the lexing of a comment. It will emit
|
||||
// itemCommentStart and consume no characters, passing control to lexComment.
|
||||
func lexCommentStart(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
lx.emit(itemCommentStart)
|
||||
return lexComment
|
||||
}
|
||||
|
||||
// lexComment lexes an entire comment. It assumes that '#' has been consumed.
|
||||
// It will consume *up to* the first new line character, and pass control
|
||||
// back to the last state on the stack.
|
||||
func lexComment(lx *lexer) stateFn {
|
||||
r := lx.peek()
|
||||
if isNL(r) || r == eof {
|
||||
lx.emit(itemText)
|
||||
return lx.pop()
|
||||
}
|
||||
lx.next()
|
||||
return lexComment
|
||||
}
|
||||
|
||||
// lexSkip ignores all slurped input and moves on to the next state.
|
||||
func lexSkip(lx *lexer, nextState stateFn) stateFn {
|
||||
return func(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
return nextState
|
||||
}
|
||||
}
|
||||
|
||||
// isWhitespace returns true if `r` is a whitespace character according
|
||||
// to the spec.
|
||||
func isWhitespace(r rune) bool {
|
||||
return r == '\t' || r == ' '
|
||||
}
|
||||
|
||||
func isNL(r rune) bool {
|
||||
return r == '\n' || r == '\r'
|
||||
}
|
||||
|
||||
func isDigit(r rune) bool {
|
||||
return r >= '0' && r <= '9'
|
||||
}
|
||||
|
||||
func isHexadecimal(r rune) bool {
|
||||
return (r >= '0' && r <= '9') ||
|
||||
(r >= 'a' && r <= 'f') ||
|
||||
(r >= 'A' && r <= 'F')
|
||||
}
|
||||
|
||||
func isBareKeyChar(r rune) bool {
|
||||
return (r >= 'A' && r <= 'Z') ||
|
||||
(r >= 'a' && r <= 'z') ||
|
||||
(r >= '0' && r <= '9') ||
|
||||
r == '_' ||
|
||||
r == '-'
|
||||
}
|
||||
|
||||
func (itype itemType) String() string {
|
||||
switch itype {
|
||||
case itemError:
|
||||
return "Error"
|
||||
case itemNIL:
|
||||
return "NIL"
|
||||
case itemEOF:
|
||||
return "EOF"
|
||||
case itemText:
|
||||
return "Text"
|
||||
case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
|
||||
return "String"
|
||||
case itemBool:
|
||||
return "Bool"
|
||||
case itemInteger:
|
||||
return "Integer"
|
||||
case itemFloat:
|
||||
return "Float"
|
||||
case itemDatetime:
|
||||
return "DateTime"
|
||||
case itemTableStart:
|
||||
return "TableStart"
|
||||
case itemTableEnd:
|
||||
return "TableEnd"
|
||||
case itemKeyStart:
|
||||
return "KeyStart"
|
||||
case itemArray:
|
||||
return "Array"
|
||||
case itemArrayEnd:
|
||||
return "ArrayEnd"
|
||||
case itemCommentStart:
|
||||
return "CommentStart"
|
||||
}
|
||||
panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
|
||||
}
|
||||
|
||||
func (item item) String() string {
|
||||
return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val)
|
||||
}
|
||||
557
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
Normal file
557
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
Normal file
@@ -0,0 +1,557 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type parser struct {
|
||||
mapping map[string]interface{}
|
||||
types map[string]tomlType
|
||||
lx *lexer
|
||||
|
||||
// A list of keys in the order that they appear in the TOML data.
|
||||
ordered []Key
|
||||
|
||||
// the full key for the current hash in scope
|
||||
context Key
|
||||
|
||||
// the base key name for everything except hashes
|
||||
currentKey string
|
||||
|
||||
// rough approximation of line number
|
||||
approxLine int
|
||||
|
||||
// A map of 'key.group.names' to whether they were created implicitly.
|
||||
implicits map[string]bool
|
||||
}
|
||||
|
||||
type parseError string
|
||||
|
||||
func (pe parseError) Error() string {
|
||||
return string(pe)
|
||||
}
|
||||
|
||||
func parse(data string) (p *parser, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
var ok bool
|
||||
if err, ok = r.(parseError); ok {
|
||||
return
|
||||
}
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
p = &parser{
|
||||
mapping: make(map[string]interface{}),
|
||||
types: make(map[string]tomlType),
|
||||
lx: lex(data),
|
||||
ordered: make([]Key, 0),
|
||||
implicits: make(map[string]bool),
|
||||
}
|
||||
for {
|
||||
item := p.next()
|
||||
if item.typ == itemEOF {
|
||||
break
|
||||
}
|
||||
p.topLevel(item)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *parser) panicf(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s",
|
||||
p.approxLine, p.current(), fmt.Sprintf(format, v...))
|
||||
panic(parseError(msg))
|
||||
}
|
||||
|
||||
func (p *parser) next() item {
|
||||
it := p.lx.nextItem()
|
||||
if it.typ == itemError {
|
||||
p.panicf("%s", it.val)
|
||||
}
|
||||
return it
|
||||
}
|
||||
|
||||
func (p *parser) bug(format string, v ...interface{}) {
|
||||
panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
|
||||
}
|
||||
|
||||
func (p *parser) expect(typ itemType) item {
|
||||
it := p.next()
|
||||
p.assertEqual(typ, it.typ)
|
||||
return it
|
||||
}
|
||||
|
||||
func (p *parser) assertEqual(expected, got itemType) {
|
||||
if expected != got {
|
||||
p.bug("Expected '%s' but got '%s'.", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) topLevel(item item) {
|
||||
switch item.typ {
|
||||
case itemCommentStart:
|
||||
p.approxLine = item.line
|
||||
p.expect(itemText)
|
||||
case itemTableStart:
|
||||
kg := p.next()
|
||||
p.approxLine = kg.line
|
||||
|
||||
var key Key
|
||||
for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() {
|
||||
key = append(key, p.keyString(kg))
|
||||
}
|
||||
p.assertEqual(itemTableEnd, kg.typ)
|
||||
|
||||
p.establishContext(key, false)
|
||||
p.setType("", tomlHash)
|
||||
p.ordered = append(p.ordered, key)
|
||||
case itemArrayTableStart:
|
||||
kg := p.next()
|
||||
p.approxLine = kg.line
|
||||
|
||||
var key Key
|
||||
for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() {
|
||||
key = append(key, p.keyString(kg))
|
||||
}
|
||||
p.assertEqual(itemArrayTableEnd, kg.typ)
|
||||
|
||||
p.establishContext(key, true)
|
||||
p.setType("", tomlArrayHash)
|
||||
p.ordered = append(p.ordered, key)
|
||||
case itemKeyStart:
|
||||
kname := p.next()
|
||||
p.approxLine = kname.line
|
||||
p.currentKey = p.keyString(kname)
|
||||
|
||||
val, typ := p.value(p.next())
|
||||
p.setValue(p.currentKey, val)
|
||||
p.setType(p.currentKey, typ)
|
||||
p.ordered = append(p.ordered, p.context.add(p.currentKey))
|
||||
p.currentKey = ""
|
||||
default:
|
||||
p.bug("Unexpected type at top level: %s", item.typ)
|
||||
}
|
||||
}
|
||||
|
||||
// Gets a string for a key (or part of a key in a table name).
|
||||
func (p *parser) keyString(it item) string {
|
||||
switch it.typ {
|
||||
case itemText:
|
||||
return it.val
|
||||
case itemString, itemMultilineString,
|
||||
itemRawString, itemRawMultilineString:
|
||||
s, _ := p.value(it)
|
||||
return s.(string)
|
||||
default:
|
||||
p.bug("Unexpected key type: %s", it.typ)
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// value translates an expected value from the lexer into a Go value wrapped
|
||||
// as an empty interface.
|
||||
func (p *parser) value(it item) (interface{}, tomlType) {
|
||||
switch it.typ {
|
||||
case itemString:
|
||||
return p.replaceEscapes(it.val), p.typeOfPrimitive(it)
|
||||
case itemMultilineString:
|
||||
trimmed := stripFirstNewline(stripEscapedWhitespace(it.val))
|
||||
return p.replaceEscapes(trimmed), p.typeOfPrimitive(it)
|
||||
case itemRawString:
|
||||
return it.val, p.typeOfPrimitive(it)
|
||||
case itemRawMultilineString:
|
||||
return stripFirstNewline(it.val), p.typeOfPrimitive(it)
|
||||
case itemBool:
|
||||
switch it.val {
|
||||
case "true":
|
||||
return true, p.typeOfPrimitive(it)
|
||||
case "false":
|
||||
return false, p.typeOfPrimitive(it)
|
||||
}
|
||||
p.bug("Expected boolean value, but got '%s'.", it.val)
|
||||
case itemInteger:
|
||||
if !numUnderscoresOK(it.val) {
|
||||
p.panicf("Invalid integer %q: underscores must be surrounded by digits",
|
||||
it.val)
|
||||
}
|
||||
val := strings.Replace(it.val, "_", "", -1)
|
||||
num, err := strconv.ParseInt(val, 10, 64)
|
||||
if err != nil {
|
||||
// Distinguish integer values. Normally, it'd be a bug if the lexer
|
||||
// provides an invalid integer, but it's possible that the number is
|
||||
// out of range of valid values (which the lexer cannot determine).
|
||||
// So mark the former as a bug but the latter as a legitimate user
|
||||
// error.
|
||||
if e, ok := err.(*strconv.NumError); ok &&
|
||||
e.Err == strconv.ErrRange {
|
||||
|
||||
p.panicf("Integer '%s' is out of the range of 64-bit "+
|
||||
"signed integers.", it.val)
|
||||
} else {
|
||||
p.bug("Expected integer value, but got '%s'.", it.val)
|
||||
}
|
||||
}
|
||||
return num, p.typeOfPrimitive(it)
|
||||
case itemFloat:
|
||||
parts := strings.FieldsFunc(it.val, func(r rune) bool {
|
||||
switch r {
|
||||
case '.', 'e', 'E':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
for _, part := range parts {
|
||||
if !numUnderscoresOK(part) {
|
||||
p.panicf("Invalid float %q: underscores must be "+
|
||||
"surrounded by digits", it.val)
|
||||
}
|
||||
}
|
||||
if !numPeriodsOK(it.val) {
|
||||
// As a special case, numbers like '123.' or '1.e2',
|
||||
// which are valid as far as Go/strconv are concerned,
|
||||
// must be rejected because TOML says that a fractional
|
||||
// part consists of '.' followed by 1+ digits.
|
||||
p.panicf("Invalid float %q: '.' must be followed "+
|
||||
"by one or more digits", it.val)
|
||||
}
|
||||
val := strings.Replace(it.val, "_", "", -1)
|
||||
num, err := strconv.ParseFloat(val, 64)
|
||||
if err != nil {
|
||||
if e, ok := err.(*strconv.NumError); ok &&
|
||||
e.Err == strconv.ErrRange {
|
||||
|
||||
p.panicf("Float '%s' is out of the range of 64-bit "+
|
||||
"IEEE-754 floating-point numbers.", it.val)
|
||||
} else {
|
||||
p.panicf("Invalid float value: %q", it.val)
|
||||
}
|
||||
}
|
||||
return num, p.typeOfPrimitive(it)
|
||||
case itemDatetime:
|
||||
var t time.Time
|
||||
var ok bool
|
||||
var err error
|
||||
for _, format := range []string{
|
||||
"2006-01-02T15:04:05Z07:00",
|
||||
"2006-01-02T15:04:05",
|
||||
"2006-01-02",
|
||||
} {
|
||||
t, err = time.ParseInLocation(format, it.val, time.Local)
|
||||
if err == nil {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
p.panicf("Invalid TOML Datetime: %q.", it.val)
|
||||
}
|
||||
return t, p.typeOfPrimitive(it)
|
||||
case itemArray:
|
||||
array := make([]interface{}, 0)
|
||||
types := make([]tomlType, 0)
|
||||
|
||||
for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
|
||||
if it.typ == itemCommentStart {
|
||||
p.expect(itemText)
|
||||
continue
|
||||
}
|
||||
|
||||
val, typ := p.value(it)
|
||||
array = append(array, val)
|
||||
types = append(types, typ)
|
||||
}
|
||||
return array, p.typeOfArray(types)
|
||||
}
|
||||
p.bug("Unexpected value type: %s", it.typ)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// numUnderscoresOK checks whether each underscore in s is surrounded by
|
||||
// characters that are not underscores.
|
||||
func numUnderscoresOK(s string) bool {
|
||||
accept := false
|
||||
for _, r := range s {
|
||||
if r == '_' {
|
||||
if !accept {
|
||||
return false
|
||||
}
|
||||
accept = false
|
||||
continue
|
||||
}
|
||||
accept = true
|
||||
}
|
||||
return accept
|
||||
}
|
||||
|
||||
// numPeriodsOK checks whether every period in s is followed by a digit.
|
||||
func numPeriodsOK(s string) bool {
|
||||
period := false
|
||||
for _, r := range s {
|
||||
if period && !isDigit(r) {
|
||||
return false
|
||||
}
|
||||
period = r == '.'
|
||||
}
|
||||
return !period
|
||||
}
|
||||
|
||||
// establishContext sets the current context of the parser,
|
||||
// where the context is either a hash or an array of hashes. Which one is
|
||||
// set depends on the value of the `array` parameter.
|
||||
//
|
||||
// Establishing the context also makes sure that the key isn't a duplicate, and
|
||||
// will create implicit hashes automatically.
|
||||
func (p *parser) establishContext(key Key, array bool) {
|
||||
var ok bool
|
||||
|
||||
// Always start at the top level and drill down for our context.
|
||||
hashContext := p.mapping
|
||||
keyContext := make(Key, 0)
|
||||
|
||||
// We only need implicit hashes for key[0:-1]
|
||||
for _, k := range key[0 : len(key)-1] {
|
||||
_, ok = hashContext[k]
|
||||
keyContext = append(keyContext, k)
|
||||
|
||||
// No key? Make an implicit hash and move on.
|
||||
if !ok {
|
||||
p.addImplicit(keyContext)
|
||||
hashContext[k] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// If the hash context is actually an array of tables, then set
|
||||
// the hash context to the last element in that array.
|
||||
//
|
||||
// Otherwise, it better be a table, since this MUST be a key group (by
|
||||
// virtue of it not being the last element in a key).
|
||||
switch t := hashContext[k].(type) {
|
||||
case []map[string]interface{}:
|
||||
hashContext = t[len(t)-1]
|
||||
case map[string]interface{}:
|
||||
hashContext = t
|
||||
default:
|
||||
p.panicf("Key '%s' was already created as a hash.", keyContext)
|
||||
}
|
||||
}
|
||||
|
||||
p.context = keyContext
|
||||
if array {
|
||||
// If this is the first element for this array, then allocate a new
|
||||
// list of tables for it.
|
||||
k := key[len(key)-1]
|
||||
if _, ok := hashContext[k]; !ok {
|
||||
hashContext[k] = make([]map[string]interface{}, 0, 5)
|
||||
}
|
||||
|
||||
// Add a new table. But make sure the key hasn't already been used
|
||||
// for something else.
|
||||
if hash, ok := hashContext[k].([]map[string]interface{}); ok {
|
||||
hashContext[k] = append(hash, make(map[string]interface{}))
|
||||
} else {
|
||||
p.panicf("Key '%s' was already created and cannot be used as "+
|
||||
"an array.", keyContext)
|
||||
}
|
||||
} else {
|
||||
p.setValue(key[len(key)-1], make(map[string]interface{}))
|
||||
}
|
||||
p.context = append(p.context, key[len(key)-1])
|
||||
}
|
||||
|
||||
// setValue sets the given key to the given value in the current context.
|
||||
// It will make sure that the key hasn't already been defined, account for
|
||||
// implicit key groups.
|
||||
func (p *parser) setValue(key string, value interface{}) {
|
||||
var tmpHash interface{}
|
||||
var ok bool
|
||||
|
||||
hash := p.mapping
|
||||
keyContext := make(Key, 0)
|
||||
for _, k := range p.context {
|
||||
keyContext = append(keyContext, k)
|
||||
if tmpHash, ok = hash[k]; !ok {
|
||||
p.bug("Context for key '%s' has not been established.", keyContext)
|
||||
}
|
||||
switch t := tmpHash.(type) {
|
||||
case []map[string]interface{}:
|
||||
// The context is a table of hashes. Pick the most recent table
|
||||
// defined as the current hash.
|
||||
hash = t[len(t)-1]
|
||||
case map[string]interface{}:
|
||||
hash = t
|
||||
default:
|
||||
p.bug("Expected hash to have type 'map[string]interface{}', but "+
|
||||
"it has '%T' instead.", tmpHash)
|
||||
}
|
||||
}
|
||||
keyContext = append(keyContext, key)
|
||||
|
||||
if _, ok := hash[key]; ok {
|
||||
// Typically, if the given key has already been set, then we have
|
||||
// to raise an error since duplicate keys are disallowed. However,
|
||||
// it's possible that a key was previously defined implicitly. In this
|
||||
// case, it is allowed to be redefined concretely. (See the
|
||||
// `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.)
|
||||
//
|
||||
// But we have to make sure to stop marking it as an implicit. (So that
|
||||
// another redefinition provokes an error.)
|
||||
//
|
||||
// Note that since it has already been defined (as a hash), we don't
|
||||
// want to overwrite it. So our business is done.
|
||||
if p.isImplicit(keyContext) {
|
||||
p.removeImplicit(keyContext)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, we have a concrete key trying to override a previous
|
||||
// key, which is *always* wrong.
|
||||
p.panicf("Key '%s' has already been defined.", keyContext)
|
||||
}
|
||||
hash[key] = value
|
||||
}
|
||||
|
||||
// setType sets the type of a particular value at a given key.
|
||||
// It should be called immediately AFTER setValue.
|
||||
//
|
||||
// Note that if `key` is empty, then the type given will be applied to the
|
||||
// current context (which is either a table or an array of tables).
|
||||
func (p *parser) setType(key string, typ tomlType) {
|
||||
keyContext := make(Key, 0, len(p.context)+1)
|
||||
for _, k := range p.context {
|
||||
keyContext = append(keyContext, k)
|
||||
}
|
||||
if len(key) > 0 { // allow type setting for hashes
|
||||
keyContext = append(keyContext, key)
|
||||
}
|
||||
p.types[keyContext.String()] = typ
|
||||
}
|
||||
|
||||
// addImplicit sets the given Key as having been created implicitly.
|
||||
func (p *parser) addImplicit(key Key) {
|
||||
p.implicits[key.String()] = true
|
||||
}
|
||||
|
||||
// removeImplicit stops tagging the given key as having been implicitly
|
||||
// created.
|
||||
func (p *parser) removeImplicit(key Key) {
|
||||
p.implicits[key.String()] = false
|
||||
}
|
||||
|
||||
// isImplicit returns true if the key group pointed to by the key was created
|
||||
// implicitly.
|
||||
func (p *parser) isImplicit(key Key) bool {
|
||||
return p.implicits[key.String()]
|
||||
}
|
||||
|
||||
// current returns the full key name of the current context.
|
||||
func (p *parser) current() string {
|
||||
if len(p.currentKey) == 0 {
|
||||
return p.context.String()
|
||||
}
|
||||
if len(p.context) == 0 {
|
||||
return p.currentKey
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", p.context, p.currentKey)
|
||||
}
|
||||
|
||||
func stripFirstNewline(s string) string {
|
||||
if len(s) == 0 || s[0] != '\n' {
|
||||
return s
|
||||
}
|
||||
return s[1:]
|
||||
}
|
||||
|
||||
func stripEscapedWhitespace(s string) string {
|
||||
esc := strings.Split(s, "\\\n")
|
||||
if len(esc) > 1 {
|
||||
for i := 1; i < len(esc); i++ {
|
||||
esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace)
|
||||
}
|
||||
}
|
||||
return strings.Join(esc, "")
|
||||
}
|
||||
|
||||
func (p *parser) replaceEscapes(str string) string {
|
||||
var replaced []rune
|
||||
s := []byte(str)
|
||||
r := 0
|
||||
for r < len(s) {
|
||||
if s[r] != '\\' {
|
||||
c, size := utf8.DecodeRune(s[r:])
|
||||
r += size
|
||||
replaced = append(replaced, c)
|
||||
continue
|
||||
}
|
||||
r += 1
|
||||
if r >= len(s) {
|
||||
p.bug("Escape sequence at end of string.")
|
||||
return ""
|
||||
}
|
||||
switch s[r] {
|
||||
default:
|
||||
p.bug("Expected valid escape code after \\, but got %q.", s[r])
|
||||
return ""
|
||||
case 'b':
|
||||
replaced = append(replaced, rune(0x0008))
|
||||
r += 1
|
||||
case 't':
|
||||
replaced = append(replaced, rune(0x0009))
|
||||
r += 1
|
||||
case 'n':
|
||||
replaced = append(replaced, rune(0x000A))
|
||||
r += 1
|
||||
case 'f':
|
||||
replaced = append(replaced, rune(0x000C))
|
||||
r += 1
|
||||
case 'r':
|
||||
replaced = append(replaced, rune(0x000D))
|
||||
r += 1
|
||||
case '"':
|
||||
replaced = append(replaced, rune(0x0022))
|
||||
r += 1
|
||||
case '\\':
|
||||
replaced = append(replaced, rune(0x005C))
|
||||
r += 1
|
||||
case 'u':
|
||||
// At this point, we know we have a Unicode escape of the form
|
||||
// `uXXXX` at [r, r+5). (Because the lexer guarantees this
|
||||
// for us.)
|
||||
escaped := p.asciiEscapeToUnicode(s[r+1 : r+5])
|
||||
replaced = append(replaced, escaped)
|
||||
r += 5
|
||||
case 'U':
|
||||
// At this point, we know we have a Unicode escape of the form
|
||||
// `uXXXX` at [r, r+9). (Because the lexer guarantees this
|
||||
// for us.)
|
||||
escaped := p.asciiEscapeToUnicode(s[r+1 : r+9])
|
||||
replaced = append(replaced, escaped)
|
||||
r += 9
|
||||
}
|
||||
}
|
||||
return string(replaced)
|
||||
}
|
||||
|
||||
func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
|
||||
s := string(bs)
|
||||
hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
|
||||
if err != nil {
|
||||
p.bug("Could not parse '%s' as a hexadecimal number, but the "+
|
||||
"lexer claims it's OK: %s", s, err)
|
||||
}
|
||||
if !utf8.ValidRune(rune(hex)) {
|
||||
p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
|
||||
}
|
||||
return rune(hex)
|
||||
}
|
||||
|
||||
func isStringType(ty itemType) bool {
|
||||
return ty == itemString || ty == itemMultilineString ||
|
||||
ty == itemRawString || ty == itemRawMultilineString
|
||||
}
|
||||
1
vendor/github.com/BurntSushi/toml/session.vim
generated
vendored
Normal file
1
vendor/github.com/BurntSushi/toml/session.vim
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
au BufWritePost *.go silent!make tags > /dev/null 2>&1
|
||||
91
vendor/github.com/BurntSushi/toml/type_check.go
generated
vendored
Normal file
91
vendor/github.com/BurntSushi/toml/type_check.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package toml
|
||||
|
||||
// tomlType represents any Go type that corresponds to a TOML type.
|
||||
// While the first draft of the TOML spec has a simplistic type system that
|
||||
// probably doesn't need this level of sophistication, we seem to be militating
|
||||
// toward adding real composite types.
|
||||
type tomlType interface {
|
||||
typeString() string
|
||||
}
|
||||
|
||||
// typeEqual accepts any two types and returns true if they are equal.
|
||||
func typeEqual(t1, t2 tomlType) bool {
|
||||
if t1 == nil || t2 == nil {
|
||||
return false
|
||||
}
|
||||
return t1.typeString() == t2.typeString()
|
||||
}
|
||||
|
||||
func typeIsHash(t tomlType) bool {
|
||||
return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
|
||||
}
|
||||
|
||||
type tomlBaseType string
|
||||
|
||||
func (btype tomlBaseType) typeString() string {
|
||||
return string(btype)
|
||||
}
|
||||
|
||||
func (btype tomlBaseType) String() string {
|
||||
return btype.typeString()
|
||||
}
|
||||
|
||||
var (
|
||||
tomlInteger tomlBaseType = "Integer"
|
||||
tomlFloat tomlBaseType = "Float"
|
||||
tomlDatetime tomlBaseType = "Datetime"
|
||||
tomlString tomlBaseType = "String"
|
||||
tomlBool tomlBaseType = "Bool"
|
||||
tomlArray tomlBaseType = "Array"
|
||||
tomlHash tomlBaseType = "Hash"
|
||||
tomlArrayHash tomlBaseType = "ArrayHash"
|
||||
)
|
||||
|
||||
// typeOfPrimitive returns a tomlType of any primitive value in TOML.
|
||||
// Primitive values are: Integer, Float, Datetime, String and Bool.
|
||||
//
|
||||
// Passing a lexer item other than the following will cause a BUG message
|
||||
// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
|
||||
func (p *parser) typeOfPrimitive(lexItem item) tomlType {
|
||||
switch lexItem.typ {
|
||||
case itemInteger:
|
||||
return tomlInteger
|
||||
case itemFloat:
|
||||
return tomlFloat
|
||||
case itemDatetime:
|
||||
return tomlDatetime
|
||||
case itemString:
|
||||
return tomlString
|
||||
case itemMultilineString:
|
||||
return tomlString
|
||||
case itemRawString:
|
||||
return tomlString
|
||||
case itemRawMultilineString:
|
||||
return tomlString
|
||||
case itemBool:
|
||||
return tomlBool
|
||||
}
|
||||
p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// typeOfArray returns a tomlType for an array given a list of types of its
|
||||
// values.
|
||||
//
|
||||
// In the current spec, if an array is homogeneous, then its type is always
|
||||
// "Array". If the array is not homogeneous, an error is generated.
|
||||
func (p *parser) typeOfArray(types []tomlType) tomlType {
|
||||
// Empty arrays are cool.
|
||||
if len(types) == 0 {
|
||||
return tomlArray
|
||||
}
|
||||
|
||||
theType := types[0]
|
||||
for _, t := range types[1:] {
|
||||
if !typeEqual(theType, t) {
|
||||
p.panicf("Array contains values of type '%s' and '%s', but "+
|
||||
"arrays must be homogeneous.", theType, t)
|
||||
}
|
||||
}
|
||||
return tomlArray
|
||||
}
|
||||
242
vendor/github.com/BurntSushi/toml/type_fields.go
generated
vendored
Normal file
242
vendor/github.com/BurntSushi/toml/type_fields.go
generated
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
package toml
|
||||
|
||||
// Struct field handling is adapted from code in encoding/json:
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the Go distribution.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A field represents a single field found in a struct.
|
||||
type field struct {
|
||||
name string // the name of the field (`toml` tag included)
|
||||
tag bool // whether field has a `toml` tag
|
||||
index []int // represents the depth of an anonymous field
|
||||
typ reflect.Type // the type of the field
|
||||
}
|
||||
|
||||
// byName sorts field by name, breaking ties with depth,
|
||||
// then breaking ties with "name came from toml tag", then
|
||||
// breaking ties with index sequence.
|
||||
type byName []field
|
||||
|
||||
func (x byName) Len() int { return len(x) }
|
||||
|
||||
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byName) Less(i, j int) bool {
|
||||
if x[i].name != x[j].name {
|
||||
return x[i].name < x[j].name
|
||||
}
|
||||
if len(x[i].index) != len(x[j].index) {
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
if x[i].tag != x[j].tag {
|
||||
return x[i].tag
|
||||
}
|
||||
return byIndex(x).Less(i, j)
|
||||
}
|
||||
|
||||
// byIndex sorts field by index sequence.
|
||||
type byIndex []field
|
||||
|
||||
func (x byIndex) Len() int { return len(x) }
|
||||
|
||||
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byIndex) Less(i, j int) bool {
|
||||
for k, xik := range x[i].index {
|
||||
if k >= len(x[j].index) {
|
||||
return false
|
||||
}
|
||||
if xik != x[j].index[k] {
|
||||
return xik < x[j].index[k]
|
||||
}
|
||||
}
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
|
||||
// typeFields returns a list of fields that TOML should recognize for the given
|
||||
// type. The algorithm is breadth-first search over the set of structs to
|
||||
// include - the top struct and then any reachable anonymous structs.
|
||||
func typeFields(t reflect.Type) []field {
|
||||
// Anonymous fields to explore at the current level and the next.
|
||||
current := []field{}
|
||||
next := []field{{typ: t}}
|
||||
|
||||
// Count of queued names for current level and the next.
|
||||
count := map[reflect.Type]int{}
|
||||
nextCount := map[reflect.Type]int{}
|
||||
|
||||
// Types already visited at an earlier level.
|
||||
visited := map[reflect.Type]bool{}
|
||||
|
||||
// Fields found.
|
||||
var fields []field
|
||||
|
||||
for len(next) > 0 {
|
||||
current, next = next, current[:0]
|
||||
count, nextCount = nextCount, map[reflect.Type]int{}
|
||||
|
||||
for _, f := range current {
|
||||
if visited[f.typ] {
|
||||
continue
|
||||
}
|
||||
visited[f.typ] = true
|
||||
|
||||
// Scan f.typ for fields to include.
|
||||
for i := 0; i < f.typ.NumField(); i++ {
|
||||
sf := f.typ.Field(i)
|
||||
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||
continue
|
||||
}
|
||||
opts := getOptions(sf.Tag)
|
||||
if opts.skip {
|
||||
continue
|
||||
}
|
||||
index := make([]int, len(f.index)+1)
|
||||
copy(index, f.index)
|
||||
index[len(f.index)] = i
|
||||
|
||||
ft := sf.Type
|
||||
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
|
||||
// Follow pointer.
|
||||
ft = ft.Elem()
|
||||
}
|
||||
|
||||
// Record found field and index sequence.
|
||||
if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||
tagged := opts.name != ""
|
||||
name := opts.name
|
||||
if name == "" {
|
||||
name = sf.Name
|
||||
}
|
||||
fields = append(fields, field{name, tagged, index, ft})
|
||||
if count[f.typ] > 1 {
|
||||
// If there were multiple instances, add a second,
|
||||
// so that the annihilation code will see a duplicate.
|
||||
// It only cares about the distinction between 1 or 2,
|
||||
// so don't bother generating any more copies.
|
||||
fields = append(fields, fields[len(fields)-1])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Record new anonymous struct to explore in next round.
|
||||
nextCount[ft]++
|
||||
if nextCount[ft] == 1 {
|
||||
f := field{name: ft.Name(), index: index, typ: ft}
|
||||
next = append(next, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(byName(fields))
|
||||
|
||||
// Delete all fields that are hidden by the Go rules for embedded fields,
|
||||
// except that fields with TOML tags are promoted.
|
||||
|
||||
// The fields are sorted in primary order of name, secondary order
|
||||
// of field index length. Loop over names; for each name, delete
|
||||
// hidden fields by choosing the one dominant field that survives.
|
||||
out := fields[:0]
|
||||
for advance, i := 0, 0; i < len(fields); i += advance {
|
||||
// One iteration per name.
|
||||
// Find the sequence of fields with the name of this first field.
|
||||
fi := fields[i]
|
||||
name := fi.name
|
||||
for advance = 1; i+advance < len(fields); advance++ {
|
||||
fj := fields[i+advance]
|
||||
if fj.name != name {
|
||||
break
|
||||
}
|
||||
}
|
||||
if advance == 1 { // Only one field with this name
|
||||
out = append(out, fi)
|
||||
continue
|
||||
}
|
||||
dominant, ok := dominantField(fields[i : i+advance])
|
||||
if ok {
|
||||
out = append(out, dominant)
|
||||
}
|
||||
}
|
||||
|
||||
fields = out
|
||||
sort.Sort(byIndex(fields))
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// dominantField looks through the fields, all of which are known to
|
||||
// have the same name, to find the single field that dominates the
|
||||
// others using Go's embedding rules, modified by the presence of
|
||||
// TOML tags. If there are multiple top-level fields, the boolean
|
||||
// will be false: This condition is an error in Go and we skip all
|
||||
// the fields.
|
||||
func dominantField(fields []field) (field, bool) {
|
||||
// The fields are sorted in increasing index-length order. The winner
|
||||
// must therefore be one with the shortest index length. Drop all
|
||||
// longer entries, which is easy: just truncate the slice.
|
||||
length := len(fields[0].index)
|
||||
tagged := -1 // Index of first tagged field.
|
||||
for i, f := range fields {
|
||||
if len(f.index) > length {
|
||||
fields = fields[:i]
|
||||
break
|
||||
}
|
||||
if f.tag {
|
||||
if tagged >= 0 {
|
||||
// Multiple tagged fields at the same level: conflict.
|
||||
// Return no field.
|
||||
return field{}, false
|
||||
}
|
||||
tagged = i
|
||||
}
|
||||
}
|
||||
if tagged >= 0 {
|
||||
return fields[tagged], true
|
||||
}
|
||||
// All remaining fields have the same length. If there's more than one,
|
||||
// we have a conflict (two fields named "X" at the same level) and we
|
||||
// return no field.
|
||||
if len(fields) > 1 {
|
||||
return field{}, false
|
||||
}
|
||||
return fields[0], true
|
||||
}
|
||||
|
||||
var fieldCache struct {
|
||||
sync.RWMutex
|
||||
m map[reflect.Type][]field
|
||||
}
|
||||
|
||||
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
|
||||
func cachedTypeFields(t reflect.Type) []field {
|
||||
fieldCache.RLock()
|
||||
f := fieldCache.m[t]
|
||||
fieldCache.RUnlock()
|
||||
if f != nil {
|
||||
return f
|
||||
}
|
||||
|
||||
// Compute fields without lock.
|
||||
// Might duplicate effort but won't hold other computations back.
|
||||
f = typeFields(t)
|
||||
if f == nil {
|
||||
f = []field{}
|
||||
}
|
||||
|
||||
fieldCache.Lock()
|
||||
if fieldCache.m == nil {
|
||||
fieldCache.m = map[reflect.Type][]field{}
|
||||
}
|
||||
fieldCache.m[t] = f
|
||||
fieldCache.Unlock()
|
||||
return f
|
||||
}
|
||||
28
vendor/github.com/imdario/mergo/LICENSE
generated
vendored
Normal file
28
vendor/github.com/imdario/mergo/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
Copyright (c) 2013 Dario Castañé. All rights reserved.
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
129
vendor/github.com/imdario/mergo/README.md
generated
vendored
Normal file
129
vendor/github.com/imdario/mergo/README.md
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
# Mergo
|
||||
|
||||
A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
|
||||
|
||||
Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region Marche.
|
||||
|
||||

|
||||
|
||||
## Status
|
||||
|
||||
It is ready for production use. It works fine after extensive use in the wild.
|
||||
|
||||
[![Build Status][1]][2]
|
||||
[![GoDoc][3]][4]
|
||||
[![GoCard][5]][6]
|
||||
|
||||
[1]: https://travis-ci.org/imdario/mergo.png
|
||||
[2]: https://travis-ci.org/imdario/mergo
|
||||
[3]: https://godoc.org/github.com/imdario/mergo?status.svg
|
||||
[4]: https://godoc.org/github.com/imdario/mergo
|
||||
[5]: https://goreportcard.com/badge/imdario/mergo
|
||||
[6]: https://goreportcard.com/report/github.com/imdario/mergo
|
||||
|
||||
### Important note
|
||||
|
||||
Mergo is intended to assign **only** zero value fields on destination with source value. Since April 6th it works like this. Before it didn't work properly, causing some random overwrites. After some issues and PRs I found it didn't merge as I designed it. Thanks to [imdario/mergo#8](https://github.com/imdario/mergo/pull/8) overwriting functions were added and the wrong behavior was clearly detected.
|
||||
|
||||
If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0).
|
||||
|
||||
### Mergo in the wild
|
||||
|
||||
- [docker/docker](https://github.com/docker/docker/)
|
||||
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
||||
- [imdario/zas](https://github.com/imdario/zas)
|
||||
- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
|
||||
- [EagerIO/Stout](https://github.com/EagerIO/Stout)
|
||||
- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
|
||||
- [russross/canvasassignments](https://github.com/russross/canvasassignments)
|
||||
- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
|
||||
- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
|
||||
- [divshot/gitling](https://github.com/divshot/gitling)
|
||||
- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
|
||||
- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
|
||||
- [elwinar/rambler](https://github.com/elwinar/rambler)
|
||||
- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
|
||||
- [jfbus/impressionist](https://github.com/jfbus/impressionist)
|
||||
- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
|
||||
- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
|
||||
- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
|
||||
- [thoas/picfit](https://github.com/thoas/picfit)
|
||||
- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
|
||||
- [jnuthong/item_search](https://github.com/jnuthong/item_search)
|
||||
- [Iris Web Framework](https://github.com/kataras/iris)
|
||||
|
||||
## Installation
|
||||
|
||||
go get github.com/imdario/mergo
|
||||
|
||||
// use in your .go code
|
||||
import (
|
||||
"github.com/imdario/mergo"
|
||||
)
|
||||
|
||||
## Usage
|
||||
|
||||
You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
if err := mergo.Merge(&dst, src); err != nil {
|
||||
// ...
|
||||
}
|
||||
|
||||
Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field.
|
||||
|
||||
if err := mergo.Map(&dst, srcMap); err != nil {
|
||||
// ...
|
||||
}
|
||||
|
||||
Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values.
|
||||
|
||||
More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo).
|
||||
|
||||
### Nice example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/imdario/mergo"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
A string
|
||||
B int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
src := Foo{
|
||||
A: "one",
|
||||
}
|
||||
|
||||
dest := Foo{
|
||||
A: "two",
|
||||
B: 2,
|
||||
}
|
||||
|
||||
mergo.Merge(&dest, src)
|
||||
|
||||
fmt.Println(dest)
|
||||
// Will print
|
||||
// {two 2}
|
||||
}
|
||||
```
|
||||
|
||||
Note: if test are failing due missing package, please execute:
|
||||
|
||||
go get gopkg.in/yaml.v1
|
||||
|
||||
## Contact me
|
||||
|
||||
If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
|
||||
|
||||
## About
|
||||
|
||||
Written by [Dario Castañé](http://dario.im).
|
||||
|
||||
## License
|
||||
|
||||
[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
|
||||
44
vendor/github.com/imdario/mergo/doc.go
generated
vendored
Normal file
44
vendor/github.com/imdario/mergo/doc.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||
// Copyright 2009 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.
|
||||
|
||||
/*
|
||||
Package mergo merges same-type structs and maps by setting default values in zero-value fields.
|
||||
|
||||
Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
Usage
|
||||
|
||||
From my own work-in-progress project:
|
||||
|
||||
type networkConfig struct {
|
||||
Protocol string
|
||||
Address string
|
||||
ServerType string `json: "server_type"`
|
||||
Port uint16
|
||||
}
|
||||
|
||||
type FssnConfig struct {
|
||||
Network networkConfig
|
||||
}
|
||||
|
||||
var fssnDefault = FssnConfig {
|
||||
networkConfig {
|
||||
"tcp",
|
||||
"127.0.0.1",
|
||||
"http",
|
||||
31560,
|
||||
},
|
||||
}
|
||||
|
||||
// Inside a function [...]
|
||||
|
||||
if err := mergo.Merge(&config, fssnDefault); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// More code [...]
|
||||
|
||||
*/
|
||||
package mergo
|
||||
156
vendor/github.com/imdario/mergo/map.go
generated
vendored
Normal file
156
vendor/github.com/imdario/mergo/map.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
// Copyright 2014 Dario Castañé. All rights reserved.
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Based on src/pkg/reflect/deepequal.go from official
|
||||
// golang's stdlib.
|
||||
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func changeInitialCase(s string, mapper func(rune) rune) string {
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
r, n := utf8.DecodeRuneInString(s)
|
||||
return string(mapper(r)) + s[n:]
|
||||
}
|
||||
|
||||
func isExported(field reflect.StructField) bool {
|
||||
r, _ := utf8.DecodeRuneInString(field.Name)
|
||||
return r >= 'A' && r <= 'Z'
|
||||
}
|
||||
|
||||
// Traverses recursively both values, assigning src's fields values to dst.
|
||||
// The map argument tracks comparisons that have already been seen, which allows
|
||||
// short circuiting on recursive types.
|
||||
func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, overwrite bool) (err error) {
|
||||
if dst.CanAddr() {
|
||||
addr := dst.UnsafeAddr()
|
||||
h := 17 * addr
|
||||
seen := visited[h]
|
||||
typ := dst.Type()
|
||||
for p := seen; p != nil; p = p.next {
|
||||
if p.ptr == addr && p.typ == typ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Remember, remember...
|
||||
visited[h] = &visit{addr, typ, seen}
|
||||
}
|
||||
zeroValue := reflect.Value{}
|
||||
switch dst.Kind() {
|
||||
case reflect.Map:
|
||||
dstMap := dst.Interface().(map[string]interface{})
|
||||
for i, n := 0, src.NumField(); i < n; i++ {
|
||||
srcType := src.Type()
|
||||
field := srcType.Field(i)
|
||||
if !isExported(field) {
|
||||
continue
|
||||
}
|
||||
fieldName := field.Name
|
||||
fieldName = changeInitialCase(fieldName, unicode.ToLower)
|
||||
if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
|
||||
dstMap[fieldName] = src.Field(i).Interface()
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
srcMap := src.Interface().(map[string]interface{})
|
||||
for key := range srcMap {
|
||||
srcValue := srcMap[key]
|
||||
fieldName := changeInitialCase(key, unicode.ToUpper)
|
||||
dstElement := dst.FieldByName(fieldName)
|
||||
if dstElement == zeroValue {
|
||||
// We discard it because the field doesn't exist.
|
||||
continue
|
||||
}
|
||||
srcElement := reflect.ValueOf(srcValue)
|
||||
dstKind := dstElement.Kind()
|
||||
srcKind := srcElement.Kind()
|
||||
if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
|
||||
srcElement = srcElement.Elem()
|
||||
srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
|
||||
} else if dstKind == reflect.Ptr {
|
||||
// Can this work? I guess it can't.
|
||||
if srcKind != reflect.Ptr && srcElement.CanAddr() {
|
||||
srcPtr := srcElement.Addr()
|
||||
srcElement = reflect.ValueOf(srcPtr)
|
||||
srcKind = reflect.Ptr
|
||||
}
|
||||
}
|
||||
if !srcElement.IsValid() {
|
||||
continue
|
||||
}
|
||||
if srcKind == dstKind {
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if srcKind == reflect.Map {
|
||||
if err = deepMap(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Map sets fields' values in dst from src.
|
||||
// src can be a map with string keys or a struct. dst must be the opposite:
|
||||
// if src is a map, dst must be a valid pointer to struct. If src is a struct,
|
||||
// dst must be map[string]interface{}.
|
||||
// It won't merge unexported (private) fields and will do recursively
|
||||
// any exported field.
|
||||
// If dst is a map, keys will be src fields' names in lower camel case.
|
||||
// Missing key in src that doesn't match a field in dst will be skipped. This
|
||||
// doesn't apply if dst is a map.
|
||||
// This is separated method from Merge because it is cleaner and it keeps sane
|
||||
// semantics: merging equal types, mapping different (restricted) types.
|
||||
func Map(dst, src interface{}) error {
|
||||
return _map(dst, src, false)
|
||||
}
|
||||
|
||||
// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overriden by
|
||||
// non-empty src attribute values.
|
||||
func MapWithOverwrite(dst, src interface{}) error {
|
||||
return _map(dst, src, true)
|
||||
}
|
||||
|
||||
func _map(dst, src interface{}, overwrite bool) error {
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
||||
err error
|
||||
)
|
||||
if vDst, vSrc, err = resolveValues(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
// To be friction-less, we redirect equal-type arguments
|
||||
// to deepMerge. Only because arguments can be anything.
|
||||
if vSrc.Kind() == vDst.Kind() {
|
||||
return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
|
||||
}
|
||||
switch vSrc.Kind() {
|
||||
case reflect.Struct:
|
||||
if vDst.Kind() != reflect.Map {
|
||||
return ErrExpectedMapAsDestination
|
||||
}
|
||||
case reflect.Map:
|
||||
if vDst.Kind() != reflect.Struct {
|
||||
return ErrExpectedStructAsDestination
|
||||
}
|
||||
default:
|
||||
return ErrNotSupported
|
||||
}
|
||||
return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
|
||||
}
|
||||
123
vendor/github.com/imdario/mergo/merge.go
generated
vendored
Normal file
123
vendor/github.com/imdario/mergo/merge.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Based on src/pkg/reflect/deepequal.go from official
|
||||
// golang's stdlib.
|
||||
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Traverses recursively both values, assigning src's fields values to dst.
|
||||
// The map argument tracks comparisons that have already been seen, which allows
|
||||
// short circuiting on recursive types.
|
||||
func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, overwrite bool) (err error) {
|
||||
if !src.IsValid() {
|
||||
return
|
||||
}
|
||||
if dst.CanAddr() {
|
||||
addr := dst.UnsafeAddr()
|
||||
h := 17 * addr
|
||||
seen := visited[h]
|
||||
typ := dst.Type()
|
||||
for p := seen; p != nil; p = p.next {
|
||||
if p.ptr == addr && p.typ == typ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Remember, remember...
|
||||
visited[h] = &visit{addr, typ, seen}
|
||||
}
|
||||
switch dst.Kind() {
|
||||
case reflect.Struct:
|
||||
for i, n := 0, dst.NumField(); i < n; i++ {
|
||||
if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, overwrite); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
for _, key := range src.MapKeys() {
|
||||
srcElement := src.MapIndex(key)
|
||||
if !srcElement.IsValid() {
|
||||
continue
|
||||
}
|
||||
dstElement := dst.MapIndex(key)
|
||||
switch srcElement.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
|
||||
if srcElement.IsNil() {
|
||||
continue
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
if !srcElement.CanInterface() {
|
||||
continue
|
||||
}
|
||||
switch reflect.TypeOf(srcElement.Interface()).Kind() {
|
||||
case reflect.Struct:
|
||||
fallthrough
|
||||
case reflect.Ptr:
|
||||
fallthrough
|
||||
case reflect.Map:
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, overwrite); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if !isEmptyValue(srcElement) && (overwrite || (!dstElement.IsValid() || isEmptyValue(dst))) {
|
||||
if dst.IsNil() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
}
|
||||
dst.SetMapIndex(key, srcElement)
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
fallthrough
|
||||
case reflect.Interface:
|
||||
if src.IsNil() {
|
||||
break
|
||||
} else if dst.IsNil() || overwrite {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, overwrite); err != nil {
|
||||
return
|
||||
}
|
||||
default:
|
||||
if dst.CanSet() && !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Merge will fill any empty for value type attributes on the dst struct using corresponding
|
||||
// src attributes if they themselves are not empty. dst and src must be valid same-type structs
|
||||
// and dst must be a pointer to struct.
|
||||
// It won't merge unexported (private) fields and will do recursively any exported field.
|
||||
func Merge(dst, src interface{}) error {
|
||||
return merge(dst, src, false)
|
||||
}
|
||||
|
||||
// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overriden by
|
||||
// non-empty src attribute values.
|
||||
func MergeWithOverwrite(dst, src interface{}) error {
|
||||
return merge(dst, src, true)
|
||||
}
|
||||
|
||||
func merge(dst, src interface{}, overwrite bool) error {
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
||||
err error
|
||||
)
|
||||
if vDst, vSrc, err = resolveValues(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
if vDst.Type() != vSrc.Type() {
|
||||
return ErrDifferentArgumentsTypes
|
||||
}
|
||||
return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, overwrite)
|
||||
}
|
||||
90
vendor/github.com/imdario/mergo/mergo.go
generated
vendored
Normal file
90
vendor/github.com/imdario/mergo/mergo.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||
// Copyright 2009 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.
|
||||
|
||||
// Based on src/pkg/reflect/deepequal.go from official
|
||||
// golang's stdlib.
|
||||
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Errors reported by Mergo when it finds invalid arguments.
|
||||
var (
|
||||
ErrNilArguments = errors.New("src and dst must not be nil")
|
||||
ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
|
||||
ErrNotSupported = errors.New("only structs and maps are supported")
|
||||
ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
|
||||
ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
|
||||
)
|
||||
|
||||
// During deepMerge, must keep track of checks that are
|
||||
// in progress. The comparison algorithm assumes that all
|
||||
// checks in progress are true when it reencounters them.
|
||||
// Visited are stored in a map indexed by 17 * a1 + a2;
|
||||
type visit struct {
|
||||
ptr uintptr
|
||||
typ reflect.Type
|
||||
next *visit
|
||||
}
|
||||
|
||||
// From src/pkg/encoding/json.
|
||||
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
|
||||
}
|
||||
|
||||
func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
|
||||
if dst == nil || src == nil {
|
||||
err = ErrNilArguments
|
||||
return
|
||||
}
|
||||
vDst = reflect.ValueOf(dst).Elem()
|
||||
if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
|
||||
err = ErrNotSupported
|
||||
return
|
||||
}
|
||||
vSrc = reflect.ValueOf(src)
|
||||
// We check if vSrc is a pointer to dereference it.
|
||||
if vSrc.Kind() == reflect.Ptr {
|
||||
vSrc = vSrc.Elem()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Traverses recursively both values, assigning src's fields values to dst.
|
||||
// The map argument tracks comparisons that have already been seen, which allows
|
||||
// short circuiting on recursive types.
|
||||
func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
|
||||
if dst.CanAddr() {
|
||||
addr := dst.UnsafeAddr()
|
||||
h := 17 * addr
|
||||
seen := visited[h]
|
||||
typ := dst.Type()
|
||||
for p := seen; p != nil; p = p.next {
|
||||
if p.ptr == addr && p.typ == typ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Remember, remember...
|
||||
visited[h] = &visit{addr, typ, seen}
|
||||
}
|
||||
return // TODO refactor
|
||||
}
|
||||
28
vendor/github.com/spf13/pflag/LICENSE
generated
vendored
Normal file
28
vendor/github.com/spf13/pflag/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
Copyright (c) 2012 Alex Ogier. All rights reserved.
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
277
vendor/github.com/spf13/pflag/README.md
generated
vendored
Normal file
277
vendor/github.com/spf13/pflag/README.md
generated
vendored
Normal file
@@ -0,0 +1,277 @@
|
||||
[](https://travis-ci.org/spf13/pflag)
|
||||
[](https://goreportcard.com/report/github.com/spf13/pflag)
|
||||
[](https://godoc.org/github.com/spf13/pflag)
|
||||
|
||||
## Description
|
||||
|
||||
pflag is a drop-in replacement for Go's flag package, implementing
|
||||
POSIX/GNU-style --flags.
|
||||
|
||||
pflag is compatible with the [GNU extensions to the POSIX recommendations
|
||||
for command-line options][1]. For a more precise description, see the
|
||||
"Command-line flag syntax" section below.
|
||||
|
||||
[1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
|
||||
|
||||
pflag is available under the same style of BSD license as the Go language,
|
||||
which can be found in the LICENSE file.
|
||||
|
||||
## Installation
|
||||
|
||||
pflag is available using the standard `go get` command.
|
||||
|
||||
Install by running:
|
||||
|
||||
go get github.com/spf13/pflag
|
||||
|
||||
Run tests by running:
|
||||
|
||||
go test github.com/spf13/pflag
|
||||
|
||||
## Usage
|
||||
|
||||
pflag is a drop-in replacement of Go's native flag package. If you import
|
||||
pflag under the name "flag" then all code should continue to function
|
||||
with no changes.
|
||||
|
||||
``` go
|
||||
import flag "github.com/spf13/pflag"
|
||||
```
|
||||
|
||||
There is one exception to this: if you directly instantiate the Flag struct
|
||||
there is one more field "Shorthand" that you will need to set.
|
||||
Most code never instantiates this struct directly, and instead uses
|
||||
functions such as String(), BoolVar(), and Var(), and is therefore
|
||||
unaffected.
|
||||
|
||||
Define flags using flag.String(), Bool(), Int(), etc.
|
||||
|
||||
This declares an integer flag, -flagname, stored in the pointer ip, with type *int.
|
||||
|
||||
``` go
|
||||
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
|
||||
```
|
||||
|
||||
If you like, you can bind the flag to a variable using the Var() functions.
|
||||
|
||||
``` go
|
||||
var flagvar int
|
||||
func init() {
|
||||
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
|
||||
}
|
||||
```
|
||||
|
||||
Or you can create custom flags that satisfy the Value interface (with
|
||||
pointer receivers) and couple them to flag parsing by
|
||||
|
||||
``` go
|
||||
flag.Var(&flagVal, "name", "help message for flagname")
|
||||
```
|
||||
|
||||
For such flags, the default value is just the initial value of the variable.
|
||||
|
||||
After all flags are defined, call
|
||||
|
||||
``` go
|
||||
flag.Parse()
|
||||
```
|
||||
|
||||
to parse the command line into the defined flags.
|
||||
|
||||
Flags may then be used directly. If you're using the flags themselves,
|
||||
they are all pointers; if you bind to variables, they're values.
|
||||
|
||||
``` go
|
||||
fmt.Println("ip has value ", *ip)
|
||||
fmt.Println("flagvar has value ", flagvar)
|
||||
```
|
||||
|
||||
There are helpers function to get values later if you have the FlagSet but
|
||||
it was difficult to keep up with all of the flag pointers in your code.
|
||||
If you have a pflag.FlagSet with a flag called 'flagname' of type int you
|
||||
can use GetInt() to get the int value. But notice that 'flagname' must exist
|
||||
and it must be an int. GetString("flagname") will fail.
|
||||
|
||||
``` go
|
||||
i, err := flagset.GetInt("flagname")
|
||||
```
|
||||
|
||||
After parsing, the arguments after the flag are available as the
|
||||
slice flag.Args() or individually as flag.Arg(i).
|
||||
The arguments are indexed from 0 through flag.NArg()-1.
|
||||
|
||||
The pflag package also defines some new functions that are not in flag,
|
||||
that give one-letter shorthands for flags. You can use these by appending
|
||||
'P' to the name of any function that defines a flag.
|
||||
|
||||
``` go
|
||||
var ip = flag.IntP("flagname", "f", 1234, "help message")
|
||||
var flagvar bool
|
||||
func init() {
|
||||
flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
|
||||
}
|
||||
flag.VarP(&flagVal, "varname", "v", "help message")
|
||||
```
|
||||
|
||||
Shorthand letters can be used with single dashes on the command line.
|
||||
Boolean shorthand flags can be combined with other shorthand flags.
|
||||
|
||||
The default set of command-line flags is controlled by
|
||||
top-level functions. The FlagSet type allows one to define
|
||||
independent sets of flags, such as to implement subcommands
|
||||
in a command-line interface. The methods of FlagSet are
|
||||
analogous to the top-level functions for the command-line
|
||||
flag set.
|
||||
|
||||
## Setting no option default values for flags
|
||||
|
||||
After you create a flag it is possible to set the pflag.NoOptDefVal for
|
||||
the given flag. Doing this changes the meaning of the flag slightly. If
|
||||
a flag has a NoOptDefVal and the flag is set on the command line without
|
||||
an option the flag will be set to the NoOptDefVal. For example given:
|
||||
|
||||
``` go
|
||||
var ip = flag.IntP("flagname", "f", 1234, "help message")
|
||||
flag.Lookup("flagname").NoOptDefVal = "4321"
|
||||
```
|
||||
|
||||
Would result in something like
|
||||
|
||||
| Parsed Arguments | Resulting Value |
|
||||
| ------------- | ------------- |
|
||||
| --flagname=1357 | ip=1357 |
|
||||
| --flagname | ip=4321 |
|
||||
| [nothing] | ip=1234 |
|
||||
|
||||
## Command line flag syntax
|
||||
|
||||
```
|
||||
--flag // boolean flags, or flags with no option default values
|
||||
--flag x // only on flags without a default value
|
||||
--flag=x
|
||||
```
|
||||
|
||||
Unlike the flag package, a single dash before an option means something
|
||||
different than a double dash. Single dashes signify a series of shorthand
|
||||
letters for flags. All but the last shorthand letter must be boolean flags
|
||||
or a flag with a default value
|
||||
|
||||
```
|
||||
// boolean or flags where the 'no option default value' is set
|
||||
-f
|
||||
-f=true
|
||||
-abc
|
||||
but
|
||||
-b true is INVALID
|
||||
|
||||
// non-boolean and flags without a 'no option default value'
|
||||
-n 1234
|
||||
-n=1234
|
||||
-n1234
|
||||
|
||||
// mixed
|
||||
-abcs "hello"
|
||||
-absd="hello"
|
||||
-abcs1234
|
||||
```
|
||||
|
||||
Flag parsing stops after the terminator "--". Unlike the flag package,
|
||||
flags can be interspersed with arguments anywhere on the command line
|
||||
before this terminator.
|
||||
|
||||
Integer flags accept 1234, 0664, 0x1234 and may be negative.
|
||||
Boolean flags (in their long form) accept 1, 0, t, f, true, false,
|
||||
TRUE, FALSE, True, False.
|
||||
Duration flags accept any input valid for time.ParseDuration.
|
||||
|
||||
## Mutating or "Normalizing" Flag names
|
||||
|
||||
It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow.
|
||||
|
||||
**Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag
|
||||
|
||||
``` go
|
||||
func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
from := []string{"-", "_"}
|
||||
to := "."
|
||||
for _, sep := range from {
|
||||
name = strings.Replace(name, sep, to, -1)
|
||||
}
|
||||
return pflag.NormalizedName(name)
|
||||
}
|
||||
|
||||
myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc)
|
||||
```
|
||||
|
||||
**Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name
|
||||
|
||||
``` go
|
||||
func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
switch name {
|
||||
case "old-flag-name":
|
||||
name = "new-flag-name"
|
||||
break
|
||||
}
|
||||
return pflag.NormalizedName(name)
|
||||
}
|
||||
|
||||
myFlagSet.SetNormalizeFunc(aliasNormalizeFunc)
|
||||
```
|
||||
|
||||
## Deprecating a flag or its shorthand
|
||||
It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used.
|
||||
|
||||
**Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead.
|
||||
```go
|
||||
// deprecate a flag by specifying its name and a usage message
|
||||
flags.MarkDeprecated("badflag", "please use --good-flag instead")
|
||||
```
|
||||
This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used.
|
||||
|
||||
**Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n".
|
||||
```go
|
||||
// deprecate a flag shorthand by specifying its flag name and a usage message
|
||||
flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only")
|
||||
```
|
||||
This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used.
|
||||
|
||||
Note that usage message is essential here, and it should not be empty.
|
||||
|
||||
## Hidden flags
|
||||
It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text.
|
||||
|
||||
**Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available.
|
||||
```go
|
||||
// hide a flag by specifying its name
|
||||
flags.MarkHidden("secretFlag")
|
||||
```
|
||||
|
||||
## Supporting Go flags when using pflag
|
||||
In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary
|
||||
to support flags defined by third-party dependencies (e.g. `golang/glog`).
|
||||
|
||||
**Example**: You want to add the Go flags to the `CommandLine` flagset
|
||||
```go
|
||||
import (
|
||||
goflag "flag"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
|
||||
|
||||
func main() {
|
||||
flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
|
||||
flag.Parse()
|
||||
}
|
||||
```
|
||||
|
||||
## More info
|
||||
|
||||
You can see the full reference documentation of the pflag package
|
||||
[at godoc.org][3], or through go's standard documentation system by
|
||||
running `godoc -http=:6060` and browsing to
|
||||
[http://localhost:6060/pkg/github.com/ogier/pflag][2] after
|
||||
installation.
|
||||
|
||||
[2]: http://localhost:6060/pkg/github.com/ogier/pflag
|
||||
[3]: http://godoc.org/github.com/ogier/pflag
|
||||
94
vendor/github.com/spf13/pflag/bool.go
generated
vendored
Normal file
94
vendor/github.com/spf13/pflag/bool.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// optional interface to indicate boolean flags that can be
|
||||
// supplied without "=value" text
|
||||
type boolFlag interface {
|
||||
Value
|
||||
IsBoolFlag() bool
|
||||
}
|
||||
|
||||
// -- bool Value
|
||||
type boolValue bool
|
||||
|
||||
func newBoolValue(val bool, p *bool) *boolValue {
|
||||
*p = val
|
||||
return (*boolValue)(p)
|
||||
}
|
||||
|
||||
func (b *boolValue) Set(s string) error {
|
||||
v, err := strconv.ParseBool(s)
|
||||
*b = boolValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *boolValue) Type() string {
|
||||
return "bool"
|
||||
}
|
||||
|
||||
func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) }
|
||||
|
||||
func (b *boolValue) IsBoolFlag() bool { return true }
|
||||
|
||||
func boolConv(sval string) (interface{}, error) {
|
||||
return strconv.ParseBool(sval)
|
||||
}
|
||||
|
||||
// GetBool return the bool value of a flag with the given name
|
||||
func (f *FlagSet) GetBool(name string) (bool, error) {
|
||||
val, err := f.getFlagType(name, "bool", boolConv)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return val.(bool), nil
|
||||
}
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a bool variable in which to store the value of the flag.
|
||||
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
|
||||
f.BoolVarP(p, name, "", value, usage)
|
||||
}
|
||||
|
||||
// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
|
||||
flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage)
|
||||
flag.NoOptDefVal = "true"
|
||||
}
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a bool variable in which to store the value of the flag.
|
||||
func BoolVar(p *bool, name string, value bool, usage string) {
|
||||
BoolVarP(p, name, "", value, usage)
|
||||
}
|
||||
|
||||
// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
|
||||
flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage)
|
||||
flag.NoOptDefVal = "true"
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a bool variable that stores the value of the flag.
|
||||
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
|
||||
return f.BoolP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool {
|
||||
p := new(bool)
|
||||
f.BoolVarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a bool variable that stores the value of the flag.
|
||||
func Bool(name string, value bool, usage string) *bool {
|
||||
return BoolP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash.
|
||||
func BoolP(name, shorthand string, value bool, usage string) *bool {
|
||||
b := CommandLine.BoolP(name, shorthand, value, usage)
|
||||
return b
|
||||
}
|
||||
147
vendor/github.com/spf13/pflag/bool_slice.go
generated
vendored
Normal file
147
vendor/github.com/spf13/pflag/bool_slice.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// -- boolSlice Value
|
||||
type boolSliceValue struct {
|
||||
value *[]bool
|
||||
changed bool
|
||||
}
|
||||
|
||||
func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue {
|
||||
bsv := new(boolSliceValue)
|
||||
bsv.value = p
|
||||
*bsv.value = val
|
||||
return bsv
|
||||
}
|
||||
|
||||
// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag.
|
||||
// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended.
|
||||
func (s *boolSliceValue) Set(val string) error {
|
||||
|
||||
// remove all quote characters
|
||||
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
|
||||
|
||||
// read flag arguments with CSV parser
|
||||
boolStrSlice, err := readAsCSV(rmQuote.Replace(val))
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
// parse boolean values into slice
|
||||
out := make([]bool, 0, len(boolStrSlice))
|
||||
for _, boolStr := range boolStrSlice {
|
||||
b, err := strconv.ParseBool(strings.TrimSpace(boolStr))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, b)
|
||||
}
|
||||
|
||||
if !s.changed {
|
||||
*s.value = out
|
||||
} else {
|
||||
*s.value = append(*s.value, out...)
|
||||
}
|
||||
|
||||
s.changed = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns a string that uniquely represents this flag's type.
|
||||
func (s *boolSliceValue) Type() string {
|
||||
return "boolSlice"
|
||||
}
|
||||
|
||||
// String defines a "native" format for this boolean slice flag value.
|
||||
func (s *boolSliceValue) String() string {
|
||||
|
||||
boolStrSlice := make([]string, len(*s.value))
|
||||
for i, b := range *s.value {
|
||||
boolStrSlice[i] = strconv.FormatBool(b)
|
||||
}
|
||||
|
||||
out, _ := writeAsCSV(boolStrSlice)
|
||||
|
||||
return "[" + out + "]"
|
||||
}
|
||||
|
||||
func boolSliceConv(val string) (interface{}, error) {
|
||||
val = strings.Trim(val, "[]")
|
||||
// Empty string would cause a slice with one (empty) entry
|
||||
if len(val) == 0 {
|
||||
return []bool{}, nil
|
||||
}
|
||||
ss := strings.Split(val, ",")
|
||||
out := make([]bool, len(ss))
|
||||
for i, t := range ss {
|
||||
var err error
|
||||
out[i], err = strconv.ParseBool(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GetBoolSlice returns the []bool value of a flag with the given name.
|
||||
func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) {
|
||||
val, err := f.getFlagType(name, "boolSlice", boolSliceConv)
|
||||
if err != nil {
|
||||
return []bool{}, err
|
||||
}
|
||||
return val.([]bool), nil
|
||||
}
|
||||
|
||||
// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []bool variable in which to store the value of the flag.
|
||||
func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
|
||||
f.VarP(newBoolSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
|
||||
f.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// BoolSliceVar defines a []bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []bool variable in which to store the value of the flag.
|
||||
func BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
|
||||
CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
|
||||
CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// BoolSlice defines a []bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []bool variable that stores the value of the flag.
|
||||
func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool {
|
||||
p := []bool{}
|
||||
f.BoolSliceVarP(&p, name, "", value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
|
||||
p := []bool{}
|
||||
f.BoolSliceVarP(&p, name, shorthand, value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// BoolSlice defines a []bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []bool variable that stores the value of the flag.
|
||||
func BoolSlice(name string, value []bool, usage string) *[]bool {
|
||||
return CommandLine.BoolSliceP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
|
||||
return CommandLine.BoolSliceP(name, shorthand, value, usage)
|
||||
}
|
||||
94
vendor/github.com/spf13/pflag/count.go
generated
vendored
Normal file
94
vendor/github.com/spf13/pflag/count.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- count Value
|
||||
type countValue int
|
||||
|
||||
func newCountValue(val int, p *int) *countValue {
|
||||
*p = val
|
||||
return (*countValue)(p)
|
||||
}
|
||||
|
||||
func (i *countValue) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
// -1 means that no specific value was passed, so increment
|
||||
if v == -1 {
|
||||
*i = countValue(*i + 1)
|
||||
} else {
|
||||
*i = countValue(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *countValue) Type() string {
|
||||
return "count"
|
||||
}
|
||||
|
||||
func (i *countValue) String() string { return strconv.Itoa(int(*i)) }
|
||||
|
||||
func countConv(sval string) (interface{}, error) {
|
||||
i, err := strconv.Atoi(sval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// GetCount return the int value of a flag with the given name
|
||||
func (f *FlagSet) GetCount(name string) (int, error) {
|
||||
val, err := f.getFlagType(name, "count", countConv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(int), nil
|
||||
}
|
||||
|
||||
// CountVar defines a count flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
// A count flag will add 1 to its value evey time it is found on the command line
|
||||
func (f *FlagSet) CountVar(p *int, name string, usage string) {
|
||||
f.CountVarP(p, name, "", usage)
|
||||
}
|
||||
|
||||
// CountVarP is like CountVar only take a shorthand for the flag name.
|
||||
func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) {
|
||||
flag := f.VarPF(newCountValue(0, p), name, shorthand, usage)
|
||||
flag.NoOptDefVal = "-1"
|
||||
}
|
||||
|
||||
// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set
|
||||
func CountVar(p *int, name string, usage string) {
|
||||
CommandLine.CountVar(p, name, usage)
|
||||
}
|
||||
|
||||
// CountVarP is like CountVar only take a shorthand for the flag name.
|
||||
func CountVarP(p *int, name, shorthand string, usage string) {
|
||||
CommandLine.CountVarP(p, name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Count defines a count flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
// A count flag will add 1 to its value evey time it is found on the command line
|
||||
func (f *FlagSet) Count(name string, usage string) *int {
|
||||
p := new(int)
|
||||
f.CountVarP(p, name, "", usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// CountP is like Count only takes a shorthand for the flag name.
|
||||
func (f *FlagSet) CountP(name, shorthand string, usage string) *int {
|
||||
p := new(int)
|
||||
f.CountVarP(p, name, shorthand, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Count like Count only the flag is placed on the CommandLine isntead of a given flag set
|
||||
func Count(name string, usage string) *int {
|
||||
return CommandLine.CountP(name, "", usage)
|
||||
}
|
||||
|
||||
// CountP is like Count only takes a shorthand for the flag name.
|
||||
func CountP(name, shorthand string, usage string) *int {
|
||||
return CommandLine.CountP(name, shorthand, usage)
|
||||
}
|
||||
86
vendor/github.com/spf13/pflag/duration.go
generated
vendored
Normal file
86
vendor/github.com/spf13/pflag/duration.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// -- time.Duration Value
|
||||
type durationValue time.Duration
|
||||
|
||||
func newDurationValue(val time.Duration, p *time.Duration) *durationValue {
|
||||
*p = val
|
||||
return (*durationValue)(p)
|
||||
}
|
||||
|
||||
func (d *durationValue) Set(s string) error {
|
||||
v, err := time.ParseDuration(s)
|
||||
*d = durationValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *durationValue) Type() string {
|
||||
return "duration"
|
||||
}
|
||||
|
||||
func (d *durationValue) String() string { return (*time.Duration)(d).String() }
|
||||
|
||||
func durationConv(sval string) (interface{}, error) {
|
||||
return time.ParseDuration(sval)
|
||||
}
|
||||
|
||||
// GetDuration return the duration value of a flag with the given name
|
||||
func (f *FlagSet) GetDuration(name string) (time.Duration, error) {
|
||||
val, err := f.getFlagType(name, "duration", durationConv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(time.Duration), nil
|
||||
}
|
||||
|
||||
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The argument p points to a time.Duration variable in which to store the value of the flag.
|
||||
func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
||||
f.VarP(newDurationValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) {
|
||||
f.VarP(newDurationValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The argument p points to a time.Duration variable in which to store the value of the flag.
|
||||
func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
||||
CommandLine.VarP(newDurationValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) {
|
||||
CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Duration defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a time.Duration variable that stores the value of the flag.
|
||||
func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration {
|
||||
p := new(time.Duration)
|
||||
f.DurationVarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration {
|
||||
p := new(time.Duration)
|
||||
f.DurationVarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Duration defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a time.Duration variable that stores the value of the flag.
|
||||
func Duration(name string, value time.Duration, usage string) *time.Duration {
|
||||
return CommandLine.DurationP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash.
|
||||
func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration {
|
||||
return CommandLine.DurationP(name, shorthand, value, usage)
|
||||
}
|
||||
1063
vendor/github.com/spf13/pflag/flag.go
generated
vendored
Normal file
1063
vendor/github.com/spf13/pflag/flag.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
88
vendor/github.com/spf13/pflag/float32.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/float32.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- float32 Value
|
||||
type float32Value float32
|
||||
|
||||
func newFloat32Value(val float32, p *float32) *float32Value {
|
||||
*p = val
|
||||
return (*float32Value)(p)
|
||||
}
|
||||
|
||||
func (f *float32Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 32)
|
||||
*f = float32Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *float32Value) Type() string {
|
||||
return "float32"
|
||||
}
|
||||
|
||||
func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) }
|
||||
|
||||
func float32Conv(sval string) (interface{}, error) {
|
||||
v, err := strconv.ParseFloat(sval, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return float32(v), nil
|
||||
}
|
||||
|
||||
// GetFloat32 return the float32 value of a flag with the given name
|
||||
func (f *FlagSet) GetFloat32(name string) (float32, error) {
|
||||
val, err := f.getFlagType(name, "float32", float32Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(float32), nil
|
||||
}
|
||||
|
||||
// Float32Var defines a float32 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float32 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage string) {
|
||||
f.VarP(newFloat32Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) {
|
||||
f.VarP(newFloat32Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Float32Var defines a float32 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float32 variable in which to store the value of the flag.
|
||||
func Float32Var(p *float32, name string, value float32, usage string) {
|
||||
CommandLine.VarP(newFloat32Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Float32VarP(p *float32, name, shorthand string, value float32, usage string) {
|
||||
CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Float32 defines a float32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float32 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Float32(name string, value float32, usage string) *float32 {
|
||||
p := new(float32)
|
||||
f.Float32VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 {
|
||||
p := new(float32)
|
||||
f.Float32VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Float32 defines a float32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float32 variable that stores the value of the flag.
|
||||
func Float32(name string, value float32, usage string) *float32 {
|
||||
return CommandLine.Float32P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Float32P(name, shorthand string, value float32, usage string) *float32 {
|
||||
return CommandLine.Float32P(name, shorthand, value, usage)
|
||||
}
|
||||
84
vendor/github.com/spf13/pflag/float64.go
generated
vendored
Normal file
84
vendor/github.com/spf13/pflag/float64.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- float64 Value
|
||||
type float64Value float64
|
||||
|
||||
func newFloat64Value(val float64, p *float64) *float64Value {
|
||||
*p = val
|
||||
return (*float64Value)(p)
|
||||
}
|
||||
|
||||
func (f *float64Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
*f = float64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *float64Value) Type() string {
|
||||
return "float64"
|
||||
}
|
||||
|
||||
func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) }
|
||||
|
||||
func float64Conv(sval string) (interface{}, error) {
|
||||
return strconv.ParseFloat(sval, 64)
|
||||
}
|
||||
|
||||
// GetFloat64 return the float64 value of a flag with the given name
|
||||
func (f *FlagSet) GetFloat64(name string) (float64, error) {
|
||||
val, err := f.getFlagType(name, "float64", float64Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(float64), nil
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) {
|
||||
f.VarP(newFloat64Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) {
|
||||
f.VarP(newFloat64Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
||||
func Float64Var(p *float64, name string, value float64, usage string) {
|
||||
CommandLine.VarP(newFloat64Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Float64VarP(p *float64, name, shorthand string, value float64, usage string) {
|
||||
CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
|
||||
p := new(float64)
|
||||
f.Float64VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 {
|
||||
p := new(float64)
|
||||
f.Float64VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
||||
func Float64(name string, value float64, usage string) *float64 {
|
||||
return CommandLine.Float64P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Float64P(name, shorthand string, value float64, usage string) *float64 {
|
||||
return CommandLine.Float64P(name, shorthand, value, usage)
|
||||
}
|
||||
101
vendor/github.com/spf13/pflag/golangflag.go
generated
vendored
Normal file
101
vendor/github.com/spf13/pflag/golangflag.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
package pflag
|
||||
|
||||
import (
|
||||
goflag "flag"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// flagValueWrapper implements pflag.Value around a flag.Value. The main
|
||||
// difference here is the addition of the Type method that returns a string
|
||||
// name of the type. As this is generally unknown, we approximate that with
|
||||
// reflection.
|
||||
type flagValueWrapper struct {
|
||||
inner goflag.Value
|
||||
flagType string
|
||||
}
|
||||
|
||||
// We are just copying the boolFlag interface out of goflag as that is what
|
||||
// they use to decide if a flag should get "true" when no arg is given.
|
||||
type goBoolFlag interface {
|
||||
goflag.Value
|
||||
IsBoolFlag() bool
|
||||
}
|
||||
|
||||
func wrapFlagValue(v goflag.Value) Value {
|
||||
// If the flag.Value happens to also be a pflag.Value, just use it directly.
|
||||
if pv, ok := v.(Value); ok {
|
||||
return pv
|
||||
}
|
||||
|
||||
pv := &flagValueWrapper{
|
||||
inner: v,
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(v)
|
||||
if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
pv.flagType = strings.TrimSuffix(t.Name(), "Value")
|
||||
return pv
|
||||
}
|
||||
|
||||
func (v *flagValueWrapper) String() string {
|
||||
return v.inner.String()
|
||||
}
|
||||
|
||||
func (v *flagValueWrapper) Set(s string) error {
|
||||
return v.inner.Set(s)
|
||||
}
|
||||
|
||||
func (v *flagValueWrapper) Type() string {
|
||||
return v.flagType
|
||||
}
|
||||
|
||||
// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag
|
||||
// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei
|
||||
// with both `-v` and `--v` in flags. If the golang flag was more than a single
|
||||
// character (ex: `verbose`) it will only be accessible via `--verbose`
|
||||
func PFlagFromGoFlag(goflag *goflag.Flag) *Flag {
|
||||
// Remember the default value as a string; it won't change.
|
||||
flag := &Flag{
|
||||
Name: goflag.Name,
|
||||
Usage: goflag.Usage,
|
||||
Value: wrapFlagValue(goflag.Value),
|
||||
// Looks like golang flags don't set DefValue correctly :-(
|
||||
//DefValue: goflag.DefValue,
|
||||
DefValue: goflag.Value.String(),
|
||||
}
|
||||
// Ex: if the golang flag was -v, allow both -v and --v to work
|
||||
if len(flag.Name) == 1 {
|
||||
flag.Shorthand = flag.Name
|
||||
}
|
||||
if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() {
|
||||
flag.NoOptDefVal = "true"
|
||||
}
|
||||
return flag
|
||||
}
|
||||
|
||||
// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet
|
||||
func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) {
|
||||
if f.Lookup(goflag.Name) != nil {
|
||||
return
|
||||
}
|
||||
newflag := PFlagFromGoFlag(goflag)
|
||||
f.AddFlag(newflag)
|
||||
}
|
||||
|
||||
// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet
|
||||
func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) {
|
||||
if newSet == nil {
|
||||
return
|
||||
}
|
||||
newSet.VisitAll(func(goflag *goflag.Flag) {
|
||||
f.AddGoFlag(goflag)
|
||||
})
|
||||
}
|
||||
84
vendor/github.com/spf13/pflag/int.go
generated
vendored
Normal file
84
vendor/github.com/spf13/pflag/int.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- int Value
|
||||
type intValue int
|
||||
|
||||
func newIntValue(val int, p *int) *intValue {
|
||||
*p = val
|
||||
return (*intValue)(p)
|
||||
}
|
||||
|
||||
func (i *intValue) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = intValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *intValue) Type() string {
|
||||
return "int"
|
||||
}
|
||||
|
||||
func (i *intValue) String() string { return strconv.Itoa(int(*i)) }
|
||||
|
||||
func intConv(sval string) (interface{}, error) {
|
||||
return strconv.Atoi(sval)
|
||||
}
|
||||
|
||||
// GetInt return the int value of a flag with the given name
|
||||
func (f *FlagSet) GetInt(name string) (int, error) {
|
||||
val, err := f.getFlagType(name, "int", intConv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(int), nil
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
|
||||
f.VarP(newIntValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) {
|
||||
f.VarP(newIntValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
func IntVar(p *int, name string, value int, usage string) {
|
||||
CommandLine.VarP(newIntValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IntVarP(p *int, name, shorthand string, value int, usage string) {
|
||||
CommandLine.VarP(newIntValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int(name string, value int, usage string) *int {
|
||||
p := new(int)
|
||||
f.IntVarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// IntP is like Int, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int {
|
||||
p := new(int)
|
||||
f.IntVarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
func Int(name string, value int, usage string) *int {
|
||||
return CommandLine.IntP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// IntP is like Int, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IntP(name, shorthand string, value int, usage string) *int {
|
||||
return CommandLine.IntP(name, shorthand, value, usage)
|
||||
}
|
||||
88
vendor/github.com/spf13/pflag/int32.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/int32.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- int32 Value
|
||||
type int32Value int32
|
||||
|
||||
func newInt32Value(val int32, p *int32) *int32Value {
|
||||
*p = val
|
||||
return (*int32Value)(p)
|
||||
}
|
||||
|
||||
func (i *int32Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 32)
|
||||
*i = int32Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *int32Value) Type() string {
|
||||
return "int32"
|
||||
}
|
||||
|
||||
func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) }
|
||||
|
||||
func int32Conv(sval string) (interface{}, error) {
|
||||
v, err := strconv.ParseInt(sval, 0, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int32(v), nil
|
||||
}
|
||||
|
||||
// GetInt32 return the int32 value of a flag with the given name
|
||||
func (f *FlagSet) GetInt32(name string) (int32, error) {
|
||||
val, err := f.getFlagType(name, "int32", int32Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(int32), nil
|
||||
}
|
||||
|
||||
// Int32Var defines an int32 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int32 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) {
|
||||
f.VarP(newInt32Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) {
|
||||
f.VarP(newInt32Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Int32Var defines an int32 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int32 variable in which to store the value of the flag.
|
||||
func Int32Var(p *int32, name string, value int32, usage string) {
|
||||
CommandLine.VarP(newInt32Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int32VarP(p *int32, name, shorthand string, value int32, usage string) {
|
||||
CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Int32 defines an int32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int32 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int32(name string, value int32, usage string) *int32 {
|
||||
p := new(int32)
|
||||
f.Int32VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 {
|
||||
p := new(int32)
|
||||
f.Int32VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int32 defines an int32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int32 variable that stores the value of the flag.
|
||||
func Int32(name string, value int32, usage string) *int32 {
|
||||
return CommandLine.Int32P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int32P(name, shorthand string, value int32, usage string) *int32 {
|
||||
return CommandLine.Int32P(name, shorthand, value, usage)
|
||||
}
|
||||
84
vendor/github.com/spf13/pflag/int64.go
generated
vendored
Normal file
84
vendor/github.com/spf13/pflag/int64.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- int64 Value
|
||||
type int64Value int64
|
||||
|
||||
func newInt64Value(val int64, p *int64) *int64Value {
|
||||
*p = val
|
||||
return (*int64Value)(p)
|
||||
}
|
||||
|
||||
func (i *int64Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = int64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *int64Value) Type() string {
|
||||
return "int64"
|
||||
}
|
||||
|
||||
func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) }
|
||||
|
||||
func int64Conv(sval string) (interface{}, error) {
|
||||
return strconv.ParseInt(sval, 0, 64)
|
||||
}
|
||||
|
||||
// GetInt64 return the int64 value of a flag with the given name
|
||||
func (f *FlagSet) GetInt64(name string) (int64, error) {
|
||||
val, err := f.getFlagType(name, "int64", int64Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(int64), nil
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) {
|
||||
f.VarP(newInt64Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) {
|
||||
f.VarP(newInt64Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int64 variable in which to store the value of the flag.
|
||||
func Int64Var(p *int64, name string, value int64, usage string) {
|
||||
CommandLine.VarP(newInt64Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int64VarP(p *int64, name, shorthand string, value int64, usage string) {
|
||||
CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int64(name string, value int64, usage string) *int64 {
|
||||
p := new(int64)
|
||||
f.Int64VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 {
|
||||
p := new(int64)
|
||||
f.Int64VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int64 variable that stores the value of the flag.
|
||||
func Int64(name string, value int64, usage string) *int64 {
|
||||
return CommandLine.Int64P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int64P(name, shorthand string, value int64, usage string) *int64 {
|
||||
return CommandLine.Int64P(name, shorthand, value, usage)
|
||||
}
|
||||
88
vendor/github.com/spf13/pflag/int8.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/int8.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- int8 Value
|
||||
type int8Value int8
|
||||
|
||||
func newInt8Value(val int8, p *int8) *int8Value {
|
||||
*p = val
|
||||
return (*int8Value)(p)
|
||||
}
|
||||
|
||||
func (i *int8Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 8)
|
||||
*i = int8Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *int8Value) Type() string {
|
||||
return "int8"
|
||||
}
|
||||
|
||||
func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) }
|
||||
|
||||
func int8Conv(sval string) (interface{}, error) {
|
||||
v, err := strconv.ParseInt(sval, 0, 8)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int8(v), nil
|
||||
}
|
||||
|
||||
// GetInt8 return the int8 value of a flag with the given name
|
||||
func (f *FlagSet) GetInt8(name string) (int8, error) {
|
||||
val, err := f.getFlagType(name, "int8", int8Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(int8), nil
|
||||
}
|
||||
|
||||
// Int8Var defines an int8 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int8 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) {
|
||||
f.VarP(newInt8Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) {
|
||||
f.VarP(newInt8Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Int8Var defines an int8 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int8 variable in which to store the value of the flag.
|
||||
func Int8Var(p *int8, name string, value int8, usage string) {
|
||||
CommandLine.VarP(newInt8Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int8VarP(p *int8, name, shorthand string, value int8, usage string) {
|
||||
CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Int8 defines an int8 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int8 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int8(name string, value int8, usage string) *int8 {
|
||||
p := new(int8)
|
||||
f.Int8VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 {
|
||||
p := new(int8)
|
||||
f.Int8VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int8 defines an int8 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int8 variable that stores the value of the flag.
|
||||
func Int8(name string, value int8, usage string) *int8 {
|
||||
return CommandLine.Int8P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Int8P(name, shorthand string, value int8, usage string) *int8 {
|
||||
return CommandLine.Int8P(name, shorthand, value, usage)
|
||||
}
|
||||
128
vendor/github.com/spf13/pflag/int_slice.go
generated
vendored
Normal file
128
vendor/github.com/spf13/pflag/int_slice.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// -- intSlice Value
|
||||
type intSliceValue struct {
|
||||
value *[]int
|
||||
changed bool
|
||||
}
|
||||
|
||||
func newIntSliceValue(val []int, p *[]int) *intSliceValue {
|
||||
isv := new(intSliceValue)
|
||||
isv.value = p
|
||||
*isv.value = val
|
||||
return isv
|
||||
}
|
||||
|
||||
func (s *intSliceValue) Set(val string) error {
|
||||
ss := strings.Split(val, ",")
|
||||
out := make([]int, len(ss))
|
||||
for i, d := range ss {
|
||||
var err error
|
||||
out[i], err = strconv.Atoi(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
if !s.changed {
|
||||
*s.value = out
|
||||
} else {
|
||||
*s.value = append(*s.value, out...)
|
||||
}
|
||||
s.changed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *intSliceValue) Type() string {
|
||||
return "intSlice"
|
||||
}
|
||||
|
||||
func (s *intSliceValue) String() string {
|
||||
out := make([]string, len(*s.value))
|
||||
for i, d := range *s.value {
|
||||
out[i] = fmt.Sprintf("%d", d)
|
||||
}
|
||||
return "[" + strings.Join(out, ",") + "]"
|
||||
}
|
||||
|
||||
func intSliceConv(val string) (interface{}, error) {
|
||||
val = strings.Trim(val, "[]")
|
||||
// Empty string would cause a slice with one (empty) entry
|
||||
if len(val) == 0 {
|
||||
return []int{}, nil
|
||||
}
|
||||
ss := strings.Split(val, ",")
|
||||
out := make([]int, len(ss))
|
||||
for i, d := range ss {
|
||||
var err error
|
||||
out[i], err = strconv.Atoi(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GetIntSlice return the []int value of a flag with the given name
|
||||
func (f *FlagSet) GetIntSlice(name string) ([]int, error) {
|
||||
val, err := f.getFlagType(name, "intSlice", intSliceConv)
|
||||
if err != nil {
|
||||
return []int{}, err
|
||||
}
|
||||
return val.([]int), nil
|
||||
}
|
||||
|
||||
// IntSliceVar defines a intSlice flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []int variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IntSliceVar(p *[]int, name string, value []int, usage string) {
|
||||
f.VarP(newIntSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) {
|
||||
f.VarP(newIntSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IntSliceVar defines a int[] flag with specified name, default value, and usage string.
|
||||
// The argument p points to a int[] variable in which to store the value of the flag.
|
||||
func IntSliceVar(p *[]int, name string, value []int, usage string) {
|
||||
CommandLine.VarP(newIntSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) {
|
||||
CommandLine.VarP(newIntSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IntSlice defines a []int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []int variable that stores the value of the flag.
|
||||
func (f *FlagSet) IntSlice(name string, value []int, usage string) *[]int {
|
||||
p := []int{}
|
||||
f.IntSliceVarP(&p, name, "", value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IntSliceP(name, shorthand string, value []int, usage string) *[]int {
|
||||
p := []int{}
|
||||
f.IntSliceVarP(&p, name, shorthand, value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// IntSlice defines a []int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []int variable that stores the value of the flag.
|
||||
func IntSlice(name string, value []int, usage string) *[]int {
|
||||
return CommandLine.IntSliceP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IntSliceP(name, shorthand string, value []int, usage string) *[]int {
|
||||
return CommandLine.IntSliceP(name, shorthand, value, usage)
|
||||
}
|
||||
94
vendor/github.com/spf13/pflag/ip.go
generated
vendored
Normal file
94
vendor/github.com/spf13/pflag/ip.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// -- net.IP value
|
||||
type ipValue net.IP
|
||||
|
||||
func newIPValue(val net.IP, p *net.IP) *ipValue {
|
||||
*p = val
|
||||
return (*ipValue)(p)
|
||||
}
|
||||
|
||||
func (i *ipValue) String() string { return net.IP(*i).String() }
|
||||
func (i *ipValue) Set(s string) error {
|
||||
ip := net.ParseIP(strings.TrimSpace(s))
|
||||
if ip == nil {
|
||||
return fmt.Errorf("failed to parse IP: %q", s)
|
||||
}
|
||||
*i = ipValue(ip)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *ipValue) Type() string {
|
||||
return "ip"
|
||||
}
|
||||
|
||||
func ipConv(sval string) (interface{}, error) {
|
||||
ip := net.ParseIP(sval)
|
||||
if ip != nil {
|
||||
return ip, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval)
|
||||
}
|
||||
|
||||
// GetIP return the net.IP value of a flag with the given name
|
||||
func (f *FlagSet) GetIP(name string) (net.IP, error) {
|
||||
val, err := f.getFlagType(name, "ip", ipConv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return val.(net.IP), nil
|
||||
}
|
||||
|
||||
// IPVar defines an net.IP flag with specified name, default value, and usage string.
|
||||
// The argument p points to an net.IP variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) {
|
||||
f.VarP(newIPValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) {
|
||||
f.VarP(newIPValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IPVar defines an net.IP flag with specified name, default value, and usage string.
|
||||
// The argument p points to an net.IP variable in which to store the value of the flag.
|
||||
func IPVar(p *net.IP, name string, value net.IP, usage string) {
|
||||
CommandLine.VarP(newIPValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) {
|
||||
CommandLine.VarP(newIPValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IP defines an net.IP flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an net.IP variable that stores the value of the flag.
|
||||
func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP {
|
||||
p := new(net.IP)
|
||||
f.IPVarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// IPP is like IP, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP {
|
||||
p := new(net.IP)
|
||||
f.IPVarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// IP defines an net.IP flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an net.IP variable that stores the value of the flag.
|
||||
func IP(name string, value net.IP, usage string) *net.IP {
|
||||
return CommandLine.IPP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// IPP is like IP, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IPP(name, shorthand string, value net.IP, usage string) *net.IP {
|
||||
return CommandLine.IPP(name, shorthand, value, usage)
|
||||
}
|
||||
148
vendor/github.com/spf13/pflag/ip_slice.go
generated
vendored
Normal file
148
vendor/github.com/spf13/pflag/ip_slice.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// -- ipSlice Value
|
||||
type ipSliceValue struct {
|
||||
value *[]net.IP
|
||||
changed bool
|
||||
}
|
||||
|
||||
func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue {
|
||||
ipsv := new(ipSliceValue)
|
||||
ipsv.value = p
|
||||
*ipsv.value = val
|
||||
return ipsv
|
||||
}
|
||||
|
||||
// Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag.
|
||||
// If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended.
|
||||
func (s *ipSliceValue) Set(val string) error {
|
||||
|
||||
// remove all quote characters
|
||||
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
|
||||
|
||||
// read flag arguments with CSV parser
|
||||
ipStrSlice, err := readAsCSV(rmQuote.Replace(val))
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
// parse ip values into slice
|
||||
out := make([]net.IP, 0, len(ipStrSlice))
|
||||
for _, ipStr := range ipStrSlice {
|
||||
ip := net.ParseIP(strings.TrimSpace(ipStr))
|
||||
if ip == nil {
|
||||
return fmt.Errorf("invalid string being converted to IP address: %s", ipStr)
|
||||
}
|
||||
out = append(out, ip)
|
||||
}
|
||||
|
||||
if !s.changed {
|
||||
*s.value = out
|
||||
} else {
|
||||
*s.value = append(*s.value, out...)
|
||||
}
|
||||
|
||||
s.changed = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns a string that uniquely represents this flag's type.
|
||||
func (s *ipSliceValue) Type() string {
|
||||
return "ipSlice"
|
||||
}
|
||||
|
||||
// String defines a "native" format for this net.IP slice flag value.
|
||||
func (s *ipSliceValue) String() string {
|
||||
|
||||
ipStrSlice := make([]string, len(*s.value))
|
||||
for i, ip := range *s.value {
|
||||
ipStrSlice[i] = ip.String()
|
||||
}
|
||||
|
||||
out, _ := writeAsCSV(ipStrSlice)
|
||||
|
||||
return "[" + out + "]"
|
||||
}
|
||||
|
||||
func ipSliceConv(val string) (interface{}, error) {
|
||||
val = strings.Trim(val, "[]")
|
||||
// Emtpy string would cause a slice with one (empty) entry
|
||||
if len(val) == 0 {
|
||||
return []net.IP{}, nil
|
||||
}
|
||||
ss := strings.Split(val, ",")
|
||||
out := make([]net.IP, len(ss))
|
||||
for i, sval := range ss {
|
||||
ip := net.ParseIP(strings.TrimSpace(sval))
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval)
|
||||
}
|
||||
out[i] = ip
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GetIPSlice returns the []net.IP value of a flag with the given name
|
||||
func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) {
|
||||
val, err := f.getFlagType(name, "ipSlice", ipSliceConv)
|
||||
if err != nil {
|
||||
return []net.IP{}, err
|
||||
}
|
||||
return val.([]net.IP), nil
|
||||
}
|
||||
|
||||
// IPSliceVar defines a ipSlice flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []net.IP variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
|
||||
f.VarP(newIPSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
|
||||
f.VarP(newIPSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IPSliceVar defines a []net.IP flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []net.IP variable in which to store the value of the flag.
|
||||
func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
|
||||
CommandLine.VarP(newIPSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
|
||||
CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IPSlice defines a []net.IP flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []net.IP variable that stores the value of that flag.
|
||||
func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP {
|
||||
p := []net.IP{}
|
||||
f.IPSliceVarP(&p, name, "", value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
|
||||
p := []net.IP{}
|
||||
f.IPSliceVarP(&p, name, shorthand, value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// IPSlice defines a []net.IP flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []net.IP variable that stores the value of the flag.
|
||||
func IPSlice(name string, value []net.IP, usage string) *[]net.IP {
|
||||
return CommandLine.IPSliceP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
|
||||
return CommandLine.IPSliceP(name, shorthand, value, usage)
|
||||
}
|
||||
122
vendor/github.com/spf13/pflag/ipmask.go
generated
vendored
Normal file
122
vendor/github.com/spf13/pflag/ipmask.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// -- net.IPMask value
|
||||
type ipMaskValue net.IPMask
|
||||
|
||||
func newIPMaskValue(val net.IPMask, p *net.IPMask) *ipMaskValue {
|
||||
*p = val
|
||||
return (*ipMaskValue)(p)
|
||||
}
|
||||
|
||||
func (i *ipMaskValue) String() string { return net.IPMask(*i).String() }
|
||||
func (i *ipMaskValue) Set(s string) error {
|
||||
ip := ParseIPv4Mask(s)
|
||||
if ip == nil {
|
||||
return fmt.Errorf("failed to parse IP mask: %q", s)
|
||||
}
|
||||
*i = ipMaskValue(ip)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *ipMaskValue) Type() string {
|
||||
return "ipMask"
|
||||
}
|
||||
|
||||
// ParseIPv4Mask written in IP form (e.g. 255.255.255.0).
|
||||
// This function should really belong to the net package.
|
||||
func ParseIPv4Mask(s string) net.IPMask {
|
||||
mask := net.ParseIP(s)
|
||||
if mask == nil {
|
||||
if len(s) != 8 {
|
||||
return nil
|
||||
}
|
||||
// net.IPMask.String() actually outputs things like ffffff00
|
||||
// so write a horrible parser for that as well :-(
|
||||
m := []int{}
|
||||
for i := 0; i < 4; i++ {
|
||||
b := "0x" + s[2*i:2*i+2]
|
||||
d, err := strconv.ParseInt(b, 0, 0)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
m = append(m, int(d))
|
||||
}
|
||||
s := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3])
|
||||
mask = net.ParseIP(s)
|
||||
if mask == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15])
|
||||
}
|
||||
|
||||
func parseIPv4Mask(sval string) (interface{}, error) {
|
||||
mask := ParseIPv4Mask(sval)
|
||||
if mask == nil {
|
||||
return nil, fmt.Errorf("unable to parse %s as net.IPMask", sval)
|
||||
}
|
||||
return mask, nil
|
||||
}
|
||||
|
||||
// GetIPv4Mask return the net.IPv4Mask value of a flag with the given name
|
||||
func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error) {
|
||||
val, err := f.getFlagType(name, "ipMask", parseIPv4Mask)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return val.(net.IPMask), nil
|
||||
}
|
||||
|
||||
// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string.
|
||||
// The argument p points to an net.IPMask variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) {
|
||||
f.VarP(newIPMaskValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) {
|
||||
f.VarP(newIPMaskValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string.
|
||||
// The argument p points to an net.IPMask variable in which to store the value of the flag.
|
||||
func IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) {
|
||||
CommandLine.VarP(newIPMaskValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) {
|
||||
CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IPMask defines an net.IPMask flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an net.IPMask variable that stores the value of the flag.
|
||||
func (f *FlagSet) IPMask(name string, value net.IPMask, usage string) *net.IPMask {
|
||||
p := new(net.IPMask)
|
||||
f.IPMaskVarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// IPMaskP is like IPMask, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask {
|
||||
p := new(net.IPMask)
|
||||
f.IPMaskVarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// IPMask defines an net.IPMask flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an net.IPMask variable that stores the value of the flag.
|
||||
func IPMask(name string, value net.IPMask, usage string) *net.IPMask {
|
||||
return CommandLine.IPMaskP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// IPMaskP is like IP, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask {
|
||||
return CommandLine.IPMaskP(name, shorthand, value, usage)
|
||||
}
|
||||
98
vendor/github.com/spf13/pflag/ipnet.go
generated
vendored
Normal file
98
vendor/github.com/spf13/pflag/ipnet.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IPNet adapts net.IPNet for use as a flag.
|
||||
type ipNetValue net.IPNet
|
||||
|
||||
func (ipnet ipNetValue) String() string {
|
||||
n := net.IPNet(ipnet)
|
||||
return n.String()
|
||||
}
|
||||
|
||||
func (ipnet *ipNetValue) Set(value string) error {
|
||||
_, n, err := net.ParseCIDR(strings.TrimSpace(value))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*ipnet = ipNetValue(*n)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*ipNetValue) Type() string {
|
||||
return "ipNet"
|
||||
}
|
||||
|
||||
func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue {
|
||||
*p = val
|
||||
return (*ipNetValue)(p)
|
||||
}
|
||||
|
||||
func ipNetConv(sval string) (interface{}, error) {
|
||||
_, n, err := net.ParseCIDR(strings.TrimSpace(sval))
|
||||
if err == nil {
|
||||
return *n, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid string being converted to IPNet: %s", sval)
|
||||
}
|
||||
|
||||
// GetIPNet return the net.IPNet value of a flag with the given name
|
||||
func (f *FlagSet) GetIPNet(name string) (net.IPNet, error) {
|
||||
val, err := f.getFlagType(name, "ipNet", ipNetConv)
|
||||
if err != nil {
|
||||
return net.IPNet{}, err
|
||||
}
|
||||
return val.(net.IPNet), nil
|
||||
}
|
||||
|
||||
// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string.
|
||||
// The argument p points to an net.IPNet variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) {
|
||||
f.VarP(newIPNetValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) {
|
||||
f.VarP(newIPNetValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string.
|
||||
// The argument p points to an net.IPNet variable in which to store the value of the flag.
|
||||
func IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) {
|
||||
CommandLine.VarP(newIPNetValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) {
|
||||
CommandLine.VarP(newIPNetValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// IPNet defines an net.IPNet flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an net.IPNet variable that stores the value of the flag.
|
||||
func (f *FlagSet) IPNet(name string, value net.IPNet, usage string) *net.IPNet {
|
||||
p := new(net.IPNet)
|
||||
f.IPNetVarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet {
|
||||
p := new(net.IPNet)
|
||||
f.IPNetVarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// IPNet defines an net.IPNet flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an net.IPNet variable that stores the value of the flag.
|
||||
func IPNet(name string, value net.IPNet, usage string) *net.IPNet {
|
||||
return CommandLine.IPNetP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash.
|
||||
func IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet {
|
||||
return CommandLine.IPNetP(name, shorthand, value, usage)
|
||||
}
|
||||
80
vendor/github.com/spf13/pflag/string.go
generated
vendored
Normal file
80
vendor/github.com/spf13/pflag/string.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package pflag
|
||||
|
||||
// -- string Value
|
||||
type stringValue string
|
||||
|
||||
func newStringValue(val string, p *string) *stringValue {
|
||||
*p = val
|
||||
return (*stringValue)(p)
|
||||
}
|
||||
|
||||
func (s *stringValue) Set(val string) error {
|
||||
*s = stringValue(val)
|
||||
return nil
|
||||
}
|
||||
func (s *stringValue) Type() string {
|
||||
return "string"
|
||||
}
|
||||
|
||||
func (s *stringValue) String() string { return string(*s) }
|
||||
|
||||
func stringConv(sval string) (interface{}, error) {
|
||||
return sval, nil
|
||||
}
|
||||
|
||||
// GetString return the string value of a flag with the given name
|
||||
func (f *FlagSet) GetString(name string) (string, error) {
|
||||
val, err := f.getFlagType(name, "string", stringConv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return val.(string), nil
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a string variable in which to store the value of the flag.
|
||||
func (f *FlagSet) StringVar(p *string, name string, value string, usage string) {
|
||||
f.VarP(newStringValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) {
|
||||
f.VarP(newStringValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a string variable in which to store the value of the flag.
|
||||
func StringVar(p *string, name string, value string, usage string) {
|
||||
CommandLine.VarP(newStringValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func StringVarP(p *string, name, shorthand string, value string, usage string) {
|
||||
CommandLine.VarP(newStringValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a string variable that stores the value of the flag.
|
||||
func (f *FlagSet) String(name string, value string, usage string) *string {
|
||||
p := new(string)
|
||||
f.StringVarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// StringP is like String, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string {
|
||||
p := new(string)
|
||||
f.StringVarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a string variable that stores the value of the flag.
|
||||
func String(name string, value string, usage string) *string {
|
||||
return CommandLine.StringP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// StringP is like String, but accepts a shorthand letter that can be used after a single dash.
|
||||
func StringP(name, shorthand string, value string, usage string) *string {
|
||||
return CommandLine.StringP(name, shorthand, value, usage)
|
||||
}
|
||||
103
vendor/github.com/spf13/pflag/string_array.go
generated
vendored
Normal file
103
vendor/github.com/spf13/pflag/string_array.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
package pflag
|
||||
|
||||
// -- stringArray Value
|
||||
type stringArrayValue struct {
|
||||
value *[]string
|
||||
changed bool
|
||||
}
|
||||
|
||||
func newStringArrayValue(val []string, p *[]string) *stringArrayValue {
|
||||
ssv := new(stringArrayValue)
|
||||
ssv.value = p
|
||||
*ssv.value = val
|
||||
return ssv
|
||||
}
|
||||
|
||||
func (s *stringArrayValue) Set(val string) error {
|
||||
if !s.changed {
|
||||
*s.value = []string{val}
|
||||
s.changed = true
|
||||
} else {
|
||||
*s.value = append(*s.value, val)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stringArrayValue) Type() string {
|
||||
return "stringArray"
|
||||
}
|
||||
|
||||
func (s *stringArrayValue) String() string {
|
||||
str, _ := writeAsCSV(*s.value)
|
||||
return "[" + str + "]"
|
||||
}
|
||||
|
||||
func stringArrayConv(sval string) (interface{}, error) {
|
||||
sval = sval[1 : len(sval)-1]
|
||||
// An empty string would cause a array with one (empty) string
|
||||
if len(sval) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
return readAsCSV(sval)
|
||||
}
|
||||
|
||||
// GetStringArray return the []string value of a flag with the given name
|
||||
func (f *FlagSet) GetStringArray(name string) ([]string, error) {
|
||||
val, err := f.getFlagType(name, "stringArray", stringArrayConv)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return val.([]string), nil
|
||||
}
|
||||
|
||||
// StringArrayVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []string variable in which to store the values of the multiple flags.
|
||||
// The value of each argument will not try to be separated by comma
|
||||
func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) {
|
||||
f.VarP(newStringArrayValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) {
|
||||
f.VarP(newStringArrayValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// StringArrayVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []string variable in which to store the value of the flag.
|
||||
// The value of each argument will not try to be separated by comma
|
||||
func StringArrayVar(p *[]string, name string, value []string, usage string) {
|
||||
CommandLine.VarP(newStringArrayValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) {
|
||||
CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// StringArray defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []string variable that stores the value of the flag.
|
||||
// The value of each argument will not try to be separated by comma
|
||||
func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string {
|
||||
p := []string{}
|
||||
f.StringArrayVarP(&p, name, "", value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string {
|
||||
p := []string{}
|
||||
f.StringArrayVarP(&p, name, shorthand, value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// StringArray defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []string variable that stores the value of the flag.
|
||||
// The value of each argument will not try to be separated by comma
|
||||
func StringArray(name string, value []string, usage string) *[]string {
|
||||
return CommandLine.StringArrayP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash.
|
||||
func StringArrayP(name, shorthand string, value []string, usage string) *[]string {
|
||||
return CommandLine.StringArrayP(name, shorthand, value, usage)
|
||||
}
|
||||
129
vendor/github.com/spf13/pflag/string_slice.go
generated
vendored
Normal file
129
vendor/github.com/spf13/pflag/string_slice.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// -- stringSlice Value
|
||||
type stringSliceValue struct {
|
||||
value *[]string
|
||||
changed bool
|
||||
}
|
||||
|
||||
func newStringSliceValue(val []string, p *[]string) *stringSliceValue {
|
||||
ssv := new(stringSliceValue)
|
||||
ssv.value = p
|
||||
*ssv.value = val
|
||||
return ssv
|
||||
}
|
||||
|
||||
func readAsCSV(val string) ([]string, error) {
|
||||
if val == "" {
|
||||
return []string{}, nil
|
||||
}
|
||||
stringReader := strings.NewReader(val)
|
||||
csvReader := csv.NewReader(stringReader)
|
||||
return csvReader.Read()
|
||||
}
|
||||
|
||||
func writeAsCSV(vals []string) (string, error) {
|
||||
b := &bytes.Buffer{}
|
||||
w := csv.NewWriter(b)
|
||||
err := w.Write(vals)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
w.Flush()
|
||||
return strings.TrimSuffix(b.String(), "\n"), nil
|
||||
}
|
||||
|
||||
func (s *stringSliceValue) Set(val string) error {
|
||||
v, err := readAsCSV(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !s.changed {
|
||||
*s.value = v
|
||||
} else {
|
||||
*s.value = append(*s.value, v...)
|
||||
}
|
||||
s.changed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stringSliceValue) Type() string {
|
||||
return "stringSlice"
|
||||
}
|
||||
|
||||
func (s *stringSliceValue) String() string {
|
||||
str, _ := writeAsCSV(*s.value)
|
||||
return "[" + str + "]"
|
||||
}
|
||||
|
||||
func stringSliceConv(sval string) (interface{}, error) {
|
||||
sval = sval[1 : len(sval)-1]
|
||||
// An empty string would cause a slice with one (empty) string
|
||||
if len(sval) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
return readAsCSV(sval)
|
||||
}
|
||||
|
||||
// GetStringSlice return the []string value of a flag with the given name
|
||||
func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
|
||||
val, err := f.getFlagType(name, "stringSlice", stringSliceConv)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return val.([]string), nil
|
||||
}
|
||||
|
||||
// StringSliceVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []string variable in which to store the value of the flag.
|
||||
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
|
||||
f.VarP(newStringSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) {
|
||||
f.VarP(newStringSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// StringSliceVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []string variable in which to store the value of the flag.
|
||||
func StringSliceVar(p *[]string, name string, value []string, usage string) {
|
||||
CommandLine.VarP(newStringSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) {
|
||||
CommandLine.VarP(newStringSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// StringSlice defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []string variable that stores the value of the flag.
|
||||
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
|
||||
p := []string{}
|
||||
f.StringSliceVarP(&p, name, "", value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage string) *[]string {
|
||||
p := []string{}
|
||||
f.StringSliceVarP(&p, name, shorthand, value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// StringSlice defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []string variable that stores the value of the flag.
|
||||
func StringSlice(name string, value []string, usage string) *[]string {
|
||||
return CommandLine.StringSliceP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func StringSliceP(name, shorthand string, value []string, usage string) *[]string {
|
||||
return CommandLine.StringSliceP(name, shorthand, value, usage)
|
||||
}
|
||||
88
vendor/github.com/spf13/pflag/uint.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/uint.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- uint Value
|
||||
type uintValue uint
|
||||
|
||||
func newUintValue(val uint, p *uint) *uintValue {
|
||||
*p = val
|
||||
return (*uintValue)(p)
|
||||
}
|
||||
|
||||
func (i *uintValue) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = uintValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uintValue) Type() string {
|
||||
return "uint"
|
||||
}
|
||||
|
||||
func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) }
|
||||
|
||||
func uintConv(sval string) (interface{}, error) {
|
||||
v, err := strconv.ParseUint(sval, 0, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint(v), nil
|
||||
}
|
||||
|
||||
// GetUint return the uint value of a flag with the given name
|
||||
func (f *FlagSet) GetUint(name string) (uint, error) {
|
||||
val, err := f.getFlagType(name, "uint", uintConv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(uint), nil
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) {
|
||||
f.VarP(newUintValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) {
|
||||
f.VarP(newUintValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func UintVar(p *uint, name string, value uint, usage string) {
|
||||
CommandLine.VarP(newUintValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func UintVarP(p *uint, name, shorthand string, value uint, usage string) {
|
||||
CommandLine.VarP(newUintValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint(name string, value uint, usage string) *uint {
|
||||
p := new(uint)
|
||||
f.UintVarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint {
|
||||
p := new(uint)
|
||||
f.UintVarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func Uint(name string, value uint, usage string) *uint {
|
||||
return CommandLine.UintP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash.
|
||||
func UintP(name, shorthand string, value uint, usage string) *uint {
|
||||
return CommandLine.UintP(name, shorthand, value, usage)
|
||||
}
|
||||
88
vendor/github.com/spf13/pflag/uint16.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/uint16.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- uint16 value
|
||||
type uint16Value uint16
|
||||
|
||||
func newUint16Value(val uint16, p *uint16) *uint16Value {
|
||||
*p = val
|
||||
return (*uint16Value)(p)
|
||||
}
|
||||
|
||||
func (i *uint16Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 16)
|
||||
*i = uint16Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uint16Value) Type() string {
|
||||
return "uint16"
|
||||
}
|
||||
|
||||
func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
|
||||
|
||||
func uint16Conv(sval string) (interface{}, error) {
|
||||
v, err := strconv.ParseUint(sval, 0, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint16(v), nil
|
||||
}
|
||||
|
||||
// GetUint16 return the uint16 value of a flag with the given name
|
||||
func (f *FlagSet) GetUint16(name string) (uint16, error) {
|
||||
val, err := f.getFlagType(name, "uint16", uint16Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(uint16), nil
|
||||
}
|
||||
|
||||
// Uint16Var defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) {
|
||||
f.VarP(newUint16Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) {
|
||||
f.VarP(newUint16Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint16Var defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func Uint16Var(p *uint16, name string, value uint16, usage string) {
|
||||
CommandLine.VarP(newUint16Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) {
|
||||
CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint16 defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint16(name string, value uint16, usage string) *uint16 {
|
||||
p := new(uint16)
|
||||
f.Uint16VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 {
|
||||
p := new(uint16)
|
||||
f.Uint16VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint16 defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func Uint16(name string, value uint16, usage string) *uint16 {
|
||||
return CommandLine.Uint16P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Uint16P(name, shorthand string, value uint16, usage string) *uint16 {
|
||||
return CommandLine.Uint16P(name, shorthand, value, usage)
|
||||
}
|
||||
88
vendor/github.com/spf13/pflag/uint32.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/uint32.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- uint32 value
|
||||
type uint32Value uint32
|
||||
|
||||
func newUint32Value(val uint32, p *uint32) *uint32Value {
|
||||
*p = val
|
||||
return (*uint32Value)(p)
|
||||
}
|
||||
|
||||
func (i *uint32Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 32)
|
||||
*i = uint32Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uint32Value) Type() string {
|
||||
return "uint32"
|
||||
}
|
||||
|
||||
func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
|
||||
|
||||
func uint32Conv(sval string) (interface{}, error) {
|
||||
v, err := strconv.ParseUint(sval, 0, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(v), nil
|
||||
}
|
||||
|
||||
// GetUint32 return the uint32 value of a flag with the given name
|
||||
func (f *FlagSet) GetUint32(name string) (uint32, error) {
|
||||
val, err := f.getFlagType(name, "uint32", uint32Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(uint32), nil
|
||||
}
|
||||
|
||||
// Uint32Var defines a uint32 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint32 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) {
|
||||
f.VarP(newUint32Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) {
|
||||
f.VarP(newUint32Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint32Var defines a uint32 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint32 variable in which to store the value of the flag.
|
||||
func Uint32Var(p *uint32, name string, value uint32, usage string) {
|
||||
CommandLine.VarP(newUint32Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) {
|
||||
CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint32 defines a uint32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint32 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint32(name string, value uint32, usage string) *uint32 {
|
||||
p := new(uint32)
|
||||
f.Uint32VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 {
|
||||
p := new(uint32)
|
||||
f.Uint32VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint32 defines a uint32 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint32 variable that stores the value of the flag.
|
||||
func Uint32(name string, value uint32, usage string) *uint32 {
|
||||
return CommandLine.Uint32P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Uint32P(name, shorthand string, value uint32, usage string) *uint32 {
|
||||
return CommandLine.Uint32P(name, shorthand, value, usage)
|
||||
}
|
||||
88
vendor/github.com/spf13/pflag/uint64.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/uint64.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- uint64 Value
|
||||
type uint64Value uint64
|
||||
|
||||
func newUint64Value(val uint64, p *uint64) *uint64Value {
|
||||
*p = val
|
||||
return (*uint64Value)(p)
|
||||
}
|
||||
|
||||
func (i *uint64Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = uint64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uint64Value) Type() string {
|
||||
return "uint64"
|
||||
}
|
||||
|
||||
func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
|
||||
|
||||
func uint64Conv(sval string) (interface{}, error) {
|
||||
v, err := strconv.ParseUint(sval, 0, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(v), nil
|
||||
}
|
||||
|
||||
// GetUint64 return the uint64 value of a flag with the given name
|
||||
func (f *FlagSet) GetUint64(name string) (uint64, error) {
|
||||
val, err := f.getFlagType(name, "uint64", uint64Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(uint64), nil
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) {
|
||||
f.VarP(newUint64Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) {
|
||||
f.VarP(newUint64Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint64 variable in which to store the value of the flag.
|
||||
func Uint64Var(p *uint64, name string, value uint64, usage string) {
|
||||
CommandLine.VarP(newUint64Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) {
|
||||
CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 {
|
||||
p := new(uint64)
|
||||
f.Uint64VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 {
|
||||
p := new(uint64)
|
||||
f.Uint64VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint64 variable that stores the value of the flag.
|
||||
func Uint64(name string, value uint64, usage string) *uint64 {
|
||||
return CommandLine.Uint64P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Uint64P(name, shorthand string, value uint64, usage string) *uint64 {
|
||||
return CommandLine.Uint64P(name, shorthand, value, usage)
|
||||
}
|
||||
88
vendor/github.com/spf13/pflag/uint8.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/uint8.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package pflag
|
||||
|
||||
import "strconv"
|
||||
|
||||
// -- uint8 Value
|
||||
type uint8Value uint8
|
||||
|
||||
func newUint8Value(val uint8, p *uint8) *uint8Value {
|
||||
*p = val
|
||||
return (*uint8Value)(p)
|
||||
}
|
||||
|
||||
func (i *uint8Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 8)
|
||||
*i = uint8Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uint8Value) Type() string {
|
||||
return "uint8"
|
||||
}
|
||||
|
||||
func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
|
||||
|
||||
func uint8Conv(sval string) (interface{}, error) {
|
||||
v, err := strconv.ParseUint(sval, 0, 8)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint8(v), nil
|
||||
}
|
||||
|
||||
// GetUint8 return the uint8 value of a flag with the given name
|
||||
func (f *FlagSet) GetUint8(name string) (uint8, error) {
|
||||
val, err := f.getFlagType(name, "uint8", uint8Conv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return val.(uint8), nil
|
||||
}
|
||||
|
||||
// Uint8Var defines a uint8 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint8 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) {
|
||||
f.VarP(newUint8Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) {
|
||||
f.VarP(newUint8Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint8Var defines a uint8 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint8 variable in which to store the value of the flag.
|
||||
func Uint8Var(p *uint8, name string, value uint8, usage string) {
|
||||
CommandLine.VarP(newUint8Value(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) {
|
||||
CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// Uint8 defines a uint8 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint8 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 {
|
||||
p := new(uint8)
|
||||
f.Uint8VarP(p, name, "", value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 {
|
||||
p := new(uint8)
|
||||
f.Uint8VarP(p, name, shorthand, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint8 defines a uint8 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint8 variable that stores the value of the flag.
|
||||
func Uint8(name string, value uint8, usage string) *uint8 {
|
||||
return CommandLine.Uint8P(name, "", value, usage)
|
||||
}
|
||||
|
||||
// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash.
|
||||
func Uint8P(name, shorthand string, value uint8, usage string) *uint8 {
|
||||
return CommandLine.Uint8P(name, shorthand, value, usage)
|
||||
}
|
||||
126
vendor/github.com/spf13/pflag/uint_slice.go
generated
vendored
Normal file
126
vendor/github.com/spf13/pflag/uint_slice.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
package pflag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// -- uintSlice Value
|
||||
type uintSliceValue struct {
|
||||
value *[]uint
|
||||
changed bool
|
||||
}
|
||||
|
||||
func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue {
|
||||
uisv := new(uintSliceValue)
|
||||
uisv.value = p
|
||||
*uisv.value = val
|
||||
return uisv
|
||||
}
|
||||
|
||||
func (s *uintSliceValue) Set(val string) error {
|
||||
ss := strings.Split(val, ",")
|
||||
out := make([]uint, len(ss))
|
||||
for i, d := range ss {
|
||||
u, err := strconv.ParseUint(d, 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out[i] = uint(u)
|
||||
}
|
||||
if !s.changed {
|
||||
*s.value = out
|
||||
} else {
|
||||
*s.value = append(*s.value, out...)
|
||||
}
|
||||
s.changed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *uintSliceValue) Type() string {
|
||||
return "uintSlice"
|
||||
}
|
||||
|
||||
func (s *uintSliceValue) String() string {
|
||||
out := make([]string, len(*s.value))
|
||||
for i, d := range *s.value {
|
||||
out[i] = fmt.Sprintf("%d", d)
|
||||
}
|
||||
return "[" + strings.Join(out, ",") + "]"
|
||||
}
|
||||
|
||||
func uintSliceConv(val string) (interface{}, error) {
|
||||
val = strings.Trim(val, "[]")
|
||||
// Empty string would cause a slice with one (empty) entry
|
||||
if len(val) == 0 {
|
||||
return []uint{}, nil
|
||||
}
|
||||
ss := strings.Split(val, ",")
|
||||
out := make([]uint, len(ss))
|
||||
for i, d := range ss {
|
||||
u, err := strconv.ParseUint(d, 10, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out[i] = uint(u)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GetUintSlice returns the []uint value of a flag with the given name.
|
||||
func (f *FlagSet) GetUintSlice(name string) ([]uint, error) {
|
||||
val, err := f.getFlagType(name, "uintSlice", uintSliceConv)
|
||||
if err != nil {
|
||||
return []uint{}, err
|
||||
}
|
||||
return val.([]uint), nil
|
||||
}
|
||||
|
||||
// UintSliceVar defines a uintSlice flag with specified name, default value, and usage string.
|
||||
// The argument p points to a []uint variable in which to store the value of the flag.
|
||||
func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) {
|
||||
f.VarP(newUintSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) {
|
||||
f.VarP(newUintSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// UintSliceVar defines a uint[] flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint[] variable in which to store the value of the flag.
|
||||
func UintSliceVar(p *[]uint, name string, value []uint, usage string) {
|
||||
CommandLine.VarP(newUintSliceValue(value, p), name, "", usage)
|
||||
}
|
||||
|
||||
// UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||
func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) {
|
||||
CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage)
|
||||
}
|
||||
|
||||
// UintSlice defines a []uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []uint variable that stores the value of the flag.
|
||||
func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint {
|
||||
p := []uint{}
|
||||
f.UintSliceVarP(&p, name, "", value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint {
|
||||
p := []uint{}
|
||||
f.UintSliceVarP(&p, name, shorthand, value, usage)
|
||||
return &p
|
||||
}
|
||||
|
||||
// UintSlice defines a []uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a []uint variable that stores the value of the flag.
|
||||
func UintSlice(name string, value []uint, usage string) *[]uint {
|
||||
return CommandLine.UintSliceP(name, "", value, usage)
|
||||
}
|
||||
|
||||
// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||
func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint {
|
||||
return CommandLine.UintSliceP(name, shorthand, value, usage)
|
||||
}
|
||||
18
vendor/vendor.json
vendored
18
vendor/vendor.json
vendored
@@ -2,6 +2,18 @@
|
||||
"comment": "",
|
||||
"ignore": "test",
|
||||
"package": [
|
||||
{
|
||||
"checksumSHA1": "hqDDDpue/5363luidNMBS8z8eJU=",
|
||||
"path": "github.com/BurntSushi/toml",
|
||||
"revision": "99064174e013895bbd9b025c31100bd1d9b590ca",
|
||||
"revisionTime": "2016-07-17T15:07:09Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "LFU+UBG4GQNDk02KRF+JFwWuO2s=",
|
||||
"path": "github.com/imdario/mergo",
|
||||
"revision": "50d4dbd4eb0e84778abe37cefef140271d96fade",
|
||||
"revisionTime": "2016-05-17T06:44:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "UelPezrYA7pmz2lDhUZGGFvrg+A=",
|
||||
"path": "github.com/mattn/go-zglob",
|
||||
@@ -14,6 +26,12 @@
|
||||
"revision": "95345c4e1c0ebc9d16a3284177f09360f4d20fab",
|
||||
"revisionTime": "2017-01-24T11:57:57Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "5KvHyB1CImtwZT3fwNkNUlc8R0k=",
|
||||
"path": "github.com/spf13/pflag",
|
||||
"revision": "9ff6c6923cfffbcd502984b8e0c80539a94968b7",
|
||||
"revisionTime": "2017-01-30T21:42:45Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "QeQ0FWfng2E1CYl1LlPuAY9jLmg=",
|
||||
"path": "gopkg.in/yaml.v2",
|
||||
|
||||
Reference in New Issue
Block a user