mirror of
https://github.com/Luzifer/vault-user-token.git
synced 2024-12-20 12:51:20 +00:00
Add dependencies
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
a446be5587
commit
9e26ade8c6
345 changed files with 135345 additions and 0 deletions
98
Godeps/Godeps.json
generated
Normal file
98
Godeps/Godeps.json
generated
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/Luzifer/vault-user-token",
|
||||||
|
"GoVersion": "go1.8",
|
||||||
|
"GodepVersion": "v79",
|
||||||
|
"Deps": [
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/Luzifer/rconfig",
|
||||||
|
"Comment": "v1.1.0",
|
||||||
|
"Rev": "c27bd3a64b5b19556914d9fec69922cf3852d585"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/Sirupsen/logrus",
|
||||||
|
"Comment": "v0.10.0-38-g3ec0642",
|
||||||
|
"Rev": "3ec0642a7fb6488f65b06f9040adc67e3990296a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/fatih/structs",
|
||||||
|
"Rev": "3fe2facc32a7fbde4b29c0f85604dc1dd22836d2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/errwrap",
|
||||||
|
"Rev": "7554cd9344cec97297fa6649b055a8c98c2a1e55"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/go-cleanhttp",
|
||||||
|
"Rev": "ad28ea4487f05916463e2423a55166280e8254b5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/go-multierror",
|
||||||
|
"Rev": "d30f09973e19c1dfcd120b2d9c4f168e68d6b5d5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/go-rootcerts",
|
||||||
|
"Rev": "6bb64b370b90e7ef1fa532be9e591a81c3493e00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl/hcl/ast",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl/hcl/parser",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl/hcl/scanner",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl/hcl/strconv",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl/hcl/token",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl/json/parser",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl/json/scanner",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/hcl/json/token",
|
||||||
|
"Rev": "ef8133da8cda503718a74741312bf50821e6de79"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/hashicorp/vault/api",
|
||||||
|
"Comment": "v0.6.0-beta2-24-gf0b06cf",
|
||||||
|
"Rev": "f0b06cf68a3a6d69d0572be23f5035c38d1f3539"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/mitchellh/go-homedir",
|
||||||
|
"Rev": "981ab348d865cf048eb7d17e78ac7192632d8415"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/mitchellh/mapstructure",
|
||||||
|
"Rev": "ca63d7c062ee3c9f34db231e352b60012b4fd0c1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/spf13/pflag",
|
||||||
|
"Rev": "c7e63cf4530bcd3ba943729cee0efeff2ebea63f"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/sys/unix",
|
||||||
|
"Rev": "8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gopkg.in/yaml.v2",
|
||||||
|
"Rev": "31c299268d302dd0aa9a0dcf765a3d58971ac83f"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
5
Godeps/Readme
generated
Normal file
5
Godeps/Readme
generated
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
This directory tree is generated automatically by godep.
|
||||||
|
|
||||||
|
Please do not edit.
|
||||||
|
|
||||||
|
See https://github.com/tools/godep for more information.
|
8
vendor/github.com/Luzifer/rconfig/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/Luzifer/rconfig/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- tip
|
||||||
|
|
||||||
|
script: go test -v -race -cover ./...
|
5
vendor/github.com/Luzifer/rconfig/History.md
generated
vendored
Normal file
5
vendor/github.com/Luzifer/rconfig/History.md
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# 1.1.0 / 2016-06-28
|
||||||
|
|
||||||
|
* Support time.Duration config parameters
|
||||||
|
* Added goreportcard badge
|
||||||
|
* Added testcase for using bool with ENV and default
|
13
vendor/github.com/Luzifer/rconfig/LICENSE
generated
vendored
Normal file
13
vendor/github.com/Luzifer/rconfig/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2015 Knut Ahlers <knut@ahlers.me>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
94
vendor/github.com/Luzifer/rconfig/README.md
generated
vendored
Normal file
94
vendor/github.com/Luzifer/rconfig/README.md
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
[![Build Status](https://travis-ci.org/Luzifer/rconfig.svg?branch=master)](https://travis-ci.org/Luzifer/rconfig)
|
||||||
|
[![License: Apache v2.0](https://badge.luzifer.io/v1/badge?color=5d79b5&title=license&text=Apache+v2.0)](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
[![Documentation](https://badge.luzifer.io/v1/badge?title=godoc&text=reference)](https://godoc.org/github.com/Luzifer/rconfig)
|
||||||
|
[![Go Report](http://goreportcard.com/badge/Luzifer/rconfig)](http://goreportcard.com/report/Luzifer/rconfig)
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
> Package rconfig implements a CLI configuration reader with struct-embedded defaults, environment variables and posix compatible flag parsing using the [pflag](https://github.com/spf13/pflag) library.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Install by running:
|
||||||
|
|
||||||
|
```
|
||||||
|
go get -u github.com/Luzifer/rconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
OR fetch a specific version:
|
||||||
|
|
||||||
|
```
|
||||||
|
go get -u gopkg.in/luzifer/rconfig.v1
|
||||||
|
```
|
||||||
|
|
||||||
|
Run tests by running:
|
||||||
|
|
||||||
|
```
|
||||||
|
go test -v -race -cover github.com/Luzifer/rconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
As a first step define a struct holding your configuration:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type config struct {
|
||||||
|
Username string `default:"unknown" flag:"user" description:"Your name"`
|
||||||
|
Details struct {
|
||||||
|
Age int `default:"25" flag:"age" env:"age" description:"Your age"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Next create an instance of that struct and let `rconfig` fill that config:
|
||||||
|
|
||||||
|
```go
|
||||||
|
var cfg config
|
||||||
|
func init() {
|
||||||
|
cfg = config{}
|
||||||
|
rconfig.Parse(&cfg)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You're ready to access your configuration:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
fmt.Printf("Hello %s, happy birthday for your %dth birthday.",
|
||||||
|
cfg.Username,
|
||||||
|
cfg.Details.Age)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Provide variable defaults by using a file
|
||||||
|
|
||||||
|
Given you have a file `~/.myapp.yml` containing some secrets or usernames (for the example below username is assumed to be "luzifer") as a default configuration for your application you can use this source code to load the defaults from that file using the `vardefault` tag in your configuration struct.
|
||||||
|
|
||||||
|
The order of the directives (lower number = higher precedence):
|
||||||
|
|
||||||
|
1. Flags provided in command line
|
||||||
|
1. Environment variables
|
||||||
|
1. Variable defaults (`vardefault` tag in the struct)
|
||||||
|
1. `default` tag in the struct
|
||||||
|
|
||||||
|
```go
|
||||||
|
type config struct {
|
||||||
|
Username string `vardefault:"username" flag:"username" description:"Your username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg = config{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rconfig.SetVariableDefaults(rconfig.VarDefaultsFromYAMLFile("~/.myapp.yml"))
|
||||||
|
rconfig.Parse(&cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Printf("Username = %s", cfg.Username)
|
||||||
|
// Output: Username = luzifer
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## More info
|
||||||
|
|
||||||
|
You can see the full reference documentation of the rconfig package [at godoc.org](https://godoc.org/github.com/Luzifer/rconfig), or through go's standard documentation system by running `godoc -http=:6060` and browsing to [http://localhost:6060/pkg/github.com/Luzifer/rconfig](http://localhost:6060/pkg/github.com/Luzifer/rconfig) after installation.
|
338
vendor/github.com/Luzifer/rconfig/config.go
generated
vendored
Normal file
338
vendor/github.com/Luzifer/rconfig/config.go
generated
vendored
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
// Package rconfig implements a CLI configuration reader with struct-embedded
|
||||||
|
// defaults, environment variables and posix compatible flag parsing using
|
||||||
|
// the pflag library.
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fs *pflag.FlagSet
|
||||||
|
variableDefaults map[string]string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
variableDefaults = make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse takes the pointer to a struct filled with variables which should be read
|
||||||
|
// from ENV, default or flag. The precedence in this is flag > ENV > default. So
|
||||||
|
// if a flag is specified on the CLI it will overwrite the ENV and otherwise ENV
|
||||||
|
// overwrites the default specified.
|
||||||
|
//
|
||||||
|
// For your configuration struct you can use the following struct-tags to control
|
||||||
|
// the behavior of rconfig:
|
||||||
|
//
|
||||||
|
// default: Set a default value
|
||||||
|
// vardefault: Read the default value from the variable defaults
|
||||||
|
// env: Read the value from this environment variable
|
||||||
|
// flag: Flag to read in format "long,short" (for example "listen,l")
|
||||||
|
// description: A help text for Usage output to guide your users
|
||||||
|
//
|
||||||
|
// The format you need to specify those values you can see in the example to this
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
func Parse(config interface{}) error {
|
||||||
|
return parse(config, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Args returns the non-flag command-line arguments.
|
||||||
|
func Args() []string {
|
||||||
|
return fs.Args()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage prints a basic usage with the corresponding defaults for the flags to
|
||||||
|
// os.Stdout. The defaults are derived from the `default` struct-tag and the ENV.
|
||||||
|
func Usage() {
|
||||||
|
if fs != nil && fs.Parsed() {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
||||||
|
fs.PrintDefaults()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVariableDefaults presets the parser with a map of default values to be used
|
||||||
|
// when specifying the vardefault tag
|
||||||
|
func SetVariableDefaults(defaults map[string]string) {
|
||||||
|
variableDefaults = defaults
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(in interface{}, args []string) error {
|
||||||
|
if args == nil {
|
||||||
|
args = os.Args
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
|
||||||
|
if err := execTags(in, fs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.Parse(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func execTags(in interface{}, fs *pflag.FlagSet) error {
|
||||||
|
if reflect.TypeOf(in).Kind() != reflect.Ptr {
|
||||||
|
return errors.New("Calling parser with non-pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.ValueOf(in).Elem().Kind() != reflect.Struct {
|
||||||
|
return errors.New("Calling parser with pointer to non-struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
st := reflect.ValueOf(in).Elem()
|
||||||
|
for i := 0; i < st.NumField(); i++ {
|
||||||
|
valField := st.Field(i)
|
||||||
|
typeField := st.Type().Field(i)
|
||||||
|
|
||||||
|
if typeField.Tag.Get("default") == "" && typeField.Tag.Get("env") == "" && typeField.Tag.Get("flag") == "" && typeField.Type.Kind() != reflect.Struct {
|
||||||
|
// None of our supported tags is present and it's not a sub-struct
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
value := varDefault(typeField.Tag.Get("vardefault"), typeField.Tag.Get("default"))
|
||||||
|
value = envDefault(typeField.Tag.Get("env"), value)
|
||||||
|
parts := strings.Split(typeField.Tag.Get("flag"), ",")
|
||||||
|
|
||||||
|
switch typeField.Type {
|
||||||
|
case reflect.TypeOf(time.Duration(0)):
|
||||||
|
v, err := time.ParseDuration(value)
|
||||||
|
if err != nil {
|
||||||
|
if value == "" {
|
||||||
|
v = time.Duration(0)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if typeField.Tag.Get("flag") != "" {
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.DurationVar(valField.Addr().Interface().(*time.Duration), parts[0], v, typeField.Tag.Get("description"))
|
||||||
|
} else {
|
||||||
|
fs.DurationVarP(valField.Addr().Interface().(*time.Duration), parts[0], parts[1], v, typeField.Tag.Get("description"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valField.Set(reflect.ValueOf(v))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typeField.Type.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
if typeField.Tag.Get("flag") != "" {
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.StringVar(valField.Addr().Interface().(*string), parts[0], value, typeField.Tag.Get("description"))
|
||||||
|
} else {
|
||||||
|
fs.StringVarP(valField.Addr().Interface().(*string), parts[0], parts[1], value, typeField.Tag.Get("description"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valField.SetString(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
v := value == "true"
|
||||||
|
if typeField.Tag.Get("flag") != "" {
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.BoolVar(valField.Addr().Interface().(*bool), parts[0], v, typeField.Tag.Get("description"))
|
||||||
|
} else {
|
||||||
|
fs.BoolVarP(valField.Addr().Interface().(*bool), parts[0], parts[1], v, typeField.Tag.Get("description"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valField.SetBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64:
|
||||||
|
vt, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
if value == "" {
|
||||||
|
vt = 0
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if typeField.Tag.Get("flag") != "" {
|
||||||
|
registerFlagInt(typeField.Type.Kind(), fs, valField.Addr().Interface(), parts, vt, typeField.Tag.Get("description"))
|
||||||
|
} else {
|
||||||
|
valField.SetInt(vt)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
vt, err := strconv.ParseUint(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
if value == "" {
|
||||||
|
vt = 0
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if typeField.Tag.Get("flag") != "" {
|
||||||
|
registerFlagUint(typeField.Type.Kind(), fs, valField.Addr().Interface(), parts, vt, typeField.Tag.Get("description"))
|
||||||
|
} else {
|
||||||
|
valField.SetUint(vt)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
vt, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
if value == "" {
|
||||||
|
vt = 0.0
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if typeField.Tag.Get("flag") != "" {
|
||||||
|
registerFlagFloat(typeField.Type.Kind(), fs, valField.Addr().Interface(), parts, vt, typeField.Tag.Get("description"))
|
||||||
|
} else {
|
||||||
|
valField.SetFloat(vt)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
if err := execTags(valField.Addr().Interface(), fs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
switch typeField.Type.Elem().Kind() {
|
||||||
|
case reflect.Int:
|
||||||
|
def := []int{}
|
||||||
|
for _, v := range strings.Split(value, ",") {
|
||||||
|
it, err := strconv.ParseInt(strings.TrimSpace(v), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
def = append(def, int(it))
|
||||||
|
}
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.IntSliceVar(valField.Addr().Interface().(*[]int), parts[0], def, typeField.Tag.Get("description"))
|
||||||
|
} else {
|
||||||
|
fs.IntSliceVarP(valField.Addr().Interface().(*[]int), parts[0], parts[1], def, typeField.Tag.Get("description"))
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
del := typeField.Tag.Get("delimiter")
|
||||||
|
if len(del) == 0 {
|
||||||
|
del = ","
|
||||||
|
}
|
||||||
|
def := strings.Split(value, del)
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.StringSliceVar(valField.Addr().Interface().(*[]string), parts[0], def, typeField.Tag.Get("description"))
|
||||||
|
} else {
|
||||||
|
fs.StringSliceVarP(valField.Addr().Interface().(*[]string), parts[0], parts[1], def, typeField.Tag.Get("description"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerFlagFloat(t reflect.Kind, fs *pflag.FlagSet, field interface{}, parts []string, vt float64, desc string) {
|
||||||
|
switch t {
|
||||||
|
case reflect.Float32:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Float32Var(field.(*float32), parts[0], float32(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Float32VarP(field.(*float32), parts[0], parts[1], float32(vt), desc)
|
||||||
|
}
|
||||||
|
case reflect.Float64:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Float64Var(field.(*float64), parts[0], float64(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Float64VarP(field.(*float64), parts[0], parts[1], float64(vt), desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerFlagInt(t reflect.Kind, fs *pflag.FlagSet, field interface{}, parts []string, vt int64, desc string) {
|
||||||
|
switch t {
|
||||||
|
case reflect.Int:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.IntVar(field.(*int), parts[0], int(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.IntVarP(field.(*int), parts[0], parts[1], int(vt), desc)
|
||||||
|
}
|
||||||
|
case reflect.Int8:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Int8Var(field.(*int8), parts[0], int8(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Int8VarP(field.(*int8), parts[0], parts[1], int8(vt), desc)
|
||||||
|
}
|
||||||
|
case reflect.Int32:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Int32Var(field.(*int32), parts[0], int32(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Int32VarP(field.(*int32), parts[0], parts[1], int32(vt), desc)
|
||||||
|
}
|
||||||
|
case reflect.Int64:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Int64Var(field.(*int64), parts[0], int64(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Int64VarP(field.(*int64), parts[0], parts[1], int64(vt), desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerFlagUint(t reflect.Kind, fs *pflag.FlagSet, field interface{}, parts []string, vt uint64, desc string) {
|
||||||
|
switch t {
|
||||||
|
case reflect.Uint:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.UintVar(field.(*uint), parts[0], uint(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.UintVarP(field.(*uint), parts[0], parts[1], uint(vt), desc)
|
||||||
|
}
|
||||||
|
case reflect.Uint8:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Uint8Var(field.(*uint8), parts[0], uint8(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Uint8VarP(field.(*uint8), parts[0], parts[1], uint8(vt), desc)
|
||||||
|
}
|
||||||
|
case reflect.Uint16:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Uint16Var(field.(*uint16), parts[0], uint16(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Uint16VarP(field.(*uint16), parts[0], parts[1], uint16(vt), desc)
|
||||||
|
}
|
||||||
|
case reflect.Uint32:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Uint32Var(field.(*uint32), parts[0], uint32(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Uint32VarP(field.(*uint32), parts[0], parts[1], uint32(vt), desc)
|
||||||
|
}
|
||||||
|
case reflect.Uint64:
|
||||||
|
if len(parts) == 1 {
|
||||||
|
fs.Uint64Var(field.(*uint64), parts[0], uint64(vt), desc)
|
||||||
|
} else {
|
||||||
|
fs.Uint64VarP(field.(*uint64), parts[0], parts[1], uint64(vt), desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func envDefault(env, def string) string {
|
||||||
|
value := def
|
||||||
|
|
||||||
|
if env != "" {
|
||||||
|
if e := os.Getenv(env); e != "" {
|
||||||
|
value = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func varDefault(name, def string) string {
|
||||||
|
value := def
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
if v, ok := variableDefaults[name]; ok {
|
||||||
|
value = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
27
vendor/github.com/Luzifer/rconfig/vardefault_providers.go
generated
vendored
Normal file
27
vendor/github.com/Luzifer/rconfig/vardefault_providers.go
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VarDefaultsFromYAMLFile reads contents of a file and calls VarDefaultsFromYAML
|
||||||
|
func VarDefaultsFromYAMLFile(filename string) map[string]string {
|
||||||
|
data, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return VarDefaultsFromYAML(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VarDefaultsFromYAML creates a vardefaults map from YAML raw data
|
||||||
|
func VarDefaultsFromYAML(in []byte) map[string]string {
|
||||||
|
out := make(map[string]string)
|
||||||
|
err := yaml.Unmarshal(in, &out)
|
||||||
|
if err != nil {
|
||||||
|
return make(map[string]string)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
1
vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
Normal file
1
vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
logrus
|
10
vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
Normal file
10
vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- tip
|
||||||
|
install:
|
||||||
|
- go get -t ./...
|
||||||
|
script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
|
66
vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
66
vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
# 0.10.0
|
||||||
|
|
||||||
|
* feature: Add a test hook (#180)
|
||||||
|
* feature: `ParseLevel` is now case-insensitive (#326)
|
||||||
|
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
|
||||||
|
* performance: avoid re-allocations on `WithFields` (#335)
|
||||||
|
|
||||||
|
# 0.9.0
|
||||||
|
|
||||||
|
* logrus/text_formatter: don't emit empty msg
|
||||||
|
* logrus/hooks/airbrake: move out of main repository
|
||||||
|
* logrus/hooks/sentry: move out of main repository
|
||||||
|
* logrus/hooks/papertrail: move out of main repository
|
||||||
|
* logrus/hooks/bugsnag: move out of main repository
|
||||||
|
* logrus/core: run tests with `-race`
|
||||||
|
* logrus/core: detect TTY based on `stderr`
|
||||||
|
* logrus/core: support `WithError` on logger
|
||||||
|
* logrus/core: Solaris support
|
||||||
|
|
||||||
|
# 0.8.7
|
||||||
|
|
||||||
|
* logrus/core: fix possible race (#216)
|
||||||
|
* logrus/doc: small typo fixes and doc improvements
|
||||||
|
|
||||||
|
|
||||||
|
# 0.8.6
|
||||||
|
|
||||||
|
* hooks/raven: allow passing an initialized client
|
||||||
|
|
||||||
|
# 0.8.5
|
||||||
|
|
||||||
|
* logrus/core: revert #208
|
||||||
|
|
||||||
|
# 0.8.4
|
||||||
|
|
||||||
|
* formatter/text: fix data race (#218)
|
||||||
|
|
||||||
|
# 0.8.3
|
||||||
|
|
||||||
|
* logrus/core: fix entry log level (#208)
|
||||||
|
* logrus/core: improve performance of text formatter by 40%
|
||||||
|
* logrus/core: expose `LevelHooks` type
|
||||||
|
* logrus/core: add support for DragonflyBSD and NetBSD
|
||||||
|
* formatter/text: print structs more verbosely
|
||||||
|
|
||||||
|
# 0.8.2
|
||||||
|
|
||||||
|
* logrus: fix more Fatal family functions
|
||||||
|
|
||||||
|
# 0.8.1
|
||||||
|
|
||||||
|
* logrus: fix not exiting on `Fatalf` and `Fatalln`
|
||||||
|
|
||||||
|
# 0.8.0
|
||||||
|
|
||||||
|
* logrus: defaults to stderr instead of stdout
|
||||||
|
* hooks/sentry: add special field for `*http.Request`
|
||||||
|
* formatter/text: ignore Windows for colors
|
||||||
|
|
||||||
|
# 0.7.3
|
||||||
|
|
||||||
|
* formatter/\*: allow configuration of timestamp layout
|
||||||
|
|
||||||
|
# 0.7.2
|
||||||
|
|
||||||
|
* formatter/text: Add configuration option for time format (#158)
|
21
vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
21
vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Simon Eskildsen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
421
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
Normal file
421
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
Normal file
|
@ -0,0 +1,421 @@
|
||||||
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus)
|
||||||
|
|
||||||
|
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||||
|
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||||
|
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
|
||||||
|
many large deployments. The core API is unlikely to change much but please
|
||||||
|
version control your Logrus to make sure you aren't fetching latest `master` on
|
||||||
|
every build.**
|
||||||
|
|
||||||
|
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||||
|
plain text):
|
||||||
|
|
||||||
|
![Colored](http://i.imgur.com/PY7qMwd.png)
|
||||||
|
|
||||||
|
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
|
||||||
|
or Splunk:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
||||||
|
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"warning","msg":"The group's number increased tremendously!",
|
||||||
|
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
||||||
|
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
||||||
|
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
||||||
|
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||||
|
```
|
||||||
|
|
||||||
|
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
|
||||||
|
attached, the output is compatible with the
|
||||||
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||||
|
exit status 1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that it's completely api-compatible with the stdlib logger, so you can
|
||||||
|
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
|
||||||
|
and you'll now have the flexibility of Logrus. You can customize it all you
|
||||||
|
want:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Log as JSON instead of the default ASCII formatter.
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
|
||||||
|
// Output to stderr instead of stdout, could also be a file.
|
||||||
|
log.SetOutput(os.Stderr)
|
||||||
|
|
||||||
|
// Only log the warning severity or above.
|
||||||
|
log.SetLevel(log.WarnLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
|
||||||
|
// A common pattern is to re-use fields between logging statements by re-using
|
||||||
|
// the logrus.Entry returned from WithFields()
|
||||||
|
contextLogger := log.WithFields(log.Fields{
|
||||||
|
"common": "this is a common field",
|
||||||
|
"other": "I also should be logged always",
|
||||||
|
})
|
||||||
|
|
||||||
|
contextLogger.Info("I'll be logged with common and other field")
|
||||||
|
contextLogger.Info("Me too")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more advanced usage such as logging to multiple locations from the same
|
||||||
|
application, you can also create an instance of the `logrus` Logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a new instance of the logger. You can have any number of instances.
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// The API for setting attributes is a little different than the package level
|
||||||
|
// exported logger. See Godoc.
|
||||||
|
log.Out = os.Stderr
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
Logrus encourages careful, structured logging though logging fields instead of
|
||||||
|
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
||||||
|
to send event %s to topic %s with key %d")`, you should log the much more
|
||||||
|
discoverable:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"event": event,
|
||||||
|
"topic": topic,
|
||||||
|
"key": key,
|
||||||
|
}).Fatal("Failed to send event")
|
||||||
|
```
|
||||||
|
|
||||||
|
We've found this API forces you to think about logging in a way that produces
|
||||||
|
much more useful logging messages. We've been in countless situations where just
|
||||||
|
a single added field to a log statement that was already there would've saved us
|
||||||
|
hours. The `WithFields` call is optional.
|
||||||
|
|
||||||
|
In general, with Logrus using any of the `printf`-family functions should be
|
||||||
|
seen as a hint you should add a field, however, you can still use the
|
||||||
|
`printf`-family functions with Logrus.
|
||||||
|
|
||||||
|
#### Hooks
|
||||||
|
|
||||||
|
You can add hooks for logging levels. For example to send errors to an exception
|
||||||
|
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||||
|
multiple places simultaneously, e.g. syslog.
|
||||||
|
|
||||||
|
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
|
`init`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||||
|
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
|
"log/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||||
|
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||||
|
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
|
||||||
|
|
||||||
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to connect to local syslog daemon")
|
||||||
|
} else {
|
||||||
|
log.AddHook(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||||
|
|
||||||
|
| Hook | Description |
|
||||||
|
| ----- | ----------- |
|
||||||
|
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||||
|
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||||
|
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
||||||
|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||||
|
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||||
|
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
|
||||||
|
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||||
|
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||||
|
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||||
|
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||||
|
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||||
|
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||||
|
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||||
|
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
||||||
|
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||||
|
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
||||||
|
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
||||||
|
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||||
|
| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
|
||||||
|
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||||
|
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||||
|
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||||
|
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
||||||
|
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
||||||
|
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
|
||||||
|
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
||||||
|
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
||||||
|
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
||||||
|
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
||||||
|
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
|
||||||
|
|
||||||
|
|
||||||
|
#### Level logging
|
||||||
|
|
||||||
|
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.Debug("Useful debugging information.")
|
||||||
|
log.Info("Something noteworthy happened!")
|
||||||
|
log.Warn("You should probably take a look at this.")
|
||||||
|
log.Error("Something failed but I'm not quitting.")
|
||||||
|
// Calls os.Exit(1) after logging
|
||||||
|
log.Fatal("Bye.")
|
||||||
|
// Calls panic() after logging
|
||||||
|
log.Panic("I'm bailing.")
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set the logging level on a `Logger`, then it will only log entries with
|
||||||
|
that severity or anything above it:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
||||||
|
log.SetLevel(log.InfoLevel)
|
||||||
|
```
|
||||||
|
|
||||||
|
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
||||||
|
environment if your application has that.
|
||||||
|
|
||||||
|
#### Entries
|
||||||
|
|
||||||
|
Besides the fields added with `WithField` or `WithFields` some fields are
|
||||||
|
automatically added to all logging events:
|
||||||
|
|
||||||
|
1. `time`. The timestamp when the entry was created.
|
||||||
|
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
||||||
|
the `AddFields` call. E.g. `Failed to send event.`
|
||||||
|
3. `level`. The logging level. E.g. `info`.
|
||||||
|
|
||||||
|
#### Environments
|
||||||
|
|
||||||
|
Logrus has no notion of environment.
|
||||||
|
|
||||||
|
If you wish for hooks and formatters to only be used in specific environments,
|
||||||
|
you should handle that yourself. For example, if your application has a global
|
||||||
|
variable `Environment`, which is a string representation of the environment you
|
||||||
|
could do:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// do something here to set environment depending on an environment variable
|
||||||
|
// or command-line flag
|
||||||
|
if Environment == "production" {
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
} else {
|
||||||
|
// The TextFormatter is default, you don't actually have to do this.
|
||||||
|
log.SetFormatter(&log.TextFormatter{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This configuration is how `logrus` was intended to be used, but JSON in
|
||||||
|
production is mostly only useful if you do log aggregation with tools like
|
||||||
|
Splunk or Logstash.
|
||||||
|
|
||||||
|
#### Formatters
|
||||||
|
|
||||||
|
The built-in logging formatters are:
|
||||||
|
|
||||||
|
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
||||||
|
without colors.
|
||||||
|
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
||||||
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
|
`DisableColors` field to `true`
|
||||||
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
|
|
||||||
|
Third party logging formatters:
|
||||||
|
|
||||||
|
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
||||||
|
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||||
|
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
|
||||||
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
||||||
|
default ones (see Entries section above):
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MyJSONFormatter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetFormatter(new(MyJSONFormatter))
|
||||||
|
|
||||||
|
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
// Note this doesn't include Time, Level and Message which are available on
|
||||||
|
// the Entry. Consult `godoc` on information about those fields or read the
|
||||||
|
// source of the official loggers.
|
||||||
|
serialized, err := json.Marshal(entry.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Logger as an `io.Writer`
|
||||||
|
|
||||||
|
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
|
||||||
|
|
||||||
|
```go
|
||||||
|
w := logger.Writer()
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
srv := http.Server{
|
||||||
|
// create a stdlib log.Logger that writes to
|
||||||
|
// logrus.Logger.
|
||||||
|
ErrorLog: log.New(w, "", 0),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each line written to that writer will be printed the usual way, using formatters
|
||||||
|
and hooks. The level for those entries is `info`.
|
||||||
|
|
||||||
|
#### Rotation
|
||||||
|
|
||||||
|
Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||||
|
external program (like `logrotate(8)`) that can compress and delete old log
|
||||||
|
entries. It should not be a feature of the application-level logger.
|
||||||
|
|
||||||
|
#### Tools
|
||||||
|
|
||||||
|
| Tool | Description |
|
||||||
|
| ---- | ----------- |
|
||||||
|
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|
||||||
|
|
||||||
|
#### Testing
|
||||||
|
|
||||||
|
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
|
||||||
|
|
||||||
|
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
|
||||||
|
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
|
||||||
|
|
||||||
|
```go
|
||||||
|
logger, hook := NewNullLogger()
|
||||||
|
logger.Error("Hello error")
|
||||||
|
|
||||||
|
assert.Equal(1, len(hook.Entries))
|
||||||
|
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||||
|
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||||
|
|
||||||
|
hook.Reset()
|
||||||
|
assert.Nil(hook.LastEntry())
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fatal handlers
|
||||||
|
|
||||||
|
Logrus can register one or more functions that will be called when any `fatal`
|
||||||
|
level message is logged. The registered handlers will be executed before
|
||||||
|
logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need
|
||||||
|
to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
|
||||||
|
|
||||||
|
```
|
||||||
|
...
|
||||||
|
handler := func() {
|
||||||
|
// gracefully shutdown something...
|
||||||
|
}
|
||||||
|
logrus.RegisterExitHandler(handler)
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Thread safty
|
||||||
|
|
||||||
|
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
|
||||||
|
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
|
||||||
|
|
||||||
|
Situation when locking is not needed includes:
|
||||||
|
|
||||||
|
* You have no hooks registered, or hooks calling is already thread-safe.
|
||||||
|
|
||||||
|
* Writing to logger.Out is already thread-safe, for example:
|
||||||
|
|
||||||
|
1) logger.Out is protected by locks.
|
||||||
|
|
||||||
|
2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing)
|
||||||
|
|
||||||
|
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
|
64
vendor/github.com/Sirupsen/logrus/alt_exit.go
generated
vendored
Normal file
64
vendor/github.com/Sirupsen/logrus/alt_exit.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
// The following code was sourced and modified from the
|
||||||
|
// https://bitbucket.org/tebeka/atexit package governed by the following license:
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
// the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
// subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var handlers = []func(){}
|
||||||
|
|
||||||
|
func runHandler(handler func()) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
handler()
|
||||||
|
}
|
||||||
|
|
||||||
|
func runHandlers() {
|
||||||
|
for _, handler := range handlers {
|
||||||
|
runHandler(handler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
|
||||||
|
func Exit(code int) {
|
||||||
|
runHandlers()
|
||||||
|
os.Exit(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
|
||||||
|
// all handlers. The handlers will also be invoked when any Fatal log entry is
|
||||||
|
// made.
|
||||||
|
//
|
||||||
|
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||||
|
// message but also needs to gracefully shutdown. An example usecase could be
|
||||||
|
// closing database connections, or sending a alert that the application is
|
||||||
|
// closing.
|
||||||
|
func RegisterExitHandler(handler func()) {
|
||||||
|
handlers = append(handlers, handler)
|
||||||
|
}
|
26
vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
26
vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
||||||
|
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"number": 1,
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
|
||||||
|
Output:
|
||||||
|
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||||
|
|
||||||
|
For a full guide visit https://github.com/Sirupsen/logrus
|
||||||
|
*/
|
||||||
|
package logrus
|
275
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
275
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bufferPool *sync.Pool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
bufferPool = &sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return new(bytes.Buffer)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defines the key when adding errors using WithError.
|
||||||
|
var ErrorKey = "error"
|
||||||
|
|
||||||
|
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||||
|
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||||
|
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||||
|
// passed around as much as you wish to avoid field duplication.
|
||||||
|
type Entry struct {
|
||||||
|
Logger *Logger
|
||||||
|
|
||||||
|
// Contains all the fields set by the user.
|
||||||
|
Data Fields
|
||||||
|
|
||||||
|
// Time at which the log entry was created
|
||||||
|
Time time.Time
|
||||||
|
|
||||||
|
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Level Level
|
||||||
|
|
||||||
|
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Message string
|
||||||
|
|
||||||
|
// When formatter is called in entry.log(), an Buffer may be set to entry
|
||||||
|
Buffer *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntry(logger *Logger) *Entry {
|
||||||
|
return &Entry{
|
||||||
|
Logger: logger,
|
||||||
|
// Default is three fields, give a little extra room
|
||||||
|
Data: make(Fields, 5),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the string representation from the reader and ultimately the
|
||||||
|
// formatter.
|
||||||
|
func (entry *Entry) String() (string, error) {
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
str := string(serialized)
|
||||||
|
return str, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
||||||
|
func (entry *Entry) WithError(err error) *Entry {
|
||||||
|
return entry.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a single field to the Entry.
|
||||||
|
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
|
return entry.WithFields(Fields{key: value})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a map of fields to the Entry.
|
||||||
|
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
|
data := make(Fields, len(entry.Data)+len(fields))
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range fields {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
return &Entry{Logger: entry.Logger, Data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is not declared with a pointer value because otherwise
|
||||||
|
// race conditions will occur when using multiple goroutines
|
||||||
|
func (entry Entry) log(level Level, msg string) {
|
||||||
|
var buffer *bytes.Buffer
|
||||||
|
entry.Time = time.Now()
|
||||||
|
entry.Level = level
|
||||||
|
entry.Message = msg
|
||||||
|
|
||||||
|
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
buffer = bufferPool.Get().(*bytes.Buffer)
|
||||||
|
buffer.Reset()
|
||||||
|
defer bufferPool.Put(buffer)
|
||||||
|
entry.Buffer = buffer
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(&entry)
|
||||||
|
entry.Buffer = nil
|
||||||
|
if err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
} else {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
_, err = entry.Logger.Out.Write(serialized)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||||
|
}
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid Entry#log() returning a value that only would make sense for
|
||||||
|
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||||
|
// directly here.
|
||||||
|
if level <= PanicLevel {
|
||||||
|
panic(&entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Debug(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Print(args ...interface{}) {
|
||||||
|
entry.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Info(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warn(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warning(args ...interface{}) {
|
||||||
|
entry.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Error(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatal(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panic(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
panic(fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Printf family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.Debug(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.Info(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||||
|
entry.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.Warn(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.Error(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.Fatal(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.Panic(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Println family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.Debug(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infoln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.Info(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Println(args ...interface{}) {
|
||||||
|
entry.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.Warn(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningln(args ...interface{}) {
|
||||||
|
entry.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.Error(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.Fatal(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.Panic(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||||
|
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||||
|
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||||
|
// string allocation, we do the simplest thing.
|
||||||
|
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||||
|
msg := fmt.Sprintln(args...)
|
||||||
|
return msg[:len(msg)-1]
|
||||||
|
}
|
193
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
193
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// std is the name of the standard logger in stdlib `log`
|
||||||
|
std = New()
|
||||||
|
)
|
||||||
|
|
||||||
|
func StandardLogger() *Logger {
|
||||||
|
return std
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOutput sets the standard logger output.
|
||||||
|
func SetOutput(out io.Writer) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Out = out
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFormatter sets the standard logger formatter.
|
||||||
|
func SetFormatter(formatter Formatter) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Formatter = formatter
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLevel sets the standard logger level.
|
||||||
|
func SetLevel(level Level) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Level = level
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLevel returns the standard logger level.
|
||||||
|
func GetLevel() Level {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
return std.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHook adds a hook to the standard logger hooks.
|
||||||
|
func AddHook(hook Hook) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||||
|
func WithError(err error) *Entry {
|
||||||
|
return std.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithField creates an entry from the standard logger and adds a field to
|
||||||
|
// it. If you want multiple fields, use `WithFields`.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithField(key string, value interface{}) *Entry {
|
||||||
|
return std.WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFields creates an entry from the standard logger and adds multiple
|
||||||
|
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||||
|
// once for each field.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithFields(fields Fields) *Entry {
|
||||||
|
return std.WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logs a message at level Debug on the standard logger.
|
||||||
|
func Debug(args ...interface{}) {
|
||||||
|
std.Debug(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print logs a message at level Info on the standard logger.
|
||||||
|
func Print(args ...interface{}) {
|
||||||
|
std.Print(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info logs a message at level Info on the standard logger.
|
||||||
|
func Info(args ...interface{}) {
|
||||||
|
std.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn logs a message at level Warn on the standard logger.
|
||||||
|
func Warn(args ...interface{}) {
|
||||||
|
std.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning logs a message at level Warn on the standard logger.
|
||||||
|
func Warning(args ...interface{}) {
|
||||||
|
std.Warning(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error logs a message at level Error on the standard logger.
|
||||||
|
func Error(args ...interface{}) {
|
||||||
|
std.Error(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic logs a message at level Panic on the standard logger.
|
||||||
|
func Panic(args ...interface{}) {
|
||||||
|
std.Panic(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatal(args ...interface{}) {
|
||||||
|
std.Fatal(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs a message at level Debug on the standard logger.
|
||||||
|
func Debugf(format string, args ...interface{}) {
|
||||||
|
std.Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf logs a message at level Info on the standard logger.
|
||||||
|
func Printf(format string, args ...interface{}) {
|
||||||
|
std.Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs a message at level Info on the standard logger.
|
||||||
|
func Infof(format string, args ...interface{}) {
|
||||||
|
std.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs a message at level Warn on the standard logger.
|
||||||
|
func Warnf(format string, args ...interface{}) {
|
||||||
|
std.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningf logs a message at level Warn on the standard logger.
|
||||||
|
func Warningf(format string, args ...interface{}) {
|
||||||
|
std.Warningf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs a message at level Error on the standard logger.
|
||||||
|
func Errorf(format string, args ...interface{}) {
|
||||||
|
std.Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicf logs a message at level Panic on the standard logger.
|
||||||
|
func Panicf(format string, args ...interface{}) {
|
||||||
|
std.Panicf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalf logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalf(format string, args ...interface{}) {
|
||||||
|
std.Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugln logs a message at level Debug on the standard logger.
|
||||||
|
func Debugln(args ...interface{}) {
|
||||||
|
std.Debugln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println logs a message at level Info on the standard logger.
|
||||||
|
func Println(args ...interface{}) {
|
||||||
|
std.Println(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infoln logs a message at level Info on the standard logger.
|
||||||
|
func Infoln(args ...interface{}) {
|
||||||
|
std.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnln logs a message at level Warn on the standard logger.
|
||||||
|
func Warnln(args ...interface{}) {
|
||||||
|
std.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningln logs a message at level Warn on the standard logger.
|
||||||
|
func Warningln(args ...interface{}) {
|
||||||
|
std.Warningln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorln logs a message at level Error on the standard logger.
|
||||||
|
func Errorln(args ...interface{}) {
|
||||||
|
std.Errorln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicln logs a message at level Panic on the standard logger.
|
||||||
|
func Panicln(args ...interface{}) {
|
||||||
|
std.Panicln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalln logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalln(args ...interface{}) {
|
||||||
|
std.Fatalln(args...)
|
||||||
|
}
|
45
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
45
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const DefaultTimestampFormat = time.RFC3339
|
||||||
|
|
||||||
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
|
//
|
||||||
|
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||||
|
// * `entry.Data["time"]`. The timestamp.
|
||||||
|
// * `entry.Data["level"]. The level the entry was logged at.
|
||||||
|
//
|
||||||
|
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||||
|
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||||
|
// logged to `logger.Out`.
|
||||||
|
type Formatter interface {
|
||||||
|
Format(*Entry) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||||
|
// dumping it. If this code wasn't there doing:
|
||||||
|
//
|
||||||
|
// logrus.WithField("level", 1).Info("hello")
|
||||||
|
//
|
||||||
|
// Would just silently drop the user provided level. Instead with this code
|
||||||
|
// it'll logged as:
|
||||||
|
//
|
||||||
|
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||||
|
//
|
||||||
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||||
|
// avoid code duplication between the two default formatters.
|
||||||
|
func prefixFieldClashes(data Fields) {
|
||||||
|
if t, ok := data["time"]; ok {
|
||||||
|
data["fields.time"] = t
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, ok := data["msg"]; ok {
|
||||||
|
data["fields.msg"] = m
|
||||||
|
}
|
||||||
|
|
||||||
|
if l, ok := data["level"]; ok {
|
||||||
|
data["fields.level"] = l
|
||||||
|
}
|
||||||
|
}
|
34
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
34
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
// A hook to be fired when logging on the logging levels returned from
|
||||||
|
// `Levels()` on your implementation of the interface. Note that this is not
|
||||||
|
// fired in a goroutine or a channel with workers, you should handle such
|
||||||
|
// functionality yourself if your call is non-blocking and you don't wish for
|
||||||
|
// the logging calls for levels returned from `Levels()` to block.
|
||||||
|
type Hook interface {
|
||||||
|
Levels() []Level
|
||||||
|
Fire(*Entry) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal type for storing the hooks on a logger instance.
|
||||||
|
type LevelHooks map[Level][]Hook
|
||||||
|
|
||||||
|
// Add a hook to an instance of logger. This is called with
|
||||||
|
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||||
|
func (hooks LevelHooks) Add(hook Hook) {
|
||||||
|
for _, level := range hook.Levels() {
|
||||||
|
hooks[level] = append(hooks[level], hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||||
|
// appropriate hooks for a log entry.
|
||||||
|
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
||||||
|
for _, hook := range hooks[level] {
|
||||||
|
if err := hook.Fire(entry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
41
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
41
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JSONFormatter struct {
|
||||||
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
data := make(Fields, len(entry.Data)+3)
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case error:
|
||||||
|
// Otherwise errors are ignored by `encoding/json`
|
||||||
|
// https://github.com/Sirupsen/logrus/issues/137
|
||||||
|
data[k] = v.Error()
|
||||||
|
default:
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefixFieldClashes(data)
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
data["time"] = entry.Time.Format(timestampFormat)
|
||||||
|
data["msg"] = entry.Message
|
||||||
|
data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
serialized, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
308
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
308
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||||
|
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||||
|
// something more adventorous, such as logging to Kafka.
|
||||||
|
Out io.Writer
|
||||||
|
// Hooks for the logger instance. These allow firing events based on logging
|
||||||
|
// levels and log entries. For example, to send errors to an error tracking
|
||||||
|
// service, log to StatsD or dump the core on fatal errors.
|
||||||
|
Hooks LevelHooks
|
||||||
|
// All log entries pass through the formatter before logged to Out. The
|
||||||
|
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||||
|
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||||
|
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||||
|
// own that implements the `Formatter` interface, see the `README` or included
|
||||||
|
// formatters for examples.
|
||||||
|
Formatter Formatter
|
||||||
|
// The logging level the logger should log at. This is typically (and defaults
|
||||||
|
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||||
|
// logged. `logrus.Debug` is useful in
|
||||||
|
Level Level
|
||||||
|
// Used to sync writing to the log. Locking is enabled by Default
|
||||||
|
mu MutexWrap
|
||||||
|
// Reusable empty entry
|
||||||
|
entryPool sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
type MutexWrap struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
disabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mw *MutexWrap) Lock() {
|
||||||
|
if !mw.disabled {
|
||||||
|
mw.lock.Lock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mw *MutexWrap) Unlock() {
|
||||||
|
if !mw.disabled {
|
||||||
|
mw.lock.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mw *MutexWrap) Disable() {
|
||||||
|
mw.disabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||||
|
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||||
|
// instantiate your own:
|
||||||
|
//
|
||||||
|
// var log = &Logger{
|
||||||
|
// Out: os.Stderr,
|
||||||
|
// Formatter: new(JSONFormatter),
|
||||||
|
// Hooks: make(LevelHooks),
|
||||||
|
// Level: logrus.DebugLevel,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// It's recommended to make this a global instance called `log`.
|
||||||
|
func New() *Logger {
|
||||||
|
return &Logger{
|
||||||
|
Out: os.Stderr,
|
||||||
|
Formatter: new(TextFormatter),
|
||||||
|
Hooks: make(LevelHooks),
|
||||||
|
Level: InfoLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) newEntry() *Entry {
|
||||||
|
entry, ok := logger.entryPool.Get().(*Entry)
|
||||||
|
if ok {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
return NewEntry(logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) releaseEntry(entry *Entry) {
|
||||||
|
logger.entryPool.Put(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a field to the log entry, note that it doesn't log until you call
|
||||||
|
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||||
|
// If you want multiple fields, use `WithFields`.
|
||||||
|
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||||
|
// each `Field`.
|
||||||
|
func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an error as single field to the log entry. All it does is call
|
||||||
|
// `WithError` for the given `error`.
|
||||||
|
func (logger *Logger) WithError(err error) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Debugf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Infof(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Printf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Errorf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Fatalf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Panicf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Debug(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Info(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Info(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warn(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warn(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Error(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Fatal(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Panic(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Debugln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Infoln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Println(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warnln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warnln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Errorln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Fatalln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Panicln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//When file is opened with appending mode, it's safe to
|
||||||
|
//write concurrently to a file (within 4k message on Linux).
|
||||||
|
//In these cases user can choose to disable the lock.
|
||||||
|
func (logger *Logger) SetNoLock() {
|
||||||
|
logger.mu.Disable()
|
||||||
|
}
|
143
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
143
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fields type, used to pass to `WithFields`.
|
||||||
|
type Fields map[string]interface{}
|
||||||
|
|
||||||
|
// Level type
|
||||||
|
type Level uint8
|
||||||
|
|
||||||
|
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||||
|
func (level Level) String() string {
|
||||||
|
switch level {
|
||||||
|
case DebugLevel:
|
||||||
|
return "debug"
|
||||||
|
case InfoLevel:
|
||||||
|
return "info"
|
||||||
|
case WarnLevel:
|
||||||
|
return "warning"
|
||||||
|
case ErrorLevel:
|
||||||
|
return "error"
|
||||||
|
case FatalLevel:
|
||||||
|
return "fatal"
|
||||||
|
case PanicLevel:
|
||||||
|
return "panic"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||||
|
func ParseLevel(lvl string) (Level, error) {
|
||||||
|
switch strings.ToLower(lvl) {
|
||||||
|
case "panic":
|
||||||
|
return PanicLevel, nil
|
||||||
|
case "fatal":
|
||||||
|
return FatalLevel, nil
|
||||||
|
case "error":
|
||||||
|
return ErrorLevel, nil
|
||||||
|
case "warn", "warning":
|
||||||
|
return WarnLevel, nil
|
||||||
|
case "info":
|
||||||
|
return InfoLevel, nil
|
||||||
|
case "debug":
|
||||||
|
return DebugLevel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var l Level
|
||||||
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A constant exposing all logging levels
|
||||||
|
var AllLevels = []Level{
|
||||||
|
PanicLevel,
|
||||||
|
FatalLevel,
|
||||||
|
ErrorLevel,
|
||||||
|
WarnLevel,
|
||||||
|
InfoLevel,
|
||||||
|
DebugLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the different logging levels. You can set the logging level to log
|
||||||
|
// on your instance of logger, obtained with `logrus.New()`.
|
||||||
|
const (
|
||||||
|
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||||
|
// message passed to Debug, Info, ...
|
||||||
|
PanicLevel Level = iota
|
||||||
|
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||||
|
// logging level is set to Panic.
|
||||||
|
FatalLevel
|
||||||
|
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||||
|
// Commonly used for hooks to send errors to an error tracking service.
|
||||||
|
ErrorLevel
|
||||||
|
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||||
|
WarnLevel
|
||||||
|
// InfoLevel level. General operational entries about what's going on inside the
|
||||||
|
// application.
|
||||||
|
InfoLevel
|
||||||
|
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||||
|
DebugLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||||
|
var (
|
||||||
|
_ StdLogger = &log.Logger{}
|
||||||
|
_ StdLogger = &Entry{}
|
||||||
|
_ StdLogger = &Logger{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// StdLogger is what your logrus-enabled library should take, that way
|
||||||
|
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||||
|
// interface, this is the closest we get, unfortunately.
|
||||||
|
type StdLogger interface {
|
||||||
|
Print(...interface{})
|
||||||
|
Printf(string, ...interface{})
|
||||||
|
Println(...interface{})
|
||||||
|
|
||||||
|
Fatal(...interface{})
|
||||||
|
Fatalf(string, ...interface{})
|
||||||
|
Fatalln(...interface{})
|
||||||
|
|
||||||
|
Panic(...interface{})
|
||||||
|
Panicf(string, ...interface{})
|
||||||
|
Panicln(...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// The FieldLogger interface generalizes the Entry and Logger types
|
||||||
|
type FieldLogger interface {
|
||||||
|
WithField(key string, value interface{}) *Entry
|
||||||
|
WithFields(fields Fields) *Entry
|
||||||
|
WithError(err error) *Entry
|
||||||
|
|
||||||
|
Debugf(format string, args ...interface{})
|
||||||
|
Infof(format string, args ...interface{})
|
||||||
|
Printf(format string, args ...interface{})
|
||||||
|
Warnf(format string, args ...interface{})
|
||||||
|
Warningf(format string, args ...interface{})
|
||||||
|
Errorf(format string, args ...interface{})
|
||||||
|
Fatalf(format string, args ...interface{})
|
||||||
|
Panicf(format string, args ...interface{})
|
||||||
|
|
||||||
|
Debug(args ...interface{})
|
||||||
|
Info(args ...interface{})
|
||||||
|
Print(args ...interface{})
|
||||||
|
Warn(args ...interface{})
|
||||||
|
Warning(args ...interface{})
|
||||||
|
Error(args ...interface{})
|
||||||
|
Fatal(args ...interface{})
|
||||||
|
Panic(args ...interface{})
|
||||||
|
|
||||||
|
Debugln(args ...interface{})
|
||||||
|
Infoln(args ...interface{})
|
||||||
|
Println(args ...interface{})
|
||||||
|
Warnln(args ...interface{})
|
||||||
|
Warningln(args ...interface{})
|
||||||
|
Errorln(args ...interface{})
|
||||||
|
Fatalln(args ...interface{})
|
||||||
|
Panicln(args ...interface{})
|
||||||
|
}
|
8
vendor/github.com/Sirupsen/logrus/terminal_appengine.go
generated
vendored
Normal file
8
vendor/github.com/Sirupsen/logrus/terminal_appengine.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// +build appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
return true
|
||||||
|
}
|
10
vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
Normal file
10
vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// +build darwin freebsd openbsd netbsd dragonfly
|
||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TIOCGETA
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
14
vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
14
vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2013 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.
|
||||||
|
|
||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TCGETS
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
22
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
22
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
fd := syscall.Stderr
|
||||||
|
var termios Termios
|
||||||
|
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||||
|
return err == 0
|
||||||
|
}
|
15
vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
Normal file
15
vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// +build solaris,!appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
|
||||||
|
return err == nil
|
||||||
|
}
|
27
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
27
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
// +build windows,!appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
var (
|
||||||
|
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
fd := syscall.Stderr
|
||||||
|
var st uint32
|
||||||
|
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||||
|
return r != 0 && e == 0
|
||||||
|
}
|
165
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
165
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nocolor = 0
|
||||||
|
red = 31
|
||||||
|
green = 32
|
||||||
|
yellow = 33
|
||||||
|
blue = 34
|
||||||
|
gray = 37
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseTimestamp time.Time
|
||||||
|
isTerminal bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
baseTimestamp = time.Now()
|
||||||
|
isTerminal = IsTerminal()
|
||||||
|
}
|
||||||
|
|
||||||
|
func miniTS() int {
|
||||||
|
return int(time.Since(baseTimestamp) / time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextFormatter struct {
|
||||||
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||||
|
ForceColors bool
|
||||||
|
|
||||||
|
// Force disabling colors.
|
||||||
|
DisableColors bool
|
||||||
|
|
||||||
|
// Disable timestamp logging. useful when output is redirected to logging
|
||||||
|
// system that already adds timestamps.
|
||||||
|
DisableTimestamp bool
|
||||||
|
|
||||||
|
// Enable logging the full timestamp when a TTY is attached instead of just
|
||||||
|
// the time passed since beginning of execution.
|
||||||
|
FullTimestamp bool
|
||||||
|
|
||||||
|
// TimestampFormat to use for display when a full timestamp is printed
|
||||||
|
TimestampFormat string
|
||||||
|
|
||||||
|
// The fields are sorted by default for a consistent output. For applications
|
||||||
|
// that log extremely frequently and don't use the JSON formatter this may not
|
||||||
|
// be desired.
|
||||||
|
DisableSorting bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
var b *bytes.Buffer
|
||||||
|
var keys []string = make([]string, 0, len(entry.Data))
|
||||||
|
for k := range entry.Data {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.DisableSorting {
|
||||||
|
sort.Strings(keys)
|
||||||
|
}
|
||||||
|
if entry.Buffer != nil {
|
||||||
|
b = entry.Buffer
|
||||||
|
} else {
|
||||||
|
b = &bytes.Buffer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixFieldClashes(entry.Data)
|
||||||
|
|
||||||
|
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
|
||||||
|
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
if isColored {
|
||||||
|
f.printColored(b, entry, keys, timestampFormat)
|
||||||
|
} else {
|
||||||
|
if !f.DisableTimestamp {
|
||||||
|
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
||||||
|
}
|
||||||
|
f.appendKeyValue(b, "level", entry.Level.String())
|
||||||
|
if entry.Message != "" {
|
||||||
|
f.appendKeyValue(b, "msg", entry.Message)
|
||||||
|
}
|
||||||
|
for _, key := range keys {
|
||||||
|
f.appendKeyValue(b, key, entry.Data[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteByte('\n')
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||||
|
var levelColor int
|
||||||
|
switch entry.Level {
|
||||||
|
case DebugLevel:
|
||||||
|
levelColor = gray
|
||||||
|
case WarnLevel:
|
||||||
|
levelColor = yellow
|
||||||
|
case ErrorLevel, FatalLevel, PanicLevel:
|
||||||
|
levelColor = red
|
||||||
|
default:
|
||||||
|
levelColor = blue
|
||||||
|
}
|
||||||
|
|
||||||
|
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||||
|
|
||||||
|
if !f.FullTimestamp {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
v := entry.Data[k]
|
||||||
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func needsQuoting(text string) bool {
|
||||||
|
for _, ch := range text {
|
||||||
|
if !((ch >= 'a' && ch <= 'z') ||
|
||||||
|
(ch >= 'A' && ch <= 'Z') ||
|
||||||
|
(ch >= '0' && ch <= '9') ||
|
||||||
|
ch == '-' || ch == '.') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||||
|
|
||||||
|
b.WriteString(key)
|
||||||
|
b.WriteByte('=')
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case string:
|
||||||
|
if !needsQuoting(value) {
|
||||||
|
b.WriteString(value)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%q", value)
|
||||||
|
}
|
||||||
|
case error:
|
||||||
|
errmsg := value.Error()
|
||||||
|
if !needsQuoting(errmsg) {
|
||||||
|
b.WriteString(errmsg)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%q", value)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Fprint(b, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteByte(' ')
|
||||||
|
}
|
53
vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
53
vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (logger *Logger) Writer() *io.PipeWriter {
|
||||||
|
return logger.WriterLevel(InfoLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
|
||||||
|
reader, writer := io.Pipe()
|
||||||
|
|
||||||
|
var printFunc func(args ...interface{})
|
||||||
|
switch level {
|
||||||
|
case DebugLevel:
|
||||||
|
printFunc = logger.Debug
|
||||||
|
case InfoLevel:
|
||||||
|
printFunc = logger.Info
|
||||||
|
case WarnLevel:
|
||||||
|
printFunc = logger.Warn
|
||||||
|
case ErrorLevel:
|
||||||
|
printFunc = logger.Error
|
||||||
|
case FatalLevel:
|
||||||
|
printFunc = logger.Fatal
|
||||||
|
case PanicLevel:
|
||||||
|
printFunc = logger.Panic
|
||||||
|
default:
|
||||||
|
printFunc = logger.Print
|
||||||
|
}
|
||||||
|
|
||||||
|
go logger.writerScanner(reader, printFunc)
|
||||||
|
runtime.SetFinalizer(writer, writerFinalizer)
|
||||||
|
|
||||||
|
return writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
for scanner.Scan() {
|
||||||
|
printFunc(scanner.Text())
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
logger.Errorf("Error while reading from Writer: %s", err)
|
||||||
|
}
|
||||||
|
reader.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func writerFinalizer(writer *io.PipeWriter) {
|
||||||
|
writer.Close()
|
||||||
|
}
|
23
vendor/github.com/fatih/structs/.gitignore
generated
vendored
Normal file
23
vendor/github.com/fatih/structs/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
11
vendor/github.com/fatih/structs/.travis.yml
generated
vendored
Normal file
11
vendor/github.com/fatih/structs/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.6
|
||||||
|
- tip
|
||||||
|
sudo: false
|
||||||
|
before_install:
|
||||||
|
- go get github.com/axw/gocov/gocov
|
||||||
|
- go get github.com/mattn/goveralls
|
||||||
|
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
|
||||||
|
script:
|
||||||
|
- $HOME/gopath/bin/goveralls -service=travis-ci
|
21
vendor/github.com/fatih/structs/LICENSE
generated
vendored
Normal file
21
vendor/github.com/fatih/structs/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Fatih Arslan
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
163
vendor/github.com/fatih/structs/README.md
generated
vendored
Normal file
163
vendor/github.com/fatih/structs/README.md
generated
vendored
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
# Structs [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/structs) [![Build Status](http://img.shields.io/travis/fatih/structs.svg?style=flat-square)](https://travis-ci.org/fatih/structs) [![Coverage Status](http://img.shields.io/coveralls/fatih/structs.svg?style=flat-square)](https://coveralls.io/r/fatih/structs)
|
||||||
|
|
||||||
|
Structs contains various utilities to work with Go (Golang) structs. It was
|
||||||
|
initially used by me to convert a struct into a `map[string]interface{}`. With
|
||||||
|
time I've added other utilities for structs. It's basically a high level
|
||||||
|
package based on primitives from the reflect package. Feel free to add new
|
||||||
|
functions or improve the existing code.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/fatih/structs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage and Examples
|
||||||
|
|
||||||
|
Just like the standard lib `strings`, `bytes` and co packages, `structs` has
|
||||||
|
many global functions to manipulate or organize your struct data. Lets define
|
||||||
|
and declare a struct:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Server struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
ID int
|
||||||
|
Enabled bool
|
||||||
|
users []string // not exported
|
||||||
|
http.Server // embedded
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Name: "gopher",
|
||||||
|
ID: 123456,
|
||||||
|
Enabled: true,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Convert a struct to a map[string]interface{}
|
||||||
|
// => {"Name":"gopher", "ID":123456, "Enabled":true}
|
||||||
|
m := structs.Map(server)
|
||||||
|
|
||||||
|
// Convert the values of a struct to a []interface{}
|
||||||
|
// => ["gopher", 123456, true]
|
||||||
|
v := structs.Values(server)
|
||||||
|
|
||||||
|
// Convert the names of a struct to a []string
|
||||||
|
// (see "Names methods" for more info about fields)
|
||||||
|
n := structs.Names(server)
|
||||||
|
|
||||||
|
// Convert the values of a struct to a []*Field
|
||||||
|
// (see "Field methods" for more info about fields)
|
||||||
|
f := structs.Fields(server)
|
||||||
|
|
||||||
|
// Return the struct name => "Server"
|
||||||
|
n := structs.Name(server)
|
||||||
|
|
||||||
|
// Check if any field of a struct is initialized or not.
|
||||||
|
h := structs.HasZero(server)
|
||||||
|
|
||||||
|
// Check if all fields of a struct is initialized or not.
|
||||||
|
z := structs.IsZero(server)
|
||||||
|
|
||||||
|
// Check if server is a struct or a pointer to struct
|
||||||
|
i := structs.IsStruct(server)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Struct methods
|
||||||
|
|
||||||
|
The structs functions can be also used as independent methods by creating a new
|
||||||
|
`*structs.Struct`. This is handy if you want to have more control over the
|
||||||
|
structs (such as retrieving a single Field).
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Create a new struct type:
|
||||||
|
s := structs.New(server)
|
||||||
|
|
||||||
|
m := s.Map() // Get a map[string]interface{}
|
||||||
|
v := s.Values() // Get a []interface{}
|
||||||
|
f := s.Fields() // Get a []*Field
|
||||||
|
n := s.Names() // Get a []string
|
||||||
|
f := s.Field(name) // Get a *Field based on the given field name
|
||||||
|
f, ok := s.FieldOk(name) // Get a *Field based on the given field name
|
||||||
|
n := s.Name() // Get the struct name
|
||||||
|
h := s.HasZero() // Check if any field is initialized
|
||||||
|
z := s.IsZero() // Check if all fields are initialized
|
||||||
|
```
|
||||||
|
|
||||||
|
### Field methods
|
||||||
|
|
||||||
|
We can easily examine a single Field for more detail. Below you can see how we
|
||||||
|
get and interact with various field methods:
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
s := structs.New(server)
|
||||||
|
|
||||||
|
// Get the Field struct for the "Name" field
|
||||||
|
name := s.Field("Name")
|
||||||
|
|
||||||
|
// Get the underlying value, value => "gopher"
|
||||||
|
value := name.Value().(string)
|
||||||
|
|
||||||
|
// Set the field's value
|
||||||
|
name.Set("another gopher")
|
||||||
|
|
||||||
|
// Get the field's kind, kind => "string"
|
||||||
|
name.Kind()
|
||||||
|
|
||||||
|
// Check if the field is exported or not
|
||||||
|
if name.IsExported() {
|
||||||
|
fmt.Println("Name field is exported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the value is a zero value, such as "" for string, 0 for int
|
||||||
|
if !name.IsZero() {
|
||||||
|
fmt.Println("Name is initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the field is an anonymous (embedded) field
|
||||||
|
if !name.IsEmbedded() {
|
||||||
|
fmt.Println("Name is not an embedded field")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Field's tag value for tag name "json", tag value => "name,omitempty"
|
||||||
|
tagValue := name.Tag("json")
|
||||||
|
```
|
||||||
|
|
||||||
|
Nested structs are supported too:
|
||||||
|
|
||||||
|
```go
|
||||||
|
addrField := s.Field("Server").Field("Addr")
|
||||||
|
|
||||||
|
// Get the value for addr
|
||||||
|
a := addrField.Value().(string)
|
||||||
|
|
||||||
|
// Or get all fields
|
||||||
|
httpServer := s.Field("Server").Fields()
|
||||||
|
```
|
||||||
|
|
||||||
|
We can also get a slice of Fields from the Struct type to iterate over all
|
||||||
|
fields. This is handy if you wish to examine all fields:
|
||||||
|
|
||||||
|
```go
|
||||||
|
s := structs.New(server)
|
||||||
|
|
||||||
|
for _, f := range s.Fields() {
|
||||||
|
fmt.Printf("field name: %+v\n", f.Name())
|
||||||
|
|
||||||
|
if f.IsExported() {
|
||||||
|
fmt.Printf("value : %+v\n", f.Value())
|
||||||
|
fmt.Printf("is zero : %+v\n", f.IsZero())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
* [Fatih Arslan](https://github.com/fatih)
|
||||||
|
* [Cihangir Savas](https://github.com/cihangir)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The MIT License (MIT) - see LICENSE.md for more details
|
132
vendor/github.com/fatih/structs/field.go
generated
vendored
Normal file
132
vendor/github.com/fatih/structs/field.go
generated
vendored
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNotExported = errors.New("field is not exported")
|
||||||
|
errNotSettable = errors.New("field is not settable")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Field represents a single struct field that encapsulates high level
|
||||||
|
// functions around the field.
|
||||||
|
type Field struct {
|
||||||
|
value reflect.Value
|
||||||
|
field reflect.StructField
|
||||||
|
defaultTag string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag returns the value associated with key in the tag string. If there is no
|
||||||
|
// such key in the tag, Tag returns the empty string.
|
||||||
|
func (f *Field) Tag(key string) string {
|
||||||
|
return f.field.Tag.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the underlying value of the field. It panics if the field
|
||||||
|
// is not exported.
|
||||||
|
func (f *Field) Value() interface{} {
|
||||||
|
return f.value.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmbedded returns true if the given field is an anonymous field (embedded)
|
||||||
|
func (f *Field) IsEmbedded() bool {
|
||||||
|
return f.field.Anonymous
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExported returns true if the given field is exported.
|
||||||
|
func (f *Field) IsExported() bool {
|
||||||
|
return f.field.PkgPath == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if the given field is not initialized (has a zero value).
|
||||||
|
// It panics if the field is not exported.
|
||||||
|
func (f *Field) IsZero() bool {
|
||||||
|
zero := reflect.Zero(f.value.Type()).Interface()
|
||||||
|
current := f.Value()
|
||||||
|
|
||||||
|
return reflect.DeepEqual(current, zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of the given field
|
||||||
|
func (f *Field) Name() string {
|
||||||
|
return f.field.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kind returns the fields kind, such as "string", "map", "bool", etc ..
|
||||||
|
func (f *Field) Kind() reflect.Kind {
|
||||||
|
return f.value.Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the field to given value v. It returns an error if the field is not
|
||||||
|
// settable (not addressable or not exported) or if the given value's type
|
||||||
|
// doesn't match the fields type.
|
||||||
|
func (f *Field) Set(val interface{}) error {
|
||||||
|
// we can't set unexported fields, so be sure this field is exported
|
||||||
|
if !f.IsExported() {
|
||||||
|
return errNotExported
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we get here? not sure...
|
||||||
|
if !f.value.CanSet() {
|
||||||
|
return errNotSettable
|
||||||
|
}
|
||||||
|
|
||||||
|
given := reflect.ValueOf(val)
|
||||||
|
|
||||||
|
if f.value.Kind() != given.Kind() {
|
||||||
|
return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
f.value.Set(given)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero sets the field to its zero value. It returns an error if the field is not
|
||||||
|
// settable (not addressable or not exported).
|
||||||
|
func (f *Field) Zero() error {
|
||||||
|
zero := reflect.Zero(f.value.Type()).Interface()
|
||||||
|
return f.Set(zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields returns a slice of Fields. This is particular handy to get the fields
|
||||||
|
// of a nested struct . A struct tag with the content of "-" ignores the
|
||||||
|
// checking of that particular field. Example:
|
||||||
|
//
|
||||||
|
// // Field is ignored by this package.
|
||||||
|
// Field *http.Request `structs:"-"`
|
||||||
|
//
|
||||||
|
// It panics if field is not exported or if field's kind is not struct
|
||||||
|
func (f *Field) Fields() []*Field {
|
||||||
|
return getFields(f.value, f.defaultTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns the field from a nested struct. It panics if the nested struct
|
||||||
|
// is not exported or if the field was not found.
|
||||||
|
func (f *Field) Field(name string) *Field {
|
||||||
|
field, ok := f.FieldOk(name)
|
||||||
|
if !ok {
|
||||||
|
panic("field not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldOk returns the field from a nested struct. The boolean returns whether
|
||||||
|
// the field was found (true) or not (false).
|
||||||
|
func (f *Field) FieldOk(name string) (*Field, bool) {
|
||||||
|
v := strctVal(f.value.Interface())
|
||||||
|
t := v.Type()
|
||||||
|
|
||||||
|
field, ok := t.FieldByName(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Field{
|
||||||
|
field: field,
|
||||||
|
value: v.FieldByName(name),
|
||||||
|
}, true
|
||||||
|
}
|
507
vendor/github.com/fatih/structs/structs.go
generated
vendored
Normal file
507
vendor/github.com/fatih/structs/structs.go
generated
vendored
Normal file
|
@ -0,0 +1,507 @@
|
||||||
|
// Package structs contains various utilities functions to work with structs.
|
||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultTagName is the default tag name for struct fields which provides
|
||||||
|
// a more granular to tweak certain structs. Lookup the necessary functions
|
||||||
|
// for more info.
|
||||||
|
DefaultTagName = "structs" // struct's field default tag name
|
||||||
|
)
|
||||||
|
|
||||||
|
// Struct encapsulates a struct type to provide several high level functions
|
||||||
|
// around the struct.
|
||||||
|
type Struct struct {
|
||||||
|
raw interface{}
|
||||||
|
value reflect.Value
|
||||||
|
TagName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new *Struct with the struct s. It panics if the s's kind is
|
||||||
|
// not struct.
|
||||||
|
func New(s interface{}) *Struct {
|
||||||
|
return &Struct{
|
||||||
|
raw: s,
|
||||||
|
value: strctVal(s),
|
||||||
|
TagName: DefaultTagName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map converts the given struct to a map[string]interface{}, where the keys
|
||||||
|
// of the map are the field names and the values of the map the associated
|
||||||
|
// values of the fields. The default key string is the struct field name but
|
||||||
|
// can be changed in the struct field's tag value. The "structs" key in the
|
||||||
|
// struct's field tag value is the key name. Example:
|
||||||
|
//
|
||||||
|
// // Field appears in map as key "myName".
|
||||||
|
// Name string `structs:"myName"`
|
||||||
|
//
|
||||||
|
// A tag value with the content of "-" ignores that particular field. Example:
|
||||||
|
//
|
||||||
|
// // Field is ignored by this package.
|
||||||
|
// Field bool `structs:"-"`
|
||||||
|
//
|
||||||
|
// A tag value with the content of "string" uses the stringer to get the value. Example:
|
||||||
|
//
|
||||||
|
// // The value will be output of Animal's String() func.
|
||||||
|
// // Map will panic if Animal does not implement String().
|
||||||
|
// Field *Animal `structs:"field,string"`
|
||||||
|
//
|
||||||
|
// A tag value with the option of "flatten" used in a struct field is to flatten its fields
|
||||||
|
// in the output map. Example:
|
||||||
|
//
|
||||||
|
// // The FieldStruct's fields will be flattened into the output map.
|
||||||
|
// FieldStruct time.Time `structs:"flatten"`
|
||||||
|
//
|
||||||
|
// A tag value with the option of "omitnested" stops iterating further if the type
|
||||||
|
// is a struct. Example:
|
||||||
|
//
|
||||||
|
// // Field is not processed further by this package.
|
||||||
|
// Field time.Time `structs:"myName,omitnested"`
|
||||||
|
// Field *http.Request `structs:",omitnested"`
|
||||||
|
//
|
||||||
|
// A tag value with the option of "omitempty" ignores that particular field if
|
||||||
|
// the field value is empty. Example:
|
||||||
|
//
|
||||||
|
// // Field appears in map as key "myName", but the field is
|
||||||
|
// // skipped if empty.
|
||||||
|
// Field string `structs:"myName,omitempty"`
|
||||||
|
//
|
||||||
|
// // Field appears in map as key "Field" (the default), but
|
||||||
|
// // the field is skipped if empty.
|
||||||
|
// Field string `structs:",omitempty"`
|
||||||
|
//
|
||||||
|
// Note that only exported fields of a struct can be accessed, non exported
|
||||||
|
// fields will be neglected.
|
||||||
|
func (s *Struct) Map() map[string]interface{} {
|
||||||
|
out := make(map[string]interface{})
|
||||||
|
s.FillMap(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// FillMap is the same as Map. Instead of returning the output, it fills the
|
||||||
|
// given map.
|
||||||
|
func (s *Struct) FillMap(out map[string]interface{}) {
|
||||||
|
if out == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := s.structFields()
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
name := field.Name
|
||||||
|
val := s.value.FieldByName(name)
|
||||||
|
isSubStruct := false
|
||||||
|
var finalVal interface{}
|
||||||
|
|
||||||
|
tagName, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||||
|
if tagName != "" {
|
||||||
|
name = tagName
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the value is a zero value and the field is marked as omitempty do
|
||||||
|
// not include
|
||||||
|
if tagOpts.Has("omitempty") {
|
||||||
|
zero := reflect.Zero(val.Type()).Interface()
|
||||||
|
current := val.Interface()
|
||||||
|
|
||||||
|
if reflect.DeepEqual(current, zero) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||||
|
// look out for embedded structs, and convert them to a
|
||||||
|
// map[string]interface{} too
|
||||||
|
n := New(val.Interface())
|
||||||
|
n.TagName = s.TagName
|
||||||
|
m := n.Map()
|
||||||
|
isSubStruct = true
|
||||||
|
if len(m) == 0 {
|
||||||
|
finalVal = val.Interface()
|
||||||
|
} else {
|
||||||
|
finalVal = m
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finalVal = val.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
if tagOpts.Has("string") {
|
||||||
|
s, ok := val.Interface().(fmt.Stringer)
|
||||||
|
if ok {
|
||||||
|
out[name] = s.String()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if isSubStruct && (tagOpts.Has("flatten")) {
|
||||||
|
for k := range finalVal.(map[string]interface{}) {
|
||||||
|
out[k] = finalVal.(map[string]interface{})[k]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out[name] = finalVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values converts the given s struct's field values to a []interface{}. A
|
||||||
|
// struct tag with the content of "-" ignores the that particular field.
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // Field is ignored by this package.
|
||||||
|
// Field int `structs:"-"`
|
||||||
|
//
|
||||||
|
// A value with the option of "omitnested" stops iterating further if the type
|
||||||
|
// is a struct. Example:
|
||||||
|
//
|
||||||
|
// // Fields is not processed further by this package.
|
||||||
|
// Field time.Time `structs:",omitnested"`
|
||||||
|
// Field *http.Request `structs:",omitnested"`
|
||||||
|
//
|
||||||
|
// A tag value with the option of "omitempty" ignores that particular field and
|
||||||
|
// is not added to the values if the field value is empty. Example:
|
||||||
|
//
|
||||||
|
// // Field is skipped if empty
|
||||||
|
// Field string `structs:",omitempty"`
|
||||||
|
//
|
||||||
|
// Note that only exported fields of a struct can be accessed, non exported
|
||||||
|
// fields will be neglected.
|
||||||
|
func (s *Struct) Values() []interface{} {
|
||||||
|
fields := s.structFields()
|
||||||
|
|
||||||
|
var t []interface{}
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
val := s.value.FieldByName(field.Name)
|
||||||
|
|
||||||
|
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||||
|
|
||||||
|
// if the value is a zero value and the field is marked as omitempty do
|
||||||
|
// not include
|
||||||
|
if tagOpts.Has("omitempty") {
|
||||||
|
zero := reflect.Zero(val.Type()).Interface()
|
||||||
|
current := val.Interface()
|
||||||
|
|
||||||
|
if reflect.DeepEqual(current, zero) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tagOpts.Has("string") {
|
||||||
|
s, ok := val.Interface().(fmt.Stringer)
|
||||||
|
if ok {
|
||||||
|
t = append(t, s.String())
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||||
|
// look out for embedded structs, and convert them to a
|
||||||
|
// []interface{} to be added to the final values slice
|
||||||
|
for _, embeddedVal := range Values(val.Interface()) {
|
||||||
|
t = append(t, embeddedVal)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t = append(t, val.Interface())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields returns a slice of Fields. A struct tag with the content of "-"
|
||||||
|
// ignores the checking of that particular field. Example:
|
||||||
|
//
|
||||||
|
// // Field is ignored by this package.
|
||||||
|
// Field bool `structs:"-"`
|
||||||
|
//
|
||||||
|
// It panics if s's kind is not struct.
|
||||||
|
func (s *Struct) Fields() []*Field {
|
||||||
|
return getFields(s.value, s.TagName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Names returns a slice of field names. A struct tag with the content of "-"
|
||||||
|
// ignores the checking of that particular field. Example:
|
||||||
|
//
|
||||||
|
// // Field is ignored by this package.
|
||||||
|
// Field bool `structs:"-"`
|
||||||
|
//
|
||||||
|
// It panics if s's kind is not struct.
|
||||||
|
func (s *Struct) Names() []string {
|
||||||
|
fields := getFields(s.value, s.TagName)
|
||||||
|
|
||||||
|
names := make([]string, len(fields))
|
||||||
|
|
||||||
|
for i, field := range fields {
|
||||||
|
names[i] = field.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFields(v reflect.Value, tagName string) []*Field {
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
t := v.Type()
|
||||||
|
|
||||||
|
var fields []*Field
|
||||||
|
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
|
||||||
|
if tag := field.Tag.Get(tagName); tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f := &Field{
|
||||||
|
field: field,
|
||||||
|
value: v.FieldByName(field.Name),
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = append(fields, f)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns a new Field struct that provides several high level functions
|
||||||
|
// around a single struct field entity. It panics if the field is not found.
|
||||||
|
func (s *Struct) Field(name string) *Field {
|
||||||
|
f, ok := s.FieldOk(name)
|
||||||
|
if !ok {
|
||||||
|
panic("field not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldOk returns a new Field struct that provides several high level functions
|
||||||
|
// around a single struct field entity. The boolean returns true if the field
|
||||||
|
// was found.
|
||||||
|
func (s *Struct) FieldOk(name string) (*Field, bool) {
|
||||||
|
t := s.value.Type()
|
||||||
|
|
||||||
|
field, ok := t.FieldByName(name)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Field{
|
||||||
|
field: field,
|
||||||
|
value: s.value.FieldByName(name),
|
||||||
|
defaultTag: s.TagName,
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if all fields in a struct is a zero value (not
|
||||||
|
// initialized) A struct tag with the content of "-" ignores the checking of
|
||||||
|
// that particular field. Example:
|
||||||
|
//
|
||||||
|
// // Field is ignored by this package.
|
||||||
|
// Field bool `structs:"-"`
|
||||||
|
//
|
||||||
|
// A value with the option of "omitnested" stops iterating further if the type
|
||||||
|
// is a struct. Example:
|
||||||
|
//
|
||||||
|
// // Field is not processed further by this package.
|
||||||
|
// Field time.Time `structs:"myName,omitnested"`
|
||||||
|
// Field *http.Request `structs:",omitnested"`
|
||||||
|
//
|
||||||
|
// Note that only exported fields of a struct can be accessed, non exported
|
||||||
|
// fields will be neglected. It panics if s's kind is not struct.
|
||||||
|
func (s *Struct) IsZero() bool {
|
||||||
|
fields := s.structFields()
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
val := s.value.FieldByName(field.Name)
|
||||||
|
|
||||||
|
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||||
|
|
||||||
|
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||||
|
ok := IsZero(val.Interface())
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero value of the given field, such as "" for string, 0 for int
|
||||||
|
zero := reflect.Zero(val.Type()).Interface()
|
||||||
|
|
||||||
|
// current value of the given field
|
||||||
|
current := val.Interface()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(current, zero) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasZero returns true if a field in a struct is not initialized (zero value).
|
||||||
|
// A struct tag with the content of "-" ignores the checking of that particular
|
||||||
|
// field. Example:
|
||||||
|
//
|
||||||
|
// // Field is ignored by this package.
|
||||||
|
// Field bool `structs:"-"`
|
||||||
|
//
|
||||||
|
// A value with the option of "omitnested" stops iterating further if the type
|
||||||
|
// is a struct. Example:
|
||||||
|
//
|
||||||
|
// // Field is not processed further by this package.
|
||||||
|
// Field time.Time `structs:"myName,omitnested"`
|
||||||
|
// Field *http.Request `structs:",omitnested"`
|
||||||
|
//
|
||||||
|
// Note that only exported fields of a struct can be accessed, non exported
|
||||||
|
// fields will be neglected. It panics if s's kind is not struct.
|
||||||
|
func (s *Struct) HasZero() bool {
|
||||||
|
fields := s.structFields()
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
val := s.value.FieldByName(field.Name)
|
||||||
|
|
||||||
|
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
|
||||||
|
|
||||||
|
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||||
|
ok := HasZero(val.Interface())
|
||||||
|
if ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero value of the given field, such as "" for string, 0 for int
|
||||||
|
zero := reflect.Zero(val.Type()).Interface()
|
||||||
|
|
||||||
|
// current value of the given field
|
||||||
|
current := val.Interface()
|
||||||
|
|
||||||
|
if reflect.DeepEqual(current, zero) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the structs's type name within its package. For more info refer
|
||||||
|
// to Name() function.
|
||||||
|
func (s *Struct) Name() string {
|
||||||
|
return s.value.Type().Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
// structFields returns the exported struct fields for a given s struct. This
|
||||||
|
// is a convenient helper method to avoid duplicate code in some of the
|
||||||
|
// functions.
|
||||||
|
func (s *Struct) structFields() []reflect.StructField {
|
||||||
|
t := s.value.Type()
|
||||||
|
|
||||||
|
var f []reflect.StructField
|
||||||
|
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
// we can't access the value of unexported fields
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't check if it's omitted
|
||||||
|
if tag := field.Tag.Get(s.TagName); tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f = append(f, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func strctVal(s interface{}) reflect.Value {
|
||||||
|
v := reflect.ValueOf(s)
|
||||||
|
|
||||||
|
// if pointer get the underlying element≤
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() != reflect.Struct {
|
||||||
|
panic("not struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map converts the given struct to a map[string]interface{}. For more info
|
||||||
|
// refer to Struct types Map() method. It panics if s's kind is not struct.
|
||||||
|
func Map(s interface{}) map[string]interface{} {
|
||||||
|
return New(s).Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FillMap is the same as Map. Instead of returning the output, it fills the
|
||||||
|
// given map.
|
||||||
|
func FillMap(s interface{}, out map[string]interface{}) {
|
||||||
|
New(s).FillMap(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values converts the given struct to a []interface{}. For more info refer to
|
||||||
|
// Struct types Values() method. It panics if s's kind is not struct.
|
||||||
|
func Values(s interface{}) []interface{} {
|
||||||
|
return New(s).Values()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields returns a slice of *Field. For more info refer to Struct types
|
||||||
|
// Fields() method. It panics if s's kind is not struct.
|
||||||
|
func Fields(s interface{}) []*Field {
|
||||||
|
return New(s).Fields()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Names returns a slice of field names. For more info refer to Struct types
|
||||||
|
// Names() method. It panics if s's kind is not struct.
|
||||||
|
func Names(s interface{}) []string {
|
||||||
|
return New(s).Names()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if all fields is equal to a zero value. For more info
|
||||||
|
// refer to Struct types IsZero() method. It panics if s's kind is not struct.
|
||||||
|
func IsZero(s interface{}) bool {
|
||||||
|
return New(s).IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasZero returns true if any field is equal to a zero value. For more info
|
||||||
|
// refer to Struct types HasZero() method. It panics if s's kind is not struct.
|
||||||
|
func HasZero(s interface{}) bool {
|
||||||
|
return New(s).HasZero()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsStruct returns true if the given variable is a struct or a pointer to
|
||||||
|
// struct.
|
||||||
|
func IsStruct(s interface{}) bool {
|
||||||
|
v := reflect.ValueOf(s)
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// uninitialized zero value of a struct
|
||||||
|
if v.Kind() == reflect.Invalid {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the structs's type name within its package. It returns an
|
||||||
|
// empty string for unnamed types. It panics if s's kind is not struct.
|
||||||
|
func Name(s interface{}) string {
|
||||||
|
return New(s).Name()
|
||||||
|
}
|
32
vendor/github.com/fatih/structs/tags.go
generated
vendored
Normal file
32
vendor/github.com/fatih/structs/tags.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package structs
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// tagOptions contains a slice of tag options
|
||||||
|
type tagOptions []string
|
||||||
|
|
||||||
|
// Has returns true if the given optiton is available in tagOptions
|
||||||
|
func (t tagOptions) Has(opt string) bool {
|
||||||
|
for _, tagOpt := range t {
|
||||||
|
if tagOpt == opt {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseTag splits a struct field's tag into its name and a list of options
|
||||||
|
// which comes after a name. A tag is in the form of: "name,option1,option2".
|
||||||
|
// The name can be neglectected.
|
||||||
|
func parseTag(tag string) (string, tagOptions) {
|
||||||
|
// tag is one of followings:
|
||||||
|
// ""
|
||||||
|
// "name"
|
||||||
|
// "name,opt"
|
||||||
|
// "name,opt,opt2"
|
||||||
|
// ",opt"
|
||||||
|
|
||||||
|
res := strings.Split(tag, ",")
|
||||||
|
return res[0], res[1:]
|
||||||
|
}
|
354
vendor/github.com/hashicorp/errwrap/LICENSE
generated
vendored
Normal file
354
vendor/github.com/hashicorp/errwrap/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. “Contributor”
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. “Contributor Version”
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor’s Contribution.
|
||||||
|
|
||||||
|
1.3. “Contribution”
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. “Covered Software”
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. “Incompatible With Secondary Licenses”
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of version
|
||||||
|
1.1 or earlier of the License, but not also under the terms of a
|
||||||
|
Secondary License.
|
||||||
|
|
||||||
|
1.6. “Executable Form”
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. “Larger Work”
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a separate
|
||||||
|
file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. “License”
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. “Licensable”
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether at the
|
||||||
|
time of the initial grant or subsequently, any and all of the rights conveyed by
|
||||||
|
this License.
|
||||||
|
|
||||||
|
1.10. “Modifications”
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to, deletion
|
||||||
|
from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. “Patent Claims” of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method, process,
|
||||||
|
and apparatus claims, in any patent Licensable by such Contributor that
|
||||||
|
would be infringed, but for the grant of the License, by the making,
|
||||||
|
using, selling, offering for sale, having made, import, or transfer of
|
||||||
|
either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. “Secondary License”
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. “Source Code Form”
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. “You” (or “Your”)
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, “You” includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, “control” means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or as
|
||||||
|
part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its Contributions
|
||||||
|
or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||||
|
effective for each Contribution on the date the Contributor first distributes
|
||||||
|
such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under this
|
||||||
|
License. No additional rights or licenses will be implied from the distribution
|
||||||
|
or licensing of Covered Software under this License. Notwithstanding Section
|
||||||
|
2.1(b) above, no patent license is granted by a Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party’s
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of its
|
||||||
|
Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks, or
|
||||||
|
logos of any Contributor (except as may be necessary to comply with the
|
||||||
|
notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this License
|
||||||
|
(see Section 10.2) or under the terms of a Secondary License (if permitted
|
||||||
|
under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its Contributions
|
||||||
|
are its original creation(s) or it has sufficient rights to grant the
|
||||||
|
rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under applicable
|
||||||
|
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under the
|
||||||
|
terms of this License. You must inform recipients that the Source Code Form
|
||||||
|
of the Covered Software is governed by the terms of this License, and how
|
||||||
|
they can obtain a copy of this License. You may not attempt to alter or
|
||||||
|
restrict the recipients’ rights in the Source Code Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this License,
|
||||||
|
or sublicense it under different terms, provided that the license for
|
||||||
|
the Executable Form does not attempt to limit or alter the recipients’
|
||||||
|
rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for the
|
||||||
|
Covered Software. If the Larger Work is a combination of Covered Software
|
||||||
|
with a work governed by one or more Secondary Licenses, and the Covered
|
||||||
|
Software is not Incompatible With Secondary Licenses, this License permits
|
||||||
|
You to additionally distribute such Covered Software under the terms of
|
||||||
|
such Secondary License(s), so that the recipient of the Larger Work may, at
|
||||||
|
their option, further distribute the Covered Software under the terms of
|
||||||
|
either this License or such Secondary License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices (including
|
||||||
|
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||||
|
of liability) contained within the Source Code Form of the Covered
|
||||||
|
Software, except that You may alter any license notices to the extent
|
||||||
|
required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on behalf
|
||||||
|
of any Contributor. You must make it absolutely clear that any such
|
||||||
|
warranty, support, indemnity, or liability obligation is offered by You
|
||||||
|
alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute, judicial
|
||||||
|
order, or regulation then You must: (a) comply with the terms of this License
|
||||||
|
to the maximum extent possible; and (b) describe the limitations and the code
|
||||||
|
they affect. Such description must be placed in a text file included with all
|
||||||
|
distributions of the Covered Software under this License. Except to the
|
||||||
|
extent prohibited by statute or regulation, such description must be
|
||||||
|
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||||
|
understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
|
||||||
|
if such Contributor fails to notify You of the non-compliance by some
|
||||||
|
reasonable means prior to 60 days after You have come back into compliance.
|
||||||
|
Moreover, Your grants from a particular Contributor are reinstated on an
|
||||||
|
ongoing basis if such Contributor notifies You of the non-compliance by
|
||||||
|
some reasonable means, this is the first time You have received notice of
|
||||||
|
non-compliance with this License from such Contributor, and You become
|
||||||
|
compliant prior to 30 days after Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions, counter-claims,
|
||||||
|
and cross-claims) alleging that a Contributor Version directly or
|
||||||
|
indirectly infringes any patent, then the rights granted to You by any and
|
||||||
|
all Contributors for the Covered Software under Section 2.1 of this License
|
||||||
|
shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an “as is” basis, without
|
||||||
|
warranty of any kind, either expressed, implied, or statutory, including,
|
||||||
|
without limitation, warranties that the Covered Software is free of defects,
|
||||||
|
merchantable, fit for a particular purpose or non-infringing. The entire
|
||||||
|
risk as to the quality and performance of the Covered Software is with You.
|
||||||
|
Should any Covered Software prove defective in any respect, You (not any
|
||||||
|
Contributor) assume the cost of any necessary servicing, repair, or
|
||||||
|
correction. This disclaimer of warranty constitutes an essential part of this
|
||||||
|
License. No use of any Covered Software is authorized under this License
|
||||||
|
except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from such
|
||||||
|
party’s negligence to the extent applicable law prohibits such limitation.
|
||||||
|
Some jurisdictions do not allow the exclusion or limitation of incidental or
|
||||||
|
consequential damages, so this exclusion and limitation may not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts of
|
||||||
|
a jurisdiction where the defendant maintains its principal place of business
|
||||||
|
and such litigation shall be governed by laws of that jurisdiction, without
|
||||||
|
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||||
|
prevent a party’s ability to bring cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject matter
|
||||||
|
hereof. If any provision of this License is held to be unenforceable, such
|
||||||
|
provision shall be reformed only to the extent necessary to make it
|
||||||
|
enforceable. Any law or regulation which provides that the language of a
|
||||||
|
contract shall be construed against the drafter shall not be used to construe
|
||||||
|
this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version of
|
||||||
|
the License under which You originally received the Covered Software, or
|
||||||
|
under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a modified
|
||||||
|
version of this License if you rename the license and remove any
|
||||||
|
references to the name of the license steward (except to note that such
|
||||||
|
modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file, then
|
||||||
|
You may include the notice in a location (such as a LICENSE file in a relevant
|
||||||
|
directory) where a recipient would be likely to look for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||||
|
|
||||||
|
This Source Code Form is “Incompatible
|
||||||
|
With Secondary Licenses”, as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
89
vendor/github.com/hashicorp/errwrap/README.md
generated
vendored
Normal file
89
vendor/github.com/hashicorp/errwrap/README.md
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
# errwrap
|
||||||
|
|
||||||
|
`errwrap` is a package for Go that formalizes the pattern of wrapping errors
|
||||||
|
and checking if an error contains another error.
|
||||||
|
|
||||||
|
There is a common pattern in Go of taking a returned `error` value and
|
||||||
|
then wrapping it (such as with `fmt.Errorf`) before returning it. The problem
|
||||||
|
with this pattern is that you completely lose the original `error` structure.
|
||||||
|
|
||||||
|
Arguably the _correct_ approach is that you should make a custom structure
|
||||||
|
implementing the `error` interface, and have the original error as a field
|
||||||
|
on that structure, such [as this example](http://golang.org/pkg/os/#PathError).
|
||||||
|
This is a good approach, but you have to know the entire chain of possible
|
||||||
|
rewrapping that happens, when you might just care about one.
|
||||||
|
|
||||||
|
`errwrap` formalizes this pattern (it doesn't matter what approach you use
|
||||||
|
above) by giving a single interface for wrapping errors, checking if a specific
|
||||||
|
error is wrapped, and extracting that error.
|
||||||
|
|
||||||
|
## Installation and Docs
|
||||||
|
|
||||||
|
Install using `go get github.com/hashicorp/errwrap`.
|
||||||
|
|
||||||
|
Full documentation is available at
|
||||||
|
http://godoc.org/github.com/hashicorp/errwrap
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
#### Basic Usage
|
||||||
|
|
||||||
|
Below is a very basic example of its usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// A function that always returns an error, but wraps it, like a real
|
||||||
|
// function might.
|
||||||
|
func tryOpen() error {
|
||||||
|
_, err := os.Open("/i/dont/exist")
|
||||||
|
if err != nil {
|
||||||
|
return errwrap.Wrapf("Doesn't exist: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := tryOpen()
|
||||||
|
|
||||||
|
// We can use the Contains helpers to check if an error contains
|
||||||
|
// another error. It is safe to do this with a nil error, or with
|
||||||
|
// an error that doesn't even use the errwrap package.
|
||||||
|
if errwrap.Contains(err, ErrNotExist) {
|
||||||
|
// Do something
|
||||||
|
}
|
||||||
|
if errwrap.ContainsType(err, new(os.PathError)) {
|
||||||
|
// Do something
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or we can use the associated `Get` functions to just extract
|
||||||
|
// a specific error. This would return nil if that specific error doesn't
|
||||||
|
// exist.
|
||||||
|
perr := errwrap.GetType(err, new(os.PathError))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Custom Types
|
||||||
|
|
||||||
|
If you're already making custom types that properly wrap errors, then
|
||||||
|
you can get all the functionality of `errwraps.Contains` and such by
|
||||||
|
implementing the `Wrapper` interface with just one function. Example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type AppError {
|
||||||
|
Code ErrorCode
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *AppError) WrappedErrors() []error {
|
||||||
|
return []error{e.Err}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now this works:
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := &AppError{Err: fmt.Errorf("an error")}
|
||||||
|
if errwrap.ContainsType(err, fmt.Errorf("")) {
|
||||||
|
// This will work!
|
||||||
|
}
|
||||||
|
```
|
169
vendor/github.com/hashicorp/errwrap/errwrap.go
generated
vendored
Normal file
169
vendor/github.com/hashicorp/errwrap/errwrap.go
generated
vendored
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
// Package errwrap implements methods to formalize error wrapping in Go.
|
||||||
|
//
|
||||||
|
// All of the top-level functions that take an `error` are built to be able
|
||||||
|
// to take any error, not just wrapped errors. This allows you to use errwrap
|
||||||
|
// without having to type-check and type-cast everywhere.
|
||||||
|
package errwrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WalkFunc is the callback called for Walk.
|
||||||
|
type WalkFunc func(error)
|
||||||
|
|
||||||
|
// Wrapper is an interface that can be implemented by custom types to
|
||||||
|
// have all the Contains, Get, etc. functions in errwrap work.
|
||||||
|
//
|
||||||
|
// When Walk reaches a Wrapper, it will call the callback for every
|
||||||
|
// wrapped error in addition to the wrapper itself. Since all the top-level
|
||||||
|
// functions in errwrap use Walk, this means that all those functions work
|
||||||
|
// with your custom type.
|
||||||
|
type Wrapper interface {
|
||||||
|
WrappedErrors() []error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap defines that outer wraps inner, returning an error type that
|
||||||
|
// can be cleanly used with the other methods in this package, such as
|
||||||
|
// Contains, GetAll, etc.
|
||||||
|
//
|
||||||
|
// This function won't modify the error message at all (the outer message
|
||||||
|
// will be used).
|
||||||
|
func Wrap(outer, inner error) error {
|
||||||
|
return &wrappedError{
|
||||||
|
Outer: outer,
|
||||||
|
Inner: inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapf wraps an error with a formatting message. This is similar to using
|
||||||
|
// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap
|
||||||
|
// errors, you should replace it with this.
|
||||||
|
//
|
||||||
|
// format is the format of the error message. The string '{{err}}' will
|
||||||
|
// be replaced with the original error message.
|
||||||
|
func Wrapf(format string, err error) error {
|
||||||
|
outerMsg := "<nil>"
|
||||||
|
if err != nil {
|
||||||
|
outerMsg = err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
outer := errors.New(strings.Replace(
|
||||||
|
format, "{{err}}", outerMsg, -1))
|
||||||
|
|
||||||
|
return Wrap(outer, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains checks if the given error contains an error with the
|
||||||
|
// message msg. If err is not a wrapped error, this will always return
|
||||||
|
// false unless the error itself happens to match this msg.
|
||||||
|
func Contains(err error, msg string) bool {
|
||||||
|
return len(GetAll(err, msg)) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsType checks if the given error contains an error with
|
||||||
|
// the same concrete type as v. If err is not a wrapped error, this will
|
||||||
|
// check the err itself.
|
||||||
|
func ContainsType(err error, v interface{}) bool {
|
||||||
|
return len(GetAllType(err, v)) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get is the same as GetAll but returns the deepest matching error.
|
||||||
|
func Get(err error, msg string) error {
|
||||||
|
es := GetAll(err, msg)
|
||||||
|
if len(es) > 0 {
|
||||||
|
return es[len(es)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetType is the same as GetAllType but returns the deepest matching error.
|
||||||
|
func GetType(err error, v interface{}) error {
|
||||||
|
es := GetAllType(err, v)
|
||||||
|
if len(es) > 0 {
|
||||||
|
return es[len(es)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAll gets all the errors that might be wrapped in err with the
|
||||||
|
// given message. The order of the errors is such that the outermost
|
||||||
|
// matching error (the most recent wrap) is index zero, and so on.
|
||||||
|
func GetAll(err error, msg string) []error {
|
||||||
|
var result []error
|
||||||
|
|
||||||
|
Walk(err, func(err error) {
|
||||||
|
if err.Error() == msg {
|
||||||
|
result = append(result, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllType gets all the errors that are the same type as v.
|
||||||
|
//
|
||||||
|
// The order of the return value is the same as described in GetAll.
|
||||||
|
func GetAllType(err error, v interface{}) []error {
|
||||||
|
var result []error
|
||||||
|
|
||||||
|
var search string
|
||||||
|
if v != nil {
|
||||||
|
search = reflect.TypeOf(v).String()
|
||||||
|
}
|
||||||
|
Walk(err, func(err error) {
|
||||||
|
var needle string
|
||||||
|
if err != nil {
|
||||||
|
needle = reflect.TypeOf(err).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if needle == search {
|
||||||
|
result = append(result, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk walks all the wrapped errors in err and calls the callback. If
|
||||||
|
// err isn't a wrapped error, this will be called once for err. If err
|
||||||
|
// is a wrapped error, the callback will be called for both the wrapper
|
||||||
|
// that implements error as well as the wrapped error itself.
|
||||||
|
func Walk(err error, cb WalkFunc) {
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e := err.(type) {
|
||||||
|
case *wrappedError:
|
||||||
|
cb(e.Outer)
|
||||||
|
Walk(e.Inner, cb)
|
||||||
|
case Wrapper:
|
||||||
|
cb(err)
|
||||||
|
|
||||||
|
for _, err := range e.WrappedErrors() {
|
||||||
|
Walk(err, cb)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
cb(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrappedError is an implementation of error that has both the
|
||||||
|
// outer and inner errors.
|
||||||
|
type wrappedError struct {
|
||||||
|
Outer error
|
||||||
|
Inner error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedError) Error() string {
|
||||||
|
return w.Outer.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *wrappedError) WrappedErrors() []error {
|
||||||
|
return []error{w.Outer, w.Inner}
|
||||||
|
}
|
363
vendor/github.com/hashicorp/go-cleanhttp/LICENSE
generated
vendored
Normal file
363
vendor/github.com/hashicorp/go-cleanhttp/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the terms of
|
||||||
|
a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a
|
||||||
|
separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether
|
||||||
|
at the time of the initial grant or subsequently, any and all of the
|
||||||
|
rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the License,
|
||||||
|
by the making, using, selling, offering for sale, having made, import,
|
||||||
|
or transfer of either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, "control" means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights to
|
||||||
|
grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter the
|
||||||
|
recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||||
|
limitations of liability) contained within the Source Code Form of the
|
||||||
|
Covered Software, except that You may alter any license notices to the
|
||||||
|
extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute,
|
||||||
|
judicial order, or regulation then You must: (a) comply with the terms of
|
||||||
|
this License to the maximum extent possible; and (b) describe the
|
||||||
|
limitations and the code they affect. Such description must be placed in a
|
||||||
|
text file included with all distributions of the Covered Software under
|
||||||
|
this License. Except to the extent prohibited by statute or regulation,
|
||||||
|
such description must be sufficiently detailed for a recipient of ordinary
|
||||||
|
skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||||
|
basis, if such Contributor fails to notify You of the non-compliance by
|
||||||
|
some reasonable means prior to 60 days after You have come back into
|
||||||
|
compliance. Moreover, Your grants from a particular Contributor are
|
||||||
|
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||||
|
non-compliance by some reasonable means, this is the first time You have
|
||||||
|
received notice of non-compliance with this License from such
|
||||||
|
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||||
|
of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an "as is" basis,
|
||||||
|
without warranty of any kind, either expressed, implied, or statutory,
|
||||||
|
including, without limitation, warranties that the Covered Software is free
|
||||||
|
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
The entire risk as to the quality and performance of the Covered Software
|
||||||
|
is with You. Should any Covered Software prove defective in any respect,
|
||||||
|
You (not any Contributor) assume the cost of any necessary servicing,
|
||||||
|
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this License. No use of any Covered Software is authorized under
|
||||||
|
this License except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from
|
||||||
|
such party's negligence to the extent applicable law prohibits such
|
||||||
|
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||||
|
incidental or consequential damages, so this exclusion and limitation may
|
||||||
|
not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts
|
||||||
|
of a jurisdiction where the defendant maintains its principal place of
|
||||||
|
business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||||
|
in this Section shall prevent a party's ability to bring cross-claims or
|
||||||
|
counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides that
|
||||||
|
the language of a contract shall be construed against the drafter shall not
|
||||||
|
be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses If You choose to distribute Source Code Form that is
|
||||||
|
Incompatible With Secondary Licenses under the terms of this version of
|
||||||
|
the License, the notice described in Exhibit B of this License must be
|
||||||
|
attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file,
|
||||||
|
then You may include the notice in a location (such as a LICENSE file in a
|
||||||
|
relevant directory) where a recipient would be likely to look for such a
|
||||||
|
notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible
|
||||||
|
With Secondary Licenses", as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
30
vendor/github.com/hashicorp/go-cleanhttp/README.md
generated
vendored
Normal file
30
vendor/github.com/hashicorp/go-cleanhttp/README.md
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# cleanhttp
|
||||||
|
|
||||||
|
Functions for accessing "clean" Go http.Client values
|
||||||
|
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The Go standard library contains a default `http.Client` called
|
||||||
|
`http.DefaultClient`. It is a common idiom in Go code to start with
|
||||||
|
`http.DefaultClient` and tweak it as necessary, and in fact, this is
|
||||||
|
encouraged; from the `http` package documentation:
|
||||||
|
|
||||||
|
> The Client's Transport typically has internal state (cached TCP connections),
|
||||||
|
so Clients should be reused instead of created as needed. Clients are safe for
|
||||||
|
concurrent use by multiple goroutines.
|
||||||
|
|
||||||
|
Unfortunately, this is a shared value, and it is not uncommon for libraries to
|
||||||
|
assume that they are free to modify it at will. With enough dependencies, it
|
||||||
|
can be very easy to encounter strange problems and race conditions due to
|
||||||
|
manipulation of this shared value across libraries and goroutines (clients are
|
||||||
|
safe for concurrent use, but writing values to the client struct itself is not
|
||||||
|
protected).
|
||||||
|
|
||||||
|
Making things worse is the fact that a bare `http.Client` will use a default
|
||||||
|
`http.Transport` called `http.DefaultTransport`, which is another global value
|
||||||
|
that behaves the same way. So it is not simply enough to replace
|
||||||
|
`http.DefaultClient` with `&http.Client{}`.
|
||||||
|
|
||||||
|
This repository provides some simple functions to get a "clean" `http.Client`
|
||||||
|
-- one that uses the same default values as the Go standard library, but
|
||||||
|
returns a client that does not share any state with other clients.
|
53
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
Normal file
53
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package cleanhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultTransport returns a new http.Transport with the same default values
|
||||||
|
// as http.DefaultTransport, but with idle connections and keepalives disabled.
|
||||||
|
func DefaultTransport() *http.Transport {
|
||||||
|
transport := DefaultPooledTransport()
|
||||||
|
transport.DisableKeepAlives = true
|
||||||
|
transport.MaxIdleConnsPerHost = -1
|
||||||
|
return transport
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPooledTransport returns a new http.Transport with similar default
|
||||||
|
// values to http.DefaultTransport. Do not use this for transient transports as
|
||||||
|
// it can leak file descriptors over time. Only use this for transports that
|
||||||
|
// will be re-used for the same host(s).
|
||||||
|
func DefaultPooledTransport() *http.Transport {
|
||||||
|
transport := &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
|
DisableKeepAlives: false,
|
||||||
|
MaxIdleConnsPerHost: 1,
|
||||||
|
}
|
||||||
|
return transport
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultClient returns a new http.Client with similar default values to
|
||||||
|
// http.Client, but with a non-shared Transport, idle connections disabled, and
|
||||||
|
// keepalives disabled.
|
||||||
|
func DefaultClient() *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: DefaultTransport(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPooledClient returns a new http.Client with the same default values
|
||||||
|
// as http.Client, but with a shared Transport. Do not use this function
|
||||||
|
// for transient clients as it can leak file descriptors over time. Only use
|
||||||
|
// this for clients that will be re-used for the same host(s).
|
||||||
|
func DefaultPooledClient() *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: DefaultPooledTransport(),
|
||||||
|
}
|
||||||
|
}
|
20
vendor/github.com/hashicorp/go-cleanhttp/doc.go
generated
vendored
Normal file
20
vendor/github.com/hashicorp/go-cleanhttp/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Package cleanhttp offers convenience utilities for acquiring "clean"
|
||||||
|
// http.Transport and http.Client structs.
|
||||||
|
//
|
||||||
|
// Values set on http.DefaultClient and http.DefaultTransport affect all
|
||||||
|
// callers. This can have detrimental effects, esepcially in TLS contexts,
|
||||||
|
// where client or root certificates set to talk to multiple endpoints can end
|
||||||
|
// up displacing each other, leading to hard-to-debug issues. This package
|
||||||
|
// provides non-shared http.Client and http.Transport structs to ensure that
|
||||||
|
// the configuration will not be overwritten by other parts of the application
|
||||||
|
// or dependencies.
|
||||||
|
//
|
||||||
|
// The DefaultClient and DefaultTransport functions disable idle connections
|
||||||
|
// and keepalives. Without ensuring that idle connections are closed before
|
||||||
|
// garbage collection, short-term clients/transports can leak file descriptors,
|
||||||
|
// eventually leading to "too many open files" errors. If you will be
|
||||||
|
// connecting to the same hosts repeatedly from the same client, you can use
|
||||||
|
// DefaultPooledClient to receive a client that has connection pooling
|
||||||
|
// semantics similar to http.DefaultClient.
|
||||||
|
//
|
||||||
|
package cleanhttp
|
353
vendor/github.com/hashicorp/go-multierror/LICENSE
generated
vendored
Normal file
353
vendor/github.com/hashicorp/go-multierror/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. “Contributor”
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. “Contributor Version”
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor’s Contribution.
|
||||||
|
|
||||||
|
1.3. “Contribution”
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. “Covered Software”
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. “Incompatible With Secondary Licenses”
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of version
|
||||||
|
1.1 or earlier of the License, but not also under the terms of a
|
||||||
|
Secondary License.
|
||||||
|
|
||||||
|
1.6. “Executable Form”
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. “Larger Work”
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a separate
|
||||||
|
file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. “License”
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. “Licensable”
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether at the
|
||||||
|
time of the initial grant or subsequently, any and all of the rights conveyed by
|
||||||
|
this License.
|
||||||
|
|
||||||
|
1.10. “Modifications”
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to, deletion
|
||||||
|
from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. “Patent Claims” of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method, process,
|
||||||
|
and apparatus claims, in any patent Licensable by such Contributor that
|
||||||
|
would be infringed, but for the grant of the License, by the making,
|
||||||
|
using, selling, offering for sale, having made, import, or transfer of
|
||||||
|
either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. “Secondary License”
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. “Source Code Form”
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. “You” (or “Your”)
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, “You” includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, “control” means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or as
|
||||||
|
part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its Contributions
|
||||||
|
or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||||
|
effective for each Contribution on the date the Contributor first distributes
|
||||||
|
such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under this
|
||||||
|
License. No additional rights or licenses will be implied from the distribution
|
||||||
|
or licensing of Covered Software under this License. Notwithstanding Section
|
||||||
|
2.1(b) above, no patent license is granted by a Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party’s
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of its
|
||||||
|
Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks, or
|
||||||
|
logos of any Contributor (except as may be necessary to comply with the
|
||||||
|
notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this License
|
||||||
|
(see Section 10.2) or under the terms of a Secondary License (if permitted
|
||||||
|
under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its Contributions
|
||||||
|
are its original creation(s) or it has sufficient rights to grant the
|
||||||
|
rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under applicable
|
||||||
|
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under the
|
||||||
|
terms of this License. You must inform recipients that the Source Code Form
|
||||||
|
of the Covered Software is governed by the terms of this License, and how
|
||||||
|
they can obtain a copy of this License. You may not attempt to alter or
|
||||||
|
restrict the recipients’ rights in the Source Code Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this License,
|
||||||
|
or sublicense it under different terms, provided that the license for
|
||||||
|
the Executable Form does not attempt to limit or alter the recipients’
|
||||||
|
rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for the
|
||||||
|
Covered Software. If the Larger Work is a combination of Covered Software
|
||||||
|
with a work governed by one or more Secondary Licenses, and the Covered
|
||||||
|
Software is not Incompatible With Secondary Licenses, this License permits
|
||||||
|
You to additionally distribute such Covered Software under the terms of
|
||||||
|
such Secondary License(s), so that the recipient of the Larger Work may, at
|
||||||
|
their option, further distribute the Covered Software under the terms of
|
||||||
|
either this License or such Secondary License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices (including
|
||||||
|
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||||
|
of liability) contained within the Source Code Form of the Covered
|
||||||
|
Software, except that You may alter any license notices to the extent
|
||||||
|
required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on behalf
|
||||||
|
of any Contributor. You must make it absolutely clear that any such
|
||||||
|
warranty, support, indemnity, or liability obligation is offered by You
|
||||||
|
alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute, judicial
|
||||||
|
order, or regulation then You must: (a) comply with the terms of this License
|
||||||
|
to the maximum extent possible; and (b) describe the limitations and the code
|
||||||
|
they affect. Such description must be placed in a text file included with all
|
||||||
|
distributions of the Covered Software under this License. Except to the
|
||||||
|
extent prohibited by statute or regulation, such description must be
|
||||||
|
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||||
|
understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
|
||||||
|
if such Contributor fails to notify You of the non-compliance by some
|
||||||
|
reasonable means prior to 60 days after You have come back into compliance.
|
||||||
|
Moreover, Your grants from a particular Contributor are reinstated on an
|
||||||
|
ongoing basis if such Contributor notifies You of the non-compliance by
|
||||||
|
some reasonable means, this is the first time You have received notice of
|
||||||
|
non-compliance with this License from such Contributor, and You become
|
||||||
|
compliant prior to 30 days after Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions, counter-claims,
|
||||||
|
and cross-claims) alleging that a Contributor Version directly or
|
||||||
|
indirectly infringes any patent, then the rights granted to You by any and
|
||||||
|
all Contributors for the Covered Software under Section 2.1 of this License
|
||||||
|
shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an “as is” basis, without
|
||||||
|
warranty of any kind, either expressed, implied, or statutory, including,
|
||||||
|
without limitation, warranties that the Covered Software is free of defects,
|
||||||
|
merchantable, fit for a particular purpose or non-infringing. The entire
|
||||||
|
risk as to the quality and performance of the Covered Software is with You.
|
||||||
|
Should any Covered Software prove defective in any respect, You (not any
|
||||||
|
Contributor) assume the cost of any necessary servicing, repair, or
|
||||||
|
correction. This disclaimer of warranty constitutes an essential part of this
|
||||||
|
License. No use of any Covered Software is authorized under this License
|
||||||
|
except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from such
|
||||||
|
party’s negligence to the extent applicable law prohibits such limitation.
|
||||||
|
Some jurisdictions do not allow the exclusion or limitation of incidental or
|
||||||
|
consequential damages, so this exclusion and limitation may not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts of
|
||||||
|
a jurisdiction where the defendant maintains its principal place of business
|
||||||
|
and such litigation shall be governed by laws of that jurisdiction, without
|
||||||
|
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||||
|
prevent a party’s ability to bring cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject matter
|
||||||
|
hereof. If any provision of this License is held to be unenforceable, such
|
||||||
|
provision shall be reformed only to the extent necessary to make it
|
||||||
|
enforceable. Any law or regulation which provides that the language of a
|
||||||
|
contract shall be construed against the drafter shall not be used to construe
|
||||||
|
this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version of
|
||||||
|
the License under which You originally received the Covered Software, or
|
||||||
|
under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a modified
|
||||||
|
version of this License if you rename the license and remove any
|
||||||
|
references to the name of the license steward (except to note that such
|
||||||
|
modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file, then
|
||||||
|
You may include the notice in a location (such as a LICENSE file in a relevant
|
||||||
|
directory) where a recipient would be likely to look for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||||
|
|
||||||
|
This Source Code Form is “Incompatible
|
||||||
|
With Secondary Licenses”, as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
91
vendor/github.com/hashicorp/go-multierror/README.md
generated
vendored
Normal file
91
vendor/github.com/hashicorp/go-multierror/README.md
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
# go-multierror
|
||||||
|
|
||||||
|
`go-multierror` is a package for Go that provides a mechanism for
|
||||||
|
representing a list of `error` values as a single `error`.
|
||||||
|
|
||||||
|
This allows a function in Go to return an `error` that might actually
|
||||||
|
be a list of errors. If the caller knows this, they can unwrap the
|
||||||
|
list and access the errors. If the caller doesn't know, the error
|
||||||
|
formats to a nice human-readable format.
|
||||||
|
|
||||||
|
`go-multierror` implements the
|
||||||
|
[errwrap](https://github.com/hashicorp/errwrap) interface so that it can
|
||||||
|
be used with that library, as well.
|
||||||
|
|
||||||
|
## Installation and Docs
|
||||||
|
|
||||||
|
Install using `go get github.com/hashicorp/go-multierror`.
|
||||||
|
|
||||||
|
Full documentation is available at
|
||||||
|
http://godoc.org/github.com/hashicorp/go-multierror
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
go-multierror is easy to use and purposely built to be unobtrusive in
|
||||||
|
existing Go applications/libraries that may not be aware of it.
|
||||||
|
|
||||||
|
**Building a list of errors**
|
||||||
|
|
||||||
|
The `Append` function is used to create a list of errors. This function
|
||||||
|
behaves a lot like the Go built-in `append` function: it doesn't matter
|
||||||
|
if the first argument is nil, a `multierror.Error`, or any other `error`,
|
||||||
|
the function behaves as you would expect.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var result error
|
||||||
|
|
||||||
|
if err := step1(); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
if err := step2(); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
```
|
||||||
|
|
||||||
|
**Customizing the formatting of the errors**
|
||||||
|
|
||||||
|
By specifying a custom `ErrorFormat`, you can customize the format
|
||||||
|
of the `Error() string` function:
|
||||||
|
|
||||||
|
```go
|
||||||
|
var result *multierror.Error
|
||||||
|
|
||||||
|
// ... accumulate errors here, maybe using Append
|
||||||
|
|
||||||
|
if result != nil {
|
||||||
|
result.ErrorFormat = func([]error) string {
|
||||||
|
return "errors!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Accessing the list of errors**
|
||||||
|
|
||||||
|
`multierror.Error` implements `error` so if the caller doesn't know about
|
||||||
|
multierror, it will work just fine. But if you're aware a multierror might
|
||||||
|
be returned, you can use type switches to access the list of errors:
|
||||||
|
|
||||||
|
```go
|
||||||
|
if err := something(); err != nil {
|
||||||
|
if merr, ok := err.(*multierror.Error); ok {
|
||||||
|
// Use merr.Errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returning a multierror only if there are errors**
|
||||||
|
|
||||||
|
If you build a `multierror.Error`, you can use the `ErrorOrNil` function
|
||||||
|
to return an `error` implementation only if there are errors to return:
|
||||||
|
|
||||||
|
```go
|
||||||
|
var result *multierror.Error
|
||||||
|
|
||||||
|
// ... accumulate errors here
|
||||||
|
|
||||||
|
// Return the `error` only if errors were added to the multierror, otherwise
|
||||||
|
// return nil since there are no errors.
|
||||||
|
return result.ErrorOrNil()
|
||||||
|
```
|
37
vendor/github.com/hashicorp/go-multierror/append.go
generated
vendored
Normal file
37
vendor/github.com/hashicorp/go-multierror/append.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package multierror
|
||||||
|
|
||||||
|
// Append is a helper function that will append more errors
|
||||||
|
// onto an Error in order to create a larger multi-error.
|
||||||
|
//
|
||||||
|
// If err is not a multierror.Error, then it will be turned into
|
||||||
|
// one. If any of the errs are multierr.Error, they will be flattened
|
||||||
|
// one level into err.
|
||||||
|
func Append(err error, errs ...error) *Error {
|
||||||
|
switch err := err.(type) {
|
||||||
|
case *Error:
|
||||||
|
// Typed nils can reach here, so initialize if we are nil
|
||||||
|
if err == nil {
|
||||||
|
err = new(Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through each error and flatten
|
||||||
|
for _, e := range errs {
|
||||||
|
switch e := e.(type) {
|
||||||
|
case *Error:
|
||||||
|
err.Errors = append(err.Errors, e.Errors...)
|
||||||
|
default:
|
||||||
|
err.Errors = append(err.Errors, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
default:
|
||||||
|
newErrs := make([]error, 0, len(errs)+1)
|
||||||
|
if err != nil {
|
||||||
|
newErrs = append(newErrs, err)
|
||||||
|
}
|
||||||
|
newErrs = append(newErrs, errs...)
|
||||||
|
|
||||||
|
return Append(&Error{}, newErrs...)
|
||||||
|
}
|
||||||
|
}
|
26
vendor/github.com/hashicorp/go-multierror/flatten.go
generated
vendored
Normal file
26
vendor/github.com/hashicorp/go-multierror/flatten.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package multierror
|
||||||
|
|
||||||
|
// Flatten flattens the given error, merging any *Errors together into
|
||||||
|
// a single *Error.
|
||||||
|
func Flatten(err error) error {
|
||||||
|
// If it isn't an *Error, just return the error as-is
|
||||||
|
if _, ok := err.(*Error); !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, make the result and flatten away!
|
||||||
|
flatErr := new(Error)
|
||||||
|
flatten(err, flatErr)
|
||||||
|
return flatErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func flatten(err error, flatErr *Error) {
|
||||||
|
switch err := err.(type) {
|
||||||
|
case *Error:
|
||||||
|
for _, e := range err.Errors {
|
||||||
|
flatten(e, flatErr)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
flatErr.Errors = append(flatErr.Errors, err)
|
||||||
|
}
|
||||||
|
}
|
23
vendor/github.com/hashicorp/go-multierror/format.go
generated
vendored
Normal file
23
vendor/github.com/hashicorp/go-multierror/format.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package multierror
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrorFormatFunc is a function callback that is called by Error to
|
||||||
|
// turn the list of errors into a string.
|
||||||
|
type ErrorFormatFunc func([]error) string
|
||||||
|
|
||||||
|
// ListFormatFunc is a basic formatter that outputs the number of errors
|
||||||
|
// that occurred along with a bullet point list of the errors.
|
||||||
|
func ListFormatFunc(es []error) string {
|
||||||
|
points := make([]string, len(es))
|
||||||
|
for i, err := range es {
|
||||||
|
points[i] = fmt.Sprintf("* %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%d error(s) occurred:\n\n%s",
|
||||||
|
len(es), strings.Join(points, "\n"))
|
||||||
|
}
|
51
vendor/github.com/hashicorp/go-multierror/multierror.go
generated
vendored
Normal file
51
vendor/github.com/hashicorp/go-multierror/multierror.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package multierror
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error is an error type to track multiple errors. This is used to
|
||||||
|
// accumulate errors in cases and return them as a single "error".
|
||||||
|
type Error struct {
|
||||||
|
Errors []error
|
||||||
|
ErrorFormat ErrorFormatFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
fn := e.ErrorFormat
|
||||||
|
if fn == nil {
|
||||||
|
fn = ListFormatFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
return fn(e.Errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorOrNil returns an error interface if this Error represents
|
||||||
|
// a list of errors, or returns nil if the list of errors is empty. This
|
||||||
|
// function is useful at the end of accumulation to make sure that the value
|
||||||
|
// returned represents the existence of errors.
|
||||||
|
func (e *Error) ErrorOrNil() error {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(e.Errors) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) GoString() string {
|
||||||
|
return fmt.Sprintf("*%#v", *e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrappedErrors returns the list of errors that this Error is wrapping.
|
||||||
|
// It is an implementatin of the errwrap.Wrapper interface so that
|
||||||
|
// multierror.Error can be used with that library.
|
||||||
|
//
|
||||||
|
// This method is not safe to be called concurrently and is no different
|
||||||
|
// than accessing the Errors field directly. It is implementd only to
|
||||||
|
// satisfy the errwrap.Wrapper interface.
|
||||||
|
func (e *Error) WrappedErrors() []error {
|
||||||
|
return e.Errors
|
||||||
|
}
|
37
vendor/github.com/hashicorp/go-multierror/prefix.go
generated
vendored
Normal file
37
vendor/github.com/hashicorp/go-multierror/prefix.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package multierror
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/errwrap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Prefix is a helper function that will prefix some text
|
||||||
|
// to the given error. If the error is a multierror.Error, then
|
||||||
|
// it will be prefixed to each wrapped error.
|
||||||
|
//
|
||||||
|
// This is useful to use when appending multiple multierrors
|
||||||
|
// together in order to give better scoping.
|
||||||
|
func Prefix(err error, prefix string) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
format := fmt.Sprintf("%s {{err}}", prefix)
|
||||||
|
switch err := err.(type) {
|
||||||
|
case *Error:
|
||||||
|
// Typed nils can reach here, so initialize if we are nil
|
||||||
|
if err == nil {
|
||||||
|
err = new(Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap each of the errors
|
||||||
|
for i, e := range err.Errors {
|
||||||
|
err.Errors[i] = errwrap.Wrapf(format, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
default:
|
||||||
|
return errwrap.Wrapf(format, err)
|
||||||
|
}
|
||||||
|
}
|
12
vendor/github.com/hashicorp/go-rootcerts/.travis.yml
generated
vendored
Normal file
12
vendor/github.com/hashicorp/go-rootcerts/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.6
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
|
||||||
|
script: make test
|
363
vendor/github.com/hashicorp/go-rootcerts/LICENSE
generated
vendored
Normal file
363
vendor/github.com/hashicorp/go-rootcerts/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the terms of
|
||||||
|
a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a
|
||||||
|
separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether
|
||||||
|
at the time of the initial grant or subsequently, any and all of the
|
||||||
|
rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the License,
|
||||||
|
by the making, using, selling, offering for sale, having made, import,
|
||||||
|
or transfer of either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, "control" means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights to
|
||||||
|
grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter the
|
||||||
|
recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||||
|
limitations of liability) contained within the Source Code Form of the
|
||||||
|
Covered Software, except that You may alter any license notices to the
|
||||||
|
extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute,
|
||||||
|
judicial order, or regulation then You must: (a) comply with the terms of
|
||||||
|
this License to the maximum extent possible; and (b) describe the
|
||||||
|
limitations and the code they affect. Such description must be placed in a
|
||||||
|
text file included with all distributions of the Covered Software under
|
||||||
|
this License. Except to the extent prohibited by statute or regulation,
|
||||||
|
such description must be sufficiently detailed for a recipient of ordinary
|
||||||
|
skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||||
|
basis, if such Contributor fails to notify You of the non-compliance by
|
||||||
|
some reasonable means prior to 60 days after You have come back into
|
||||||
|
compliance. Moreover, Your grants from a particular Contributor are
|
||||||
|
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||||
|
non-compliance by some reasonable means, this is the first time You have
|
||||||
|
received notice of non-compliance with this License from such
|
||||||
|
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||||
|
of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an "as is" basis,
|
||||||
|
without warranty of any kind, either expressed, implied, or statutory,
|
||||||
|
including, without limitation, warranties that the Covered Software is free
|
||||||
|
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
The entire risk as to the quality and performance of the Covered Software
|
||||||
|
is with You. Should any Covered Software prove defective in any respect,
|
||||||
|
You (not any Contributor) assume the cost of any necessary servicing,
|
||||||
|
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this License. No use of any Covered Software is authorized under
|
||||||
|
this License except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from
|
||||||
|
such party's negligence to the extent applicable law prohibits such
|
||||||
|
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||||
|
incidental or consequential damages, so this exclusion and limitation may
|
||||||
|
not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts
|
||||||
|
of a jurisdiction where the defendant maintains its principal place of
|
||||||
|
business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||||
|
in this Section shall prevent a party's ability to bring cross-claims or
|
||||||
|
counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides that
|
||||||
|
the language of a contract shall be construed against the drafter shall not
|
||||||
|
be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses If You choose to distribute Source Code Form that is
|
||||||
|
Incompatible With Secondary Licenses under the terms of this version of
|
||||||
|
the License, the notice described in Exhibit B of this License must be
|
||||||
|
attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file,
|
||||||
|
then You may include the notice in a location (such as a LICENSE file in a
|
||||||
|
relevant directory) where a recipient would be likely to look for such a
|
||||||
|
notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible
|
||||||
|
With Secondary Licenses", as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
8
vendor/github.com/hashicorp/go-rootcerts/Makefile
generated
vendored
Normal file
8
vendor/github.com/hashicorp/go-rootcerts/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
TEST?=./...
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test $(TEST) $(TESTARGS) -timeout=3s -parallel=4
|
||||||
|
go vet $(TEST)
|
||||||
|
go test $(TEST) -race
|
||||||
|
|
||||||
|
.PHONY: test
|
43
vendor/github.com/hashicorp/go-rootcerts/README.md
generated
vendored
Normal file
43
vendor/github.com/hashicorp/go-rootcerts/README.md
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# rootcerts
|
||||||
|
|
||||||
|
Functions for loading root certificates for TLS connections.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
Go's standard library `crypto/tls` provides a common mechanism for configuring
|
||||||
|
TLS connections in `tls.Config`. The `RootCAs` field on this struct is a pool
|
||||||
|
of certificates for the client to use as a trust store when verifying server
|
||||||
|
certificates.
|
||||||
|
|
||||||
|
This library contains utility functions for loading certificates destined for
|
||||||
|
that field, as well as one other important thing:
|
||||||
|
|
||||||
|
When the `RootCAs` field is `nil`, the standard library attempts to load the
|
||||||
|
host's root CA set. This behavior is OS-specific, and the Darwin
|
||||||
|
implementation contains [a bug that prevents trusted certificates from the
|
||||||
|
System and Login keychains from being loaded][1]. This library contains
|
||||||
|
Darwin-specific behavior that works around that bug.
|
||||||
|
|
||||||
|
[1]: https://github.com/golang/go/issues/14514
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
Here's a snippet demonstrating how this library is meant to be used:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func httpClient() (*http.Client, error)
|
||||||
|
tlsConfig := &tls.Config{}
|
||||||
|
err := rootcerts.ConfigureTLS(tlsConfig, &rootcerts.Config{
|
||||||
|
CAFile: os.Getenv("MYAPP_CAFILE"),
|
||||||
|
CAPath: os.Getenv("MYAPP_CAPATH"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := cleanhttp.DefaultClient()
|
||||||
|
t := cleanhttp.DefaultTransport()
|
||||||
|
t.TLSClientConfig = tlsConfig
|
||||||
|
c.Transport = t
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
```
|
9
vendor/github.com/hashicorp/go-rootcerts/doc.go
generated
vendored
Normal file
9
vendor/github.com/hashicorp/go-rootcerts/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// Package rootcerts contains functions to aid in loading CA certificates for
|
||||||
|
// TLS connections.
|
||||||
|
//
|
||||||
|
// In addition, its default behavior on Darwin works around an open issue [1]
|
||||||
|
// in Go's crypto/x509 that prevents certicates from being loaded from the
|
||||||
|
// System or Login keychains.
|
||||||
|
//
|
||||||
|
// [1] https://github.com/golang/go/issues/14514
|
||||||
|
package rootcerts
|
103
vendor/github.com/hashicorp/go-rootcerts/rootcerts.go
generated
vendored
Normal file
103
vendor/github.com/hashicorp/go-rootcerts/rootcerts.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package rootcerts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config determines where LoadCACerts will load certificates from. When both
|
||||||
|
// CAFile and CAPath are blank, this library's functions will either load
|
||||||
|
// system roots explicitly and return them, or set the CertPool to nil to allow
|
||||||
|
// Go's standard library to load system certs.
|
||||||
|
type Config struct {
|
||||||
|
// CAFile is a path to a PEM-encoded certificate file or bundle. Takes
|
||||||
|
// precedence over CAPath.
|
||||||
|
CAFile string
|
||||||
|
|
||||||
|
// CAPath is a path to a directory populated with PEM-encoded certificates.
|
||||||
|
CAPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigureTLS sets up the RootCAs on the provided tls.Config based on the
|
||||||
|
// Config specified.
|
||||||
|
func ConfigureTLS(t *tls.Config, c *Config) error {
|
||||||
|
if t == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
pool, err := LoadCACerts(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.RootCAs = pool
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadCACerts loads a CertPool based on the Config specified.
|
||||||
|
func LoadCACerts(c *Config) (*x509.CertPool, error) {
|
||||||
|
if c == nil {
|
||||||
|
c = &Config{}
|
||||||
|
}
|
||||||
|
if c.CAFile != "" {
|
||||||
|
return LoadCAFile(c.CAFile)
|
||||||
|
}
|
||||||
|
if c.CAPath != "" {
|
||||||
|
return LoadCAPath(c.CAPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadSystemCAs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadCAFile loads a single PEM-encoded file from the path specified.
|
||||||
|
func LoadCAFile(caFile string) (*x509.CertPool, error) {
|
||||||
|
pool := x509.NewCertPool()
|
||||||
|
|
||||||
|
pem, err := ioutil.ReadFile(caFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error loading CA File: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := pool.AppendCertsFromPEM(pem)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Error loading CA File: Couldn't parse PEM in: %s", caFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pool, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadCAPath walks the provided path and loads all certificates encounted into
|
||||||
|
// a pool.
|
||||||
|
func LoadCAPath(caPath string) (*x509.CertPool, error) {
|
||||||
|
pool := x509.NewCertPool()
|
||||||
|
walkFn := func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pem, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error loading file from CAPath: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := pool.AppendCertsFromPEM(pem)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Error loading CA Path: Couldn't parse PEM in: %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := filepath.Walk(caPath, walkFn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pool, nil
|
||||||
|
}
|
12
vendor/github.com/hashicorp/go-rootcerts/rootcerts_base.go
generated
vendored
Normal file
12
vendor/github.com/hashicorp/go-rootcerts/rootcerts_base.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// +build !darwin
|
||||||
|
|
||||||
|
package rootcerts
|
||||||
|
|
||||||
|
import "crypto/x509"
|
||||||
|
|
||||||
|
// LoadSystemCAs does nothing on non-Darwin systems. We return nil so that
|
||||||
|
// default behavior of standard TLS config libraries is triggered, which is to
|
||||||
|
// load system certs.
|
||||||
|
func LoadSystemCAs() (*x509.CertPool, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
48
vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go
generated
vendored
Normal file
48
vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package rootcerts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoadSystemCAs has special behavior on Darwin systems to work around
|
||||||
|
func LoadSystemCAs() (*x509.CertPool, error) {
|
||||||
|
pool := x509.NewCertPool()
|
||||||
|
|
||||||
|
for _, keychain := range certKeychains() {
|
||||||
|
err := addCertsFromKeychain(pool, keychain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pool, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addCertsFromKeychain(pool *x509.CertPool, keychain string) error {
|
||||||
|
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", keychain)
|
||||||
|
data, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.AppendCertsFromPEM(data)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func certKeychains() []string {
|
||||||
|
keychains := []string{
|
||||||
|
"/System/Library/Keychains/SystemRootCertificates.keychain",
|
||||||
|
"/Library/Keychains/System.keychain",
|
||||||
|
}
|
||||||
|
home, err := homedir.Dir()
|
||||||
|
if err == nil {
|
||||||
|
loginKeychain := path.Join(home, "Library", "Keychains", "login.keychain")
|
||||||
|
keychains = append(keychains, loginKeychain)
|
||||||
|
}
|
||||||
|
return keychains
|
||||||
|
}
|
9
vendor/github.com/hashicorp/hcl/.gitignore
generated
vendored
Normal file
9
vendor/github.com/hashicorp/hcl/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
y.output
|
||||||
|
|
||||||
|
# ignore intellij files
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
*.test
|
3
vendor/github.com/hashicorp/hcl/.travis.yml
generated
vendored
Normal file
3
vendor/github.com/hashicorp/hcl/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
go: 1.7
|
354
vendor/github.com/hashicorp/hcl/LICENSE
generated
vendored
Normal file
354
vendor/github.com/hashicorp/hcl/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. “Contributor”
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. “Contributor Version”
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor’s Contribution.
|
||||||
|
|
||||||
|
1.3. “Contribution”
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. “Covered Software”
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. “Incompatible With Secondary Licenses”
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of version
|
||||||
|
1.1 or earlier of the License, but not also under the terms of a
|
||||||
|
Secondary License.
|
||||||
|
|
||||||
|
1.6. “Executable Form”
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. “Larger Work”
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a separate
|
||||||
|
file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. “License”
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. “Licensable”
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether at the
|
||||||
|
time of the initial grant or subsequently, any and all of the rights conveyed by
|
||||||
|
this License.
|
||||||
|
|
||||||
|
1.10. “Modifications”
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to, deletion
|
||||||
|
from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. “Patent Claims” of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method, process,
|
||||||
|
and apparatus claims, in any patent Licensable by such Contributor that
|
||||||
|
would be infringed, but for the grant of the License, by the making,
|
||||||
|
using, selling, offering for sale, having made, import, or transfer of
|
||||||
|
either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. “Secondary License”
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. “Source Code Form”
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. “You” (or “Your”)
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, “You” includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, “control” means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or as
|
||||||
|
part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its Contributions
|
||||||
|
or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||||
|
effective for each Contribution on the date the Contributor first distributes
|
||||||
|
such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under this
|
||||||
|
License. No additional rights or licenses will be implied from the distribution
|
||||||
|
or licensing of Covered Software under this License. Notwithstanding Section
|
||||||
|
2.1(b) above, no patent license is granted by a Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party’s
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of its
|
||||||
|
Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks, or
|
||||||
|
logos of any Contributor (except as may be necessary to comply with the
|
||||||
|
notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this License
|
||||||
|
(see Section 10.2) or under the terms of a Secondary License (if permitted
|
||||||
|
under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its Contributions
|
||||||
|
are its original creation(s) or it has sufficient rights to grant the
|
||||||
|
rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under applicable
|
||||||
|
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under the
|
||||||
|
terms of this License. You must inform recipients that the Source Code Form
|
||||||
|
of the Covered Software is governed by the terms of this License, and how
|
||||||
|
they can obtain a copy of this License. You may not attempt to alter or
|
||||||
|
restrict the recipients’ rights in the Source Code Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this License,
|
||||||
|
or sublicense it under different terms, provided that the license for
|
||||||
|
the Executable Form does not attempt to limit or alter the recipients’
|
||||||
|
rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for the
|
||||||
|
Covered Software. If the Larger Work is a combination of Covered Software
|
||||||
|
with a work governed by one or more Secondary Licenses, and the Covered
|
||||||
|
Software is not Incompatible With Secondary Licenses, this License permits
|
||||||
|
You to additionally distribute such Covered Software under the terms of
|
||||||
|
such Secondary License(s), so that the recipient of the Larger Work may, at
|
||||||
|
their option, further distribute the Covered Software under the terms of
|
||||||
|
either this License or such Secondary License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices (including
|
||||||
|
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||||
|
of liability) contained within the Source Code Form of the Covered
|
||||||
|
Software, except that You may alter any license notices to the extent
|
||||||
|
required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on behalf
|
||||||
|
of any Contributor. You must make it absolutely clear that any such
|
||||||
|
warranty, support, indemnity, or liability obligation is offered by You
|
||||||
|
alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute, judicial
|
||||||
|
order, or regulation then You must: (a) comply with the terms of this License
|
||||||
|
to the maximum extent possible; and (b) describe the limitations and the code
|
||||||
|
they affect. Such description must be placed in a text file included with all
|
||||||
|
distributions of the Covered Software under this License. Except to the
|
||||||
|
extent prohibited by statute or regulation, such description must be
|
||||||
|
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||||
|
understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
|
||||||
|
if such Contributor fails to notify You of the non-compliance by some
|
||||||
|
reasonable means prior to 60 days after You have come back into compliance.
|
||||||
|
Moreover, Your grants from a particular Contributor are reinstated on an
|
||||||
|
ongoing basis if such Contributor notifies You of the non-compliance by
|
||||||
|
some reasonable means, this is the first time You have received notice of
|
||||||
|
non-compliance with this License from such Contributor, and You become
|
||||||
|
compliant prior to 30 days after Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions, counter-claims,
|
||||||
|
and cross-claims) alleging that a Contributor Version directly or
|
||||||
|
indirectly infringes any patent, then the rights granted to You by any and
|
||||||
|
all Contributors for the Covered Software under Section 2.1 of this License
|
||||||
|
shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an “as is” basis, without
|
||||||
|
warranty of any kind, either expressed, implied, or statutory, including,
|
||||||
|
without limitation, warranties that the Covered Software is free of defects,
|
||||||
|
merchantable, fit for a particular purpose or non-infringing. The entire
|
||||||
|
risk as to the quality and performance of the Covered Software is with You.
|
||||||
|
Should any Covered Software prove defective in any respect, You (not any
|
||||||
|
Contributor) assume the cost of any necessary servicing, repair, or
|
||||||
|
correction. This disclaimer of warranty constitutes an essential part of this
|
||||||
|
License. No use of any Covered Software is authorized under this License
|
||||||
|
except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from such
|
||||||
|
party’s negligence to the extent applicable law prohibits such limitation.
|
||||||
|
Some jurisdictions do not allow the exclusion or limitation of incidental or
|
||||||
|
consequential damages, so this exclusion and limitation may not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts of
|
||||||
|
a jurisdiction where the defendant maintains its principal place of business
|
||||||
|
and such litigation shall be governed by laws of that jurisdiction, without
|
||||||
|
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||||
|
prevent a party’s ability to bring cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject matter
|
||||||
|
hereof. If any provision of this License is held to be unenforceable, such
|
||||||
|
provision shall be reformed only to the extent necessary to make it
|
||||||
|
enforceable. Any law or regulation which provides that the language of a
|
||||||
|
contract shall be construed against the drafter shall not be used to construe
|
||||||
|
this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version of
|
||||||
|
the License under which You originally received the Covered Software, or
|
||||||
|
under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a modified
|
||||||
|
version of this License if you rename the license and remove any
|
||||||
|
references to the name of the license steward (except to note that such
|
||||||
|
modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file, then
|
||||||
|
You may include the notice in a location (such as a LICENSE file in a relevant
|
||||||
|
directory) where a recipient would be likely to look for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||||
|
|
||||||
|
This Source Code Form is “Incompatible
|
||||||
|
With Secondary Licenses”, as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
18
vendor/github.com/hashicorp/hcl/Makefile
generated
vendored
Normal file
18
vendor/github.com/hashicorp/hcl/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
TEST?=./...
|
||||||
|
|
||||||
|
default: test
|
||||||
|
|
||||||
|
fmt: generate
|
||||||
|
go fmt ./...
|
||||||
|
|
||||||
|
test: generate
|
||||||
|
go get -t ./...
|
||||||
|
go test $(TEST) $(TESTARGS)
|
||||||
|
|
||||||
|
generate:
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
updatedeps:
|
||||||
|
go get -u golang.org/x/tools/cmd/stringer
|
||||||
|
|
||||||
|
.PHONY: default generate test updatedeps
|
125
vendor/github.com/hashicorp/hcl/README.md
generated
vendored
Normal file
125
vendor/github.com/hashicorp/hcl/README.md
generated
vendored
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
# HCL
|
||||||
|
|
||||||
|
[![GoDoc](https://godoc.org/github.com/hashicorp/hcl?status.png)](https://godoc.org/github.com/hashicorp/hcl) [![Build Status](https://travis-ci.org/hashicorp/hcl.svg?branch=master)](https://travis-ci.org/hashicorp/hcl)
|
||||||
|
|
||||||
|
HCL (HashiCorp Configuration Language) is a configuration language built
|
||||||
|
by HashiCorp. The goal of HCL is to build a structured configuration language
|
||||||
|
that is both human and machine friendly for use with command-line tools, but
|
||||||
|
specifically targeted towards DevOps tools, servers, etc.
|
||||||
|
|
||||||
|
HCL is also fully JSON compatible. That is, JSON can be used as completely
|
||||||
|
valid input to a system expecting HCL. This helps makes systems
|
||||||
|
interoperable with other systems.
|
||||||
|
|
||||||
|
HCL is heavily inspired by
|
||||||
|
[libucl](https://github.com/vstakhov/libucl),
|
||||||
|
nginx configuration, and others similar.
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
A common question when viewing HCL is to ask the question: why not
|
||||||
|
JSON, YAML, etc.?
|
||||||
|
|
||||||
|
Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com)
|
||||||
|
used a variety of configuration languages from full programming languages
|
||||||
|
such as Ruby to complete data structure languages such as JSON. What we
|
||||||
|
learned is that some people wanted human-friendly configuration languages
|
||||||
|
and some people wanted machine-friendly languages.
|
||||||
|
|
||||||
|
JSON fits a nice balance in this, but is fairly verbose and most
|
||||||
|
importantly doesn't support comments. With YAML, we found that beginners
|
||||||
|
had a really hard time determining what the actual structure was, and
|
||||||
|
ended up guessing more often than not whether to use a hyphen, colon, etc.
|
||||||
|
in order to represent some configuration key.
|
||||||
|
|
||||||
|
Full programming languages such as Ruby enable complex behavior
|
||||||
|
a configuration language shouldn't usually allow, and also forces
|
||||||
|
people to learn some set of Ruby.
|
||||||
|
|
||||||
|
Because of this, we decided to create our own configuration language
|
||||||
|
that is JSON-compatible. Our configuration language (HCL) is designed
|
||||||
|
to be written and modified by humans. The API for HCL allows JSON
|
||||||
|
as an input so that it is also machine-friendly (machines can generate
|
||||||
|
JSON instead of trying to generate HCL).
|
||||||
|
|
||||||
|
Our goal with HCL is not to alienate other configuration languages.
|
||||||
|
It is instead to provide HCL as a specialized language for our tools,
|
||||||
|
and JSON as the interoperability layer.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
For a complete grammar, please see the parser itself. A high-level overview
|
||||||
|
of the syntax and grammar is listed here.
|
||||||
|
|
||||||
|
* Single line comments start with `#` or `//`
|
||||||
|
|
||||||
|
* Multi-line comments are wrapped in `/*` and `*/`. Nested block comments
|
||||||
|
are not allowed. A multi-line comment (also known as a block comment)
|
||||||
|
terminates at the first `*/` found.
|
||||||
|
|
||||||
|
* Values are assigned with the syntax `key = value` (whitespace doesn't
|
||||||
|
matter). The value can be any primitive: a string, number, boolean,
|
||||||
|
object, or list.
|
||||||
|
|
||||||
|
* Strings are double-quoted and can contain any UTF-8 characters.
|
||||||
|
Example: `"Hello, World"`
|
||||||
|
|
||||||
|
* Multi-line strings start with `<<EOF` at the end of a line, and end
|
||||||
|
with `EOF` on its own line ([here documents](https://en.wikipedia.org/wiki/Here_document)).
|
||||||
|
Any text may be used in place of `EOF`. Example:
|
||||||
|
```
|
||||||
|
<<FOO
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
FOO
|
||||||
|
```
|
||||||
|
|
||||||
|
* Numbers are assumed to be base 10. If you prefix a number with 0x,
|
||||||
|
it is treated as a hexadecimal. If it is prefixed with 0, it is
|
||||||
|
treated as an octal. Numbers can be in scientific notation: "1e10".
|
||||||
|
|
||||||
|
* Boolean values: `true`, `false`
|
||||||
|
|
||||||
|
* Arrays can be made by wrapping it in `[]`. Example:
|
||||||
|
`["foo", "bar", 42]`. Arrays can contain primitives,
|
||||||
|
other arrays, and objects. As an alternative, lists
|
||||||
|
of objects can be created with repeated blocks, using
|
||||||
|
this structure:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
service {
|
||||||
|
key = "value"
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
key = "value"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Objects and nested objects are created using the structure shown below:
|
||||||
|
|
||||||
|
```
|
||||||
|
variable "ami" {
|
||||||
|
description = "the AMI to use"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
This would be equivalent to the following json:
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"variable": {
|
||||||
|
"ami": {
|
||||||
|
"description": "the AMI to use"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
|
Thanks to:
|
||||||
|
|
||||||
|
* [@vstakhov](https://github.com/vstakhov) - The original libucl parser
|
||||||
|
and syntax that HCL was based off of.
|
||||||
|
|
||||||
|
* [@fatih](https://github.com/fatih) - The rewritten HCL parser
|
||||||
|
in pure Go (no goyacc) and support for a printer.
|
19
vendor/github.com/hashicorp/hcl/appveyor.yml
generated
vendored
Normal file
19
vendor/github.com/hashicorp/hcl/appveyor.yml
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
version: "build-{branch}-{build}"
|
||||||
|
image: Visual Studio 2015
|
||||||
|
clone_folder: c:\gopath\src\github.com\hashicorp\hcl
|
||||||
|
environment:
|
||||||
|
GOPATH: c:\gopath
|
||||||
|
init:
|
||||||
|
- git config --global core.autocrlf true
|
||||||
|
install:
|
||||||
|
- cmd: >-
|
||||||
|
echo %Path%
|
||||||
|
|
||||||
|
go version
|
||||||
|
|
||||||
|
go env
|
||||||
|
|
||||||
|
go get -t ./...
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- cmd: go test -v ./...
|
716
vendor/github.com/hashicorp/hcl/decoder.go
generated
vendored
Normal file
716
vendor/github.com/hashicorp/hcl/decoder.go
generated
vendored
Normal file
|
@ -0,0 +1,716 @@
|
||||||
|
package hcl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
"github.com/hashicorp/hcl/hcl/parser"
|
||||||
|
"github.com/hashicorp/hcl/hcl/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is the tag to use with structures to have settings for HCL
|
||||||
|
const tagName = "hcl"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// nodeType holds a reference to the type of ast.Node
|
||||||
|
nodeType reflect.Type = findNodeType()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unmarshal accepts a byte slice as input and writes the
|
||||||
|
// data to the value pointed to by v.
|
||||||
|
func Unmarshal(bs []byte, v interface{}) error {
|
||||||
|
root, err := parse(bs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return DecodeObject(v, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode reads the given input and decodes it into the structure
|
||||||
|
// given by `out`.
|
||||||
|
func Decode(out interface{}, in string) error {
|
||||||
|
obj, err := Parse(in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return DecodeObject(out, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeObject is a lower-level version of Decode. It decodes a
|
||||||
|
// raw Object into the given output.
|
||||||
|
func DecodeObject(out interface{}, n ast.Node) error {
|
||||||
|
val := reflect.ValueOf(out)
|
||||||
|
if val.Kind() != reflect.Ptr {
|
||||||
|
return errors.New("result must be a pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have the file, we really decode the root node
|
||||||
|
if f, ok := n.(*ast.File); ok {
|
||||||
|
n = f.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
var d decoder
|
||||||
|
return d.decode("root", n, val.Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
type decoder struct {
|
||||||
|
stack []reflect.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
k := result
|
||||||
|
|
||||||
|
// If we have an interface with a valid value, we use that
|
||||||
|
// for the check.
|
||||||
|
if result.Kind() == reflect.Interface {
|
||||||
|
elem := result.Elem()
|
||||||
|
if elem.IsValid() {
|
||||||
|
k = elem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push current onto stack unless it is an interface.
|
||||||
|
if k.Kind() != reflect.Interface {
|
||||||
|
d.stack = append(d.stack, k.Kind())
|
||||||
|
|
||||||
|
// Schedule a pop
|
||||||
|
defer func() {
|
||||||
|
d.stack = d.stack[:len(d.stack)-1]
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch k.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return d.decodeBool(name, node, result)
|
||||||
|
case reflect.Float64:
|
||||||
|
return d.decodeFloat(name, node, result)
|
||||||
|
case reflect.Int:
|
||||||
|
return d.decodeInt(name, node, result)
|
||||||
|
case reflect.Interface:
|
||||||
|
// When we see an interface, we make our own thing
|
||||||
|
return d.decodeInterface(name, node, result)
|
||||||
|
case reflect.Map:
|
||||||
|
return d.decodeMap(name, node, result)
|
||||||
|
case reflect.Ptr:
|
||||||
|
return d.decodePtr(name, node, result)
|
||||||
|
case reflect.Slice:
|
||||||
|
return d.decodeSlice(name, node, result)
|
||||||
|
case reflect.String:
|
||||||
|
return d.decodeString(name, node, result)
|
||||||
|
case reflect.Struct:
|
||||||
|
return d.decodeStruct(name, node, result)
|
||||||
|
default:
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *ast.LiteralType:
|
||||||
|
if n.Token.Type == token.BOOL {
|
||||||
|
v, err := strconv.ParseBool(n.Token.Text)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Set(reflect.ValueOf(v))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: unknown type %T", name, node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *ast.LiteralType:
|
||||||
|
if n.Token.Type == token.FLOAT {
|
||||||
|
v, err := strconv.ParseFloat(n.Token.Text, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Set(reflect.ValueOf(v))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: unknown type %T", name, node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *ast.LiteralType:
|
||||||
|
switch n.Token.Type {
|
||||||
|
case token.NUMBER:
|
||||||
|
v, err := strconv.ParseInt(n.Token.Text, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Set(reflect.ValueOf(int(v)))
|
||||||
|
return nil
|
||||||
|
case token.STRING:
|
||||||
|
v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Set(reflect.ValueOf(int(v)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: unknown type %T", name, node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
// When we see an ast.Node, we retain the value to enable deferred decoding.
|
||||||
|
// Very useful in situations where we want to preserve ast.Node information
|
||||||
|
// like Pos
|
||||||
|
if result.Type() == nodeType && result.CanSet() {
|
||||||
|
result.Set(reflect.ValueOf(node))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var set reflect.Value
|
||||||
|
redecode := true
|
||||||
|
|
||||||
|
// For testing types, ObjectType should just be treated as a list. We
|
||||||
|
// set this to a temporary var because we want to pass in the real node.
|
||||||
|
testNode := node
|
||||||
|
if ot, ok := node.(*ast.ObjectType); ok {
|
||||||
|
testNode = ot.List
|
||||||
|
}
|
||||||
|
|
||||||
|
switch n := testNode.(type) {
|
||||||
|
case *ast.ObjectList:
|
||||||
|
// If we're at the root or we're directly within a slice, then we
|
||||||
|
// decode objects into map[string]interface{}, otherwise we decode
|
||||||
|
// them into lists.
|
||||||
|
if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice {
|
||||||
|
var temp map[string]interface{}
|
||||||
|
tempVal := reflect.ValueOf(temp)
|
||||||
|
result := reflect.MakeMap(
|
||||||
|
reflect.MapOf(
|
||||||
|
reflect.TypeOf(""),
|
||||||
|
tempVal.Type().Elem()))
|
||||||
|
|
||||||
|
set = result
|
||||||
|
} else {
|
||||||
|
var temp []map[string]interface{}
|
||||||
|
tempVal := reflect.ValueOf(temp)
|
||||||
|
result := reflect.MakeSlice(
|
||||||
|
reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items))
|
||||||
|
set = result
|
||||||
|
}
|
||||||
|
case *ast.ObjectType:
|
||||||
|
// If we're at the root or we're directly within a slice, then we
|
||||||
|
// decode objects into map[string]interface{}, otherwise we decode
|
||||||
|
// them into lists.
|
||||||
|
if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice {
|
||||||
|
var temp map[string]interface{}
|
||||||
|
tempVal := reflect.ValueOf(temp)
|
||||||
|
result := reflect.MakeMap(
|
||||||
|
reflect.MapOf(
|
||||||
|
reflect.TypeOf(""),
|
||||||
|
tempVal.Type().Elem()))
|
||||||
|
|
||||||
|
set = result
|
||||||
|
} else {
|
||||||
|
var temp []map[string]interface{}
|
||||||
|
tempVal := reflect.ValueOf(temp)
|
||||||
|
result := reflect.MakeSlice(
|
||||||
|
reflect.SliceOf(tempVal.Type().Elem()), 0, 1)
|
||||||
|
set = result
|
||||||
|
}
|
||||||
|
case *ast.ListType:
|
||||||
|
var temp []interface{}
|
||||||
|
tempVal := reflect.ValueOf(temp)
|
||||||
|
result := reflect.MakeSlice(
|
||||||
|
reflect.SliceOf(tempVal.Type().Elem()), 0, 0)
|
||||||
|
set = result
|
||||||
|
case *ast.LiteralType:
|
||||||
|
switch n.Token.Type {
|
||||||
|
case token.BOOL:
|
||||||
|
var result bool
|
||||||
|
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
|
||||||
|
case token.FLOAT:
|
||||||
|
var result float64
|
||||||
|
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
|
||||||
|
case token.NUMBER:
|
||||||
|
var result int
|
||||||
|
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
|
||||||
|
case token.STRING, token.HEREDOC:
|
||||||
|
set = reflect.Indirect(reflect.New(reflect.TypeOf("")))
|
||||||
|
default:
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf(
|
||||||
|
"%s: cannot decode into interface: %T",
|
||||||
|
name, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the result to what its supposed to be, then reset
|
||||||
|
// result so we don't reflect into this method anymore.
|
||||||
|
result.Set(set)
|
||||||
|
|
||||||
|
if redecode {
|
||||||
|
// Revisit the node so that we can use the newly instantiated
|
||||||
|
// thing and populate it.
|
||||||
|
if err := d.decode(name, node, result); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
if item, ok := node.(*ast.ObjectItem); ok {
|
||||||
|
node = &ast.ObjectList{Items: []*ast.ObjectItem{item}}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ot, ok := node.(*ast.ObjectType); ok {
|
||||||
|
node = ot.List
|
||||||
|
}
|
||||||
|
|
||||||
|
n, ok := node.(*ast.ObjectList)
|
||||||
|
if !ok {
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: not an object type for map (%T)", name, node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have an interface, then we can address the interface,
|
||||||
|
// but not the slice itself, so get the element but set the interface
|
||||||
|
set := result
|
||||||
|
if result.Kind() == reflect.Interface {
|
||||||
|
result = result.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
resultType := result.Type()
|
||||||
|
resultElemType := resultType.Elem()
|
||||||
|
resultKeyType := resultType.Key()
|
||||||
|
if resultKeyType.Kind() != reflect.String {
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: map must have string keys", name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a map if it is nil
|
||||||
|
resultMap := result
|
||||||
|
if result.IsNil() {
|
||||||
|
resultMap = reflect.MakeMap(
|
||||||
|
reflect.MapOf(resultKeyType, resultElemType))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through each element and decode it.
|
||||||
|
done := make(map[string]struct{})
|
||||||
|
for _, item := range n.Items {
|
||||||
|
if item.Val == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// github.com/hashicorp/terraform/issue/5740
|
||||||
|
if len(item.Keys) == 0 {
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: map must have string keys", name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the key we're dealing with, which is the first item
|
||||||
|
keyStr := item.Keys[0].Token.Value().(string)
|
||||||
|
|
||||||
|
// If we've already processed this key, then ignore it
|
||||||
|
if _, ok := done[keyStr]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the value. If we have more than one key, then we
|
||||||
|
// get the objectlist of only these keys.
|
||||||
|
itemVal := item.Val
|
||||||
|
if len(item.Keys) > 1 {
|
||||||
|
itemVal = n.Filter(keyStr)
|
||||||
|
done[keyStr] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the field name
|
||||||
|
fieldName := fmt.Sprintf("%s.%s", name, keyStr)
|
||||||
|
|
||||||
|
// Get the key/value as reflection values
|
||||||
|
key := reflect.ValueOf(keyStr)
|
||||||
|
val := reflect.Indirect(reflect.New(resultElemType))
|
||||||
|
|
||||||
|
// If we have a pre-existing value in the map, use that
|
||||||
|
oldVal := resultMap.MapIndex(key)
|
||||||
|
if oldVal.IsValid() {
|
||||||
|
val.Set(oldVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode!
|
||||||
|
if err := d.decode(fieldName, itemVal, val); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the value on the map
|
||||||
|
resultMap.SetMapIndex(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the final map if we can
|
||||||
|
set.Set(resultMap)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
// Create an element of the concrete (non pointer) type and decode
|
||||||
|
// into that. Then set the value of the pointer to this type.
|
||||||
|
resultType := result.Type()
|
||||||
|
resultElemType := resultType.Elem()
|
||||||
|
val := reflect.New(resultElemType)
|
||||||
|
if err := d.decode(name, node, reflect.Indirect(val)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Set(val)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
// If we have an interface, then we can address the interface,
|
||||||
|
// but not the slice itself, so get the element but set the interface
|
||||||
|
set := result
|
||||||
|
if result.Kind() == reflect.Interface {
|
||||||
|
result = result.Elem()
|
||||||
|
}
|
||||||
|
// Create the slice if it isn't nil
|
||||||
|
resultType := result.Type()
|
||||||
|
resultElemType := resultType.Elem()
|
||||||
|
if result.IsNil() {
|
||||||
|
resultSliceType := reflect.SliceOf(resultElemType)
|
||||||
|
result = reflect.MakeSlice(
|
||||||
|
resultSliceType, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out the items we'll be copying into the slice
|
||||||
|
var items []ast.Node
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *ast.ObjectList:
|
||||||
|
items = make([]ast.Node, len(n.Items))
|
||||||
|
for i, item := range n.Items {
|
||||||
|
items[i] = item
|
||||||
|
}
|
||||||
|
case *ast.ObjectType:
|
||||||
|
items = []ast.Node{n}
|
||||||
|
case *ast.ListType:
|
||||||
|
items = n.List
|
||||||
|
default:
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("unknown slice type: %T", node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, item := range items {
|
||||||
|
fieldName := fmt.Sprintf("%s[%d]", name, i)
|
||||||
|
|
||||||
|
// Decode
|
||||||
|
val := reflect.Indirect(reflect.New(resultElemType))
|
||||||
|
|
||||||
|
// if item is an object that was decoded from ambiguous JSON and
|
||||||
|
// flattened, make sure it's expanded if it needs to decode into a
|
||||||
|
// defined structure.
|
||||||
|
item := expandObject(item, val)
|
||||||
|
|
||||||
|
if err := d.decode(fieldName, item, val); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append it onto the slice
|
||||||
|
result = reflect.Append(result, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
set.Set(result)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// expandObject detects if an ambiguous JSON object was flattened to a List which
|
||||||
|
// should be decoded into a struct, and expands the ast to properly deocode.
|
||||||
|
func expandObject(node ast.Node, result reflect.Value) ast.Node {
|
||||||
|
item, ok := node.(*ast.ObjectItem)
|
||||||
|
if !ok {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
elemType := result.Type()
|
||||||
|
|
||||||
|
// our target type must be a struct
|
||||||
|
switch elemType.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
switch elemType.Elem().Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
//OK
|
||||||
|
default:
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
//OK
|
||||||
|
default:
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
// A list value will have a key and field name. If it had more fields,
|
||||||
|
// it wouldn't have been flattened.
|
||||||
|
if len(item.Keys) != 2 {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
keyToken := item.Keys[0].Token
|
||||||
|
item.Keys = item.Keys[1:]
|
||||||
|
|
||||||
|
// we need to un-flatten the ast enough to decode
|
||||||
|
newNode := &ast.ObjectItem{
|
||||||
|
Keys: []*ast.ObjectKey{
|
||||||
|
&ast.ObjectKey{
|
||||||
|
Token: keyToken,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Val: &ast.ObjectType{
|
||||||
|
List: &ast.ObjectList{
|
||||||
|
Items: []*ast.ObjectItem{item},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return newNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *ast.LiteralType:
|
||||||
|
switch n.Token.Type {
|
||||||
|
case token.NUMBER:
|
||||||
|
result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type()))
|
||||||
|
return nil
|
||||||
|
case token.STRING, token.HEREDOC:
|
||||||
|
result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: unknown type for string %T", name, node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error {
|
||||||
|
var item *ast.ObjectItem
|
||||||
|
if it, ok := node.(*ast.ObjectItem); ok {
|
||||||
|
item = it
|
||||||
|
node = it.Val
|
||||||
|
}
|
||||||
|
|
||||||
|
if ot, ok := node.(*ast.ObjectType); ok {
|
||||||
|
node = ot.List
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the special case where the object itself is a literal. Previously
|
||||||
|
// the yacc parser would always ensure top-level elements were arrays. The new
|
||||||
|
// parser does not make the same guarantees, thus we need to convert any
|
||||||
|
// top-level literal elements into a list.
|
||||||
|
if _, ok := node.(*ast.LiteralType); ok && item != nil {
|
||||||
|
node = &ast.ObjectList{Items: []*ast.ObjectItem{item}}
|
||||||
|
}
|
||||||
|
|
||||||
|
list, ok := node.(*ast.ObjectList)
|
||||||
|
if !ok {
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This slice will keep track of all the structs we'll be decoding.
|
||||||
|
// There can be more than one struct if there are embedded structs
|
||||||
|
// that are squashed.
|
||||||
|
structs := make([]reflect.Value, 1, 5)
|
||||||
|
structs[0] = result
|
||||||
|
|
||||||
|
// Compile the list of all the fields that we're going to be decoding
|
||||||
|
// from all the structs.
|
||||||
|
fields := make(map[*reflect.StructField]reflect.Value)
|
||||||
|
for len(structs) > 0 {
|
||||||
|
structVal := structs[0]
|
||||||
|
structs = structs[1:]
|
||||||
|
|
||||||
|
structType := structVal.Type()
|
||||||
|
for i := 0; i < structType.NumField(); i++ {
|
||||||
|
fieldType := structType.Field(i)
|
||||||
|
tagParts := strings.Split(fieldType.Tag.Get(tagName), ",")
|
||||||
|
|
||||||
|
// Ignore fields with tag name "-"
|
||||||
|
if tagParts[0] == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldType.Anonymous {
|
||||||
|
fieldKind := fieldType.Type.Kind()
|
||||||
|
if fieldKind != reflect.Struct {
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: unsupported type to struct: %s",
|
||||||
|
fieldType.Name, fieldKind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have an embedded field. We "squash" the fields down
|
||||||
|
// if specified in the tag.
|
||||||
|
squash := false
|
||||||
|
for _, tag := range tagParts[1:] {
|
||||||
|
if tag == "squash" {
|
||||||
|
squash = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if squash {
|
||||||
|
structs = append(
|
||||||
|
structs, result.FieldByName(fieldType.Name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal struct field, store it away
|
||||||
|
fields[&fieldType] = structVal.Field(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usedKeys := make(map[string]struct{})
|
||||||
|
decodedFields := make([]string, 0, len(fields))
|
||||||
|
decodedFieldsVal := make([]reflect.Value, 0)
|
||||||
|
unusedKeysVal := make([]reflect.Value, 0)
|
||||||
|
for fieldType, field := range fields {
|
||||||
|
if !field.IsValid() {
|
||||||
|
// This should never happen
|
||||||
|
panic("field is not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can't set the field, then it is unexported or something,
|
||||||
|
// and we just continue onwards.
|
||||||
|
if !field.CanSet() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldName := fieldType.Name
|
||||||
|
|
||||||
|
tagValue := fieldType.Tag.Get(tagName)
|
||||||
|
tagParts := strings.SplitN(tagValue, ",", 2)
|
||||||
|
if len(tagParts) >= 2 {
|
||||||
|
switch tagParts[1] {
|
||||||
|
case "decodedFields":
|
||||||
|
decodedFieldsVal = append(decodedFieldsVal, field)
|
||||||
|
continue
|
||||||
|
case "key":
|
||||||
|
if item == nil {
|
||||||
|
return &parser.PosError{
|
||||||
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: %s asked for 'key', impossible",
|
||||||
|
name, fieldName),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
field.SetString(item.Keys[0].Token.Value().(string))
|
||||||
|
continue
|
||||||
|
case "unusedKeys":
|
||||||
|
unusedKeysVal = append(unusedKeysVal, field)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tagParts[0] != "" {
|
||||||
|
fieldName = tagParts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the element we'll use to decode. If it is a single
|
||||||
|
// match (only object with the field), then we decode it exactly.
|
||||||
|
// If it is a prefix match, then we decode the matches.
|
||||||
|
filter := list.Filter(fieldName)
|
||||||
|
|
||||||
|
prefixMatches := filter.Children()
|
||||||
|
matches := filter.Elem()
|
||||||
|
if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track the used key
|
||||||
|
usedKeys[fieldName] = struct{}{}
|
||||||
|
|
||||||
|
// Create the field name and decode. We range over the elements
|
||||||
|
// because we actually want the value.
|
||||||
|
fieldName = fmt.Sprintf("%s.%s", name, fieldName)
|
||||||
|
if len(prefixMatches.Items) > 0 {
|
||||||
|
if err := d.decode(fieldName, prefixMatches, field); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, match := range matches.Items {
|
||||||
|
var decodeNode ast.Node = match.Val
|
||||||
|
if ot, ok := decodeNode.(*ast.ObjectType); ok {
|
||||||
|
decodeNode = &ast.ObjectList{Items: ot.List.Items}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.decode(fieldName, decodeNode, field); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedFields = append(decodedFields, fieldType.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(decodedFieldsVal) > 0 {
|
||||||
|
// Sort it so that it is deterministic
|
||||||
|
sort.Strings(decodedFields)
|
||||||
|
|
||||||
|
for _, v := range decodedFieldsVal {
|
||||||
|
v.Set(reflect.ValueOf(decodedFields))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// findNodeType returns the type of ast.Node
|
||||||
|
func findNodeType() reflect.Type {
|
||||||
|
var nodeContainer struct {
|
||||||
|
Node ast.Node
|
||||||
|
}
|
||||||
|
value := reflect.ValueOf(nodeContainer).FieldByName("Node")
|
||||||
|
return value.Type()
|
||||||
|
}
|
11
vendor/github.com/hashicorp/hcl/hcl.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/hcl/hcl.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// Package hcl decodes HCL into usable Go structures.
|
||||||
|
//
|
||||||
|
// hcl input can come in either pure HCL format or JSON format.
|
||||||
|
// It can be parsed into an AST, and then decoded into a structure,
|
||||||
|
// or it can be decoded directly from a string into a structure.
|
||||||
|
//
|
||||||
|
// If you choose to parse HCL into a raw AST, the benefit is that you
|
||||||
|
// can write custom visitor implementations to implement custom
|
||||||
|
// semantic checks. By default, HCL does not perform any semantic
|
||||||
|
// checks.
|
||||||
|
package hcl
|
218
vendor/github.com/hashicorp/hcl/hcl/ast/ast.go
generated
vendored
Normal file
218
vendor/github.com/hashicorp/hcl/hcl/ast/ast.go
generated
vendored
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
// Package ast declares the types used to represent syntax trees for HCL
|
||||||
|
// (HashiCorp Configuration Language)
|
||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/hcl/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Node is an element in the abstract syntax tree.
|
||||||
|
type Node interface {
|
||||||
|
node()
|
||||||
|
Pos() token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (File) node() {}
|
||||||
|
func (ObjectList) node() {}
|
||||||
|
func (ObjectKey) node() {}
|
||||||
|
func (ObjectItem) node() {}
|
||||||
|
func (Comment) node() {}
|
||||||
|
func (CommentGroup) node() {}
|
||||||
|
func (ObjectType) node() {}
|
||||||
|
func (LiteralType) node() {}
|
||||||
|
func (ListType) node() {}
|
||||||
|
|
||||||
|
// File represents a single HCL file
|
||||||
|
type File struct {
|
||||||
|
Node Node // usually a *ObjectList
|
||||||
|
Comments []*CommentGroup // list of all comments in the source
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) Pos() token.Pos {
|
||||||
|
return f.Node.Pos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectList represents a list of ObjectItems. An HCL file itself is an
|
||||||
|
// ObjectList.
|
||||||
|
type ObjectList struct {
|
||||||
|
Items []*ObjectItem
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectList) Add(item *ObjectItem) {
|
||||||
|
o.Items = append(o.Items, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter filters out the objects with the given key list as a prefix.
|
||||||
|
//
|
||||||
|
// The returned list of objects contain ObjectItems where the keys have
|
||||||
|
// this prefix already stripped off. This might result in objects with
|
||||||
|
// zero-length key lists if they have no children.
|
||||||
|
//
|
||||||
|
// If no matches are found, an empty ObjectList (non-nil) is returned.
|
||||||
|
func (o *ObjectList) Filter(keys ...string) *ObjectList {
|
||||||
|
var result ObjectList
|
||||||
|
for _, item := range o.Items {
|
||||||
|
// If there aren't enough keys, then ignore this
|
||||||
|
if len(item.Keys) < len(keys) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
match := true
|
||||||
|
for i, key := range item.Keys[:len(keys)] {
|
||||||
|
key := key.Token.Value().(string)
|
||||||
|
if key != keys[i] && !strings.EqualFold(key, keys[i]) {
|
||||||
|
match = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip off the prefix from the children
|
||||||
|
newItem := *item
|
||||||
|
newItem.Keys = newItem.Keys[len(keys):]
|
||||||
|
result.Add(&newItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Children returns further nested objects (key length > 0) within this
|
||||||
|
// ObjectList. This should be used with Filter to get at child items.
|
||||||
|
func (o *ObjectList) Children() *ObjectList {
|
||||||
|
var result ObjectList
|
||||||
|
for _, item := range o.Items {
|
||||||
|
if len(item.Keys) > 0 {
|
||||||
|
result.Add(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elem returns items in the list that are direct element assignments
|
||||||
|
// (key length == 0). This should be used with Filter to get at elements.
|
||||||
|
func (o *ObjectList) Elem() *ObjectList {
|
||||||
|
var result ObjectList
|
||||||
|
for _, item := range o.Items {
|
||||||
|
if len(item.Keys) == 0 {
|
||||||
|
result.Add(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectList) Pos() token.Pos {
|
||||||
|
// always returns the uninitiliazed position
|
||||||
|
return o.Items[0].Pos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectItem represents a HCL Object Item. An item is represented with a key
|
||||||
|
// (or keys). It can be an assignment or an object (both normal and nested)
|
||||||
|
type ObjectItem struct {
|
||||||
|
// keys is only one length long if it's of type assignment. If it's a
|
||||||
|
// nested object it can be larger than one. In that case "assign" is
|
||||||
|
// invalid as there is no assignments for a nested object.
|
||||||
|
Keys []*ObjectKey
|
||||||
|
|
||||||
|
// assign contains the position of "=", if any
|
||||||
|
Assign token.Pos
|
||||||
|
|
||||||
|
// val is the item itself. It can be an object,list, number, bool or a
|
||||||
|
// string. If key length is larger than one, val can be only of type
|
||||||
|
// Object.
|
||||||
|
Val Node
|
||||||
|
|
||||||
|
LeadComment *CommentGroup // associated lead comment
|
||||||
|
LineComment *CommentGroup // associated line comment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectItem) Pos() token.Pos {
|
||||||
|
// I'm not entirely sure what causes this, but removing this causes
|
||||||
|
// a test failure. We should investigate at some point.
|
||||||
|
if len(o.Keys) == 0 {
|
||||||
|
return token.Pos{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.Keys[0].Pos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectKeys are either an identifier or of type string.
|
||||||
|
type ObjectKey struct {
|
||||||
|
Token token.Token
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectKey) Pos() token.Pos {
|
||||||
|
return o.Token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// LiteralType represents a literal of basic type. Valid types are:
|
||||||
|
// token.NUMBER, token.FLOAT, token.BOOL and token.STRING
|
||||||
|
type LiteralType struct {
|
||||||
|
Token token.Token
|
||||||
|
|
||||||
|
// associated line comment, only when used in a list
|
||||||
|
LineComment *CommentGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LiteralType) Pos() token.Pos {
|
||||||
|
return l.Token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListStatement represents a HCL List type
|
||||||
|
type ListType struct {
|
||||||
|
Lbrack token.Pos // position of "["
|
||||||
|
Rbrack token.Pos // position of "]"
|
||||||
|
List []Node // the elements in lexical order
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListType) Pos() token.Pos {
|
||||||
|
return l.Lbrack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListType) Add(node Node) {
|
||||||
|
l.List = append(l.List, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectType represents a HCL Object Type
|
||||||
|
type ObjectType struct {
|
||||||
|
Lbrace token.Pos // position of "{"
|
||||||
|
Rbrace token.Pos // position of "}"
|
||||||
|
List *ObjectList // the nodes in lexical order
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectType) Pos() token.Pos {
|
||||||
|
return o.Lbrace
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comment node represents a single //, # style or /*- style commment
|
||||||
|
type Comment struct {
|
||||||
|
Start token.Pos // position of / or #
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Comment) Pos() token.Pos {
|
||||||
|
return c.Start
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommentGroup node represents a sequence of comments with no other tokens and
|
||||||
|
// no empty lines between.
|
||||||
|
type CommentGroup struct {
|
||||||
|
List []*Comment // len(List) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommentGroup) Pos() token.Pos {
|
||||||
|
return c.List[0].Pos()
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// GoStringer
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) }
|
||||||
|
func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) }
|
52
vendor/github.com/hashicorp/hcl/hcl/ast/walk.go
generated
vendored
Normal file
52
vendor/github.com/hashicorp/hcl/hcl/ast/walk.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package ast
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// WalkFunc describes a function to be called for each node during a Walk. The
|
||||||
|
// returned node can be used to rewrite the AST. Walking stops the returned
|
||||||
|
// bool is false.
|
||||||
|
type WalkFunc func(Node) (Node, bool)
|
||||||
|
|
||||||
|
// Walk traverses an AST in depth-first order: It starts by calling fn(node);
|
||||||
|
// node must not be nil. If fn returns true, Walk invokes fn recursively for
|
||||||
|
// each of the non-nil children of node, followed by a call of fn(nil). The
|
||||||
|
// returned node of fn can be used to rewrite the passed node to fn.
|
||||||
|
func Walk(node Node, fn WalkFunc) Node {
|
||||||
|
rewritten, ok := fn(node)
|
||||||
|
if !ok {
|
||||||
|
return rewritten
|
||||||
|
}
|
||||||
|
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *File:
|
||||||
|
n.Node = Walk(n.Node, fn)
|
||||||
|
case *ObjectList:
|
||||||
|
for i, item := range n.Items {
|
||||||
|
n.Items[i] = Walk(item, fn).(*ObjectItem)
|
||||||
|
}
|
||||||
|
case *ObjectKey:
|
||||||
|
// nothing to do
|
||||||
|
case *ObjectItem:
|
||||||
|
for i, k := range n.Keys {
|
||||||
|
n.Keys[i] = Walk(k, fn).(*ObjectKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Val != nil {
|
||||||
|
n.Val = Walk(n.Val, fn)
|
||||||
|
}
|
||||||
|
case *LiteralType:
|
||||||
|
// nothing to do
|
||||||
|
case *ListType:
|
||||||
|
for i, l := range n.List {
|
||||||
|
n.List[i] = Walk(l, fn)
|
||||||
|
}
|
||||||
|
case *ObjectType:
|
||||||
|
n.List = Walk(n.List, fn).(*ObjectList)
|
||||||
|
default:
|
||||||
|
// should we panic here?
|
||||||
|
fmt.Printf("unknown type: %T\n", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn(nil)
|
||||||
|
return rewritten
|
||||||
|
}
|
17
vendor/github.com/hashicorp/hcl/hcl/parser/error.go
generated
vendored
Normal file
17
vendor/github.com/hashicorp/hcl/hcl/parser/error.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/hcl/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PosError is a parse error that contains a position.
|
||||||
|
type PosError struct {
|
||||||
|
Pos token.Pos
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PosError) Error() string {
|
||||||
|
return fmt.Sprintf("At %s: %s", e.Pos, e.Err)
|
||||||
|
}
|
489
vendor/github.com/hashicorp/hcl/hcl/parser/parser.go
generated
vendored
Normal file
489
vendor/github.com/hashicorp/hcl/hcl/parser/parser.go
generated
vendored
Normal file
|
@ -0,0 +1,489 @@
|
||||||
|
// Package parser implements a parser for HCL (HashiCorp Configuration
|
||||||
|
// Language)
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
"github.com/hashicorp/hcl/hcl/scanner"
|
||||||
|
"github.com/hashicorp/hcl/hcl/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Parser struct {
|
||||||
|
sc *scanner.Scanner
|
||||||
|
|
||||||
|
// Last read token
|
||||||
|
tok token.Token
|
||||||
|
commaPrev token.Token
|
||||||
|
|
||||||
|
comments []*ast.CommentGroup
|
||||||
|
leadComment *ast.CommentGroup // last lead comment
|
||||||
|
lineComment *ast.CommentGroup // last line comment
|
||||||
|
|
||||||
|
enableTrace bool
|
||||||
|
indent int
|
||||||
|
n int // buffer size (max = 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParser(src []byte) *Parser {
|
||||||
|
return &Parser{
|
||||||
|
sc: scanner.New(src),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse returns the fully parsed source and returns the abstract syntax tree.
|
||||||
|
func Parse(src []byte) (*ast.File, error) {
|
||||||
|
p := newParser(src)
|
||||||
|
return p.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
var errEofToken = errors.New("EOF token found")
|
||||||
|
|
||||||
|
// Parse returns the fully parsed source and returns the abstract syntax tree.
|
||||||
|
func (p *Parser) Parse() (*ast.File, error) {
|
||||||
|
f := &ast.File{}
|
||||||
|
var err, scerr error
|
||||||
|
p.sc.Error = func(pos token.Pos, msg string) {
|
||||||
|
scerr = &PosError{Pos: pos, Err: errors.New(msg)}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Node, err = p.objectList()
|
||||||
|
if scerr != nil {
|
||||||
|
return nil, scerr
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Comments = p.comments
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) objectList() (*ast.ObjectList, error) {
|
||||||
|
defer un(trace(p, "ParseObjectList"))
|
||||||
|
node := &ast.ObjectList{}
|
||||||
|
|
||||||
|
for {
|
||||||
|
n, err := p.objectItem()
|
||||||
|
if err == errEofToken {
|
||||||
|
break // we are finished
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't return a nil node, because might want to use already
|
||||||
|
// collected items.
|
||||||
|
if err != nil {
|
||||||
|
return node, err
|
||||||
|
}
|
||||||
|
|
||||||
|
node.Add(n)
|
||||||
|
|
||||||
|
// object lists can be optionally comma-delimited e.g. when a list of maps
|
||||||
|
// is being expressed, so a comma is allowed here - it's simply consumed
|
||||||
|
tok := p.scan()
|
||||||
|
if tok.Type != token.COMMA {
|
||||||
|
p.unscan()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) consumeComment() (comment *ast.Comment, endline int) {
|
||||||
|
endline = p.tok.Pos.Line
|
||||||
|
|
||||||
|
// count the endline if it's multiline comment, ie starting with /*
|
||||||
|
if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' {
|
||||||
|
// don't use range here - no need to decode Unicode code points
|
||||||
|
for i := 0; i < len(p.tok.Text); i++ {
|
||||||
|
if p.tok.Text[i] == '\n' {
|
||||||
|
endline++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text}
|
||||||
|
p.tok = p.sc.Scan()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) {
|
||||||
|
var list []*ast.Comment
|
||||||
|
endline = p.tok.Pos.Line
|
||||||
|
|
||||||
|
for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n {
|
||||||
|
var comment *ast.Comment
|
||||||
|
comment, endline = p.consumeComment()
|
||||||
|
list = append(list, comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add comment group to the comments list
|
||||||
|
comments = &ast.CommentGroup{List: list}
|
||||||
|
p.comments = append(p.comments, comments)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// objectItem parses a single object item
|
||||||
|
func (p *Parser) objectItem() (*ast.ObjectItem, error) {
|
||||||
|
defer un(trace(p, "ParseObjectItem"))
|
||||||
|
|
||||||
|
keys, err := p.objectKey()
|
||||||
|
if len(keys) > 0 && err == errEofToken {
|
||||||
|
// We ignore eof token here since it is an error if we didn't
|
||||||
|
// receive a value (but we did receive a key) for the item.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE {
|
||||||
|
// This is a strange boolean statement, but what it means is:
|
||||||
|
// We have keys with no value, and we're likely in an object
|
||||||
|
// (since RBrace ends an object). For this, we set err to nil so
|
||||||
|
// we continue and get the error below of having the wrong value
|
||||||
|
// type.
|
||||||
|
err = nil
|
||||||
|
|
||||||
|
// Reset the token type so we don't think it completed fine. See
|
||||||
|
// objectType which uses p.tok.Type to check if we're done with
|
||||||
|
// the object.
|
||||||
|
p.tok.Type = token.EOF
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
o := &ast.ObjectItem{
|
||||||
|
Keys: keys,
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.leadComment != nil {
|
||||||
|
o.LeadComment = p.leadComment
|
||||||
|
p.leadComment = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch p.tok.Type {
|
||||||
|
case token.ASSIGN:
|
||||||
|
o.Assign = p.tok.Pos
|
||||||
|
o.Val, err = p.object()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case token.LBRACE:
|
||||||
|
o.Val, err = p.objectType()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
keyStr := make([]string, 0, len(keys))
|
||||||
|
for _, k := range keys {
|
||||||
|
keyStr = append(keyStr, k.Token.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"key '%s' expected start of object ('{') or assignment ('=')",
|
||||||
|
strings.Join(keyStr, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// do a look-ahead for line comment
|
||||||
|
p.scan()
|
||||||
|
if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil {
|
||||||
|
o.LineComment = p.lineComment
|
||||||
|
p.lineComment = nil
|
||||||
|
}
|
||||||
|
p.unscan()
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// objectKey parses an object key and returns a ObjectKey AST
|
||||||
|
func (p *Parser) objectKey() ([]*ast.ObjectKey, error) {
|
||||||
|
keyCount := 0
|
||||||
|
keys := make([]*ast.ObjectKey, 0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
tok := p.scan()
|
||||||
|
switch tok.Type {
|
||||||
|
case token.EOF:
|
||||||
|
// It is very important to also return the keys here as well as
|
||||||
|
// the error. This is because we need to be able to tell if we
|
||||||
|
// did parse keys prior to finding the EOF, or if we just found
|
||||||
|
// a bare EOF.
|
||||||
|
return keys, errEofToken
|
||||||
|
case token.ASSIGN:
|
||||||
|
// assignment or object only, but not nested objects. this is not
|
||||||
|
// allowed: `foo bar = {}`
|
||||||
|
if keyCount > 1 {
|
||||||
|
return nil, &PosError{
|
||||||
|
Pos: p.tok.Pos,
|
||||||
|
Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if keyCount == 0 {
|
||||||
|
return nil, &PosError{
|
||||||
|
Pos: p.tok.Pos,
|
||||||
|
Err: errors.New("no object keys found!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys, nil
|
||||||
|
case token.LBRACE:
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// If we have no keys, then it is a syntax error. i.e. {{}} is not
|
||||||
|
// allowed.
|
||||||
|
if len(keys) == 0 {
|
||||||
|
err = &PosError{
|
||||||
|
Pos: p.tok.Pos,
|
||||||
|
Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// object
|
||||||
|
return keys, err
|
||||||
|
case token.IDENT, token.STRING:
|
||||||
|
keyCount++
|
||||||
|
keys = append(keys, &ast.ObjectKey{Token: p.tok})
|
||||||
|
case token.ILLEGAL:
|
||||||
|
fmt.Println("illegal")
|
||||||
|
default:
|
||||||
|
return keys, &PosError{
|
||||||
|
Pos: p.tok.Pos,
|
||||||
|
Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// object parses any type of object, such as number, bool, string, object or
|
||||||
|
// list.
|
||||||
|
func (p *Parser) object() (ast.Node, error) {
|
||||||
|
defer un(trace(p, "ParseType"))
|
||||||
|
tok := p.scan()
|
||||||
|
|
||||||
|
switch tok.Type {
|
||||||
|
case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC:
|
||||||
|
return p.literalType()
|
||||||
|
case token.LBRACE:
|
||||||
|
return p.objectType()
|
||||||
|
case token.LBRACK:
|
||||||
|
return p.listType()
|
||||||
|
case token.COMMENT:
|
||||||
|
// implement comment
|
||||||
|
case token.EOF:
|
||||||
|
return nil, errEofToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, &PosError{
|
||||||
|
Pos: tok.Pos,
|
||||||
|
Err: fmt.Errorf("Unknown token: %+v", tok),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// objectType parses an object type and returns a ObjectType AST
|
||||||
|
func (p *Parser) objectType() (*ast.ObjectType, error) {
|
||||||
|
defer un(trace(p, "ParseObjectType"))
|
||||||
|
|
||||||
|
// we assume that the currently scanned token is a LBRACE
|
||||||
|
o := &ast.ObjectType{
|
||||||
|
Lbrace: p.tok.Pos,
|
||||||
|
}
|
||||||
|
|
||||||
|
l, err := p.objectList()
|
||||||
|
|
||||||
|
// if we hit RBRACE, we are good to go (means we parsed all Items), if it's
|
||||||
|
// not a RBRACE, it's an syntax error and we just return it.
|
||||||
|
if err != nil && p.tok.Type != token.RBRACE {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no error, we should be at a RBRACE to end the object
|
||||||
|
if p.tok.Type != token.RBRACE {
|
||||||
|
return nil, fmt.Errorf("object expected closing RBRACE got: %s", p.tok.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
o.List = l
|
||||||
|
o.Rbrace = p.tok.Pos // advanced via parseObjectList
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// listType parses a list type and returns a ListType AST
|
||||||
|
func (p *Parser) listType() (*ast.ListType, error) {
|
||||||
|
defer un(trace(p, "ParseListType"))
|
||||||
|
|
||||||
|
// we assume that the currently scanned token is a LBRACK
|
||||||
|
l := &ast.ListType{
|
||||||
|
Lbrack: p.tok.Pos,
|
||||||
|
}
|
||||||
|
|
||||||
|
needComma := false
|
||||||
|
for {
|
||||||
|
tok := p.scan()
|
||||||
|
if needComma {
|
||||||
|
switch tok.Type {
|
||||||
|
case token.COMMA, token.RBRACK:
|
||||||
|
default:
|
||||||
|
return nil, &PosError{
|
||||||
|
Pos: tok.Pos,
|
||||||
|
Err: fmt.Errorf(
|
||||||
|
"error parsing list, expected comma or list end, got: %s",
|
||||||
|
tok.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch tok.Type {
|
||||||
|
case token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC:
|
||||||
|
node, err := p.literalType()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Add(node)
|
||||||
|
needComma = true
|
||||||
|
case token.COMMA:
|
||||||
|
// get next list item or we are at the end
|
||||||
|
// do a look-ahead for line comment
|
||||||
|
p.scan()
|
||||||
|
if p.lineComment != nil && len(l.List) > 0 {
|
||||||
|
lit, ok := l.List[len(l.List)-1].(*ast.LiteralType)
|
||||||
|
if ok {
|
||||||
|
lit.LineComment = p.lineComment
|
||||||
|
l.List[len(l.List)-1] = lit
|
||||||
|
p.lineComment = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.unscan()
|
||||||
|
|
||||||
|
needComma = false
|
||||||
|
continue
|
||||||
|
case token.LBRACE:
|
||||||
|
// Looks like a nested object, so parse it out
|
||||||
|
node, err := p.objectType()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &PosError{
|
||||||
|
Pos: tok.Pos,
|
||||||
|
Err: fmt.Errorf(
|
||||||
|
"error while trying to parse object within list: %s", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.Add(node)
|
||||||
|
needComma = true
|
||||||
|
case token.BOOL:
|
||||||
|
// TODO(arslan) should we support? not supported by HCL yet
|
||||||
|
case token.LBRACK:
|
||||||
|
// TODO(arslan) should we support nested lists? Even though it's
|
||||||
|
// written in README of HCL, it's not a part of the grammar
|
||||||
|
// (not defined in parse.y)
|
||||||
|
case token.RBRACK:
|
||||||
|
// finished
|
||||||
|
l.Rbrack = p.tok.Pos
|
||||||
|
return l, nil
|
||||||
|
default:
|
||||||
|
return nil, &PosError{
|
||||||
|
Pos: tok.Pos,
|
||||||
|
Err: fmt.Errorf("unexpected token while parsing list: %s", tok.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// literalType parses a literal type and returns a LiteralType AST
|
||||||
|
func (p *Parser) literalType() (*ast.LiteralType, error) {
|
||||||
|
defer un(trace(p, "ParseLiteral"))
|
||||||
|
|
||||||
|
return &ast.LiteralType{
|
||||||
|
Token: p.tok,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan returns the next token from the underlying scanner. If a token has
|
||||||
|
// been unscanned then read that instead. In the process, it collects any
|
||||||
|
// comment groups encountered, and remembers the last lead and line comments.
|
||||||
|
func (p *Parser) scan() token.Token {
|
||||||
|
// If we have a token on the buffer, then return it.
|
||||||
|
if p.n != 0 {
|
||||||
|
p.n = 0
|
||||||
|
return p.tok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise read the next token from the scanner and Save it to the buffer
|
||||||
|
// in case we unscan later.
|
||||||
|
prev := p.tok
|
||||||
|
p.tok = p.sc.Scan()
|
||||||
|
|
||||||
|
if p.tok.Type == token.COMMENT {
|
||||||
|
var comment *ast.CommentGroup
|
||||||
|
var endline int
|
||||||
|
|
||||||
|
// fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n",
|
||||||
|
// p.tok.Pos.Line, prev.Pos.Line, endline)
|
||||||
|
if p.tok.Pos.Line == prev.Pos.Line {
|
||||||
|
// The comment is on same line as the previous token; it
|
||||||
|
// cannot be a lead comment but may be a line comment.
|
||||||
|
comment, endline = p.consumeCommentGroup(0)
|
||||||
|
if p.tok.Pos.Line != endline {
|
||||||
|
// The next token is on a different line, thus
|
||||||
|
// the last comment group is a line comment.
|
||||||
|
p.lineComment = comment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume successor comments, if any
|
||||||
|
endline = -1
|
||||||
|
for p.tok.Type == token.COMMENT {
|
||||||
|
comment, endline = p.consumeCommentGroup(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endline+1 == p.tok.Pos.Line && p.tok.Type != token.RBRACE {
|
||||||
|
switch p.tok.Type {
|
||||||
|
case token.RBRACE, token.RBRACK:
|
||||||
|
// Do not count for these cases
|
||||||
|
default:
|
||||||
|
// The next token is following on the line immediately after the
|
||||||
|
// comment group, thus the last comment group is a lead comment.
|
||||||
|
p.leadComment = comment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.tok
|
||||||
|
}
|
||||||
|
|
||||||
|
// unscan pushes the previously read token back onto the buffer.
|
||||||
|
func (p *Parser) unscan() {
|
||||||
|
p.n = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Parsing support
|
||||||
|
|
||||||
|
func (p *Parser) printTrace(a ...interface{}) {
|
||||||
|
if !p.enableTrace {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
|
||||||
|
const n = len(dots)
|
||||||
|
fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column)
|
||||||
|
|
||||||
|
i := 2 * p.indent
|
||||||
|
for i > n {
|
||||||
|
fmt.Print(dots)
|
||||||
|
i -= n
|
||||||
|
}
|
||||||
|
// i <= n
|
||||||
|
fmt.Print(dots[0:i])
|
||||||
|
fmt.Println(a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func trace(p *Parser, msg string) *Parser {
|
||||||
|
p.printTrace(msg, "(")
|
||||||
|
p.indent++
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage pattern: defer un(trace(p, "..."))
|
||||||
|
func un(p *Parser) {
|
||||||
|
p.indent--
|
||||||
|
p.printTrace(")")
|
||||||
|
}
|
645
vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
generated
vendored
Normal file
645
vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
generated
vendored
Normal file
|
@ -0,0 +1,645 @@
|
||||||
|
// Package scanner implements a scanner for HCL (HashiCorp Configuration
|
||||||
|
// Language) source text.
|
||||||
|
package scanner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/hcl/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// eof represents a marker rune for the end of the reader.
|
||||||
|
const eof = rune(0)
|
||||||
|
|
||||||
|
// Scanner defines a lexical scanner
|
||||||
|
type Scanner struct {
|
||||||
|
buf *bytes.Buffer // Source buffer for advancing and scanning
|
||||||
|
src []byte // Source buffer for immutable access
|
||||||
|
|
||||||
|
// Source Position
|
||||||
|
srcPos token.Pos // current position
|
||||||
|
prevPos token.Pos // previous position, used for peek() method
|
||||||
|
|
||||||
|
lastCharLen int // length of last character in bytes
|
||||||
|
lastLineLen int // length of last line in characters (for correct column reporting)
|
||||||
|
|
||||||
|
tokStart int // token text start position
|
||||||
|
tokEnd int // token text end position
|
||||||
|
|
||||||
|
// Error is called for each error encountered. If no Error
|
||||||
|
// function is set, the error is reported to os.Stderr.
|
||||||
|
Error func(pos token.Pos, msg string)
|
||||||
|
|
||||||
|
// ErrorCount is incremented by one for each error encountered.
|
||||||
|
ErrorCount int
|
||||||
|
|
||||||
|
// tokPos is the start position of most recently scanned token; set by
|
||||||
|
// Scan. The Filename field is always left untouched by the Scanner. If
|
||||||
|
// an error is reported (via Error) and Position is invalid, the scanner is
|
||||||
|
// not inside a token.
|
||||||
|
tokPos token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates and initializes a new instance of Scanner using src as
|
||||||
|
// its source content.
|
||||||
|
func New(src []byte) *Scanner {
|
||||||
|
// even though we accept a src, we read from a io.Reader compatible type
|
||||||
|
// (*bytes.Buffer). So in the future we might easily change it to streaming
|
||||||
|
// read.
|
||||||
|
b := bytes.NewBuffer(src)
|
||||||
|
s := &Scanner{
|
||||||
|
buf: b,
|
||||||
|
src: src,
|
||||||
|
}
|
||||||
|
|
||||||
|
// srcPosition always starts with 1
|
||||||
|
s.srcPos.Line = 1
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// next reads the next rune from the bufferred reader. Returns the rune(0) if
|
||||||
|
// an error occurs (or io.EOF is returned).
|
||||||
|
func (s *Scanner) next() rune {
|
||||||
|
ch, size, err := s.buf.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
// advance for error reporting
|
||||||
|
s.srcPos.Column++
|
||||||
|
s.srcPos.Offset += size
|
||||||
|
s.lastCharLen = size
|
||||||
|
return eof
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == utf8.RuneError && size == 1 {
|
||||||
|
s.srcPos.Column++
|
||||||
|
s.srcPos.Offset += size
|
||||||
|
s.lastCharLen = size
|
||||||
|
s.err("illegal UTF-8 encoding")
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// remember last position
|
||||||
|
s.prevPos = s.srcPos
|
||||||
|
|
||||||
|
s.srcPos.Column++
|
||||||
|
s.lastCharLen = size
|
||||||
|
s.srcPos.Offset += size
|
||||||
|
|
||||||
|
if ch == '\n' {
|
||||||
|
s.srcPos.Line++
|
||||||
|
s.lastLineLen = s.srcPos.Column
|
||||||
|
s.srcPos.Column = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// debug
|
||||||
|
// fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column)
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// unread unreads the previous read Rune and updates the source position
|
||||||
|
func (s *Scanner) unread() {
|
||||||
|
if err := s.buf.UnreadRune(); err != nil {
|
||||||
|
panic(err) // this is user fault, we should catch it
|
||||||
|
}
|
||||||
|
s.srcPos = s.prevPos // put back last position
|
||||||
|
}
|
||||||
|
|
||||||
|
// peek returns the next rune without advancing the reader.
|
||||||
|
func (s *Scanner) peek() rune {
|
||||||
|
peek, _, err := s.buf.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
return eof
|
||||||
|
}
|
||||||
|
|
||||||
|
s.buf.UnreadRune()
|
||||||
|
return peek
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan scans the next token and returns the token.
|
||||||
|
func (s *Scanner) Scan() token.Token {
|
||||||
|
ch := s.next()
|
||||||
|
|
||||||
|
// skip white space
|
||||||
|
for isWhitespace(ch) {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
var tok token.Type
|
||||||
|
|
||||||
|
// token text markings
|
||||||
|
s.tokStart = s.srcPos.Offset - s.lastCharLen
|
||||||
|
|
||||||
|
// token position, initial next() is moving the offset by one(size of rune
|
||||||
|
// actually), though we are interested with the starting point
|
||||||
|
s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen
|
||||||
|
if s.srcPos.Column > 0 {
|
||||||
|
// common case: last character was not a '\n'
|
||||||
|
s.tokPos.Line = s.srcPos.Line
|
||||||
|
s.tokPos.Column = s.srcPos.Column
|
||||||
|
} else {
|
||||||
|
// last character was a '\n'
|
||||||
|
// (we cannot be at the beginning of the source
|
||||||
|
// since we have called next() at least once)
|
||||||
|
s.tokPos.Line = s.srcPos.Line - 1
|
||||||
|
s.tokPos.Column = s.lastLineLen
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isLetter(ch):
|
||||||
|
tok = token.IDENT
|
||||||
|
lit := s.scanIdentifier()
|
||||||
|
if lit == "true" || lit == "false" {
|
||||||
|
tok = token.BOOL
|
||||||
|
}
|
||||||
|
case isDecimal(ch):
|
||||||
|
tok = s.scanNumber(ch)
|
||||||
|
default:
|
||||||
|
switch ch {
|
||||||
|
case eof:
|
||||||
|
tok = token.EOF
|
||||||
|
case '"':
|
||||||
|
tok = token.STRING
|
||||||
|
s.scanString()
|
||||||
|
case '#', '/':
|
||||||
|
tok = token.COMMENT
|
||||||
|
s.scanComment(ch)
|
||||||
|
case '.':
|
||||||
|
tok = token.PERIOD
|
||||||
|
ch = s.peek()
|
||||||
|
if isDecimal(ch) {
|
||||||
|
tok = token.FLOAT
|
||||||
|
ch = s.scanMantissa(ch)
|
||||||
|
ch = s.scanExponent(ch)
|
||||||
|
}
|
||||||
|
case '<':
|
||||||
|
tok = token.HEREDOC
|
||||||
|
s.scanHeredoc()
|
||||||
|
case '[':
|
||||||
|
tok = token.LBRACK
|
||||||
|
case ']':
|
||||||
|
tok = token.RBRACK
|
||||||
|
case '{':
|
||||||
|
tok = token.LBRACE
|
||||||
|
case '}':
|
||||||
|
tok = token.RBRACE
|
||||||
|
case ',':
|
||||||
|
tok = token.COMMA
|
||||||
|
case '=':
|
||||||
|
tok = token.ASSIGN
|
||||||
|
case '+':
|
||||||
|
tok = token.ADD
|
||||||
|
case '-':
|
||||||
|
if isDecimal(s.peek()) {
|
||||||
|
ch := s.next()
|
||||||
|
tok = s.scanNumber(ch)
|
||||||
|
} else {
|
||||||
|
tok = token.SUB
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
s.err("illegal char")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finish token ending
|
||||||
|
s.tokEnd = s.srcPos.Offset
|
||||||
|
|
||||||
|
// create token literal
|
||||||
|
var tokenText string
|
||||||
|
if s.tokStart >= 0 {
|
||||||
|
tokenText = string(s.src[s.tokStart:s.tokEnd])
|
||||||
|
}
|
||||||
|
s.tokStart = s.tokEnd // ensure idempotency of tokenText() call
|
||||||
|
|
||||||
|
return token.Token{
|
||||||
|
Type: tok,
|
||||||
|
Pos: s.tokPos,
|
||||||
|
Text: tokenText,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scanner) scanComment(ch rune) {
|
||||||
|
// single line comments
|
||||||
|
if ch == '#' || (ch == '/' && s.peek() != '*') {
|
||||||
|
if ch == '/' && s.peek() != '/' {
|
||||||
|
s.err("expected '/' for comment")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = s.next()
|
||||||
|
for ch != '\n' && ch >= 0 && ch != eof {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
if ch != eof && ch >= 0 {
|
||||||
|
s.unread()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// be sure we get the character after /* This allows us to find comment's
|
||||||
|
// that are not erminated
|
||||||
|
if ch == '/' {
|
||||||
|
s.next()
|
||||||
|
ch = s.next() // read character after "/*"
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for /* - style comments
|
||||||
|
for {
|
||||||
|
if ch < 0 || ch == eof {
|
||||||
|
s.err("comment not terminated")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ch0 := ch
|
||||||
|
ch = s.next()
|
||||||
|
if ch0 == '*' && ch == '/' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanNumber scans a HCL number definition starting with the given rune
|
||||||
|
func (s *Scanner) scanNumber(ch rune) token.Type {
|
||||||
|
if ch == '0' {
|
||||||
|
// check for hexadecimal, octal or float
|
||||||
|
ch = s.next()
|
||||||
|
if ch == 'x' || ch == 'X' {
|
||||||
|
// hexadecimal
|
||||||
|
ch = s.next()
|
||||||
|
found := false
|
||||||
|
for isHexadecimal(ch) {
|
||||||
|
ch = s.next()
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
s.err("illegal hexadecimal number")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch != eof {
|
||||||
|
s.unread()
|
||||||
|
}
|
||||||
|
|
||||||
|
return token.NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
// now it's either something like: 0421(octal) or 0.1231(float)
|
||||||
|
illegalOctal := false
|
||||||
|
for isDecimal(ch) {
|
||||||
|
ch = s.next()
|
||||||
|
if ch == '8' || ch == '9' {
|
||||||
|
// this is just a possibility. For example 0159 is illegal, but
|
||||||
|
// 0159.23 is valid. So we mark a possible illegal octal. If
|
||||||
|
// the next character is not a period, we'll print the error.
|
||||||
|
illegalOctal = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == 'e' || ch == 'E' {
|
||||||
|
ch = s.scanExponent(ch)
|
||||||
|
return token.FLOAT
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '.' {
|
||||||
|
ch = s.scanFraction(ch)
|
||||||
|
|
||||||
|
if ch == 'e' || ch == 'E' {
|
||||||
|
ch = s.next()
|
||||||
|
ch = s.scanExponent(ch)
|
||||||
|
}
|
||||||
|
return token.FLOAT
|
||||||
|
}
|
||||||
|
|
||||||
|
if illegalOctal {
|
||||||
|
s.err("illegal octal number")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch != eof {
|
||||||
|
s.unread()
|
||||||
|
}
|
||||||
|
return token.NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
s.scanMantissa(ch)
|
||||||
|
ch = s.next() // seek forward
|
||||||
|
if ch == 'e' || ch == 'E' {
|
||||||
|
ch = s.scanExponent(ch)
|
||||||
|
return token.FLOAT
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '.' {
|
||||||
|
ch = s.scanFraction(ch)
|
||||||
|
if ch == 'e' || ch == 'E' {
|
||||||
|
ch = s.next()
|
||||||
|
ch = s.scanExponent(ch)
|
||||||
|
}
|
||||||
|
return token.FLOAT
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch != eof {
|
||||||
|
s.unread()
|
||||||
|
}
|
||||||
|
return token.NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanMantissa scans the mantissa begining from the rune. It returns the next
|
||||||
|
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
|
||||||
|
func (s *Scanner) scanMantissa(ch rune) rune {
|
||||||
|
scanned := false
|
||||||
|
for isDecimal(ch) {
|
||||||
|
ch = s.next()
|
||||||
|
scanned = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if scanned && ch != eof {
|
||||||
|
s.unread()
|
||||||
|
}
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanFraction scans the fraction after the '.' rune
|
||||||
|
func (s *Scanner) scanFraction(ch rune) rune {
|
||||||
|
if ch == '.' {
|
||||||
|
ch = s.peek() // we peek just to see if we can move forward
|
||||||
|
ch = s.scanMantissa(ch)
|
||||||
|
}
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanExponent scans the remaining parts of an exponent after the 'e' or 'E'
|
||||||
|
// rune.
|
||||||
|
func (s *Scanner) scanExponent(ch rune) rune {
|
||||||
|
if ch == 'e' || ch == 'E' {
|
||||||
|
ch = s.next()
|
||||||
|
if ch == '-' || ch == '+' {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
ch = s.scanMantissa(ch)
|
||||||
|
}
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanHeredoc scans a heredoc string
|
||||||
|
func (s *Scanner) scanHeredoc() {
|
||||||
|
// Scan the second '<' in example: '<<EOF'
|
||||||
|
if s.next() != '<' {
|
||||||
|
s.err("heredoc expected second '<', didn't see it")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the original offset so we can read just the heredoc ident
|
||||||
|
offs := s.srcPos.Offset
|
||||||
|
|
||||||
|
// Scan the identifier
|
||||||
|
ch := s.next()
|
||||||
|
|
||||||
|
// Indented heredoc syntax
|
||||||
|
if ch == '-' {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
for isLetter(ch) || isDigit(ch) {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reached an EOF then that is not good
|
||||||
|
if ch == eof {
|
||||||
|
s.err("heredoc not terminated")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore the '\r' in Windows line endings
|
||||||
|
if ch == '\r' {
|
||||||
|
if s.peek() == '\n' {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't reach a newline then that is also not good
|
||||||
|
if ch != '\n' {
|
||||||
|
s.err("invalid characters in heredoc anchor")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the identifier
|
||||||
|
identBytes := s.src[offs : s.srcPos.Offset-s.lastCharLen]
|
||||||
|
if len(identBytes) == 0 {
|
||||||
|
s.err("zero-length heredoc anchor")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var identRegexp *regexp.Regexp
|
||||||
|
if identBytes[0] == '-' {
|
||||||
|
identRegexp = regexp.MustCompile(fmt.Sprintf(`[[:space:]]*%s\z`, identBytes[1:]))
|
||||||
|
} else {
|
||||||
|
identRegexp = regexp.MustCompile(fmt.Sprintf(`[[:space:]]*%s\z`, identBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the actual string value
|
||||||
|
lineStart := s.srcPos.Offset
|
||||||
|
for {
|
||||||
|
ch := s.next()
|
||||||
|
|
||||||
|
// Special newline handling.
|
||||||
|
if ch == '\n' {
|
||||||
|
// Math is fast, so we first compare the byte counts to see if we have a chance
|
||||||
|
// of seeing the same identifier - if the length is less than the number of bytes
|
||||||
|
// in the identifier, this cannot be a valid terminator.
|
||||||
|
lineBytesLen := s.srcPos.Offset - s.lastCharLen - lineStart
|
||||||
|
if lineBytesLen >= len(identBytes) && identRegexp.Match(s.src[lineStart:s.srcPos.Offset-s.lastCharLen]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not an anchor match, record the start of a new line
|
||||||
|
lineStart = s.srcPos.Offset
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == eof {
|
||||||
|
s.err("heredoc not terminated")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanString scans a quoted string
|
||||||
|
func (s *Scanner) scanString() {
|
||||||
|
braces := 0
|
||||||
|
for {
|
||||||
|
// '"' opening already consumed
|
||||||
|
// read character after quote
|
||||||
|
ch := s.next()
|
||||||
|
|
||||||
|
if ch < 0 || ch == eof {
|
||||||
|
s.err("literal not terminated")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '"' && braces == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're going into a ${} then we can ignore quotes for awhile
|
||||||
|
if braces == 0 && ch == '$' && s.peek() == '{' {
|
||||||
|
braces++
|
||||||
|
s.next()
|
||||||
|
} else if braces > 0 && ch == '{' {
|
||||||
|
braces++
|
||||||
|
}
|
||||||
|
if braces > 0 && ch == '}' {
|
||||||
|
braces--
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '\\' {
|
||||||
|
s.scanEscape()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanEscape scans an escape sequence
|
||||||
|
func (s *Scanner) scanEscape() rune {
|
||||||
|
// http://en.cppreference.com/w/cpp/language/escape
|
||||||
|
ch := s.next() // read character after '/'
|
||||||
|
switch ch {
|
||||||
|
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"':
|
||||||
|
// nothing to do
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||||
|
// octal notation
|
||||||
|
ch = s.scanDigits(ch, 8, 3)
|
||||||
|
case 'x':
|
||||||
|
// hexademical notation
|
||||||
|
ch = s.scanDigits(s.next(), 16, 2)
|
||||||
|
case 'u':
|
||||||
|
// universal character name
|
||||||
|
ch = s.scanDigits(s.next(), 16, 4)
|
||||||
|
case 'U':
|
||||||
|
// universal character name
|
||||||
|
ch = s.scanDigits(s.next(), 16, 8)
|
||||||
|
default:
|
||||||
|
s.err("illegal char escape")
|
||||||
|
}
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanDigits scans a rune with the given base for n times. For example an
|
||||||
|
// octal notation \184 would yield in scanDigits(ch, 8, 3)
|
||||||
|
func (s *Scanner) scanDigits(ch rune, base, n int) rune {
|
||||||
|
start := n
|
||||||
|
for n > 0 && digitVal(ch) < base {
|
||||||
|
ch = s.next()
|
||||||
|
if ch == eof {
|
||||||
|
// If we see an EOF, we halt any more scanning of digits
|
||||||
|
// immediately.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
s.err("illegal char escape")
|
||||||
|
}
|
||||||
|
|
||||||
|
if n != start {
|
||||||
|
// we scanned all digits, put the last non digit char back,
|
||||||
|
// only if we read anything at all
|
||||||
|
s.unread()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanIdentifier scans an identifier and returns the literal string
|
||||||
|
func (s *Scanner) scanIdentifier() string {
|
||||||
|
offs := s.srcPos.Offset - s.lastCharLen
|
||||||
|
ch := s.next()
|
||||||
|
for isLetter(ch) || isDigit(ch) || ch == '-' || ch == '.' {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch != eof {
|
||||||
|
s.unread() // we got identifier, put back latest char
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(s.src[offs:s.srcPos.Offset])
|
||||||
|
}
|
||||||
|
|
||||||
|
// recentPosition returns the position of the character immediately after the
|
||||||
|
// character or token returned by the last call to Scan.
|
||||||
|
func (s *Scanner) recentPosition() (pos token.Pos) {
|
||||||
|
pos.Offset = s.srcPos.Offset - s.lastCharLen
|
||||||
|
switch {
|
||||||
|
case s.srcPos.Column > 0:
|
||||||
|
// common case: last character was not a '\n'
|
||||||
|
pos.Line = s.srcPos.Line
|
||||||
|
pos.Column = s.srcPos.Column
|
||||||
|
case s.lastLineLen > 0:
|
||||||
|
// last character was a '\n'
|
||||||
|
// (we cannot be at the beginning of the source
|
||||||
|
// since we have called next() at least once)
|
||||||
|
pos.Line = s.srcPos.Line - 1
|
||||||
|
pos.Column = s.lastLineLen
|
||||||
|
default:
|
||||||
|
// at the beginning of the source
|
||||||
|
pos.Line = 1
|
||||||
|
pos.Column = 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// err prints the error of any scanning to s.Error function. If the function is
|
||||||
|
// not defined, by default it prints them to os.Stderr
|
||||||
|
func (s *Scanner) err(msg string) {
|
||||||
|
s.ErrorCount++
|
||||||
|
pos := s.recentPosition()
|
||||||
|
|
||||||
|
if s.Error != nil {
|
||||||
|
s.Error(pos, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isHexadecimal returns true if the given rune is a letter
|
||||||
|
func isLetter(ch rune) bool {
|
||||||
|
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDigit returns true if the given rune is a decimal digit
|
||||||
|
func isDigit(ch rune) bool {
|
||||||
|
return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDecimal returns true if the given rune is a decimal number
|
||||||
|
func isDecimal(ch rune) bool {
|
||||||
|
return '0' <= ch && ch <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
// isHexadecimal returns true if the given rune is an hexadecimal number
|
||||||
|
func isHexadecimal(ch rune) bool {
|
||||||
|
return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F'
|
||||||
|
}
|
||||||
|
|
||||||
|
// isWhitespace returns true if the rune is a space, tab, newline or carriage return
|
||||||
|
func isWhitespace(ch rune) bool {
|
||||||
|
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
|
||||||
|
}
|
||||||
|
|
||||||
|
// digitVal returns the integer value of a given octal,decimal or hexadecimal rune
|
||||||
|
func digitVal(ch rune) int {
|
||||||
|
switch {
|
||||||
|
case '0' <= ch && ch <= '9':
|
||||||
|
return int(ch - '0')
|
||||||
|
case 'a' <= ch && ch <= 'f':
|
||||||
|
return int(ch - 'a' + 10)
|
||||||
|
case 'A' <= ch && ch <= 'F':
|
||||||
|
return int(ch - 'A' + 10)
|
||||||
|
}
|
||||||
|
return 16 // larger than any legal digit val
|
||||||
|
}
|
244
vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go
generated
vendored
Normal file
244
vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go
generated
vendored
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
package strconv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrSyntax indicates that a value does not have the right syntax for the target type.
|
||||||
|
var ErrSyntax = errors.New("invalid syntax")
|
||||||
|
|
||||||
|
// Unquote interprets s as a single-quoted, double-quoted,
|
||||||
|
// or backquoted Go string literal, returning the string value
|
||||||
|
// that s quotes. (If s is single-quoted, it would be a Go
|
||||||
|
// character literal; Unquote returns the corresponding
|
||||||
|
// one-character string.)
|
||||||
|
func Unquote(s string) (t string, err error) {
|
||||||
|
n := len(s)
|
||||||
|
if n < 2 {
|
||||||
|
return "", ErrSyntax
|
||||||
|
}
|
||||||
|
quote := s[0]
|
||||||
|
if quote != s[n-1] {
|
||||||
|
return "", ErrSyntax
|
||||||
|
}
|
||||||
|
s = s[1 : n-1]
|
||||||
|
|
||||||
|
if quote != '"' {
|
||||||
|
return "", ErrSyntax
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it trivial? Avoid allocation.
|
||||||
|
if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') {
|
||||||
|
switch quote {
|
||||||
|
case '"':
|
||||||
|
return s, nil
|
||||||
|
case '\'':
|
||||||
|
r, size := utf8.DecodeRuneInString(s)
|
||||||
|
if size == len(s) && (r != utf8.RuneError || size != 1) {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var runeTmp [utf8.UTFMax]byte
|
||||||
|
buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
|
||||||
|
for len(s) > 0 {
|
||||||
|
// If we're starting a '${}' then let it through un-unquoted.
|
||||||
|
// Specifically: we don't unquote any characters within the `${}`
|
||||||
|
// section, except for escaped backslashes, which we handle specifically.
|
||||||
|
if s[0] == '$' && len(s) > 1 && s[1] == '{' {
|
||||||
|
buf = append(buf, '$', '{')
|
||||||
|
s = s[2:]
|
||||||
|
|
||||||
|
// Continue reading until we find the closing brace, copying as-is
|
||||||
|
braces := 1
|
||||||
|
for len(s) > 0 && braces > 0 {
|
||||||
|
r, size := utf8.DecodeRuneInString(s)
|
||||||
|
if r == utf8.RuneError {
|
||||||
|
return "", ErrSyntax
|
||||||
|
}
|
||||||
|
|
||||||
|
s = s[size:]
|
||||||
|
|
||||||
|
// We special case escaped backslashes in interpolations, converting
|
||||||
|
// them to their unescaped equivalents.
|
||||||
|
if r == '\\' {
|
||||||
|
q, _ := utf8.DecodeRuneInString(s)
|
||||||
|
switch q {
|
||||||
|
case '\\':
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n := utf8.EncodeRune(runeTmp[:], r)
|
||||||
|
buf = append(buf, runeTmp[:n]...)
|
||||||
|
|
||||||
|
switch r {
|
||||||
|
case '{':
|
||||||
|
braces++
|
||||||
|
case '}':
|
||||||
|
braces--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if braces != 0 {
|
||||||
|
return "", ErrSyntax
|
||||||
|
}
|
||||||
|
if len(s) == 0 {
|
||||||
|
// If there's no string left, we're done!
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
// If there's more left, we need to pop back up to the top of the loop
|
||||||
|
// in case there's another interpolation in this string.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c, multibyte, ss, err := unquoteChar(s, quote)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s = ss
|
||||||
|
if c < utf8.RuneSelf || !multibyte {
|
||||||
|
buf = append(buf, byte(c))
|
||||||
|
} else {
|
||||||
|
n := utf8.EncodeRune(runeTmp[:], c)
|
||||||
|
buf = append(buf, runeTmp[:n]...)
|
||||||
|
}
|
||||||
|
if quote == '\'' && len(s) != 0 {
|
||||||
|
// single-quoted must be single character
|
||||||
|
return "", ErrSyntax
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// contains reports whether the string contains the byte c.
|
||||||
|
func contains(s string, c byte) bool {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] == c {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func unhex(b byte) (v rune, ok bool) {
|
||||||
|
c := rune(b)
|
||||||
|
switch {
|
||||||
|
case '0' <= c && c <= '9':
|
||||||
|
return c - '0', true
|
||||||
|
case 'a' <= c && c <= 'f':
|
||||||
|
return c - 'a' + 10, true
|
||||||
|
case 'A' <= c && c <= 'F':
|
||||||
|
return c - 'A' + 10, true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) {
|
||||||
|
// easy cases
|
||||||
|
switch c := s[0]; {
|
||||||
|
case c == quote && (quote == '\'' || quote == '"'):
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
case c >= utf8.RuneSelf:
|
||||||
|
r, size := utf8.DecodeRuneInString(s)
|
||||||
|
return r, true, s[size:], nil
|
||||||
|
case c != '\\':
|
||||||
|
return rune(s[0]), false, s[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hard case: c is backslash
|
||||||
|
if len(s) <= 1 {
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c := s[1]
|
||||||
|
s = s[2:]
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case 'a':
|
||||||
|
value = '\a'
|
||||||
|
case 'b':
|
||||||
|
value = '\b'
|
||||||
|
case 'f':
|
||||||
|
value = '\f'
|
||||||
|
case 'n':
|
||||||
|
value = '\n'
|
||||||
|
case 'r':
|
||||||
|
value = '\r'
|
||||||
|
case 't':
|
||||||
|
value = '\t'
|
||||||
|
case 'v':
|
||||||
|
value = '\v'
|
||||||
|
case 'x', 'u', 'U':
|
||||||
|
n := 0
|
||||||
|
switch c {
|
||||||
|
case 'x':
|
||||||
|
n = 2
|
||||||
|
case 'u':
|
||||||
|
n = 4
|
||||||
|
case 'U':
|
||||||
|
n = 8
|
||||||
|
}
|
||||||
|
var v rune
|
||||||
|
if len(s) < n {
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for j := 0; j < n; j++ {
|
||||||
|
x, ok := unhex(s[j])
|
||||||
|
if !ok {
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v = v<<4 | x
|
||||||
|
}
|
||||||
|
s = s[n:]
|
||||||
|
if c == 'x' {
|
||||||
|
// single-byte string, possibly not UTF-8
|
||||||
|
value = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if v > utf8.MaxRune {
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value = v
|
||||||
|
multibyte = true
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||||
|
v := rune(c) - '0'
|
||||||
|
if len(s) < 2 {
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for j := 0; j < 2; j++ { // one digit already; two more
|
||||||
|
x := rune(s[j]) - '0'
|
||||||
|
if x < 0 || x > 7 {
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v = (v << 3) | x
|
||||||
|
}
|
||||||
|
s = s[2:]
|
||||||
|
if v > 255 {
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value = v
|
||||||
|
case '\\':
|
||||||
|
value = '\\'
|
||||||
|
case '\'', '"':
|
||||||
|
if c != quote {
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value = rune(c)
|
||||||
|
default:
|
||||||
|
err = ErrSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tail = s
|
||||||
|
return
|
||||||
|
}
|
46
vendor/github.com/hashicorp/hcl/hcl/token/position.go
generated
vendored
Normal file
46
vendor/github.com/hashicorp/hcl/hcl/token/position.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package token
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Pos describes an arbitrary source position
|
||||||
|
// including the file, line, and column location.
|
||||||
|
// A Position is valid if the line number is > 0.
|
||||||
|
type Pos struct {
|
||||||
|
Filename string // filename, if any
|
||||||
|
Offset int // offset, starting at 0
|
||||||
|
Line int // line number, starting at 1
|
||||||
|
Column int // column number, starting at 1 (character count)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid returns true if the position is valid.
|
||||||
|
func (p *Pos) IsValid() bool { return p.Line > 0 }
|
||||||
|
|
||||||
|
// String returns a string in one of several forms:
|
||||||
|
//
|
||||||
|
// file:line:column valid position with file name
|
||||||
|
// line:column valid position without file name
|
||||||
|
// file invalid position with file name
|
||||||
|
// - invalid position without file name
|
||||||
|
func (p Pos) String() string {
|
||||||
|
s := p.Filename
|
||||||
|
if p.IsValid() {
|
||||||
|
if s != "" {
|
||||||
|
s += ":"
|
||||||
|
}
|
||||||
|
s += fmt.Sprintf("%d:%d", p.Line, p.Column)
|
||||||
|
}
|
||||||
|
if s == "" {
|
||||||
|
s = "-"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before reports whether the position p is before u.
|
||||||
|
func (p Pos) Before(u Pos) bool {
|
||||||
|
return u.Offset > p.Offset || u.Line > p.Line
|
||||||
|
}
|
||||||
|
|
||||||
|
// After reports whether the position p is after u.
|
||||||
|
func (p Pos) After(u Pos) bool {
|
||||||
|
return u.Offset < p.Offset || u.Line < p.Line
|
||||||
|
}
|
219
vendor/github.com/hashicorp/hcl/hcl/token/token.go
generated
vendored
Normal file
219
vendor/github.com/hashicorp/hcl/hcl/token/token.go
generated
vendored
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
// Package token defines constants representing the lexical tokens for HCL
|
||||||
|
// (HashiCorp Configuration Language)
|
||||||
|
package token
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
hclstrconv "github.com/hashicorp/hcl/hcl/strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token defines a single HCL token which can be obtained via the Scanner
|
||||||
|
type Token struct {
|
||||||
|
Type Type
|
||||||
|
Pos Pos
|
||||||
|
Text string
|
||||||
|
JSON bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language)
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Special tokens
|
||||||
|
ILLEGAL Type = iota
|
||||||
|
EOF
|
||||||
|
COMMENT
|
||||||
|
|
||||||
|
identifier_beg
|
||||||
|
IDENT // literals
|
||||||
|
literal_beg
|
||||||
|
NUMBER // 12345
|
||||||
|
FLOAT // 123.45
|
||||||
|
BOOL // true,false
|
||||||
|
STRING // "abc"
|
||||||
|
HEREDOC // <<FOO\nbar\nFOO
|
||||||
|
literal_end
|
||||||
|
identifier_end
|
||||||
|
|
||||||
|
operator_beg
|
||||||
|
LBRACK // [
|
||||||
|
LBRACE // {
|
||||||
|
COMMA // ,
|
||||||
|
PERIOD // .
|
||||||
|
|
||||||
|
RBRACK // ]
|
||||||
|
RBRACE // }
|
||||||
|
|
||||||
|
ASSIGN // =
|
||||||
|
ADD // +
|
||||||
|
SUB // -
|
||||||
|
operator_end
|
||||||
|
)
|
||||||
|
|
||||||
|
var tokens = [...]string{
|
||||||
|
ILLEGAL: "ILLEGAL",
|
||||||
|
|
||||||
|
EOF: "EOF",
|
||||||
|
COMMENT: "COMMENT",
|
||||||
|
|
||||||
|
IDENT: "IDENT",
|
||||||
|
NUMBER: "NUMBER",
|
||||||
|
FLOAT: "FLOAT",
|
||||||
|
BOOL: "BOOL",
|
||||||
|
STRING: "STRING",
|
||||||
|
|
||||||
|
LBRACK: "LBRACK",
|
||||||
|
LBRACE: "LBRACE",
|
||||||
|
COMMA: "COMMA",
|
||||||
|
PERIOD: "PERIOD",
|
||||||
|
HEREDOC: "HEREDOC",
|
||||||
|
|
||||||
|
RBRACK: "RBRACK",
|
||||||
|
RBRACE: "RBRACE",
|
||||||
|
|
||||||
|
ASSIGN: "ASSIGN",
|
||||||
|
ADD: "ADD",
|
||||||
|
SUB: "SUB",
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string corresponding to the token tok.
|
||||||
|
func (t Type) String() string {
|
||||||
|
s := ""
|
||||||
|
if 0 <= t && t < Type(len(tokens)) {
|
||||||
|
s = tokens[t]
|
||||||
|
}
|
||||||
|
if s == "" {
|
||||||
|
s = "token(" + strconv.Itoa(int(t)) + ")"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsIdentifier returns true for tokens corresponding to identifiers and basic
|
||||||
|
// type literals; it returns false otherwise.
|
||||||
|
func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end }
|
||||||
|
|
||||||
|
// IsLiteral returns true for tokens corresponding to basic type literals; it
|
||||||
|
// returns false otherwise.
|
||||||
|
func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end }
|
||||||
|
|
||||||
|
// IsOperator returns true for tokens corresponding to operators and
|
||||||
|
// delimiters; it returns false otherwise.
|
||||||
|
func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end }
|
||||||
|
|
||||||
|
// String returns the token's literal text. Note that this is only
|
||||||
|
// applicable for certain token types, such as token.IDENT,
|
||||||
|
// token.STRING, etc..
|
||||||
|
func (t Token) String() string {
|
||||||
|
return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the properly typed value for this token. The type of
|
||||||
|
// the returned interface{} is guaranteed based on the Type field.
|
||||||
|
//
|
||||||
|
// This can only be called for literal types. If it is called for any other
|
||||||
|
// type, this will panic.
|
||||||
|
func (t Token) Value() interface{} {
|
||||||
|
switch t.Type {
|
||||||
|
case BOOL:
|
||||||
|
if t.Text == "true" {
|
||||||
|
return true
|
||||||
|
} else if t.Text == "false" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("unknown bool value: " + t.Text)
|
||||||
|
case FLOAT:
|
||||||
|
v, err := strconv.ParseFloat(t.Text, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return float64(v)
|
||||||
|
case NUMBER:
|
||||||
|
v, err := strconv.ParseInt(t.Text, 0, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(v)
|
||||||
|
case IDENT:
|
||||||
|
return t.Text
|
||||||
|
case HEREDOC:
|
||||||
|
return unindentHeredoc(t.Text)
|
||||||
|
case STRING:
|
||||||
|
// Determine the Unquote method to use. If it came from JSON,
|
||||||
|
// then we need to use the built-in unquote since we have to
|
||||||
|
// escape interpolations there.
|
||||||
|
f := hclstrconv.Unquote
|
||||||
|
if t.JSON {
|
||||||
|
f = strconv.Unquote
|
||||||
|
}
|
||||||
|
|
||||||
|
// This case occurs if json null is used
|
||||||
|
if t.Text == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := f(t.Text)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("unquote %s err: %s", t.Text, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unimplemented Value for type: %s", t.Type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unindentHeredoc returns the string content of a HEREDOC if it is started with <<
|
||||||
|
// and the content of a HEREDOC with the hanging indent removed if it is started with
|
||||||
|
// a <<-, and the terminating line is at least as indented as the least indented line.
|
||||||
|
func unindentHeredoc(heredoc string) string {
|
||||||
|
// We need to find the end of the marker
|
||||||
|
idx := strings.IndexByte(heredoc, '\n')
|
||||||
|
if idx == -1 {
|
||||||
|
panic("heredoc doesn't contain newline")
|
||||||
|
}
|
||||||
|
|
||||||
|
unindent := heredoc[2] == '-'
|
||||||
|
|
||||||
|
// We can optimize if the heredoc isn't marked for indentation
|
||||||
|
if !unindent {
|
||||||
|
return string(heredoc[idx+1 : len(heredoc)-idx+1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to unindent each line based on the indentation level of the marker
|
||||||
|
lines := strings.Split(string(heredoc[idx+1:len(heredoc)-idx+2]), "\n")
|
||||||
|
whitespacePrefix := lines[len(lines)-1]
|
||||||
|
|
||||||
|
isIndented := true
|
||||||
|
for _, v := range lines {
|
||||||
|
if strings.HasPrefix(v, whitespacePrefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
isIndented = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all lines are not at least as indented as the terminating mark, return the
|
||||||
|
// heredoc as is, but trim the leading space from the marker on the final line.
|
||||||
|
if !isIndented {
|
||||||
|
return strings.TrimRight(string(heredoc[idx+1:len(heredoc)-idx+1]), " \t")
|
||||||
|
}
|
||||||
|
|
||||||
|
unindentedLines := make([]string, len(lines))
|
||||||
|
for k, v := range lines {
|
||||||
|
if k == len(lines)-1 {
|
||||||
|
unindentedLines[k] = ""
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
unindentedLines[k] = strings.TrimPrefix(v, whitespacePrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(unindentedLines, "\n")
|
||||||
|
}
|
111
vendor/github.com/hashicorp/hcl/json/parser/flatten.go
generated
vendored
Normal file
111
vendor/github.com/hashicorp/hcl/json/parser/flatten.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import "github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
|
||||||
|
// flattenObjects takes an AST node, walks it, and flattens
|
||||||
|
func flattenObjects(node ast.Node) {
|
||||||
|
ast.Walk(node, func(n ast.Node) (ast.Node, bool) {
|
||||||
|
// We only care about lists, because this is what we modify
|
||||||
|
list, ok := n.(*ast.ObjectList)
|
||||||
|
if !ok {
|
||||||
|
return n, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild the item list
|
||||||
|
items := make([]*ast.ObjectItem, 0, len(list.Items))
|
||||||
|
frontier := make([]*ast.ObjectItem, len(list.Items))
|
||||||
|
copy(frontier, list.Items)
|
||||||
|
for len(frontier) > 0 {
|
||||||
|
// Pop the current item
|
||||||
|
n := len(frontier)
|
||||||
|
item := frontier[n-1]
|
||||||
|
frontier = frontier[:n-1]
|
||||||
|
|
||||||
|
switch v := item.Val.(type) {
|
||||||
|
case *ast.ObjectType:
|
||||||
|
items, frontier = flattenObjectType(v, item, items, frontier)
|
||||||
|
case *ast.ListType:
|
||||||
|
items, frontier = flattenListType(v, item, items, frontier)
|
||||||
|
default:
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the list since the frontier model runs things backwards
|
||||||
|
for i := len(items)/2 - 1; i >= 0; i-- {
|
||||||
|
opp := len(items) - 1 - i
|
||||||
|
items[i], items[opp] = items[opp], items[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done! Set the original items
|
||||||
|
list.Items = items
|
||||||
|
return n, true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenListType(
|
||||||
|
ot *ast.ListType,
|
||||||
|
item *ast.ObjectItem,
|
||||||
|
items []*ast.ObjectItem,
|
||||||
|
frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
|
||||||
|
// All the elements of this object must also be objects!
|
||||||
|
for _, subitem := range ot.List {
|
||||||
|
if _, ok := subitem.(*ast.ObjectType); !ok {
|
||||||
|
items = append(items, item)
|
||||||
|
return items, frontier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Great! We have a match go through all the items and flatten
|
||||||
|
for _, elem := range ot.List {
|
||||||
|
// Add it to the frontier so that we can recurse
|
||||||
|
frontier = append(frontier, &ast.ObjectItem{
|
||||||
|
Keys: item.Keys,
|
||||||
|
Assign: item.Assign,
|
||||||
|
Val: elem,
|
||||||
|
LeadComment: item.LeadComment,
|
||||||
|
LineComment: item.LineComment,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, frontier
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenObjectType(
|
||||||
|
ot *ast.ObjectType,
|
||||||
|
item *ast.ObjectItem,
|
||||||
|
items []*ast.ObjectItem,
|
||||||
|
frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
|
||||||
|
// If the list has no items we do not have to flatten anything
|
||||||
|
if ot.List.Items == nil {
|
||||||
|
items = append(items, item)
|
||||||
|
return items, frontier
|
||||||
|
}
|
||||||
|
|
||||||
|
// All the elements of this object must also be objects!
|
||||||
|
for _, subitem := range ot.List.Items {
|
||||||
|
if _, ok := subitem.Val.(*ast.ObjectType); !ok {
|
||||||
|
items = append(items, item)
|
||||||
|
return items, frontier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Great! We have a match go through all the items and flatten
|
||||||
|
for _, subitem := range ot.List.Items {
|
||||||
|
// Copy the new key
|
||||||
|
keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys))
|
||||||
|
copy(keys, item.Keys)
|
||||||
|
copy(keys[len(item.Keys):], subitem.Keys)
|
||||||
|
|
||||||
|
// Add it to the frontier so that we can recurse
|
||||||
|
frontier = append(frontier, &ast.ObjectItem{
|
||||||
|
Keys: keys,
|
||||||
|
Assign: item.Assign,
|
||||||
|
Val: subitem.Val,
|
||||||
|
LeadComment: item.LeadComment,
|
||||||
|
LineComment: item.LineComment,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, frontier
|
||||||
|
}
|
303
vendor/github.com/hashicorp/hcl/json/parser/parser.go
generated
vendored
Normal file
303
vendor/github.com/hashicorp/hcl/json/parser/parser.go
generated
vendored
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
"github.com/hashicorp/hcl/json/scanner"
|
||||||
|
"github.com/hashicorp/hcl/json/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Parser struct {
|
||||||
|
sc *scanner.Scanner
|
||||||
|
|
||||||
|
// Last read token
|
||||||
|
tok token.Token
|
||||||
|
commaPrev token.Token
|
||||||
|
|
||||||
|
enableTrace bool
|
||||||
|
indent int
|
||||||
|
n int // buffer size (max = 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParser(src []byte) *Parser {
|
||||||
|
return &Parser{
|
||||||
|
sc: scanner.New(src),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse returns the fully parsed source and returns the abstract syntax tree.
|
||||||
|
func Parse(src []byte) (*ast.File, error) {
|
||||||
|
p := newParser(src)
|
||||||
|
return p.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
var errEofToken = errors.New("EOF token found")
|
||||||
|
|
||||||
|
// Parse returns the fully parsed source and returns the abstract syntax tree.
|
||||||
|
func (p *Parser) Parse() (*ast.File, error) {
|
||||||
|
f := &ast.File{}
|
||||||
|
var err, scerr error
|
||||||
|
p.sc.Error = func(pos token.Pos, msg string) {
|
||||||
|
scerr = fmt.Errorf("%s: %s", pos, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The root must be an object in JSON
|
||||||
|
object, err := p.object()
|
||||||
|
if scerr != nil {
|
||||||
|
return nil, scerr
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We make our final node an object list so it is more HCL compatible
|
||||||
|
f.Node = object.List
|
||||||
|
|
||||||
|
// Flatten it, which finds patterns and turns them into more HCL-like
|
||||||
|
// AST trees.
|
||||||
|
flattenObjects(f.Node)
|
||||||
|
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) objectList() (*ast.ObjectList, error) {
|
||||||
|
defer un(trace(p, "ParseObjectList"))
|
||||||
|
node := &ast.ObjectList{}
|
||||||
|
|
||||||
|
for {
|
||||||
|
n, err := p.objectItem()
|
||||||
|
if err == errEofToken {
|
||||||
|
break // we are finished
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't return a nil node, because might want to use already
|
||||||
|
// collected items.
|
||||||
|
if err != nil {
|
||||||
|
return node, err
|
||||||
|
}
|
||||||
|
|
||||||
|
node.Add(n)
|
||||||
|
|
||||||
|
// Check for a followup comma. If it isn't a comma, then we're done
|
||||||
|
if tok := p.scan(); tok.Type != token.COMMA {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// objectItem parses a single object item
|
||||||
|
func (p *Parser) objectItem() (*ast.ObjectItem, error) {
|
||||||
|
defer un(trace(p, "ParseObjectItem"))
|
||||||
|
|
||||||
|
keys, err := p.objectKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
o := &ast.ObjectItem{
|
||||||
|
Keys: keys,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch p.tok.Type {
|
||||||
|
case token.COLON:
|
||||||
|
o.Val, err = p.objectValue()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// objectKey parses an object key and returns a ObjectKey AST
|
||||||
|
func (p *Parser) objectKey() ([]*ast.ObjectKey, error) {
|
||||||
|
keyCount := 0
|
||||||
|
keys := make([]*ast.ObjectKey, 0)
|
||||||
|
|
||||||
|
for {
|
||||||
|
tok := p.scan()
|
||||||
|
switch tok.Type {
|
||||||
|
case token.EOF:
|
||||||
|
return nil, errEofToken
|
||||||
|
case token.STRING:
|
||||||
|
keyCount++
|
||||||
|
keys = append(keys, &ast.ObjectKey{
|
||||||
|
Token: p.tok.HCLToken(),
|
||||||
|
})
|
||||||
|
case token.COLON:
|
||||||
|
// If we have a zero keycount it means that we never got
|
||||||
|
// an object key, i.e. `{ :`. This is a syntax error.
|
||||||
|
if keyCount == 0 {
|
||||||
|
return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done
|
||||||
|
return keys, nil
|
||||||
|
case token.ILLEGAL:
|
||||||
|
fmt.Println("illegal")
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// object parses any type of object, such as number, bool, string, object or
|
||||||
|
// list.
|
||||||
|
func (p *Parser) objectValue() (ast.Node, error) {
|
||||||
|
defer un(trace(p, "ParseObjectValue"))
|
||||||
|
tok := p.scan()
|
||||||
|
|
||||||
|
switch tok.Type {
|
||||||
|
case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING:
|
||||||
|
return p.literalType()
|
||||||
|
case token.LBRACE:
|
||||||
|
return p.objectType()
|
||||||
|
case token.LBRACK:
|
||||||
|
return p.listType()
|
||||||
|
case token.EOF:
|
||||||
|
return nil, errEofToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok)
|
||||||
|
}
|
||||||
|
|
||||||
|
// object parses any type of object, such as number, bool, string, object or
|
||||||
|
// list.
|
||||||
|
func (p *Parser) object() (*ast.ObjectType, error) {
|
||||||
|
defer un(trace(p, "ParseType"))
|
||||||
|
tok := p.scan()
|
||||||
|
|
||||||
|
switch tok.Type {
|
||||||
|
case token.LBRACE:
|
||||||
|
return p.objectType()
|
||||||
|
case token.EOF:
|
||||||
|
return nil, errEofToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok)
|
||||||
|
}
|
||||||
|
|
||||||
|
// objectType parses an object type and returns a ObjectType AST
|
||||||
|
func (p *Parser) objectType() (*ast.ObjectType, error) {
|
||||||
|
defer un(trace(p, "ParseObjectType"))
|
||||||
|
|
||||||
|
// we assume that the currently scanned token is a LBRACE
|
||||||
|
o := &ast.ObjectType{}
|
||||||
|
|
||||||
|
l, err := p.objectList()
|
||||||
|
|
||||||
|
// if we hit RBRACE, we are good to go (means we parsed all Items), if it's
|
||||||
|
// not a RBRACE, it's an syntax error and we just return it.
|
||||||
|
if err != nil && p.tok.Type != token.RBRACE {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
o.List = l
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// listType parses a list type and returns a ListType AST
|
||||||
|
func (p *Parser) listType() (*ast.ListType, error) {
|
||||||
|
defer un(trace(p, "ParseListType"))
|
||||||
|
|
||||||
|
// we assume that the currently scanned token is a LBRACK
|
||||||
|
l := &ast.ListType{}
|
||||||
|
|
||||||
|
for {
|
||||||
|
tok := p.scan()
|
||||||
|
switch tok.Type {
|
||||||
|
case token.NUMBER, token.FLOAT, token.STRING:
|
||||||
|
node, err := p.literalType()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Add(node)
|
||||||
|
case token.COMMA:
|
||||||
|
continue
|
||||||
|
case token.LBRACE:
|
||||||
|
node, err := p.objectType()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Add(node)
|
||||||
|
case token.BOOL:
|
||||||
|
// TODO(arslan) should we support? not supported by HCL yet
|
||||||
|
case token.LBRACK:
|
||||||
|
// TODO(arslan) should we support nested lists? Even though it's
|
||||||
|
// written in README of HCL, it's not a part of the grammar
|
||||||
|
// (not defined in parse.y)
|
||||||
|
case token.RBRACK:
|
||||||
|
// finished
|
||||||
|
return l, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// literalType parses a literal type and returns a LiteralType AST
|
||||||
|
func (p *Parser) literalType() (*ast.LiteralType, error) {
|
||||||
|
defer un(trace(p, "ParseLiteral"))
|
||||||
|
|
||||||
|
return &ast.LiteralType{
|
||||||
|
Token: p.tok.HCLToken(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan returns the next token from the underlying scanner. If a token has
|
||||||
|
// been unscanned then read that instead.
|
||||||
|
func (p *Parser) scan() token.Token {
|
||||||
|
// If we have a token on the buffer, then return it.
|
||||||
|
if p.n != 0 {
|
||||||
|
p.n = 0
|
||||||
|
return p.tok
|
||||||
|
}
|
||||||
|
|
||||||
|
p.tok = p.sc.Scan()
|
||||||
|
return p.tok
|
||||||
|
}
|
||||||
|
|
||||||
|
// unscan pushes the previously read token back onto the buffer.
|
||||||
|
func (p *Parser) unscan() {
|
||||||
|
p.n = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Parsing support
|
||||||
|
|
||||||
|
func (p *Parser) printTrace(a ...interface{}) {
|
||||||
|
if !p.enableTrace {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
|
||||||
|
const n = len(dots)
|
||||||
|
fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column)
|
||||||
|
|
||||||
|
i := 2 * p.indent
|
||||||
|
for i > n {
|
||||||
|
fmt.Print(dots)
|
||||||
|
i -= n
|
||||||
|
}
|
||||||
|
// i <= n
|
||||||
|
fmt.Print(dots[0:i])
|
||||||
|
fmt.Println(a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func trace(p *Parser, msg string) *Parser {
|
||||||
|
p.printTrace(msg, "(")
|
||||||
|
p.indent++
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage pattern: defer un(trace(p, "..."))
|
||||||
|
func un(p *Parser) {
|
||||||
|
p.indent--
|
||||||
|
p.printTrace(")")
|
||||||
|
}
|
451
vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
generated
vendored
Normal file
451
vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
generated
vendored
Normal file
|
@ -0,0 +1,451 @@
|
||||||
|
package scanner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/json/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// eof represents a marker rune for the end of the reader.
|
||||||
|
const eof = rune(0)
|
||||||
|
|
||||||
|
// Scanner defines a lexical scanner
|
||||||
|
type Scanner struct {
|
||||||
|
buf *bytes.Buffer // Source buffer for advancing and scanning
|
||||||
|
src []byte // Source buffer for immutable access
|
||||||
|
|
||||||
|
// Source Position
|
||||||
|
srcPos token.Pos // current position
|
||||||
|
prevPos token.Pos // previous position, used for peek() method
|
||||||
|
|
||||||
|
lastCharLen int // length of last character in bytes
|
||||||
|
lastLineLen int // length of last line in characters (for correct column reporting)
|
||||||
|
|
||||||
|
tokStart int // token text start position
|
||||||
|
tokEnd int // token text end position
|
||||||
|
|
||||||
|
// Error is called for each error encountered. If no Error
|
||||||
|
// function is set, the error is reported to os.Stderr.
|
||||||
|
Error func(pos token.Pos, msg string)
|
||||||
|
|
||||||
|
// ErrorCount is incremented by one for each error encountered.
|
||||||
|
ErrorCount int
|
||||||
|
|
||||||
|
// tokPos is the start position of most recently scanned token; set by
|
||||||
|
// Scan. The Filename field is always left untouched by the Scanner. If
|
||||||
|
// an error is reported (via Error) and Position is invalid, the scanner is
|
||||||
|
// not inside a token.
|
||||||
|
tokPos token.Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates and initializes a new instance of Scanner using src as
|
||||||
|
// its source content.
|
||||||
|
func New(src []byte) *Scanner {
|
||||||
|
// even though we accept a src, we read from a io.Reader compatible type
|
||||||
|
// (*bytes.Buffer). So in the future we might easily change it to streaming
|
||||||
|
// read.
|
||||||
|
b := bytes.NewBuffer(src)
|
||||||
|
s := &Scanner{
|
||||||
|
buf: b,
|
||||||
|
src: src,
|
||||||
|
}
|
||||||
|
|
||||||
|
// srcPosition always starts with 1
|
||||||
|
s.srcPos.Line = 1
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// next reads the next rune from the bufferred reader. Returns the rune(0) if
|
||||||
|
// an error occurs (or io.EOF is returned).
|
||||||
|
func (s *Scanner) next() rune {
|
||||||
|
ch, size, err := s.buf.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
// advance for error reporting
|
||||||
|
s.srcPos.Column++
|
||||||
|
s.srcPos.Offset += size
|
||||||
|
s.lastCharLen = size
|
||||||
|
return eof
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == utf8.RuneError && size == 1 {
|
||||||
|
s.srcPos.Column++
|
||||||
|
s.srcPos.Offset += size
|
||||||
|
s.lastCharLen = size
|
||||||
|
s.err("illegal UTF-8 encoding")
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// remember last position
|
||||||
|
s.prevPos = s.srcPos
|
||||||
|
|
||||||
|
s.srcPos.Column++
|
||||||
|
s.lastCharLen = size
|
||||||
|
s.srcPos.Offset += size
|
||||||
|
|
||||||
|
if ch == '\n' {
|
||||||
|
s.srcPos.Line++
|
||||||
|
s.lastLineLen = s.srcPos.Column
|
||||||
|
s.srcPos.Column = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// debug
|
||||||
|
// fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column)
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// unread unreads the previous read Rune and updates the source position
|
||||||
|
func (s *Scanner) unread() {
|
||||||
|
if err := s.buf.UnreadRune(); err != nil {
|
||||||
|
panic(err) // this is user fault, we should catch it
|
||||||
|
}
|
||||||
|
s.srcPos = s.prevPos // put back last position
|
||||||
|
}
|
||||||
|
|
||||||
|
// peek returns the next rune without advancing the reader.
|
||||||
|
func (s *Scanner) peek() rune {
|
||||||
|
peek, _, err := s.buf.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
return eof
|
||||||
|
}
|
||||||
|
|
||||||
|
s.buf.UnreadRune()
|
||||||
|
return peek
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan scans the next token and returns the token.
|
||||||
|
func (s *Scanner) Scan() token.Token {
|
||||||
|
ch := s.next()
|
||||||
|
|
||||||
|
// skip white space
|
||||||
|
for isWhitespace(ch) {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
var tok token.Type
|
||||||
|
|
||||||
|
// token text markings
|
||||||
|
s.tokStart = s.srcPos.Offset - s.lastCharLen
|
||||||
|
|
||||||
|
// token position, initial next() is moving the offset by one(size of rune
|
||||||
|
// actually), though we are interested with the starting point
|
||||||
|
s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen
|
||||||
|
if s.srcPos.Column > 0 {
|
||||||
|
// common case: last character was not a '\n'
|
||||||
|
s.tokPos.Line = s.srcPos.Line
|
||||||
|
s.tokPos.Column = s.srcPos.Column
|
||||||
|
} else {
|
||||||
|
// last character was a '\n'
|
||||||
|
// (we cannot be at the beginning of the source
|
||||||
|
// since we have called next() at least once)
|
||||||
|
s.tokPos.Line = s.srcPos.Line - 1
|
||||||
|
s.tokPos.Column = s.lastLineLen
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isLetter(ch):
|
||||||
|
lit := s.scanIdentifier()
|
||||||
|
if lit == "true" || lit == "false" {
|
||||||
|
tok = token.BOOL
|
||||||
|
} else if lit == "null" {
|
||||||
|
tok = token.NULL
|
||||||
|
} else {
|
||||||
|
s.err("illegal char")
|
||||||
|
}
|
||||||
|
case isDecimal(ch):
|
||||||
|
tok = s.scanNumber(ch)
|
||||||
|
default:
|
||||||
|
switch ch {
|
||||||
|
case eof:
|
||||||
|
tok = token.EOF
|
||||||
|
case '"':
|
||||||
|
tok = token.STRING
|
||||||
|
s.scanString()
|
||||||
|
case '.':
|
||||||
|
tok = token.PERIOD
|
||||||
|
ch = s.peek()
|
||||||
|
if isDecimal(ch) {
|
||||||
|
tok = token.FLOAT
|
||||||
|
ch = s.scanMantissa(ch)
|
||||||
|
ch = s.scanExponent(ch)
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
tok = token.LBRACK
|
||||||
|
case ']':
|
||||||
|
tok = token.RBRACK
|
||||||
|
case '{':
|
||||||
|
tok = token.LBRACE
|
||||||
|
case '}':
|
||||||
|
tok = token.RBRACE
|
||||||
|
case ',':
|
||||||
|
tok = token.COMMA
|
||||||
|
case ':':
|
||||||
|
tok = token.COLON
|
||||||
|
case '-':
|
||||||
|
if isDecimal(s.peek()) {
|
||||||
|
ch := s.next()
|
||||||
|
tok = s.scanNumber(ch)
|
||||||
|
} else {
|
||||||
|
s.err("illegal char")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
s.err("illegal char: " + string(ch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finish token ending
|
||||||
|
s.tokEnd = s.srcPos.Offset
|
||||||
|
|
||||||
|
// create token literal
|
||||||
|
var tokenText string
|
||||||
|
if s.tokStart >= 0 {
|
||||||
|
tokenText = string(s.src[s.tokStart:s.tokEnd])
|
||||||
|
}
|
||||||
|
s.tokStart = s.tokEnd // ensure idempotency of tokenText() call
|
||||||
|
|
||||||
|
return token.Token{
|
||||||
|
Type: tok,
|
||||||
|
Pos: s.tokPos,
|
||||||
|
Text: tokenText,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanNumber scans a HCL number definition starting with the given rune
|
||||||
|
func (s *Scanner) scanNumber(ch rune) token.Type {
|
||||||
|
zero := ch == '0'
|
||||||
|
pos := s.srcPos
|
||||||
|
|
||||||
|
s.scanMantissa(ch)
|
||||||
|
ch = s.next() // seek forward
|
||||||
|
if ch == 'e' || ch == 'E' {
|
||||||
|
ch = s.scanExponent(ch)
|
||||||
|
return token.FLOAT
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '.' {
|
||||||
|
ch = s.scanFraction(ch)
|
||||||
|
if ch == 'e' || ch == 'E' {
|
||||||
|
ch = s.next()
|
||||||
|
ch = s.scanExponent(ch)
|
||||||
|
}
|
||||||
|
return token.FLOAT
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch != eof {
|
||||||
|
s.unread()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a larger number and this is zero, error
|
||||||
|
if zero && pos != s.srcPos {
|
||||||
|
s.err("numbers cannot start with 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return token.NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanMantissa scans the mantissa begining from the rune. It returns the next
|
||||||
|
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
|
||||||
|
func (s *Scanner) scanMantissa(ch rune) rune {
|
||||||
|
scanned := false
|
||||||
|
for isDecimal(ch) {
|
||||||
|
ch = s.next()
|
||||||
|
scanned = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if scanned && ch != eof {
|
||||||
|
s.unread()
|
||||||
|
}
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanFraction scans the fraction after the '.' rune
|
||||||
|
func (s *Scanner) scanFraction(ch rune) rune {
|
||||||
|
if ch == '.' {
|
||||||
|
ch = s.peek() // we peek just to see if we can move forward
|
||||||
|
ch = s.scanMantissa(ch)
|
||||||
|
}
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanExponent scans the remaining parts of an exponent after the 'e' or 'E'
|
||||||
|
// rune.
|
||||||
|
func (s *Scanner) scanExponent(ch rune) rune {
|
||||||
|
if ch == 'e' || ch == 'E' {
|
||||||
|
ch = s.next()
|
||||||
|
if ch == '-' || ch == '+' {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
ch = s.scanMantissa(ch)
|
||||||
|
}
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanString scans a quoted string
|
||||||
|
func (s *Scanner) scanString() {
|
||||||
|
braces := 0
|
||||||
|
for {
|
||||||
|
// '"' opening already consumed
|
||||||
|
// read character after quote
|
||||||
|
ch := s.next()
|
||||||
|
|
||||||
|
if ch == '\n' || ch < 0 || ch == eof {
|
||||||
|
s.err("literal not terminated")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '"' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're going into a ${} then we can ignore quotes for awhile
|
||||||
|
if braces == 0 && ch == '$' && s.peek() == '{' {
|
||||||
|
braces++
|
||||||
|
s.next()
|
||||||
|
} else if braces > 0 && ch == '{' {
|
||||||
|
braces++
|
||||||
|
}
|
||||||
|
if braces > 0 && ch == '}' {
|
||||||
|
braces--
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '\\' {
|
||||||
|
s.scanEscape()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanEscape scans an escape sequence
|
||||||
|
func (s *Scanner) scanEscape() rune {
|
||||||
|
// http://en.cppreference.com/w/cpp/language/escape
|
||||||
|
ch := s.next() // read character after '/'
|
||||||
|
switch ch {
|
||||||
|
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"':
|
||||||
|
// nothing to do
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||||
|
// octal notation
|
||||||
|
ch = s.scanDigits(ch, 8, 3)
|
||||||
|
case 'x':
|
||||||
|
// hexademical notation
|
||||||
|
ch = s.scanDigits(s.next(), 16, 2)
|
||||||
|
case 'u':
|
||||||
|
// universal character name
|
||||||
|
ch = s.scanDigits(s.next(), 16, 4)
|
||||||
|
case 'U':
|
||||||
|
// universal character name
|
||||||
|
ch = s.scanDigits(s.next(), 16, 8)
|
||||||
|
default:
|
||||||
|
s.err("illegal char escape")
|
||||||
|
}
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanDigits scans a rune with the given base for n times. For example an
|
||||||
|
// octal notation \184 would yield in scanDigits(ch, 8, 3)
|
||||||
|
func (s *Scanner) scanDigits(ch rune, base, n int) rune {
|
||||||
|
for n > 0 && digitVal(ch) < base {
|
||||||
|
ch = s.next()
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
s.err("illegal char escape")
|
||||||
|
}
|
||||||
|
|
||||||
|
// we scanned all digits, put the last non digit char back
|
||||||
|
s.unread()
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanIdentifier scans an identifier and returns the literal string
|
||||||
|
func (s *Scanner) scanIdentifier() string {
|
||||||
|
offs := s.srcPos.Offset - s.lastCharLen
|
||||||
|
ch := s.next()
|
||||||
|
for isLetter(ch) || isDigit(ch) || ch == '-' {
|
||||||
|
ch = s.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch != eof {
|
||||||
|
s.unread() // we got identifier, put back latest char
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(s.src[offs:s.srcPos.Offset])
|
||||||
|
}
|
||||||
|
|
||||||
|
// recentPosition returns the position of the character immediately after the
|
||||||
|
// character or token returned by the last call to Scan.
|
||||||
|
func (s *Scanner) recentPosition() (pos token.Pos) {
|
||||||
|
pos.Offset = s.srcPos.Offset - s.lastCharLen
|
||||||
|
switch {
|
||||||
|
case s.srcPos.Column > 0:
|
||||||
|
// common case: last character was not a '\n'
|
||||||
|
pos.Line = s.srcPos.Line
|
||||||
|
pos.Column = s.srcPos.Column
|
||||||
|
case s.lastLineLen > 0:
|
||||||
|
// last character was a '\n'
|
||||||
|
// (we cannot be at the beginning of the source
|
||||||
|
// since we have called next() at least once)
|
||||||
|
pos.Line = s.srcPos.Line - 1
|
||||||
|
pos.Column = s.lastLineLen
|
||||||
|
default:
|
||||||
|
// at the beginning of the source
|
||||||
|
pos.Line = 1
|
||||||
|
pos.Column = 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// err prints the error of any scanning to s.Error function. If the function is
|
||||||
|
// not defined, by default it prints them to os.Stderr
|
||||||
|
func (s *Scanner) err(msg string) {
|
||||||
|
s.ErrorCount++
|
||||||
|
pos := s.recentPosition()
|
||||||
|
|
||||||
|
if s.Error != nil {
|
||||||
|
s.Error(pos, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isHexadecimal returns true if the given rune is a letter
|
||||||
|
func isLetter(ch rune) bool {
|
||||||
|
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isHexadecimal returns true if the given rune is a decimal digit
|
||||||
|
func isDigit(ch rune) bool {
|
||||||
|
return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isHexadecimal returns true if the given rune is a decimal number
|
||||||
|
func isDecimal(ch rune) bool {
|
||||||
|
return '0' <= ch && ch <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
// isHexadecimal returns true if the given rune is an hexadecimal number
|
||||||
|
func isHexadecimal(ch rune) bool {
|
||||||
|
return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F'
|
||||||
|
}
|
||||||
|
|
||||||
|
// isWhitespace returns true if the rune is a space, tab, newline or carriage return
|
||||||
|
func isWhitespace(ch rune) bool {
|
||||||
|
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
|
||||||
|
}
|
||||||
|
|
||||||
|
// digitVal returns the integer value of a given octal,decimal or hexadecimal rune
|
||||||
|
func digitVal(ch rune) int {
|
||||||
|
switch {
|
||||||
|
case '0' <= ch && ch <= '9':
|
||||||
|
return int(ch - '0')
|
||||||
|
case 'a' <= ch && ch <= 'f':
|
||||||
|
return int(ch - 'a' + 10)
|
||||||
|
case 'A' <= ch && ch <= 'F':
|
||||||
|
return int(ch - 'A' + 10)
|
||||||
|
}
|
||||||
|
return 16 // larger than any legal digit val
|
||||||
|
}
|
46
vendor/github.com/hashicorp/hcl/json/token/position.go
generated
vendored
Normal file
46
vendor/github.com/hashicorp/hcl/json/token/position.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package token
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Pos describes an arbitrary source position
|
||||||
|
// including the file, line, and column location.
|
||||||
|
// A Position is valid if the line number is > 0.
|
||||||
|
type Pos struct {
|
||||||
|
Filename string // filename, if any
|
||||||
|
Offset int // offset, starting at 0
|
||||||
|
Line int // line number, starting at 1
|
||||||
|
Column int // column number, starting at 1 (character count)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid returns true if the position is valid.
|
||||||
|
func (p *Pos) IsValid() bool { return p.Line > 0 }
|
||||||
|
|
||||||
|
// String returns a string in one of several forms:
|
||||||
|
//
|
||||||
|
// file:line:column valid position with file name
|
||||||
|
// line:column valid position without file name
|
||||||
|
// file invalid position with file name
|
||||||
|
// - invalid position without file name
|
||||||
|
func (p Pos) String() string {
|
||||||
|
s := p.Filename
|
||||||
|
if p.IsValid() {
|
||||||
|
if s != "" {
|
||||||
|
s += ":"
|
||||||
|
}
|
||||||
|
s += fmt.Sprintf("%d:%d", p.Line, p.Column)
|
||||||
|
}
|
||||||
|
if s == "" {
|
||||||
|
s = "-"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before reports whether the position p is before u.
|
||||||
|
func (p Pos) Before(u Pos) bool {
|
||||||
|
return u.Offset > p.Offset || u.Line > p.Line
|
||||||
|
}
|
||||||
|
|
||||||
|
// After reports whether the position p is after u.
|
||||||
|
func (p Pos) After(u Pos) bool {
|
||||||
|
return u.Offset < p.Offset || u.Line < p.Line
|
||||||
|
}
|
118
vendor/github.com/hashicorp/hcl/json/token/token.go
generated
vendored
Normal file
118
vendor/github.com/hashicorp/hcl/json/token/token.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
package token
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
hcltoken "github.com/hashicorp/hcl/hcl/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token defines a single HCL token which can be obtained via the Scanner
|
||||||
|
type Token struct {
|
||||||
|
Type Type
|
||||||
|
Pos Pos
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language)
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Special tokens
|
||||||
|
ILLEGAL Type = iota
|
||||||
|
EOF
|
||||||
|
|
||||||
|
identifier_beg
|
||||||
|
literal_beg
|
||||||
|
NUMBER // 12345
|
||||||
|
FLOAT // 123.45
|
||||||
|
BOOL // true,false
|
||||||
|
STRING // "abc"
|
||||||
|
NULL // null
|
||||||
|
literal_end
|
||||||
|
identifier_end
|
||||||
|
|
||||||
|
operator_beg
|
||||||
|
LBRACK // [
|
||||||
|
LBRACE // {
|
||||||
|
COMMA // ,
|
||||||
|
PERIOD // .
|
||||||
|
COLON // :
|
||||||
|
|
||||||
|
RBRACK // ]
|
||||||
|
RBRACE // }
|
||||||
|
|
||||||
|
operator_end
|
||||||
|
)
|
||||||
|
|
||||||
|
var tokens = [...]string{
|
||||||
|
ILLEGAL: "ILLEGAL",
|
||||||
|
|
||||||
|
EOF: "EOF",
|
||||||
|
|
||||||
|
NUMBER: "NUMBER",
|
||||||
|
FLOAT: "FLOAT",
|
||||||
|
BOOL: "BOOL",
|
||||||
|
STRING: "STRING",
|
||||||
|
NULL: "NULL",
|
||||||
|
|
||||||
|
LBRACK: "LBRACK",
|
||||||
|
LBRACE: "LBRACE",
|
||||||
|
COMMA: "COMMA",
|
||||||
|
PERIOD: "PERIOD",
|
||||||
|
COLON: "COLON",
|
||||||
|
|
||||||
|
RBRACK: "RBRACK",
|
||||||
|
RBRACE: "RBRACE",
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string corresponding to the token tok.
|
||||||
|
func (t Type) String() string {
|
||||||
|
s := ""
|
||||||
|
if 0 <= t && t < Type(len(tokens)) {
|
||||||
|
s = tokens[t]
|
||||||
|
}
|
||||||
|
if s == "" {
|
||||||
|
s = "token(" + strconv.Itoa(int(t)) + ")"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsIdentifier returns true for tokens corresponding to identifiers and basic
|
||||||
|
// type literals; it returns false otherwise.
|
||||||
|
func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end }
|
||||||
|
|
||||||
|
// IsLiteral returns true for tokens corresponding to basic type literals; it
|
||||||
|
// returns false otherwise.
|
||||||
|
func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end }
|
||||||
|
|
||||||
|
// IsOperator returns true for tokens corresponding to operators and
|
||||||
|
// delimiters; it returns false otherwise.
|
||||||
|
func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end }
|
||||||
|
|
||||||
|
// String returns the token's literal text. Note that this is only
|
||||||
|
// applicable for certain token types, such as token.IDENT,
|
||||||
|
// token.STRING, etc..
|
||||||
|
func (t Token) String() string {
|
||||||
|
return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HCLToken converts this token to an HCL token.
|
||||||
|
//
|
||||||
|
// The token type must be a literal type or this will panic.
|
||||||
|
func (t Token) HCLToken() hcltoken.Token {
|
||||||
|
switch t.Type {
|
||||||
|
case BOOL:
|
||||||
|
return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text}
|
||||||
|
case FLOAT:
|
||||||
|
return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text}
|
||||||
|
case NULL:
|
||||||
|
return hcltoken.Token{Type: hcltoken.STRING, Text: ""}
|
||||||
|
case NUMBER:
|
||||||
|
return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text}
|
||||||
|
case STRING:
|
||||||
|
return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true}
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type))
|
||||||
|
}
|
||||||
|
}
|
38
vendor/github.com/hashicorp/hcl/lex.go
generated
vendored
Normal file
38
vendor/github.com/hashicorp/hcl/lex.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package hcl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lexModeValue byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
lexModeUnknown lexModeValue = iota
|
||||||
|
lexModeHcl
|
||||||
|
lexModeJson
|
||||||
|
)
|
||||||
|
|
||||||
|
// lexMode returns whether we're going to be parsing in JSON
|
||||||
|
// mode or HCL mode.
|
||||||
|
func lexMode(v []byte) lexModeValue {
|
||||||
|
var (
|
||||||
|
r rune
|
||||||
|
w int
|
||||||
|
offset int
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
r, w = utf8.DecodeRune(v[offset:])
|
||||||
|
offset += w
|
||||||
|
if unicode.IsSpace(r) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r == '{' {
|
||||||
|
return lexModeJson
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return lexModeHcl
|
||||||
|
}
|
39
vendor/github.com/hashicorp/hcl/parse.go
generated
vendored
Normal file
39
vendor/github.com/hashicorp/hcl/parse.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package hcl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
hclParser "github.com/hashicorp/hcl/hcl/parser"
|
||||||
|
jsonParser "github.com/hashicorp/hcl/json/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseBytes accepts as input byte slice and returns ast tree.
|
||||||
|
//
|
||||||
|
// Input can be either JSON or HCL
|
||||||
|
func ParseBytes(in []byte) (*ast.File, error) {
|
||||||
|
return parse(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseString accepts input as a string and returns ast tree.
|
||||||
|
func ParseString(input string) (*ast.File, error) {
|
||||||
|
return parse([]byte(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(in []byte) (*ast.File, error) {
|
||||||
|
switch lexMode(in) {
|
||||||
|
case lexModeHcl:
|
||||||
|
return hclParser.Parse(in)
|
||||||
|
case lexModeJson:
|
||||||
|
return jsonParser.Parse(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("unknown config format")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the given input and returns the root object.
|
||||||
|
//
|
||||||
|
// The input format can be either HCL or JSON.
|
||||||
|
func Parse(input string) (*ast.File, error) {
|
||||||
|
return parse([]byte(input))
|
||||||
|
}
|
363
vendor/github.com/hashicorp/vault/LICENSE
generated
vendored
Normal file
363
vendor/github.com/hashicorp/vault/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the terms of
|
||||||
|
a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a
|
||||||
|
separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether
|
||||||
|
at the time of the initial grant or subsequently, any and all of the
|
||||||
|
rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the License,
|
||||||
|
by the making, using, selling, offering for sale, having made, import,
|
||||||
|
or transfer of either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, "control" means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights to
|
||||||
|
grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter the
|
||||||
|
recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||||
|
limitations of liability) contained within the Source Code Form of the
|
||||||
|
Covered Software, except that You may alter any license notices to the
|
||||||
|
extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute,
|
||||||
|
judicial order, or regulation then You must: (a) comply with the terms of
|
||||||
|
this License to the maximum extent possible; and (b) describe the
|
||||||
|
limitations and the code they affect. Such description must be placed in a
|
||||||
|
text file included with all distributions of the Covered Software under
|
||||||
|
this License. Except to the extent prohibited by statute or regulation,
|
||||||
|
such description must be sufficiently detailed for a recipient of ordinary
|
||||||
|
skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||||
|
basis, if such Contributor fails to notify You of the non-compliance by
|
||||||
|
some reasonable means prior to 60 days after You have come back into
|
||||||
|
compliance. Moreover, Your grants from a particular Contributor are
|
||||||
|
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||||
|
non-compliance by some reasonable means, this is the first time You have
|
||||||
|
received notice of non-compliance with this License from such
|
||||||
|
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||||
|
of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an "as is" basis,
|
||||||
|
without warranty of any kind, either expressed, implied, or statutory,
|
||||||
|
including, without limitation, warranties that the Covered Software is free
|
||||||
|
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
The entire risk as to the quality and performance of the Covered Software
|
||||||
|
is with You. Should any Covered Software prove defective in any respect,
|
||||||
|
You (not any Contributor) assume the cost of any necessary servicing,
|
||||||
|
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this License. No use of any Covered Software is authorized under
|
||||||
|
this License except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from
|
||||||
|
such party's negligence to the extent applicable law prohibits such
|
||||||
|
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||||
|
incidental or consequential damages, so this exclusion and limitation may
|
||||||
|
not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts
|
||||||
|
of a jurisdiction where the defendant maintains its principal place of
|
||||||
|
business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||||
|
in this Section shall prevent a party's ability to bring cross-claims or
|
||||||
|
counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides that
|
||||||
|
the language of a contract shall be construed against the drafter shall not
|
||||||
|
be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses If You choose to distribute Source Code Form that is
|
||||||
|
Incompatible With Secondary Licenses under the terms of this version of
|
||||||
|
the License, the notice described in Exhibit B of this License must be
|
||||||
|
attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file,
|
||||||
|
then You may include the notice in a location (such as a LICENSE file in a
|
||||||
|
relevant directory) where a recipient would be likely to look for such a
|
||||||
|
notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible
|
||||||
|
With Secondary Licenses", as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
611
vendor/github.com/hashicorp/vault/api/SPEC.md
generated
vendored
Normal file
611
vendor/github.com/hashicorp/vault/api/SPEC.md
generated
vendored
Normal file
|
@ -0,0 +1,611 @@
|
||||||
|
FORMAT: 1A
|
||||||
|
|
||||||
|
# vault
|
||||||
|
|
||||||
|
The Vault API gives you full access to the Vault project.
|
||||||
|
|
||||||
|
If you're browsing this API specifiction in GitHub or in raw
|
||||||
|
format, please excuse some of the odd formatting. This document
|
||||||
|
is in api-blueprint format that is read by viewers such as
|
||||||
|
Apiary.
|
||||||
|
|
||||||
|
## Sealed vs. Unsealed
|
||||||
|
|
||||||
|
Whenever an individual Vault server is started, it is started
|
||||||
|
in the _sealed_ state. In this state, it knows where its data
|
||||||
|
is located, but the data is encrypted and Vault doesn't have the
|
||||||
|
encryption keys to access it. Before Vault can operate, it must
|
||||||
|
be _unsealed_.
|
||||||
|
|
||||||
|
**Note:** Sealing/unsealing has no relationship to _authentication_
|
||||||
|
which is separate and still required once the Vault is unsealed.
|
||||||
|
|
||||||
|
Instead of being sealed with a single key, we utilize
|
||||||
|
[Shamir's Secret Sharing](http://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing)
|
||||||
|
to shard a key into _n_ parts such that _t_ parts are required
|
||||||
|
to reconstruct the original key, where `t <= n`. This means that
|
||||||
|
Vault itself doesn't know the original key, and no single person
|
||||||
|
has the original key (unless `n = 1`, or `t` parts are given to
|
||||||
|
a single person).
|
||||||
|
|
||||||
|
Unsealing is done via an unauthenticated
|
||||||
|
[unseal API](#reference/seal/unseal/unseal). This API takes a single
|
||||||
|
master shard and progresses the unsealing process. Once all shards
|
||||||
|
are given, the Vault is either unsealed or resets the unsealing
|
||||||
|
process if the key was invalid.
|
||||||
|
|
||||||
|
The entire seal/unseal state is server-wide. This allows multiple
|
||||||
|
distinct operators to use the unseal API (or more likely the
|
||||||
|
`vault unseal` command) from separate computers/networks and never
|
||||||
|
have to transmit their key in order to unseal the vault in a
|
||||||
|
distributed fashion.
|
||||||
|
|
||||||
|
## Transport
|
||||||
|
|
||||||
|
The API is expected to be accessed over a TLS connection at
|
||||||
|
all times, with a valid certificate that is verified by a well
|
||||||
|
behaved client.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Once the Vault is unsealed, every other operation requires
|
||||||
|
authentication. There are multiple methods for authentication
|
||||||
|
that can be enabled (see
|
||||||
|
[authentication](#reference/authentication)).
|
||||||
|
|
||||||
|
Authentication is done with the login endpoint. The login endpoint
|
||||||
|
returns an access token that is set as the `X-Vault-Token` header.
|
||||||
|
|
||||||
|
## Help
|
||||||
|
|
||||||
|
To retrieve the help for any API within Vault, including mounted
|
||||||
|
backends, credential providers, etc. then append `?help=1` to any
|
||||||
|
URL. If you have valid permission to access the path, then the help text
|
||||||
|
will be returned with the following structure:
|
||||||
|
|
||||||
|
{
|
||||||
|
"help": "help text"
|
||||||
|
}
|
||||||
|
|
||||||
|
## Error Response
|
||||||
|
|
||||||
|
A common JSON structure is always returned to return errors:
|
||||||
|
|
||||||
|
{
|
||||||
|
"errors": [
|
||||||
|
"message",
|
||||||
|
"another message"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
This structure will be sent down for any non-20x HTTP status.
|
||||||
|
|
||||||
|
## HTTP Status Codes
|
||||||
|
|
||||||
|
The following HTTP status codes are used throughout the API.
|
||||||
|
|
||||||
|
- `200` - Success with data.
|
||||||
|
- `204` - Success, no data returned.
|
||||||
|
- `400` - Invalid request, missing or invalid data.
|
||||||
|
- `403` - Forbidden, your authentication details are either
|
||||||
|
incorrect or you don't have access to this feature.
|
||||||
|
- `404` - Invalid path. This can both mean that the path truly
|
||||||
|
doesn't exist or that you don't have permission to view a
|
||||||
|
specific path. We use 404 in some cases to avoid state leakage.
|
||||||
|
- `429` - Rate limit exceeded. Try again after waiting some period
|
||||||
|
of time.
|
||||||
|
- `500` - Internal server error. An internal error has occurred,
|
||||||
|
try again later. If the error persists, report a bug.
|
||||||
|
- `503` - Vault is down for maintenance or is currently sealed.
|
||||||
|
Try again later.
|
||||||
|
|
||||||
|
# Group Initialization
|
||||||
|
|
||||||
|
## Initialization [/sys/init]
|
||||||
|
### Initialization Status [GET]
|
||||||
|
Returns the status of whether the vault is initialized or not. The
|
||||||
|
vault doesn't have to be unsealed for this operation.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"initialized": true
|
||||||
|
}
|
||||||
|
|
||||||
|
### Initialize [POST]
|
||||||
|
Initialize the vault. This is an unauthenticated request to initially
|
||||||
|
setup a new vault. Although this is unauthenticated, it is still safe:
|
||||||
|
data cannot be in vault prior to initialization, and any future
|
||||||
|
authentication will fail if you didn't initialize it yourself.
|
||||||
|
Additionally, once initialized, a vault cannot be reinitialized.
|
||||||
|
|
||||||
|
This API is the only time Vault will ever be aware of your keys, and
|
||||||
|
the only time the keys will ever be returned in one unit. Care should
|
||||||
|
be taken to ensure that the output of this request is never logged,
|
||||||
|
and that the keys are properly distributed.
|
||||||
|
|
||||||
|
The response also contains the initial root token that can be used
|
||||||
|
as authentication in order to initially configure Vault once it is
|
||||||
|
unsealed. Just as with the unseal keys, this is the only time Vault is
|
||||||
|
ever aware of this token.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"secret_shares": 5,
|
||||||
|
"secret_threshold": 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"keys": ["one", "two", "three"],
|
||||||
|
"root_token": "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Group Seal/Unseal
|
||||||
|
|
||||||
|
## Seal Status [/sys/seal-status]
|
||||||
|
### Seal Status [GET]
|
||||||
|
Returns the status of whether the vault is currently
|
||||||
|
sealed or not, as well as the progress of unsealing.
|
||||||
|
|
||||||
|
The response has the following attributes:
|
||||||
|
|
||||||
|
- sealed (boolean) - If true, the vault is sealed. Otherwise,
|
||||||
|
it is unsealed.
|
||||||
|
- t (int) - The "t" value for the master key, or the number
|
||||||
|
of shards needed total to unseal the vault.
|
||||||
|
- n (int) - The "n" value for the master key, or the total
|
||||||
|
number of shards of the key distributed.
|
||||||
|
- progress (int) - The number of master key shards that have
|
||||||
|
been entered so far towards unsealing the vault.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"sealed": true,
|
||||||
|
"t": 3,
|
||||||
|
"n": 5,
|
||||||
|
"progress": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
## Seal [/sys/seal]
|
||||||
|
### Seal [PUT]
|
||||||
|
Seal the vault.
|
||||||
|
|
||||||
|
Sealing the vault locks Vault from any future operations on any
|
||||||
|
secrets or system configuration until the vault is once again
|
||||||
|
unsealed. Internally, sealing throws away the keys to access the
|
||||||
|
encrypted vault data, so Vault is unable to access the data without
|
||||||
|
unsealing to get the encryption keys.
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
## Unseal [/sys/unseal]
|
||||||
|
### Unseal [PUT]
|
||||||
|
Unseal the vault.
|
||||||
|
|
||||||
|
Unseal the vault by entering a portion of the master key. The
|
||||||
|
response object will tell you if the unseal is complete or
|
||||||
|
only partial.
|
||||||
|
|
||||||
|
If the vault is already unsealed, this does nothing. It is
|
||||||
|
not an error, the return value just says the vault is unsealed.
|
||||||
|
Due to the architecture of Vault, we cannot validate whether
|
||||||
|
any portion of the unseal key given is valid until all keys
|
||||||
|
are inputted, therefore unsealing an already unsealed vault
|
||||||
|
is still a success even if the input key is invalid.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"sealed": true,
|
||||||
|
"t": 3,
|
||||||
|
"n": 5,
|
||||||
|
"progress": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Group Authentication
|
||||||
|
|
||||||
|
## List Auth Methods [/sys/auth]
|
||||||
|
### List all auth methods [GET]
|
||||||
|
Lists all available authentication methods.
|
||||||
|
|
||||||
|
This returns the name of the authentication method as well as
|
||||||
|
a human-friendly long-form help text for the method that can be
|
||||||
|
shown to the user as documentation.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"token": {
|
||||||
|
"type": "token",
|
||||||
|
"description": "Token authentication"
|
||||||
|
},
|
||||||
|
"oauth": {
|
||||||
|
"type": "oauth",
|
||||||
|
"description": "OAuth authentication"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
## Single Auth Method [/sys/auth/{id}]
|
||||||
|
|
||||||
|
+ Parameters
|
||||||
|
+ id (required, string) ... The ID of the auth method.
|
||||||
|
|
||||||
|
### Enable an auth method [PUT]
|
||||||
|
Enables an authentication method.
|
||||||
|
|
||||||
|
The body of the request depends on the authentication method
|
||||||
|
being used. Please reference the documentation for the specific
|
||||||
|
authentication method you're enabling in order to determine what
|
||||||
|
parameters you must give it.
|
||||||
|
|
||||||
|
If an authentication method is already enabled, then this can be
|
||||||
|
used to change the configuration, including even the type of
|
||||||
|
the configuration.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "type",
|
||||||
|
"key": "value",
|
||||||
|
"key2": "value2"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
### Disable an auth method [DELETE]
|
||||||
|
Disables an authentication method. Previously authenticated sessions
|
||||||
|
are immediately invalidated.
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
# Group Policies
|
||||||
|
|
||||||
|
Policies are named permission sets that identities returned by
|
||||||
|
credential stores are bound to. This separates _authentication_
|
||||||
|
from _authorization_.
|
||||||
|
|
||||||
|
## Policies [/sys/policy]
|
||||||
|
### List all Policies [GET]
|
||||||
|
|
||||||
|
List all the policies.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"policies": ["root"]
|
||||||
|
}
|
||||||
|
|
||||||
|
## Single Policy [/sys/policy/{id}]
|
||||||
|
|
||||||
|
+ Parameters
|
||||||
|
+ id (required, string) ... The name of the policy
|
||||||
|
|
||||||
|
### Upsert [PUT]
|
||||||
|
|
||||||
|
Create or update a policy with the given ID.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"rules": "HCL"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
### Delete [DELETE]
|
||||||
|
|
||||||
|
Delete a policy with the given ID. Any identities bound to this
|
||||||
|
policy will immediately become "deny all" despite already being
|
||||||
|
authenticated.
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
# Group Mounts
|
||||||
|
|
||||||
|
Logical backends are mounted at _mount points_, similar to
|
||||||
|
filesystems. This allows you to mount the "aws" logical backend
|
||||||
|
at the "aws-us-east" path, so all access is at `/aws-us-east/keys/foo`
|
||||||
|
for example. This enables multiple logical backends to be enabled.
|
||||||
|
|
||||||
|
## Mounts [/sys/mounts]
|
||||||
|
### List all mounts [GET]
|
||||||
|
|
||||||
|
Lists all the active mount points.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"aws": {
|
||||||
|
"type": "aws",
|
||||||
|
"description": "AWS"
|
||||||
|
},
|
||||||
|
"pg": {
|
||||||
|
"type": "postgresql",
|
||||||
|
"description": "PostgreSQL dynamic users"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
## Single Mount [/sys/mounts/{path}]
|
||||||
|
### New Mount [POST]
|
||||||
|
|
||||||
|
Mount a logical backend to a new path.
|
||||||
|
|
||||||
|
Configuration for this new backend is done via the normal
|
||||||
|
read/write mechanism once it is mounted.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "aws",
|
||||||
|
"description": "EU AWS tokens"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
### Unmount [DELETE]
|
||||||
|
|
||||||
|
Unmount a mount point.
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
## Remount [/sys/remount]
|
||||||
|
### Remount [POST]
|
||||||
|
|
||||||
|
Move an already-mounted backend to a new path.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"from": "aws",
|
||||||
|
"to": "aws-east"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
# Group Audit Backends
|
||||||
|
|
||||||
|
Audit backends are responsible for shuttling the audit logs that
|
||||||
|
Vault generates to a durable system for future querying. By default,
|
||||||
|
audit logs are not stored anywhere.
|
||||||
|
|
||||||
|
## Audit Backends [/sys/audit]
|
||||||
|
### List Enabled Audit Backends [GET]
|
||||||
|
|
||||||
|
List all the enabled audit backends
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"file": {
|
||||||
|
"type": "file",
|
||||||
|
"description": "Send audit logs to a file",
|
||||||
|
"options": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
## Single Audit Backend [/sys/audit/{path}]
|
||||||
|
|
||||||
|
+ Parameters
|
||||||
|
+ path (required, string) ... The path where the audit backend is mounted
|
||||||
|
|
||||||
|
### Enable [PUT]
|
||||||
|
|
||||||
|
Enable an audit backend.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"description": "send to a file",
|
||||||
|
"options": {
|
||||||
|
"path": "/var/log/vault.audit.log"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
### Disable [DELETE]
|
||||||
|
|
||||||
|
Disable an audit backend.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
# Group Secrets
|
||||||
|
|
||||||
|
## Generic [/{mount}/{path}]
|
||||||
|
|
||||||
|
This group documents the general format of reading and writing
|
||||||
|
to Vault. The exact structure of the keyspace is defined by the
|
||||||
|
logical backends in use, so documentation related to
|
||||||
|
a specific backend should be referenced for details on what keys
|
||||||
|
and routes are expected.
|
||||||
|
|
||||||
|
The path for examples are `/prefix/path`, but in practice
|
||||||
|
these will be defined by the backends that are mounted. For
|
||||||
|
example, reading an AWS key might be at the `/aws/root` path.
|
||||||
|
These paths are defined by the logical backends.
|
||||||
|
|
||||||
|
+ Parameters
|
||||||
|
+ mount (required, string) ... The mount point for the
|
||||||
|
logical backend. Example: `aws`.
|
||||||
|
+ path (optional, string) ... The path within the backend
|
||||||
|
to read or write data.
|
||||||
|
|
||||||
|
### Read [GET]
|
||||||
|
|
||||||
|
Read data from vault.
|
||||||
|
|
||||||
|
The data read from the vault can either be a secret or
|
||||||
|
arbitrary configuration data. The type of data returned
|
||||||
|
depends on the path, and is defined by the logical backend.
|
||||||
|
|
||||||
|
If the return value is a secret, then the return structure
|
||||||
|
is a mixture of arbitrary key/value along with the following
|
||||||
|
fields which are guaranteed to exist:
|
||||||
|
|
||||||
|
- `lease_id` (string) - A unique ID used for renewal and
|
||||||
|
revocation.
|
||||||
|
|
||||||
|
- `renewable` (bool) - If true, then this key can be renewed.
|
||||||
|
If a key can't be renewed, then a new key must be requested
|
||||||
|
after the lease duration period.
|
||||||
|
|
||||||
|
- `lease_duration` (int) - The time in seconds that a secret is
|
||||||
|
valid for before it must be renewed.
|
||||||
|
|
||||||
|
- `lease_duration_max` (int) - The maximum amount of time in
|
||||||
|
seconds that a secret is valid for. This will always be
|
||||||
|
greater than or equal to `lease_duration`. The difference
|
||||||
|
between this and `lease_duration` is an overlap window
|
||||||
|
where multiple keys may be valid.
|
||||||
|
|
||||||
|
If the return value is not a secret, then the return structure
|
||||||
|
is an arbitrary JSON object.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"lease_id": "UUID",
|
||||||
|
"lease_duration": 3600,
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
|
||||||
|
### Write [PUT]
|
||||||
|
|
||||||
|
Write data to vault.
|
||||||
|
|
||||||
|
The behavior and arguments to the write are defined by
|
||||||
|
the logical backend.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
# Group Lease Management
|
||||||
|
|
||||||
|
## Renew Key [/sys/renew/{id}]
|
||||||
|
|
||||||
|
+ Parameters
|
||||||
|
+ id (required, string) ... The `lease_id` of the secret
|
||||||
|
to renew.
|
||||||
|
|
||||||
|
### Renew [PUT]
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"lease_id": "...",
|
||||||
|
"lease_duration": 3600,
|
||||||
|
"access_key": "foo",
|
||||||
|
"secret_key": "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
## Revoke Key [/sys/revoke/{id}]
|
||||||
|
|
||||||
|
+ Parameters
|
||||||
|
+ id (required, string) ... The `lease_id` of the secret
|
||||||
|
to revoke.
|
||||||
|
|
||||||
|
### Revoke [PUT]
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
# Group Backend: AWS
|
||||||
|
|
||||||
|
## Root Key [/aws/root]
|
||||||
|
### Set the Key [PUT]
|
||||||
|
|
||||||
|
Set the root key that the logical backend will use to create
|
||||||
|
new secrets, IAM policies, etc.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"access_key": "key",
|
||||||
|
"secret_key": "key",
|
||||||
|
"region": "us-east-1"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
## Policies [/aws/policies]
|
||||||
|
### List Policies [GET]
|
||||||
|
|
||||||
|
List all the policies that can be used to create keys.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
[{
|
||||||
|
"name": "root",
|
||||||
|
"description": "Root access"
|
||||||
|
}, {
|
||||||
|
"name": "web-deploy",
|
||||||
|
"description": "Enough permissions to deploy the web app."
|
||||||
|
}]
|
||||||
|
|
||||||
|
## Single Policy [/aws/policies/{name}]
|
||||||
|
|
||||||
|
+ Parameters
|
||||||
|
+ name (required, string) ... Name of the policy.
|
||||||
|
|
||||||
|
### Read [GET]
|
||||||
|
|
||||||
|
Read a policy.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"policy": "base64-encoded policy"
|
||||||
|
}
|
||||||
|
|
||||||
|
### Upsert [PUT]
|
||||||
|
|
||||||
|
Create or update a policy.
|
||||||
|
|
||||||
|
+ Request (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"policy": "base64-encoded policy"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
### Delete [DELETE]
|
||||||
|
|
||||||
|
Delete the policy with the given name.
|
||||||
|
|
||||||
|
+ Response 204
|
||||||
|
|
||||||
|
## Generate Access Keys [/aws/keys/{policy}]
|
||||||
|
### Create [GET]
|
||||||
|
|
||||||
|
This generates a new keypair for the given policy.
|
||||||
|
|
||||||
|
+ Parameters
|
||||||
|
+ policy (required, string) ... The policy under which to create
|
||||||
|
the key pair.
|
||||||
|
|
||||||
|
+ Response 200 (application/json)
|
||||||
|
|
||||||
|
{
|
||||||
|
"lease_id": "...",
|
||||||
|
"lease_duration": 3600,
|
||||||
|
"access_key": "foo",
|
||||||
|
"secret_key": "bar"
|
||||||
|
}
|
11
vendor/github.com/hashicorp/vault/api/auth.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/vault/api/auth.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
// Auth is used to perform credential backend related operations.
|
||||||
|
type Auth struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth is used to return the client for credential-backend API calls.
|
||||||
|
func (c *Client) Auth() *Auth {
|
||||||
|
return &Auth{c: c}
|
||||||
|
}
|
176
vendor/github.com/hashicorp/vault/api/auth_token.go
generated
vendored
Normal file
176
vendor/github.com/hashicorp/vault/api/auth_token.go
generated
vendored
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
// TokenAuth is used to perform token backend operations on Vault
|
||||||
|
type TokenAuth struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token is used to return the client for token-backend API calls
|
||||||
|
func (a *Auth) Token() *TokenAuth {
|
||||||
|
return &TokenAuth{c: a.c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TokenAuth) Create(opts *TokenCreateRequest) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("POST", "/v1/auth/token/create")
|
||||||
|
if err := r.SetJSONBody(opts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TokenAuth) CreateWithRole(opts *TokenCreateRequest, roleName string) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("POST", "/v1/auth/token/create/"+roleName)
|
||||||
|
if err := r.SetJSONBody(opts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TokenAuth) Lookup(token string) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/auth/token/lookup/"+token)
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TokenAuth) LookupAccessor(accessor string) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("POST", "/v1/auth/token/lookup-accessor/"+accessor)
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TokenAuth) LookupSelf() (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/auth/token/lookup-self")
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TokenAuth) Renew(token string, increment int) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/auth/token/renew/"+token)
|
||||||
|
|
||||||
|
body := map[string]interface{}{"increment": increment}
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TokenAuth) RenewSelf(increment int) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/auth/token/renew-self")
|
||||||
|
|
||||||
|
body := map[string]interface{}{"increment": increment}
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeAccessor revokes a token associated with the given accessor
|
||||||
|
// along with all the child tokens.
|
||||||
|
func (c *TokenAuth) RevokeAccessor(accessor string) error {
|
||||||
|
r := c.c.NewRequest("POST", "/v1/auth/token/revoke-accessor/"+accessor)
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeOrphan revokes a token without revoking the tree underneath it (so
|
||||||
|
// child tokens are orphaned rather than revoked)
|
||||||
|
func (c *TokenAuth) RevokeOrphan(token string) error {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/auth/token/revoke-orphan/"+token)
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeSelf revokes the token making the call
|
||||||
|
func (c *TokenAuth) RevokeSelf(token string) error {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/auth/token/revoke-self")
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeTree is the "normal" revoke operation that revokes the given token and
|
||||||
|
// the entire tree underneath -- all of its child tokens, their child tokens,
|
||||||
|
// etc.
|
||||||
|
func (c *TokenAuth) RevokeTree(token string) error {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/auth/token/revoke/"+token)
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenCreateRequest is the options structure for creating a token.
|
||||||
|
type TokenCreateRequest struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Policies []string `json:"policies,omitempty"`
|
||||||
|
Metadata map[string]string `json:"meta,omitempty"`
|
||||||
|
Lease string `json:"lease,omitempty"`
|
||||||
|
TTL string `json:"ttl,omitempty"`
|
||||||
|
NoParent bool `json:"no_parent,omitempty"`
|
||||||
|
NoDefaultPolicy bool `json:"no_default_policy,omitempty"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
NumUses int `json:"num_uses"`
|
||||||
|
}
|
333
vendor/github.com/hashicorp/vault/api/client.go
generated
vendored
Normal file
333
vendor/github.com/hashicorp/vault/api/client.go
generated
vendored
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
|
"github.com/hashicorp/go-rootcerts"
|
||||||
|
)
|
||||||
|
|
||||||
|
const EnvVaultAddress = "VAULT_ADDR"
|
||||||
|
const EnvVaultCACert = "VAULT_CACERT"
|
||||||
|
const EnvVaultCAPath = "VAULT_CAPATH"
|
||||||
|
const EnvVaultClientCert = "VAULT_CLIENT_CERT"
|
||||||
|
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
|
||||||
|
const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
|
||||||
|
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
|
||||||
|
const EnvVaultWrapTTL = "VAULT_WRAP_TTL"
|
||||||
|
|
||||||
|
var (
|
||||||
|
errRedirect = errors.New("redirect")
|
||||||
|
)
|
||||||
|
|
||||||
|
// WrappingLookupFunc is a function that, given an HTTP verb and a path,
|
||||||
|
// returns an optional string duration to be used for response wrapping (e.g.
|
||||||
|
// "15s", or simply "15"). The path will not begin with "/v1/" or "v1/" or "/",
|
||||||
|
// however, end-of-path forward slashes are not trimmed, so must match your
|
||||||
|
// called path precisely.
|
||||||
|
type WrappingLookupFunc func(operation, path string) string
|
||||||
|
|
||||||
|
// Config is used to configure the creation of the client.
|
||||||
|
type Config struct {
|
||||||
|
// Address is the address of the Vault server. This should be a complete
|
||||||
|
// URL such as "http://vault.example.com". If you need a custom SSL
|
||||||
|
// cert or want to enable insecure mode, you need to specify a custom
|
||||||
|
// HttpClient.
|
||||||
|
Address string
|
||||||
|
|
||||||
|
// HttpClient is the HTTP client to use, which will currently always have the
|
||||||
|
// same values as http.DefaultClient. This is used to control redirect behavior.
|
||||||
|
HttpClient *http.Client
|
||||||
|
|
||||||
|
redirectSetup sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultConfig returns a default configuration for the client. It is
|
||||||
|
// safe to modify the return value of this function.
|
||||||
|
//
|
||||||
|
// The default Address is https://127.0.0.1:8200, but this can be overridden by
|
||||||
|
// setting the `VAULT_ADDR` environment variable.
|
||||||
|
func DefaultConfig() *Config {
|
||||||
|
config := &Config{
|
||||||
|
Address: "https://127.0.0.1:8200",
|
||||||
|
|
||||||
|
HttpClient: cleanhttp.DefaultClient(),
|
||||||
|
}
|
||||||
|
config.HttpClient.Timeout = time.Second * 60
|
||||||
|
transport := config.HttpClient.Transport.(*http.Transport)
|
||||||
|
transport.TLSHandshakeTimeout = 10 * time.Second
|
||||||
|
transport.TLSClientConfig = &tls.Config{
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := os.Getenv(EnvVaultAddress); v != "" {
|
||||||
|
config.Address = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadEnvironment reads configuration information from the
|
||||||
|
// environment. If there is an error, no configuration value
|
||||||
|
// is updated.
|
||||||
|
func (c *Config) ReadEnvironment() error {
|
||||||
|
var envAddress string
|
||||||
|
var envCACert string
|
||||||
|
var envCAPath string
|
||||||
|
var envClientCert string
|
||||||
|
var envClientKey string
|
||||||
|
var envInsecure bool
|
||||||
|
var foundInsecure bool
|
||||||
|
var envTLSServerName string
|
||||||
|
|
||||||
|
var clientCert tls.Certificate
|
||||||
|
var foundClientCert bool
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if v := os.Getenv(EnvVaultAddress); v != "" {
|
||||||
|
envAddress = v
|
||||||
|
}
|
||||||
|
if v := os.Getenv(EnvVaultCACert); v != "" {
|
||||||
|
envCACert = v
|
||||||
|
}
|
||||||
|
if v := os.Getenv(EnvVaultCAPath); v != "" {
|
||||||
|
envCAPath = v
|
||||||
|
}
|
||||||
|
if v := os.Getenv(EnvVaultClientCert); v != "" {
|
||||||
|
envClientCert = v
|
||||||
|
}
|
||||||
|
if v := os.Getenv(EnvVaultClientKey); v != "" {
|
||||||
|
envClientKey = v
|
||||||
|
}
|
||||||
|
if v := os.Getenv(EnvVaultInsecure); v != "" {
|
||||||
|
var err error
|
||||||
|
envInsecure, err = strconv.ParseBool(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Could not parse VAULT_SKIP_VERIFY")
|
||||||
|
}
|
||||||
|
foundInsecure = true
|
||||||
|
}
|
||||||
|
if v := os.Getenv(EnvVaultTLSServerName); v != "" {
|
||||||
|
envTLSServerName = v
|
||||||
|
}
|
||||||
|
// If we need custom TLS configuration, then set it
|
||||||
|
if envCACert != "" || envCAPath != "" || envClientCert != "" || envClientKey != "" || envInsecure {
|
||||||
|
if envClientCert != "" && envClientKey != "" {
|
||||||
|
clientCert, err = tls.LoadX509KeyPair(envClientCert, envClientKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
foundClientCert = true
|
||||||
|
} else if envClientCert != "" || envClientKey != "" {
|
||||||
|
return fmt.Errorf("Both client cert and client key must be provided")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if envAddress != "" {
|
||||||
|
c.Address = envAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
|
||||||
|
if foundInsecure {
|
||||||
|
clientTLSConfig.InsecureSkipVerify = envInsecure
|
||||||
|
}
|
||||||
|
|
||||||
|
if foundClientCert {
|
||||||
|
clientTLSConfig.Certificates = []tls.Certificate{clientCert}
|
||||||
|
}
|
||||||
|
if envTLSServerName != "" {
|
||||||
|
clientTLSConfig.ServerName = envTLSServerName
|
||||||
|
}
|
||||||
|
|
||||||
|
rootConfig := &rootcerts.Config{
|
||||||
|
CAFile: envCACert,
|
||||||
|
CAPath: envCAPath,
|
||||||
|
}
|
||||||
|
err = rootcerts.ConfigureTLS(clientTLSConfig, rootConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client is the client to the Vault API. Create a client with
|
||||||
|
// NewClient.
|
||||||
|
type Client struct {
|
||||||
|
addr *url.URL
|
||||||
|
config *Config
|
||||||
|
token string
|
||||||
|
wrappingLookupFunc WrappingLookupFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a new client for the given configuration.
|
||||||
|
//
|
||||||
|
// If the environment variable `VAULT_TOKEN` is present, the token will be
|
||||||
|
// automatically added to the client. Otherwise, you must manually call
|
||||||
|
// `SetToken()`.
|
||||||
|
func NewClient(c *Config) (*Client, error) {
|
||||||
|
u, err := url.Parse(c.Address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.HttpClient == nil {
|
||||||
|
c.HttpClient = DefaultConfig().HttpClient
|
||||||
|
}
|
||||||
|
|
||||||
|
redirFunc := func() {
|
||||||
|
// Ensure redirects are not automatically followed
|
||||||
|
// Note that this is sane for the API client as it has its own
|
||||||
|
// redirect handling logic (and thus also for command/meta),
|
||||||
|
// but in e.g. http_test actual redirect handling is necessary
|
||||||
|
c.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||||
|
return errRedirect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.redirectSetup.Do(redirFunc)
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
addr: u,
|
||||||
|
config: c,
|
||||||
|
}
|
||||||
|
|
||||||
|
if token := os.Getenv("VAULT_TOKEN"); token != "" {
|
||||||
|
client.SetToken(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
|
||||||
|
// for a given operation and path
|
||||||
|
func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) {
|
||||||
|
c.wrappingLookupFunc = lookupFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token returns the access token being used by this client. It will
|
||||||
|
// return the empty string if there is no token set.
|
||||||
|
func (c *Client) Token() string {
|
||||||
|
return c.token
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetToken sets the token directly. This won't perform any auth
|
||||||
|
// verification, it simply sets the token properly for future requests.
|
||||||
|
func (c *Client) SetToken(v string) {
|
||||||
|
c.token = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearToken deletes the token if it is set or does nothing otherwise.
|
||||||
|
func (c *Client) ClearToken() {
|
||||||
|
c.token = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRequest creates a new raw request object to query the Vault server
|
||||||
|
// configured for this client. This is an advanced method and generally
|
||||||
|
// doesn't need to be called externally.
|
||||||
|
func (c *Client) NewRequest(method, path string) *Request {
|
||||||
|
req := &Request{
|
||||||
|
Method: method,
|
||||||
|
URL: &url.URL{
|
||||||
|
Scheme: c.addr.Scheme,
|
||||||
|
Host: c.addr.Host,
|
||||||
|
Path: path,
|
||||||
|
},
|
||||||
|
ClientToken: c.token,
|
||||||
|
Params: make(map[string][]string),
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.wrappingLookupFunc != nil {
|
||||||
|
var lookupPath string
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(path, "/v1/"):
|
||||||
|
lookupPath = strings.TrimPrefix(path, "/v1/")
|
||||||
|
case strings.HasPrefix(path, "v1/"):
|
||||||
|
lookupPath = strings.TrimPrefix(path, "v1/")
|
||||||
|
default:
|
||||||
|
lookupPath = path
|
||||||
|
}
|
||||||
|
req.WrapTTL = c.wrappingLookupFunc(method, lookupPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawRequest performs the raw request given. This request may be against
|
||||||
|
// a Vault server not configured with this client. This is an advanced operation
|
||||||
|
// that generally won't need to be called externally.
|
||||||
|
func (c *Client) RawRequest(r *Request) (*Response, error) {
|
||||||
|
redirectCount := 0
|
||||||
|
START:
|
||||||
|
req, err := r.ToHTTP()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result *Response
|
||||||
|
resp, err := c.config.HttpClient.Do(req)
|
||||||
|
if resp != nil {
|
||||||
|
result = &Response{Response: resp}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if urlErr, ok := err.(*url.Error); ok && urlErr.Err == errRedirect {
|
||||||
|
err = nil
|
||||||
|
} else if strings.Contains(err.Error(), "tls: oversized") {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"%s\n\n"+
|
||||||
|
"This error usually means that the server is running with TLS disabled\n"+
|
||||||
|
"but the client is configured to use TLS. Please either enable TLS\n"+
|
||||||
|
"on the server or run the client with -address set to an address\n"+
|
||||||
|
"that uses the http protocol:\n\n"+
|
||||||
|
" vault <command> -address http://<address>\n\n"+
|
||||||
|
"You can also set the VAULT_ADDR environment variable:\n\n\n"+
|
||||||
|
" VAULT_ADDR=http://<address> vault <command>\n\n"+
|
||||||
|
"where <address> is replaced by the actual address to the server.",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a redirect, only allowing for a single redirect
|
||||||
|
if (resp.StatusCode == 301 || resp.StatusCode == 302 || resp.StatusCode == 307) && redirectCount == 0 {
|
||||||
|
// Parse the updated location
|
||||||
|
respLoc, err := resp.Location()
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a protocol downgrade doesn't happen
|
||||||
|
if req.URL.Scheme == "https" && respLoc.Scheme != "https" {
|
||||||
|
return result, fmt.Errorf("redirect would cause protocol downgrade")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the request
|
||||||
|
r.URL = respLoc
|
||||||
|
|
||||||
|
// Reset the request body if any
|
||||||
|
if err := r.ResetJSONBody(); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry the request
|
||||||
|
redirectCount++
|
||||||
|
goto START
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := result.Error(); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
25
vendor/github.com/hashicorp/vault/api/help.go
generated
vendored
Normal file
25
vendor/github.com/hashicorp/vault/api/help.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Help reads the help information for the given path.
|
||||||
|
func (c *Client) Help(path string) (*Help, error) {
|
||||||
|
r := c.NewRequest("GET", fmt.Sprintf("/v1/%s", path))
|
||||||
|
r.Params.Add("help", "1")
|
||||||
|
resp, err := c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result Help
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Help struct {
|
||||||
|
Help string `json:"help"`
|
||||||
|
SeeAlso []string `json:"see_also"`
|
||||||
|
}
|
82
vendor/github.com/hashicorp/vault/api/logical.go
generated
vendored
Normal file
82
vendor/github.com/hashicorp/vault/api/logical.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
// Logical is used to perform logical backend operations on Vault.
|
||||||
|
type Logical struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logical is used to return the client for logical-backend API calls.
|
||||||
|
func (c *Client) Logical() *Logical {
|
||||||
|
return &Logical{c: c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Logical) Read(path string) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/"+path)
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if resp != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
if resp != nil && resp.StatusCode == 404 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Logical) List(path string) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/"+path)
|
||||||
|
r.Params.Set("list", "true")
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if resp != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
if resp != nil && resp.StatusCode == 404 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/"+path)
|
||||||
|
if err := r.SetJSONBody(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if resp != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == 200 {
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Logical) Delete(path string) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("DELETE", "/v1/"+path)
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if resp != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == 200 {
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
71
vendor/github.com/hashicorp/vault/api/request.go
generated
vendored
Normal file
71
vendor/github.com/hashicorp/vault/api/request.go
generated
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Request is a raw request configuration structure used to initiate
|
||||||
|
// API requests to the Vault server.
|
||||||
|
type Request struct {
|
||||||
|
Method string
|
||||||
|
URL *url.URL
|
||||||
|
Params url.Values
|
||||||
|
ClientToken string
|
||||||
|
WrapTTL string
|
||||||
|
Obj interface{}
|
||||||
|
Body io.Reader
|
||||||
|
BodySize int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetJSONBody is used to set a request body that is a JSON-encoded value.
|
||||||
|
func (r *Request) SetJSONBody(val interface{}) error {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := json.NewEncoder(buf)
|
||||||
|
if err := enc.Encode(val); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Obj = val
|
||||||
|
r.Body = buf
|
||||||
|
r.BodySize = int64(buf.Len())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetJSONBody is used to reset the body for a redirect
|
||||||
|
func (r *Request) ResetJSONBody() error {
|
||||||
|
if r.Body == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return r.SetJSONBody(r.Obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToHTTP turns this request into a valid *http.Request for use with the
|
||||||
|
// net/http package.
|
||||||
|
func (r *Request) ToHTTP() (*http.Request, error) {
|
||||||
|
// Encode the query parameters
|
||||||
|
r.URL.RawQuery = r.Params.Encode()
|
||||||
|
|
||||||
|
// Create the HTTP request
|
||||||
|
req, err := http.NewRequest(r.Method, r.URL.RequestURI(), r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.URL.Scheme = r.URL.Scheme
|
||||||
|
req.URL.Host = r.URL.Host
|
||||||
|
req.Host = r.URL.Host
|
||||||
|
|
||||||
|
if len(r.ClientToken) != 0 {
|
||||||
|
req.Header.Set("X-Vault-Token", r.ClientToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.WrapTTL) != 0 {
|
||||||
|
req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
75
vendor/github.com/hashicorp/vault/api/response.go
generated
vendored
Normal file
75
vendor/github.com/hashicorp/vault/api/response.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Response is a raw response that wraps an HTTP response.
|
||||||
|
type Response struct {
|
||||||
|
*http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeJSON will decode the response body to a JSON structure. This
|
||||||
|
// will consume the response body, but will not close it. Close must
|
||||||
|
// still be called.
|
||||||
|
func (r *Response) DecodeJSON(out interface{}) error {
|
||||||
|
dec := json.NewDecoder(r.Body)
|
||||||
|
dec.UseNumber()
|
||||||
|
return dec.Decode(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns an error response if there is one. If there is an error,
|
||||||
|
// this will fully consume the response body, but will not close it. The
|
||||||
|
// body must still be closed manually.
|
||||||
|
func (r *Response) Error() error {
|
||||||
|
// 200 to 399 are okay status codes
|
||||||
|
if r.StatusCode >= 200 && r.StatusCode < 400 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have an error. Let's copy the body into our own buffer first,
|
||||||
|
// so that if we can't decode JSON, we can at least copy it raw.
|
||||||
|
var bodyBuf bytes.Buffer
|
||||||
|
if _, err := io.Copy(&bodyBuf, r.Body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the error response if we can. Note that we wrap the bodyBuf
|
||||||
|
// in a bytes.Reader here so that the JSON decoder doesn't move the
|
||||||
|
// read pointer for the original buffer.
|
||||||
|
var resp ErrorResponse
|
||||||
|
dec := json.NewDecoder(bytes.NewReader(bodyBuf.Bytes()))
|
||||||
|
dec.UseNumber()
|
||||||
|
if err := dec.Decode(&resp); err != nil {
|
||||||
|
// Ignore the decoding error and just drop the raw response
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error making API request.\n\n"+
|
||||||
|
"URL: %s %s\n"+
|
||||||
|
"Code: %d. Raw Message:\n\n%s",
|
||||||
|
r.Request.Method, r.Request.URL.String(),
|
||||||
|
r.StatusCode, bodyBuf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var errBody bytes.Buffer
|
||||||
|
errBody.WriteString(fmt.Sprintf(
|
||||||
|
"Error making API request.\n\n"+
|
||||||
|
"URL: %s %s\n"+
|
||||||
|
"Code: %d. Errors:\n\n",
|
||||||
|
r.Request.Method, r.Request.URL.String(),
|
||||||
|
r.StatusCode))
|
||||||
|
for _, err := range resp.Errors {
|
||||||
|
errBody.WriteString(fmt.Sprintf("* %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf(errBody.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorResponse is the raw structure of errors when they're returned by the
|
||||||
|
// HTTP API.
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Errors []string
|
||||||
|
}
|
61
vendor/github.com/hashicorp/vault/api/secret.go
generated
vendored
Normal file
61
vendor/github.com/hashicorp/vault/api/secret.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Secret is the structure returned for every secret within Vault.
|
||||||
|
type Secret struct {
|
||||||
|
LeaseID string `json:"lease_id"`
|
||||||
|
LeaseDuration int `json:"lease_duration"`
|
||||||
|
Renewable bool `json:"renewable"`
|
||||||
|
|
||||||
|
// Data is the actual contents of the secret. The format of the data
|
||||||
|
// is arbitrary and up to the secret backend.
|
||||||
|
Data map[string]interface{} `json:"data"`
|
||||||
|
|
||||||
|
// Warnings contains any warnings related to the operation. These
|
||||||
|
// are not issues that caused the command to fail, but that the
|
||||||
|
// client should be aware of.
|
||||||
|
Warnings []string `json:"warnings"`
|
||||||
|
|
||||||
|
// Auth, if non-nil, means that there was authentication information
|
||||||
|
// attached to this response.
|
||||||
|
Auth *SecretAuth `json:"auth,omitempty"`
|
||||||
|
|
||||||
|
// WrapInfo, if non-nil, means that the initial response was wrapped in the
|
||||||
|
// cubbyhole of the given token (which has a TTL of the given number of
|
||||||
|
// seconds)
|
||||||
|
WrapInfo *SecretWrapInfo `json:"wrap_info,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretWrapInfo contains wrapping information if we have it.
|
||||||
|
type SecretWrapInfo struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
TTL int `json:"ttl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretAuth is the structure containing auth information if we have it.
|
||||||
|
type SecretAuth struct {
|
||||||
|
ClientToken string `json:"client_token"`
|
||||||
|
Accessor string `json:"accessor"`
|
||||||
|
Policies []string `json:"policies"`
|
||||||
|
Metadata map[string]string `json:"metadata"`
|
||||||
|
|
||||||
|
LeaseDuration int `json:"lease_duration"`
|
||||||
|
Renewable bool `json:"renewable"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseSecret is used to parse a secret value from JSON from an io.Reader.
|
||||||
|
func ParseSecret(r io.Reader) (*Secret, error) {
|
||||||
|
// First decode the JSON into a map[string]interface{}
|
||||||
|
var secret Secret
|
||||||
|
dec := json.NewDecoder(r)
|
||||||
|
dec.UseNumber()
|
||||||
|
if err := dec.Decode(&secret); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &secret, nil
|
||||||
|
}
|
38
vendor/github.com/hashicorp/vault/api/ssh.go
generated
vendored
Normal file
38
vendor/github.com/hashicorp/vault/api/ssh.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// SSH is used to return a client to invoke operations on SSH backend.
|
||||||
|
type SSH struct {
|
||||||
|
c *Client
|
||||||
|
MountPoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSH returns the client for logical-backend API calls.
|
||||||
|
func (c *Client) SSH() *SSH {
|
||||||
|
return c.SSHWithMountPoint(SSHHelperDefaultMountPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSHWithMountPoint returns the client with specific SSH mount point.
|
||||||
|
func (c *Client) SSHWithMountPoint(mountPoint string) *SSH {
|
||||||
|
return &SSH{
|
||||||
|
c: c,
|
||||||
|
MountPoint: mountPoint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credential invokes the SSH backend API to create a credential to establish an SSH session.
|
||||||
|
func (c *SSH) Credential(role string, data map[string]interface{}) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/%s/creds/%s", c.MountPoint, role))
|
||||||
|
if err := r.SetJSONBody(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
239
vendor/github.com/hashicorp/vault/api/ssh_agent.go
generated
vendored
Normal file
239
vendor/github.com/hashicorp/vault/api/ssh_agent.go
generated
vendored
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/hashicorp/go-rootcerts"
|
||||||
|
"github.com/hashicorp/hcl"
|
||||||
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SSHHelperDefaultMountPoint is the default path at which SSH backend will be
|
||||||
|
// mounted in the Vault server.
|
||||||
|
SSHHelperDefaultMountPoint = "ssh"
|
||||||
|
|
||||||
|
// VerifyEchoRequest is the echo request message sent as OTP by the helper.
|
||||||
|
VerifyEchoRequest = "verify-echo-request"
|
||||||
|
|
||||||
|
// VerifyEchoResponse is the echo response message sent as a response to OTP
|
||||||
|
// matching echo request.
|
||||||
|
VerifyEchoResponse = "verify-echo-response"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SSHHelper is a structure representing a vault-ssh-helper which can talk to vault server
|
||||||
|
// in order to verify the OTP entered by the user. It contains the path at which
|
||||||
|
// SSH backend is mounted at the server.
|
||||||
|
type SSHHelper struct {
|
||||||
|
c *Client
|
||||||
|
MountPoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSHVerifyResponse is a structure representing the fields in Vault server's
|
||||||
|
// response.
|
||||||
|
type SSHVerifyResponse struct {
|
||||||
|
// Usually empty. If the request OTP is echo request message, this will
|
||||||
|
// be set to the corresponding echo response message.
|
||||||
|
Message string `mapstructure:"message"`
|
||||||
|
|
||||||
|
// Username associated with the OTP
|
||||||
|
Username string `mapstructure:"username"`
|
||||||
|
|
||||||
|
// IP associated with the OTP
|
||||||
|
IP string `mapstructure:"ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSHHelperConfig is a structure which represents the entries from the vault-ssh-helper's configuration file.
|
||||||
|
type SSHHelperConfig struct {
|
||||||
|
VaultAddr string `hcl:"vault_addr"`
|
||||||
|
SSHMountPoint string `hcl:"ssh_mount_point"`
|
||||||
|
CACert string `hcl:"ca_cert"`
|
||||||
|
CAPath string `hcl:"ca_path"`
|
||||||
|
AllowedCidrList string `hcl:"allowed_cidr_list"`
|
||||||
|
TLSSkipVerify bool `hcl:"tls_skip_verify"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTLSParameters sets the TLS parameters for this SSH agent.
|
||||||
|
func (c *SSHHelperConfig) SetTLSParameters(clientConfig *Config, certPool *x509.CertPool) {
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
InsecureSkipVerify: c.TLSSkipVerify,
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
RootCAs: certPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
transport := cleanhttp.DefaultTransport()
|
||||||
|
transport.TLSClientConfig = tlsConfig
|
||||||
|
clientConfig.HttpClient.Transport = transport
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a new client for the configuration. This client will be used by the
|
||||||
|
// vault-ssh-helper to communicate with Vault server and verify the OTP entered by user.
|
||||||
|
// If the configuration supplies Vault SSL certificates, then the client will
|
||||||
|
// have TLS configured in its transport.
|
||||||
|
func (c *SSHHelperConfig) NewClient() (*Client, error) {
|
||||||
|
// Creating a default client configuration for communicating with vault server.
|
||||||
|
clientConfig := DefaultConfig()
|
||||||
|
|
||||||
|
// Pointing the client to the actual address of vault server.
|
||||||
|
clientConfig.Address = c.VaultAddr
|
||||||
|
|
||||||
|
// Check if certificates are provided via config file.
|
||||||
|
if c.CACert != "" || c.CAPath != "" || c.TLSSkipVerify {
|
||||||
|
rootConfig := &rootcerts.Config{
|
||||||
|
CAFile: c.CACert,
|
||||||
|
CAPath: c.CAPath,
|
||||||
|
}
|
||||||
|
certPool, err := rootcerts.LoadCACerts(rootConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Enable TLS on the HTTP client information
|
||||||
|
c.SetTLSParameters(clientConfig, certPool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating the client object for the given configuration
|
||||||
|
client, err := NewClient(clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadSSHHelperConfig loads ssh-helper's configuration from the file and populates the corresponding
|
||||||
|
// in-memory structure.
|
||||||
|
//
|
||||||
|
// Vault address is a required parameter.
|
||||||
|
// Mount point defaults to "ssh".
|
||||||
|
func LoadSSHHelperConfig(path string) (*SSHHelperConfig, error) {
|
||||||
|
contents, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return nil, multierror.Prefix(err, "ssh_helper:")
|
||||||
|
}
|
||||||
|
return ParseSSHHelperConfig(string(contents))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseSSHHelperConfig parses the given contents as a string for the SSHHelper
|
||||||
|
// configuration.
|
||||||
|
func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) {
|
||||||
|
root, err := hcl.Parse(string(contents))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ssh_helper: error parsing config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
list, ok := root.Node.(*ast.ObjectList)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("ssh_helper: error parsing config: file doesn't contain a root object")
|
||||||
|
}
|
||||||
|
|
||||||
|
valid := []string{
|
||||||
|
"vault_addr",
|
||||||
|
"ssh_mount_point",
|
||||||
|
"ca_cert",
|
||||||
|
"ca_path",
|
||||||
|
"allowed_cidr_list",
|
||||||
|
"tls_skip_verify",
|
||||||
|
}
|
||||||
|
if err := checkHCLKeys(list, valid); err != nil {
|
||||||
|
return nil, multierror.Prefix(err, "ssh_helper:")
|
||||||
|
}
|
||||||
|
|
||||||
|
var c SSHHelperConfig
|
||||||
|
c.SSHMountPoint = SSHHelperDefaultMountPoint
|
||||||
|
if err := hcl.DecodeObject(&c, list); err != nil {
|
||||||
|
return nil, multierror.Prefix(err, "ssh_helper:")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.VaultAddr == "" {
|
||||||
|
return nil, fmt.Errorf("ssh_helper: missing config 'vault_addr'")
|
||||||
|
}
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSHHelper creates an SSHHelper object which can talk to Vault server with SSH backend
|
||||||
|
// mounted at default path ("ssh").
|
||||||
|
func (c *Client) SSHHelper() *SSHHelper {
|
||||||
|
return c.SSHHelperWithMountPoint(SSHHelperDefaultMountPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSHHelperWithMountPoint creates an SSHHelper object which can talk to Vault server with SSH backend
|
||||||
|
// mounted at a specific mount point.
|
||||||
|
func (c *Client) SSHHelperWithMountPoint(mountPoint string) *SSHHelper {
|
||||||
|
return &SSHHelper{
|
||||||
|
c: c,
|
||||||
|
MountPoint: mountPoint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify verifies if the key provided by user is present in Vault server. The response
|
||||||
|
// will contain the IP address and username associated with the OTP. In case the
|
||||||
|
// OTP matches the echo request message, instead of searching an entry for the OTP,
|
||||||
|
// an echo response message is returned. This feature is used by ssh-helper to verify if
|
||||||
|
// its configured correctly.
|
||||||
|
func (c *SSHHelper) Verify(otp string) (*SSHVerifyResponse, error) {
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"otp": otp,
|
||||||
|
}
|
||||||
|
verifyPath := fmt.Sprintf("/v1/%s/verify", c.MountPoint)
|
||||||
|
r := c.c.NewRequest("PUT", verifyPath)
|
||||||
|
if err := r.SetJSONBody(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
secret, err := ParseSecret(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if secret.Data == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var verifyResp SSHVerifyResponse
|
||||||
|
err = mapstructure.Decode(secret.Data, &verifyResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &verifyResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkHCLKeys(node ast.Node, valid []string) error {
|
||||||
|
var list *ast.ObjectList
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *ast.ObjectList:
|
||||||
|
list = n
|
||||||
|
case *ast.ObjectType:
|
||||||
|
list = n.List
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cannot check HCL keys of type %T", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
validMap := make(map[string]struct{}, len(valid))
|
||||||
|
for _, v := range valid {
|
||||||
|
validMap[v] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result error
|
||||||
|
for _, item := range list.Items {
|
||||||
|
key := item.Keys[0].Token.Value().(string)
|
||||||
|
if _, ok := validMap[key]; !ok {
|
||||||
|
result = multierror.Append(result, fmt.Errorf(
|
||||||
|
"invalid key '%s' on line %d", key, item.Assign.Line))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
11
vendor/github.com/hashicorp/vault/api/sys.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/vault/api/sys.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
// Sys is used to perform system-related operations on Vault.
|
||||||
|
type Sys struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sys is used to return the client for sys-related API calls.
|
||||||
|
func (c *Client) Sys() *Sys {
|
||||||
|
return &Sys{c: c}
|
||||||
|
}
|
85
vendor/github.com/hashicorp/vault/api/sys_audit.go
generated
vendored
Normal file
85
vendor/github.com/hashicorp/vault/api/sys_audit.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Sys) AuditHash(path string, input string) (string, error) {
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"input": input,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit-hash/%s", path))
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
type d struct {
|
||||||
|
Hash string
|
||||||
|
}
|
||||||
|
|
||||||
|
var result d
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return result.Hash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) ListAudit() (map[string]*Audit, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/sys/audit")
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result map[string]*Audit
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) EnableAudit(
|
||||||
|
path string, auditType string, desc string, opts map[string]string) error {
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"type": auditType,
|
||||||
|
"description": desc,
|
||||||
|
"options": opts,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit/%s", path))
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) DisableAudit(path string) error {
|
||||||
|
r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/audit/%s", path))
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err == nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structures for the requests/resposne are all down here. They aren't
|
||||||
|
// individually documentd because the map almost directly to the raw HTTP API
|
||||||
|
// documentation. Please refer to that documentation for more details.
|
||||||
|
|
||||||
|
type Audit struct {
|
||||||
|
Path string
|
||||||
|
Type string
|
||||||
|
Description string
|
||||||
|
Options map[string]string
|
||||||
|
}
|
56
vendor/github.com/hashicorp/vault/api/sys_auth.go
generated
vendored
Normal file
56
vendor/github.com/hashicorp/vault/api/sys_auth.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Sys) ListAuth() (map[string]*AuthMount, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/sys/auth")
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result map[string]*AuthMount
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) EnableAuth(path, authType, desc string) error {
|
||||||
|
body := map[string]string{
|
||||||
|
"type": authType,
|
||||||
|
"description": desc,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/auth/%s", path))
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) DisableAuth(path string) error {
|
||||||
|
r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/auth/%s", path))
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err == nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structures for the requests/resposne are all down here. They aren't
|
||||||
|
// individually documentd because the map almost directly to the raw HTTP API
|
||||||
|
// documentation. Please refer to that documentation for more details.
|
||||||
|
|
||||||
|
type AuthMount struct {
|
||||||
|
Type string
|
||||||
|
Description string
|
||||||
|
}
|
60
vendor/github.com/hashicorp/vault/api/sys_capabilities.go
generated
vendored
Normal file
60
vendor/github.com/hashicorp/vault/api/sys_capabilities.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
func (c *Sys) CapabilitiesSelf(path string) ([]string, error) {
|
||||||
|
body := map[string]string{
|
||||||
|
"path": path,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := c.c.NewRequest("POST", "/v1/sys/capabilities-self")
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result map[string]interface{}
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var capabilities []string
|
||||||
|
capabilitiesRaw := result["capabilities"].([]interface{})
|
||||||
|
for _, capability := range capabilitiesRaw {
|
||||||
|
capabilities = append(capabilities, capability.(string))
|
||||||
|
}
|
||||||
|
return capabilities, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) Capabilities(token, path string) ([]string, error) {
|
||||||
|
body := map[string]string{
|
||||||
|
"token": token,
|
||||||
|
"path": path,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := c.c.NewRequest("POST", "/v1/sys/capabilities")
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result map[string]interface{}
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var capabilities []string
|
||||||
|
capabilitiesRaw := result["capabilities"].([]interface{})
|
||||||
|
for _, capability := range capabilitiesRaw {
|
||||||
|
capabilities = append(capabilities, capability.(string))
|
||||||
|
}
|
||||||
|
return capabilities, nil
|
||||||
|
}
|
77
vendor/github.com/hashicorp/vault/api/sys_generate_root.go
generated
vendored
Normal file
77
vendor/github.com/hashicorp/vault/api/sys_generate_root.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
func (c *Sys) GenerateRootStatus() (*GenerateRootStatusResponse, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/sys/generate-root/attempt")
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result GenerateRootStatusResponse
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) GenerateRootInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) {
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"otp": otp,
|
||||||
|
"pgp_key": pgpKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/sys/generate-root/attempt")
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result GenerateRootStatusResponse
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) GenerateRootCancel() error {
|
||||||
|
r := c.c.NewRequest("DELETE", "/v1/sys/generate-root/attempt")
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err == nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) GenerateRootUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) {
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"key": shard,
|
||||||
|
"nonce": nonce,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/sys/generate-root/update")
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result GenerateRootStatusResponse
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenerateRootStatusResponse struct {
|
||||||
|
Nonce string
|
||||||
|
Started bool
|
||||||
|
Progress int
|
||||||
|
Required int
|
||||||
|
Complete bool
|
||||||
|
EncodedRootToken string `json:"encoded_root_token"`
|
||||||
|
PGPFingerprint string `json:"pgp_fingerprint"`
|
||||||
|
}
|
51
vendor/github.com/hashicorp/vault/api/sys_init.go
generated
vendored
Normal file
51
vendor/github.com/hashicorp/vault/api/sys_init.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
func (c *Sys) InitStatus() (bool, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/sys/init")
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result InitStatusResponse
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return result.Initialized, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Sys) Init(opts *InitRequest) (*InitResponse, error) {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/sys/init")
|
||||||
|
if err := r.SetJSONBody(opts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var result InitResponse
|
||||||
|
err = resp.DecodeJSON(&result)
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type InitRequest struct {
|
||||||
|
SecretShares int `json:"secret_shares"`
|
||||||
|
SecretThreshold int `json:"secret_threshold"`
|
||||||
|
StoredShares int `json:"stored_shares"`
|
||||||
|
PGPKeys []string `json:"pgp_keys"`
|
||||||
|
RecoveryShares int `json:"recovery_shares"`
|
||||||
|
RecoveryThreshold int `json:"recovery_threshold"`
|
||||||
|
RecoveryPGPKeys []string `json:"recovery_pgp_keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InitStatusResponse struct {
|
||||||
|
Initialized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type InitResponse struct {
|
||||||
|
Keys []string
|
||||||
|
RecoveryKeys []string `json:"recovery_keys"`
|
||||||
|
RootToken string `json:"root_token"`
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue