mirror of
https://github.com/Luzifer/vault-openvpn.git
synced 2025-01-11 22:21:51 +00:00
Update dependencies for using cobra
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
695e366e88
commit
2cbf5dd6ac
2985 changed files with 80404 additions and 835165 deletions
184
Gopkg.lock
generated
184
Gopkg.lock
generated
|
@ -2,25 +2,12 @@
|
|||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Luzifer/rconfig"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
revision = "7aef1d393c1e2d0758901853b59981c7adc67c7e"
|
||||
version = "v1.2.0"
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "f006c2ac4710855cf0f916dd6b77acf6b048dc6e"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fatih/structs"
|
||||
packages = ["."]
|
||||
revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/snappy"
|
||||
packages = ["."]
|
||||
revision = "553a641470496b2327abcac10b36396bd98e45c9"
|
||||
|
@ -35,13 +22,13 @@
|
|||
branch = "master"
|
||||
name = "github.com/hashicorp/go-cleanhttp"
|
||||
packages = ["."]
|
||||
revision = "3573b8b52aa7b37b9358d966a898feb387f62437"
|
||||
revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/go-multierror"
|
||||
packages = ["."]
|
||||
revision = "83588e72410abfbe4df460eeb6f30841ae47d4c4"
|
||||
revision = "b7773ae218740a7be65057fc60b366a49b538a44"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -49,17 +36,53 @@
|
|||
packages = ["."]
|
||||
revision = "6bb64b370b90e7ef1fa532be9e591a81c3493e00"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hashicorp/go-sockaddr"
|
||||
packages = ["."]
|
||||
revision = "7165ee14aff120ee3642aa2bcf2dea8eebef29c3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [".","hcl/ast","hcl/parser","hcl/scanner","hcl/strconv","hcl/token","json/parser","json/scanner","json/token"]
|
||||
revision = "42e33e2d55a0ff1d6263f738896ea8c13571a8d0"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token"
|
||||
]
|
||||
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hashicorp/vault"
|
||||
packages = ["api","helper/certutil","helper/compressutil","helper/errutil","helper/jsonutil","helper/parseutil"]
|
||||
revision = "6b29fb2b7f70ed538ee2b3c057335d706b6d4e36"
|
||||
version = "v0.8.3"
|
||||
packages = [
|
||||
"api",
|
||||
"helper/certutil",
|
||||
"helper/compressutil",
|
||||
"helper/errutil",
|
||||
"helper/jsonutil",
|
||||
"helper/parseutil",
|
||||
"helper/strutil"
|
||||
]
|
||||
revision = "756fdc4587350daf1c65b93647b2cc31a6f119cd"
|
||||
version = "v0.10.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-runewidth"
|
||||
|
@ -71,71 +94,136 @@
|
|||
branch = "master"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
revision = "b8bc1bf767474819792c23f32d8286a45736f1c6"
|
||||
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
revision = "d0303fe809921458f417bcf828397a65db30a7e4"
|
||||
revision = "a4e142e9c047c904fa2f1e144d9a84e6133024bc"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/olekukonko/tablewriter"
|
||||
packages = ["."]
|
||||
revision = "a7a4c189eb47ed33ce7b35f2880070a0c82a67d4"
|
||||
revision = "d4647c9c7a84d847478d890b816b7d8b62b0b279"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/ryanuber/go-glob"
|
||||
packages = ["."]
|
||||
revision = "256dc444b735e061061cf46c809487313d5b0065"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sethgrid/pester"
|
||||
packages = ["."]
|
||||
revision = "0af5bab1e1ea2860c5aef8e77427bab011d774d8"
|
||||
revision = "ed9870dad3170c0b25ab9b11830cc57c3a7798fb"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
||||
version = "v1.0.5"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem"
|
||||
]
|
||||
revision = "63644898a8da0bc22138abf860edaf5277b6102e"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||
version = "v1.0.0"
|
||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
revision = "9419663f5a44be8b34ca85f08abc5fe1be11f8a3"
|
||||
revision = "ab813273cd59e1333f7ae7bff5d027d4aadf528c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = ["http2","http2/hpack","idna","lex/httplex"]
|
||||
revision = "a04bdaca5b32abe1c069418fb7088ae607de5bd0"
|
||||
packages = [
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"lex/httplex"
|
||||
]
|
||||
revision = "f5dfe339be1d06f81b22525fe34671ee7d2c8904"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix","windows"]
|
||||
revision = "ebfc5b4631820b793c9010c87fd8fef0f39eb082"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows"
|
||||
]
|
||||
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/text"
|
||||
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
|
||||
revision = "825fc78a2fd6fa0a5447e300189e3219e05e1f25"
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable"
|
||||
]
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/validator.v2"
|
||||
packages = ["."]
|
||||
revision = "460c83432a98c35224a6fe352acf8b23e067ad06"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "338132dcce86eed0dc26d5c2a448092d59a299761c47da97aed0c6e98e8c355d"
|
||||
inputs-digest = "d5c94eece84d41716e83088082c119c84736465b21834e66ed176c3ba5bbccf5"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
37
Gopkg.toml
37
Gopkg.toml
|
@ -1,7 +1,6 @@
|
|||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
|
@ -17,25 +16,39 @@
|
|||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Luzifer/rconfig"
|
||||
version = "1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Sirupsen/logrus"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/hashicorp/vault"
|
||||
version = "0.10.1"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/olekukonko/tablewriter"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
version = "1.0.5"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/cobra"
|
||||
version = "0.0.3"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/viper"
|
||||
version = "1.0.2"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
|
8
vendor/github.com/Luzifer/rconfig/.travis.yml
generated
vendored
8
vendor/github.com/Luzifer/rconfig/.travis.yml
generated
vendored
|
@ -1,8 +0,0 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
- 1.7
|
||||
- tip
|
||||
|
||||
script: go test -v -race -cover ./...
|
9
vendor/github.com/Luzifer/rconfig/History.md
generated
vendored
9
vendor/github.com/Luzifer/rconfig/History.md
generated
vendored
|
@ -1,9 +0,0 @@
|
|||
# 1.2.0 / 2017-06-19
|
||||
|
||||
* Add ParseAndValidate method
|
||||
|
||||
# 1.1.0 / 2016-06-28
|
||||
|
||||
* Support time.Duration config parameters
|
||||
* Added goreportcard badge
|
||||
* Added testcase for using bool with ENV and default
|
87
vendor/github.com/Luzifer/rconfig/README.md
generated
vendored
87
vendor/github.com/Luzifer/rconfig/README.md
generated
vendored
|
@ -1,87 +0,0 @@
|
|||
[![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
|
||||
|
||||
A very simple usecase is to just configure a struct inside the vars section of your `main.go` and to parse the commandline flags from the `main()` function:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Luzifer/rconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
cfg = struct {
|
||||
Username string `default:"unknown" flag:"user" description:"Your name"`
|
||||
Details struct {
|
||||
Age int `default:"25" flag:"age" env:"age" description:"Your age"`
|
||||
}
|
||||
}{}
|
||||
)
|
||||
|
||||
func main() {
|
||||
rconfig.Parse(&cfg)
|
||||
|
||||
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
|
||||
var cfg = struct {
|
||||
Username string `vardefault:"username" flag:"username" description:"Your username"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
rconfig.SetVariableDefaults(rconfig.VarDefaultsFromYAMLFile("~/.myapp.yml"))
|
||||
rconfig.Parse(&cfg)
|
||||
|
||||
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.
|
70
vendor/github.com/Luzifer/rconfig/bool_test.go
generated
vendored
70
vendor/github.com/Luzifer/rconfig/bool_test.go
generated
vendored
|
@ -1,70 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing bool parsing", func() {
|
||||
type t struct {
|
||||
Test1 bool `default:"true"`
|
||||
Test2 bool `default:"false" flag:"test2"`
|
||||
Test3 bool `default:"true" flag:"test3,t"`
|
||||
Test4 bool `flag:"test4"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--test2",
|
||||
"-t",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test1).To(Equal(true))
|
||||
Expect(cfg.Test2).To(Equal(true))
|
||||
Expect(cfg.Test3).To(Equal(true))
|
||||
Expect(cfg.Test4).To(Equal(false))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Testing to set bool from ENV with default", func() {
|
||||
type t struct {
|
||||
Test1 bool `default:"true" env:"TEST1"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
os.Unsetenv("TEST1")
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test1).To(Equal(true))
|
||||
})
|
||||
})
|
356
vendor/github.com/Luzifer/rconfig/config.go
generated
vendored
356
vendor/github.com/Luzifer/rconfig/config.go
generated
vendored
|
@ -1,356 +0,0 @@
|
|||
// 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"
|
||||
validator "gopkg.in/validator.v2"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// ParseAndValidate works exactly like Parse but implements an additional run of
|
||||
// the go-validator package on the configuration struct. Therefore additonal struct
|
||||
// tags are supported like described in the readme file of the go-validator package:
|
||||
//
|
||||
// https://github.com/go-validator/validator/tree/v2#usage
|
||||
func ParseAndValidate(config interface{}) error {
|
||||
return parseAndValidate(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 parseAndValidate(in interface{}, args []string) error {
|
||||
if err := parse(in, args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validator.Validate(in)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
41
vendor/github.com/Luzifer/rconfig/duration_test.go
generated
vendored
41
vendor/github.com/Luzifer/rconfig/duration_test.go
generated
vendored
|
@ -1,41 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Duration", func() {
|
||||
type t struct {
|
||||
Test time.Duration `flag:"duration"`
|
||||
TestS time.Duration `flag:"other-duration,o"`
|
||||
TestDef time.Duration `default:"30h"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--duration=23s", "-o", "45m",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal(23 * time.Second))
|
||||
Expect(cfg.TestS).To(Equal(45 * time.Minute))
|
||||
|
||||
Expect(cfg.TestDef).To(Equal(30 * time.Hour))
|
||||
})
|
||||
})
|
56
vendor/github.com/Luzifer/rconfig/errors_test.go
generated
vendored
56
vendor/github.com/Luzifer/rconfig/errors_test.go
generated
vendored
|
@ -1,56 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing errors", func() {
|
||||
|
||||
It("should not accept string as int", func() {
|
||||
Expect(parse(&struct {
|
||||
A int `default:"a"`
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept string as float", func() {
|
||||
Expect(parse(&struct {
|
||||
A float32 `default:"a"`
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept string as uint", func() {
|
||||
Expect(parse(&struct {
|
||||
A uint `default:"a"`
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept string as uint in sub-struct", func() {
|
||||
Expect(parse(&struct {
|
||||
B struct {
|
||||
A uint `default:"a"`
|
||||
}
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept string slice as int slice", func() {
|
||||
Expect(parse(&struct {
|
||||
A []int `default:"a,bn"`
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept variables not being pointers", func() {
|
||||
cfg := struct {
|
||||
A string `default:"a"`
|
||||
}{}
|
||||
|
||||
Expect(parse(cfg, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept variables not being pointers to structs", func() {
|
||||
cfg := "test"
|
||||
|
||||
Expect(parse(cfg, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
})
|
37
vendor/github.com/Luzifer/rconfig/example_test.go
generated
vendored
37
vendor/github.com/Luzifer/rconfig/example_test.go
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ExampleParse() {
|
||||
// We're building an example configuration with a sub-struct to be filled
|
||||
// by the Parse command.
|
||||
config := struct {
|
||||
Username string `default:"unknown" flag:"user,u" description:"Your name"`
|
||||
Details struct {
|
||||
Age int `default:"25" flag:"age" description:"Your age"`
|
||||
}
|
||||
}{}
|
||||
|
||||
// To have more relieable results we're setting os.Args to a known value.
|
||||
// In real-life use cases you wouldn't do this but parse the original
|
||||
// commandline arguments.
|
||||
os.Args = []string{
|
||||
"example",
|
||||
"--user=Luzifer",
|
||||
}
|
||||
|
||||
Parse(&config)
|
||||
|
||||
fmt.Printf("Hello %s, happy birthday for your %dth birthday.",
|
||||
config.Username,
|
||||
config.Details.Age)
|
||||
|
||||
// You can also show an usage message for your user
|
||||
Usage()
|
||||
|
||||
// Output:
|
||||
// Hello Luzifer, happy birthday for your 25th birthday.
|
||||
}
|
44
vendor/github.com/Luzifer/rconfig/float_test.go
generated
vendored
44
vendor/github.com/Luzifer/rconfig/float_test.go
generated
vendored
|
@ -1,44 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing float parsing", func() {
|
||||
type t struct {
|
||||
Test32 float32 `flag:"float32"`
|
||||
Test32P float32 `flag:"float32p,3"`
|
||||
Test64 float64 `flag:"float64"`
|
||||
Test64P float64 `flag:"float64p,6"`
|
||||
TestDef float32 `default:"66.256"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--float32=5.5", "-3", "6.6",
|
||||
"--float64=7.7", "-6", "8.8",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test32).To(Equal(float32(5.5)))
|
||||
Expect(cfg.Test32P).To(Equal(float32(6.6)))
|
||||
Expect(cfg.Test64).To(Equal(float64(7.7)))
|
||||
Expect(cfg.Test64P).To(Equal(float64(8.8)))
|
||||
|
||||
Expect(cfg.TestDef).To(Equal(float32(66.256)))
|
||||
})
|
||||
})
|
128
vendor/github.com/Luzifer/rconfig/general_test.go
generated
vendored
128
vendor/github.com/Luzifer/rconfig/general_test.go
generated
vendored
|
@ -1,128 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing general parsing", func() {
|
||||
type t struct {
|
||||
Test string `default:"foo" env:"shell" flag:"shell" description:"Test"`
|
||||
Test2 string `default:"blub" env:"testvar" flag:"testvar,t" description:"Test"`
|
||||
DefaultFlag string `default:"goo"`
|
||||
SadFlag string
|
||||
}
|
||||
|
||||
type tValidated struct {
|
||||
Test string `flag:"test" default:"" validate:"nonzero"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
Context("with defined arguments", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--shell=test23",
|
||||
"-t", "bla",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have parsed the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal("test23"))
|
||||
Expect(cfg.Test2).To(Equal("bla"))
|
||||
Expect(cfg.SadFlag).To(Equal(""))
|
||||
Expect(cfg.DefaultFlag).To(Equal("goo"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("with no arguments", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the default value", func() {
|
||||
Expect(cfg.Test).To(Equal("foo"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("with no arguments and set env", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{}
|
||||
os.Setenv("shell", "test546")
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
os.Unsetenv("shell")
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the value from env", func() {
|
||||
Expect(cfg.Test).To(Equal("test546"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("with additional arguments", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--shell=test23",
|
||||
"-t", "bla",
|
||||
"positional1", "positional2",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have parsed the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal("test23"))
|
||||
Expect(cfg.Test2).To(Equal("bla"))
|
||||
Expect(cfg.SadFlag).To(Equal(""))
|
||||
Expect(cfg.DefaultFlag).To(Equal("goo"))
|
||||
})
|
||||
It("should have detected the positional arguments", func() {
|
||||
Expect(Args()).To(Equal([]string{"positional1", "positional2"}))
|
||||
})
|
||||
})
|
||||
|
||||
Context("making use of the validator package", func() {
|
||||
var cfgValidated tValidated
|
||||
|
||||
BeforeEach(func() {
|
||||
cfgValidated = tValidated{}
|
||||
args = []string{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parseAndValidate(&cfgValidated, args)
|
||||
})
|
||||
|
||||
It("should have errored", func() { Expect(err).To(HaveOccurred()) })
|
||||
})
|
||||
|
||||
})
|
54
vendor/github.com/Luzifer/rconfig/int_test.go
generated
vendored
54
vendor/github.com/Luzifer/rconfig/int_test.go
generated
vendored
|
@ -1,54 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing int parsing", func() {
|
||||
type t struct {
|
||||
Test int `flag:"int"`
|
||||
TestP int `flag:"intp,i"`
|
||||
Test8 int8 `flag:"int8"`
|
||||
Test8P int8 `flag:"int8p,8"`
|
||||
Test32 int32 `flag:"int32"`
|
||||
Test32P int32 `flag:"int32p,3"`
|
||||
Test64 int64 `flag:"int64"`
|
||||
Test64P int64 `flag:"int64p,6"`
|
||||
TestDef int8 `default:"66"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--int=1", "-i", "2",
|
||||
"--int8=3", "-8", "4",
|
||||
"--int32=5", "-3", "6",
|
||||
"--int64=7", "-6", "8",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal(1))
|
||||
Expect(cfg.TestP).To(Equal(2))
|
||||
Expect(cfg.Test8).To(Equal(int8(3)))
|
||||
Expect(cfg.Test8P).To(Equal(int8(4)))
|
||||
Expect(cfg.Test32).To(Equal(int32(5)))
|
||||
Expect(cfg.Test32P).To(Equal(int32(6)))
|
||||
Expect(cfg.Test64).To(Equal(int64(7)))
|
||||
Expect(cfg.Test64P).To(Equal(int64(8)))
|
||||
|
||||
Expect(cfg.TestDef).To(Equal(int8(66)))
|
||||
})
|
||||
})
|
40
vendor/github.com/Luzifer/rconfig/os-args_test.go
generated
vendored
40
vendor/github.com/Luzifer/rconfig/os-args_test.go
generated
vendored
|
@ -1,40 +0,0 @@
|
|||
package rconfig_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/Luzifer/rconfig"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing os.Args", func() {
|
||||
type t struct {
|
||||
A string `default:"a" flag:"a"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
cfg t
|
||||
)
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = Parse(&cfg)
|
||||
})
|
||||
|
||||
Context("With only valid arguments", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
os.Args = []string{"--a=bar"}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.A).To(Equal("bar"))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
87
vendor/github.com/Luzifer/rconfig/precedence_test.go
generated
vendored
87
vendor/github.com/Luzifer/rconfig/precedence_test.go
generated
vendored
|
@ -1,87 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Precedence", func() {
|
||||
|
||||
type t struct {
|
||||
A int `default:"1" vardefault:"a" env:"a" flag:"avar,a" description:"a"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
cfg t
|
||||
args []string
|
||||
vardefaults map[string]string
|
||||
)
|
||||
|
||||
JustBeforeEach(func() {
|
||||
cfg = t{}
|
||||
SetVariableDefaults(vardefaults)
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
Context("Provided: Flag, Env, Default, VarDefault", func() {
|
||||
BeforeEach(func() {
|
||||
args = []string{"-a", "5"}
|
||||
os.Setenv("a", "8")
|
||||
vardefaults = map[string]string{
|
||||
"a": "3",
|
||||
}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the flag value", func() {
|
||||
Expect(cfg.A).To(Equal(5))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Provided: Env, Default, VarDefault", func() {
|
||||
BeforeEach(func() {
|
||||
args = []string{}
|
||||
os.Setenv("a", "8")
|
||||
vardefaults = map[string]string{
|
||||
"a": "3",
|
||||
}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the env value", func() {
|
||||
Expect(cfg.A).To(Equal(8))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Provided: Default, VarDefault", func() {
|
||||
BeforeEach(func() {
|
||||
args = []string{}
|
||||
os.Unsetenv("a")
|
||||
vardefaults = map[string]string{
|
||||
"a": "3",
|
||||
}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the vardefault value", func() {
|
||||
Expect(cfg.A).To(Equal(3))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Provided: Default", func() {
|
||||
BeforeEach(func() {
|
||||
args = []string{}
|
||||
os.Unsetenv("a")
|
||||
vardefaults = map[string]string{}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the default value", func() {
|
||||
Expect(cfg.A).To(Equal(1))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
13
vendor/github.com/Luzifer/rconfig/rconfig_suite_test.go
generated
vendored
13
vendor/github.com/Luzifer/rconfig/rconfig_suite_test.go
generated
vendored
|
@ -1,13 +0,0 @@
|
|||
package rconfig_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRconfig(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Rconfig Suite")
|
||||
}
|
51
vendor/github.com/Luzifer/rconfig/slice_test.go
generated
vendored
51
vendor/github.com/Luzifer/rconfig/slice_test.go
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing slices", func() {
|
||||
type t struct {
|
||||
Int []int `default:"1,2,3" flag:"int"`
|
||||
String []string `default:"a,b,c" flag:"string"`
|
||||
IntP []int `default:"1,2,3" flag:"intp,i"`
|
||||
StringP []string `default:"a,b,c" flag:"stringp,s"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--int=4,5", "-s", "hallo,welt",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values for int-slice", func() {
|
||||
Expect(len(cfg.Int)).To(Equal(2))
|
||||
Expect(cfg.Int).To(Equal([]int{4, 5}))
|
||||
Expect(cfg.Int).NotTo(Equal([]int{5, 4}))
|
||||
})
|
||||
It("should have the expected values for int-shorthand-slice", func() {
|
||||
Expect(len(cfg.IntP)).To(Equal(3))
|
||||
Expect(cfg.IntP).To(Equal([]int{1, 2, 3}))
|
||||
})
|
||||
It("should have the expected values for string-slice", func() {
|
||||
Expect(len(cfg.String)).To(Equal(3))
|
||||
Expect(cfg.String).To(Equal([]string{"a", "b", "c"}))
|
||||
})
|
||||
It("should have the expected values for string-shorthand-slice", func() {
|
||||
Expect(len(cfg.StringP)).To(Equal(2))
|
||||
Expect(cfg.StringP).To(Equal([]string{"hallo", "welt"}))
|
||||
})
|
||||
})
|
36
vendor/github.com/Luzifer/rconfig/sub-struct_test.go
generated
vendored
36
vendor/github.com/Luzifer/rconfig/sub-struct_test.go
generated
vendored
|
@ -1,36 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing sub-structs", func() {
|
||||
type t struct {
|
||||
Test string `default:"blubb"`
|
||||
Sub struct {
|
||||
Test string `default:"Hallo"`
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal("blubb"))
|
||||
Expect(cfg.Sub.Test).To(Equal("Hallo"))
|
||||
})
|
||||
})
|
59
vendor/github.com/Luzifer/rconfig/uint_test.go
generated
vendored
59
vendor/github.com/Luzifer/rconfig/uint_test.go
generated
vendored
|
@ -1,59 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing uint parsing", func() {
|
||||
type t struct {
|
||||
Test uint `flag:"int"`
|
||||
TestP uint `flag:"intp,i"`
|
||||
Test8 uint8 `flag:"int8"`
|
||||
Test8P uint8 `flag:"int8p,8"`
|
||||
Test16 uint16 `flag:"int16"`
|
||||
Test16P uint16 `flag:"int16p,1"`
|
||||
Test32 uint32 `flag:"int32"`
|
||||
Test32P uint32 `flag:"int32p,3"`
|
||||
Test64 uint64 `flag:"int64"`
|
||||
Test64P uint64 `flag:"int64p,6"`
|
||||
TestDef uint8 `default:"66"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--int=1", "-i", "2",
|
||||
"--int8=3", "-8", "4",
|
||||
"--int32=5", "-3", "6",
|
||||
"--int64=7", "-6", "8",
|
||||
"--int16=9", "-1", "10",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal(uint(1)))
|
||||
Expect(cfg.TestP).To(Equal(uint(2)))
|
||||
Expect(cfg.Test8).To(Equal(uint8(3)))
|
||||
Expect(cfg.Test8P).To(Equal(uint8(4)))
|
||||
Expect(cfg.Test32).To(Equal(uint32(5)))
|
||||
Expect(cfg.Test32P).To(Equal(uint32(6)))
|
||||
Expect(cfg.Test64).To(Equal(uint64(7)))
|
||||
Expect(cfg.Test64P).To(Equal(uint64(8)))
|
||||
Expect(cfg.Test16).To(Equal(uint16(9)))
|
||||
Expect(cfg.Test16P).To(Equal(uint16(10)))
|
||||
|
||||
Expect(cfg.TestDef).To(Equal(uint8(66)))
|
||||
})
|
||||
})
|
27
vendor/github.com/Luzifer/rconfig/vardefault_providers.go
generated
vendored
27
vendor/github.com/Luzifer/rconfig/vardefault_providers.go
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
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
|
||||
}
|
122
vendor/github.com/Luzifer/rconfig/vardefault_test.go
generated
vendored
122
vendor/github.com/Luzifer/rconfig/vardefault_test.go
generated
vendored
|
@ -1,122 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing variable defaults", func() {
|
||||
|
||||
type t struct {
|
||||
MySecretValue string `default:"secret" env:"foo" vardefault:"my_secret_value"`
|
||||
MyUsername string `default:"luzifer" vardefault:"username"`
|
||||
SomeVar string `flag:"var" description:"some variable"`
|
||||
IntVar int64 `vardefault:"int_var" default:"23"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
cfg t
|
||||
args = []string{}
|
||||
vardefaults = map[string]string{
|
||||
"my_secret_value": "veryverysecretkey",
|
||||
"unkownkey": "hi there",
|
||||
"int_var": "42",
|
||||
}
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
Context("With manually provided variables", func() {
|
||||
BeforeEach(func() {
|
||||
SetVariableDefaults(vardefaults)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Context("With defaults from YAML data", func() {
|
||||
BeforeEach(func() {
|
||||
yamlData := []byte("---\nmy_secret_value: veryverysecretkey\nunknownkey: hi there\nint_var: 42\n")
|
||||
SetVariableDefaults(VarDefaultsFromYAML(yamlData))
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Context("With defaults from YAML file", func() {
|
||||
var tmp *os.File
|
||||
|
||||
BeforeEach(func() {
|
||||
tmp, _ = ioutil.TempFile("", "")
|
||||
yamlData := "---\nmy_secret_value: veryverysecretkey\nunknownkey: hi there\nint_var: 42\n"
|
||||
tmp.WriteString(yamlData)
|
||||
SetVariableDefaults(VarDefaultsFromYAMLFile(tmp.Name()))
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
tmp.Close()
|
||||
os.Remove(tmp.Name())
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Context("With defaults from invalid YAML data", func() {
|
||||
BeforeEach(func() {
|
||||
yamlData := []byte("---\nmy_secret_value = veryverysecretkey\nunknownkey = hi there\nint_var = 42\n")
|
||||
SetVariableDefaults(VarDefaultsFromYAML(yamlData))
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(23)))
|
||||
Expect(cfg.MySecretValue).To(Equal("secret"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Context("With defaults from non existent YAML file", func() {
|
||||
BeforeEach(func() {
|
||||
file := "/tmp/this_file_should_not_exist_146e26723r"
|
||||
SetVariableDefaults(VarDefaultsFromYAMLFile(file))
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(23)))
|
||||
Expect(cfg.MySecretValue).To(Equal("secret"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
83
vendor/github.com/Sirupsen/logrus/alt_exit_test.go
generated
vendored
83
vendor/github.com/Sirupsen/logrus/alt_exit_test.go
generated
vendored
|
@ -1,83 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
current := len(handlers)
|
||||
RegisterExitHandler(func() {})
|
||||
if len(handlers) != current+1 {
|
||||
t.Fatalf("expected %d handlers, got %d", current+1, len(handlers))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "test_handler")
|
||||
if err != nil {
|
||||
log.Fatalf("can't create temp dir. %q", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
gofile := filepath.Join(tempDir, "gofile.go")
|
||||
if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil {
|
||||
t.Fatalf("can't create go file. %q", err)
|
||||
}
|
||||
|
||||
outfile := filepath.Join(tempDir, "outfile.out")
|
||||
arg := time.Now().UTC().String()
|
||||
err = exec.Command("go", "run", gofile, outfile, arg).Run()
|
||||
if err == nil {
|
||||
t.Fatalf("completed normally, should have failed")
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(outfile)
|
||||
if err != nil {
|
||||
t.Fatalf("can't read output file %s. %q", outfile, err)
|
||||
}
|
||||
|
||||
if string(data) != arg {
|
||||
t.Fatalf("bad data. Expected %q, got %q", data, arg)
|
||||
}
|
||||
}
|
||||
|
||||
var testprog = []byte(`
|
||||
// Test program for atexit, gets output file and data as arguments and writes
|
||||
// data to output file in atexit handler.
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
var outfile = ""
|
||||
var data = ""
|
||||
|
||||
func handler() {
|
||||
ioutil.WriteFile(outfile, []byte(data), 0666)
|
||||
}
|
||||
|
||||
func badHandler() {
|
||||
n := 0
|
||||
fmt.Println(1/n)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
outfile = flag.Arg(0)
|
||||
data = flag.Arg(1)
|
||||
|
||||
logrus.RegisterExitHandler(handler)
|
||||
logrus.RegisterExitHandler(badHandler)
|
||||
logrus.Fatal("Bye bye")
|
||||
}
|
||||
`)
|
77
vendor/github.com/Sirupsen/logrus/entry_test.go
generated
vendored
77
vendor/github.com/Sirupsen/logrus/entry_test.go
generated
vendored
|
@ -1,77 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEntryWithError(t *testing.T) {
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
defer func() {
|
||||
ErrorKey = "error"
|
||||
}()
|
||||
|
||||
err := fmt.Errorf("kaboom at layer %d", 4711)
|
||||
|
||||
assert.Equal(err, WithError(err).Data["error"])
|
||||
|
||||
logger := New()
|
||||
logger.Out = &bytes.Buffer{}
|
||||
entry := NewEntry(logger)
|
||||
|
||||
assert.Equal(err, entry.WithError(err).Data["error"])
|
||||
|
||||
ErrorKey = "err"
|
||||
|
||||
assert.Equal(err, entry.WithError(err).Data["err"])
|
||||
|
||||
}
|
||||
|
||||
func TestEntryPanicln(t *testing.T) {
|
||||
errBoom := fmt.Errorf("boom time")
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
switch pVal := p.(type) {
|
||||
case *Entry:
|
||||
assert.Equal(t, "kaboom", pVal.Message)
|
||||
assert.Equal(t, errBoom, pVal.Data["err"])
|
||||
default:
|
||||
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
||||
}
|
||||
}()
|
||||
|
||||
logger := New()
|
||||
logger.Out = &bytes.Buffer{}
|
||||
entry := NewEntry(logger)
|
||||
entry.WithField("err", errBoom).Panicln("kaboom")
|
||||
}
|
||||
|
||||
func TestEntryPanicf(t *testing.T) {
|
||||
errBoom := fmt.Errorf("boom again")
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
switch pVal := p.(type) {
|
||||
case *Entry:
|
||||
assert.Equal(t, "kaboom true", pVal.Message)
|
||||
assert.Equal(t, errBoom, pVal.Data["err"])
|
||||
default:
|
||||
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
||||
}
|
||||
}()
|
||||
|
||||
logger := New()
|
||||
logger.Out = &bytes.Buffer{}
|
||||
entry := NewEntry(logger)
|
||||
entry.WithField("err", errBoom).Panicf("kaboom %v", true)
|
||||
}
|
69
vendor/github.com/Sirupsen/logrus/example_basic_test.go
generated
vendored
69
vendor/github.com/Sirupsen/logrus/example_basic_test.go
generated
vendored
|
@ -1,69 +0,0 @@
|
|||
package logrus_test
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Example_basic() {
|
||||
var log = logrus.New()
|
||||
log.Formatter = new(logrus.JSONFormatter)
|
||||
log.Formatter = new(logrus.TextFormatter) //default
|
||||
log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output
|
||||
log.Level = logrus.DebugLevel
|
||||
log.Out = os.Stdout
|
||||
|
||||
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
|
||||
// if err == nil {
|
||||
// log.Out = file
|
||||
// } else {
|
||||
// log.Info("Failed to log to file, using default stderr")
|
||||
// }
|
||||
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
entry := err.(*logrus.Entry)
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"err_animal": entry.Data["animal"],
|
||||
"err_size": entry.Data["size"],
|
||||
"err_level": entry.Level,
|
||||
"err_message": entry.Message,
|
||||
"number": 100,
|
||||
}).Error("The ice breaks!") // or use Fatal() to force the process to exit with a nonzero code
|
||||
}
|
||||
}()
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"number": 8,
|
||||
}).Debug("Started observing beach")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 122,
|
||||
}).Warn("The group's number increased tremendously!")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"temperature": -4,
|
||||
}).Debug("Temperature changes")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "orca",
|
||||
"size": 9009,
|
||||
}).Panic("It's over 9000!")
|
||||
|
||||
// Output:
|
||||
// level=debug msg="Started observing beach" animal=walrus number=8
|
||||
// level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||
// level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||
// level=debug msg="Temperature changes" temperature=-4
|
||||
// level=panic msg="It's over 9000!" animal=orca size=9009
|
||||
// level=error msg="The ice breaks!" err_animal=orca err_level=panic err_message="It's over 9000!" err_size=9009 number=100 omg=true
|
||||
}
|
35
vendor/github.com/Sirupsen/logrus/example_hook_test.go
generated
vendored
35
vendor/github.com/Sirupsen/logrus/example_hook_test.go
generated
vendored
|
@ -1,35 +0,0 @@
|
|||
package logrus_test
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Example_hook() {
|
||||
var log = logrus.New()
|
||||
log.Formatter = new(logrus.TextFormatter) // default
|
||||
log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output
|
||||
log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
|
||||
log.Out = os.Stdout
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 122,
|
||||
}).Warn("The group's number increased tremendously!")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 100,
|
||||
}).Error("The ice breaks!")
|
||||
|
||||
// Output:
|
||||
// level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||
// level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||
// level=error msg="The ice breaks!" number=100 omg=true
|
||||
}
|
101
vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
generated
vendored
101
vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
generated
vendored
|
@ -1,101 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// smallFields is a small size data set for benchmarking
|
||||
var smallFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
}
|
||||
|
||||
// largeFields is a large size data set for benchmarking
|
||||
var largeFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
"five": "six",
|
||||
"seven": "eight",
|
||||
"nine": "ten",
|
||||
"eleven": "twelve",
|
||||
"thirteen": "fourteen",
|
||||
"fifteen": "sixteen",
|
||||
"seventeen": "eighteen",
|
||||
"nineteen": "twenty",
|
||||
"a": "b",
|
||||
"c": "d",
|
||||
"e": "f",
|
||||
"g": "h",
|
||||
"i": "j",
|
||||
"k": "l",
|
||||
"m": "n",
|
||||
"o": "p",
|
||||
"q": "r",
|
||||
"s": "t",
|
||||
"u": "v",
|
||||
"w": "x",
|
||||
"y": "z",
|
||||
"this": "will",
|
||||
"make": "thirty",
|
||||
"entries": "yeah",
|
||||
}
|
||||
|
||||
var errorFields = Fields{
|
||||
"foo": fmt.Errorf("bar"),
|
||||
"baz": fmt.Errorf("qux"),
|
||||
}
|
||||
|
||||
func BenchmarkErrorTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallColoredTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeColoredTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallJSONFormatter(b *testing.B) {
|
||||
doBenchmark(b, &JSONFormatter{}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeJSONFormatter(b *testing.B) {
|
||||
doBenchmark(b, &JSONFormatter{}, largeFields)
|
||||
}
|
||||
|
||||
func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
|
||||
logger := New()
|
||||
|
||||
entry := &Entry{
|
||||
Time: time.Time{},
|
||||
Level: InfoLevel,
|
||||
Message: "message",
|
||||
Data: fields,
|
||||
Logger: logger,
|
||||
}
|
||||
var d []byte
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
d, err = formatter.Format(entry)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(d)))
|
||||
}
|
||||
}
|
122
vendor/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
122
vendor/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
|
@ -1,122 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type TestHook struct {
|
||||
Fired bool
|
||||
}
|
||||
|
||||
func (hook *TestHook) Fire(entry *Entry) error {
|
||||
hook.Fired = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *TestHook) Levels() []Level {
|
||||
return []Level{
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
ErrorLevel,
|
||||
FatalLevel,
|
||||
PanicLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookFires(t *testing.T) {
|
||||
hook := new(TestHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
assert.Equal(t, hook.Fired, false)
|
||||
|
||||
log.Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, true)
|
||||
})
|
||||
}
|
||||
|
||||
type ModifyHook struct {
|
||||
}
|
||||
|
||||
func (hook *ModifyHook) Fire(entry *Entry) error {
|
||||
entry.Data["wow"] = "whale"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *ModifyHook) Levels() []Level {
|
||||
return []Level{
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
ErrorLevel,
|
||||
FatalLevel,
|
||||
PanicLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookCanModifyEntry(t *testing.T) {
|
||||
hook := new(ModifyHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.WithField("wow", "elephant").Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["wow"], "whale")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCanFireMultipleHooks(t *testing.T) {
|
||||
hook1 := new(ModifyHook)
|
||||
hook2 := new(TestHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook1)
|
||||
log.Hooks.Add(hook2)
|
||||
|
||||
log.WithField("wow", "elephant").Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["wow"], "whale")
|
||||
assert.Equal(t, hook2.Fired, true)
|
||||
})
|
||||
}
|
||||
|
||||
type ErrorHook struct {
|
||||
Fired bool
|
||||
}
|
||||
|
||||
func (hook *ErrorHook) Fire(entry *Entry) error {
|
||||
hook.Fired = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *ErrorHook) Levels() []Level {
|
||||
return []Level{
|
||||
ErrorLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorHookShouldntFireOnInfo(t *testing.T) {
|
||||
hook := new(ErrorHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestErrorHookShouldFireOnError(t *testing.T) {
|
||||
hook := new(ErrorHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.Error("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, true)
|
||||
})
|
||||
}
|
39
vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
39
vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
|
@ -1,39 +0,0 @@
|
|||
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"log/syslog"
|
||||
"github.com/sirupsen/logrus"
|
||||
lSyslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := lSyslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following.
|
||||
|
||||
```go
|
||||
import (
|
||||
"log/syslog"
|
||||
"github.com/sirupsen/logrus"
|
||||
lSyslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
55
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
55
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
// +build !windows,!nacl,!plan9
|
||||
|
||||
package syslog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/syslog"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// SyslogHook to send logs via syslog.
|
||||
type SyslogHook struct {
|
||||
Writer *syslog.Writer
|
||||
SyslogNetwork string
|
||||
SyslogRaddr string
|
||||
}
|
||||
|
||||
// Creates a hook to be added to an instance of logger. This is called with
|
||||
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
|
||||
// `if err == nil { log.Hooks.Add(hook) }`
|
||||
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
|
||||
w, err := syslog.Dial(network, raddr, priority, tag)
|
||||
return &SyslogHook{w, network, raddr}, err
|
||||
}
|
||||
|
||||
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
|
||||
line, err := entry.String()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
switch entry.Level {
|
||||
case logrus.PanicLevel:
|
||||
return hook.Writer.Crit(line)
|
||||
case logrus.FatalLevel:
|
||||
return hook.Writer.Crit(line)
|
||||
case logrus.ErrorLevel:
|
||||
return hook.Writer.Err(line)
|
||||
case logrus.WarnLevel:
|
||||
return hook.Writer.Warning(line)
|
||||
case logrus.InfoLevel:
|
||||
return hook.Writer.Info(line)
|
||||
case logrus.DebugLevel:
|
||||
return hook.Writer.Debug(line)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (hook *SyslogHook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
27
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
27
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
package syslog
|
||||
|
||||
import (
|
||||
"log/syslog"
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestLocalhostAddAndPrint(t *testing.T) {
|
||||
log := logrus.New()
|
||||
hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unable to connect to local syslog.")
|
||||
}
|
||||
|
||||
log.Hooks.Add(hook)
|
||||
|
||||
for _, level := range hook.Levels() {
|
||||
if len(log.Hooks[level]) != 1 {
|
||||
t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Congratulations!")
|
||||
}
|
95
vendor/github.com/Sirupsen/logrus/hooks/test/test.go
generated
vendored
95
vendor/github.com/Sirupsen/logrus/hooks/test/test.go
generated
vendored
|
@ -1,95 +0,0 @@
|
|||
// The Test package is used for testing logrus. It is here for backwards
|
||||
// compatibility from when logrus' organization was upper-case. Please use
|
||||
// lower-case logrus and the `null` package instead of this one.
|
||||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Hook is a hook designed for dealing with logs in test scenarios.
|
||||
type Hook struct {
|
||||
// Entries is an array of all entries that have been received by this hook.
|
||||
// For safe access, use the AllEntries() method, rather than reading this
|
||||
// value directly.
|
||||
Entries []*logrus.Entry
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewGlobal installs a test hook for the global logger.
|
||||
func NewGlobal() *Hook {
|
||||
|
||||
hook := new(Hook)
|
||||
logrus.AddHook(hook)
|
||||
|
||||
return hook
|
||||
|
||||
}
|
||||
|
||||
// NewLocal installs a test hook for a given local logger.
|
||||
func NewLocal(logger *logrus.Logger) *Hook {
|
||||
|
||||
hook := new(Hook)
|
||||
logger.Hooks.Add(hook)
|
||||
|
||||
return hook
|
||||
|
||||
}
|
||||
|
||||
// NewNullLogger creates a discarding logger and installs the test hook.
|
||||
func NewNullLogger() (*logrus.Logger, *Hook) {
|
||||
|
||||
logger := logrus.New()
|
||||
logger.Out = ioutil.Discard
|
||||
|
||||
return logger, NewLocal(logger)
|
||||
|
||||
}
|
||||
|
||||
func (t *Hook) Fire(e *logrus.Entry) error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.Entries = append(t.Entries, e)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Hook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
// LastEntry returns the last entry that was logged or nil.
|
||||
func (t *Hook) LastEntry() *logrus.Entry {
|
||||
t.mu.RLock()
|
||||
defer t.mu.RUnlock()
|
||||
i := len(t.Entries) - 1
|
||||
if i < 0 {
|
||||
return nil
|
||||
}
|
||||
// Make a copy, for safety
|
||||
e := *t.Entries[i]
|
||||
return &e
|
||||
}
|
||||
|
||||
// AllEntries returns all entries that were logged.
|
||||
func (t *Hook) AllEntries() []*logrus.Entry {
|
||||
t.mu.RLock()
|
||||
defer t.mu.RUnlock()
|
||||
// Make a copy so the returned value won't race with future log requests
|
||||
entries := make([]*logrus.Entry, len(t.Entries))
|
||||
for i, entry := range t.Entries {
|
||||
// Make a copy, for safety
|
||||
e := *entry
|
||||
entries[i] = &e
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
// Reset removes all Entries from this test hook.
|
||||
func (t *Hook) Reset() {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.Entries = make([]*logrus.Entry, 0)
|
||||
}
|
39
vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
generated
vendored
39
vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
generated
vendored
|
@ -1,39 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAllHooks(t *testing.T) {
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
logger, hook := NewNullLogger()
|
||||
assert.Nil(hook.LastEntry())
|
||||
assert.Equal(0, len(hook.Entries))
|
||||
|
||||
logger.Error("Hello error")
|
||||
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||
assert.Equal(1, len(hook.Entries))
|
||||
|
||||
logger.Warn("Hello warning")
|
||||
assert.Equal(logrus.WarnLevel, hook.LastEntry().Level)
|
||||
assert.Equal("Hello warning", hook.LastEntry().Message)
|
||||
assert.Equal(2, len(hook.Entries))
|
||||
|
||||
hook.Reset()
|
||||
assert.Nil(hook.LastEntry())
|
||||
assert.Equal(0, len(hook.Entries))
|
||||
|
||||
hook = NewGlobal()
|
||||
|
||||
logrus.Error("Hello error")
|
||||
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||
assert.Equal(1, len(hook.Entries))
|
||||
|
||||
}
|
199
vendor/github.com/Sirupsen/logrus/json_formatter_test.go
generated
vendored
199
vendor/github.com/Sirupsen/logrus/json_formatter_test.go
generated
vendored
|
@ -1,199 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestErrorNotLost(t *testing.T) {
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
b, err := formatter.Format(WithField("error", errors.New("wild walrus")))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
if entry["error"] != "wild walrus" {
|
||||
t.Fatal("Error field not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorNotLostOnFieldNotNamedError(t *testing.T) {
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
b, err := formatter.Format(WithField("omg", errors.New("wild walrus")))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
if entry["omg"] != "wild walrus" {
|
||||
t.Fatal("Error field not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldClashWithTime(t *testing.T) {
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
b, err := formatter.Format(WithField("time", "right now!"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
if entry["fields.time"] != "right now!" {
|
||||
t.Fatal("fields.time not set to original time field")
|
||||
}
|
||||
|
||||
if entry["time"] != "0001-01-01T00:00:00Z" {
|
||||
t.Fatal("time field not set to current time, was: ", entry["time"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldClashWithMsg(t *testing.T) {
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
b, err := formatter.Format(WithField("msg", "something"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
if entry["fields.msg"] != "something" {
|
||||
t.Fatal("fields.msg not set to original msg field")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldClashWithLevel(t *testing.T) {
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
b, err := formatter.Format(WithField("level", "something"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
if entry["fields.level"] != "something" {
|
||||
t.Fatal("fields.level not set to original level field")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONEntryEndsWithNewline(t *testing.T) {
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
b, err := formatter.Format(WithField("level", "something"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
if b[len(b)-1] != '\n' {
|
||||
t.Fatal("Expected JSON log entry to end with a newline")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONMessageKey(t *testing.T) {
|
||||
formatter := &JSONFormatter{
|
||||
FieldMap: FieldMap{
|
||||
FieldKeyMsg: "message",
|
||||
},
|
||||
}
|
||||
|
||||
b, err := formatter.Format(&Entry{Message: "oh hai"})
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
s := string(b)
|
||||
if !(strings.Contains(s, "message") && strings.Contains(s, "oh hai")) {
|
||||
t.Fatal("Expected JSON to format message key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONLevelKey(t *testing.T) {
|
||||
formatter := &JSONFormatter{
|
||||
FieldMap: FieldMap{
|
||||
FieldKeyLevel: "somelevel",
|
||||
},
|
||||
}
|
||||
|
||||
b, err := formatter.Format(WithField("level", "something"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
s := string(b)
|
||||
if !strings.Contains(s, "somelevel") {
|
||||
t.Fatal("Expected JSON to format level key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONTimeKey(t *testing.T) {
|
||||
formatter := &JSONFormatter{
|
||||
FieldMap: FieldMap{
|
||||
FieldKeyTime: "timeywimey",
|
||||
},
|
||||
}
|
||||
|
||||
b, err := formatter.Format(WithField("level", "something"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
s := string(b)
|
||||
if !strings.Contains(s, "timeywimey") {
|
||||
t.Fatal("Expected JSON to format time key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONDisableTimestamp(t *testing.T) {
|
||||
formatter := &JSONFormatter{
|
||||
DisableTimestamp: true,
|
||||
}
|
||||
|
||||
b, err := formatter.Format(WithField("level", "something"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
s := string(b)
|
||||
if strings.Contains(s, FieldKeyTime) {
|
||||
t.Error("Did not prevent timestamp", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONEnableTimestamp(t *testing.T) {
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
b, err := formatter.Format(WithField("level", "something"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
s := string(b)
|
||||
if !strings.Contains(s, FieldKeyTime) {
|
||||
t.Error("Timestamp not present", s)
|
||||
}
|
||||
}
|
61
vendor/github.com/Sirupsen/logrus/logger_bench_test.go
generated
vendored
61
vendor/github.com/Sirupsen/logrus/logger_bench_test.go
generated
vendored
|
@ -1,61 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// smallFields is a small size data set for benchmarking
|
||||
var loggerFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
}
|
||||
|
||||
func BenchmarkDummyLogger(b *testing.B) {
|
||||
nullf, err := os.OpenFile("/dev/null", os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
b.Fatalf("%v", err)
|
||||
}
|
||||
defer nullf.Close()
|
||||
doLoggerBenchmark(b, nullf, &TextFormatter{DisableColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkDummyLoggerNoLock(b *testing.B) {
|
||||
nullf, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
b.Fatalf("%v", err)
|
||||
}
|
||||
defer nullf.Close()
|
||||
doLoggerBenchmarkNoLock(b, nullf, &TextFormatter{DisableColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func doLoggerBenchmark(b *testing.B, out *os.File, formatter Formatter, fields Fields) {
|
||||
logger := Logger{
|
||||
Out: out,
|
||||
Level: InfoLevel,
|
||||
Formatter: formatter,
|
||||
}
|
||||
entry := logger.WithFields(fields)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
entry.Info("aaa")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fields Fields) {
|
||||
logger := Logger{
|
||||
Out: out,
|
||||
Level: InfoLevel,
|
||||
Formatter: formatter,
|
||||
}
|
||||
logger.SetNoLock()
|
||||
entry := logger.WithFields(fields)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
entry.Info("aaa")
|
||||
}
|
||||
})
|
||||
}
|
386
vendor/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
386
vendor/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
|
@ -1,386 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
log(logger)
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assertions(fields)
|
||||
}
|
||||
|
||||
func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = &TextFormatter{
|
||||
DisableColors: true,
|
||||
}
|
||||
|
||||
log(logger)
|
||||
|
||||
fields := make(map[string]string)
|
||||
for _, kv := range strings.Split(buffer.String(), " ") {
|
||||
if !strings.Contains(kv, "=") {
|
||||
continue
|
||||
}
|
||||
kvArr := strings.Split(kv, "=")
|
||||
key := strings.TrimSpace(kvArr[0])
|
||||
val := kvArr[1]
|
||||
if kvArr[1][0] == '"' {
|
||||
var err error
|
||||
val, err = strconv.Unquote(val)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
fields[key] = val
|
||||
}
|
||||
assertions(fields)
|
||||
}
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfo(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWarn(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Warn("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "warning")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln("test", "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test test")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln("test", 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln(10, 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "10 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln(10, 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "10 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test", 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test", "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "testtest")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithFieldsShouldAllowAssignments(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
localLog := logger.WithFields(Fields{
|
||||
"key1": "value1",
|
||||
})
|
||||
|
||||
localLog.WithField("key2", "value2").Info("test")
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, "value2", fields["key2"])
|
||||
assert.Equal(t, "value1", fields["key1"])
|
||||
|
||||
buffer = bytes.Buffer{}
|
||||
fields = Fields{}
|
||||
localLog.Info("test")
|
||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, ok := fields["key2"]
|
||||
assert.Equal(t, false, ok)
|
||||
assert.Equal(t, "value1", fields["key1"])
|
||||
}
|
||||
|
||||
func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("msg", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("msg", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["fields.msg"], "hello")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("time", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["fields.time"], "hello")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("level", 1).Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only
|
||||
})
|
||||
}
|
||||
|
||||
func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
|
||||
LogAndAssertText(t, func(log *Logger) {
|
||||
ll := log.WithField("herp", "derp")
|
||||
ll.Info("hello")
|
||||
ll.Info("bye")
|
||||
}, func(fields map[string]string) {
|
||||
for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
|
||||
if _, ok := fields[fieldName]; ok {
|
||||
t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
|
||||
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
llog := logger.WithField("context", "eating raw fish")
|
||||
|
||||
llog.Info("looks delicious")
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.NoError(t, err, "should have decoded first message")
|
||||
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||
assert.Equal(t, fields["msg"], "looks delicious")
|
||||
assert.Equal(t, fields["context"], "eating raw fish")
|
||||
|
||||
buffer.Reset()
|
||||
|
||||
llog.Warn("omg it is!")
|
||||
|
||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.NoError(t, err, "should have decoded second message")
|
||||
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||
assert.Equal(t, fields["msg"], "omg it is!")
|
||||
assert.Equal(t, fields["context"], "eating raw fish")
|
||||
assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
|
||||
|
||||
}
|
||||
|
||||
func TestConvertLevelToString(t *testing.T) {
|
||||
assert.Equal(t, "debug", DebugLevel.String())
|
||||
assert.Equal(t, "info", InfoLevel.String())
|
||||
assert.Equal(t, "warning", WarnLevel.String())
|
||||
assert.Equal(t, "error", ErrorLevel.String())
|
||||
assert.Equal(t, "fatal", FatalLevel.String())
|
||||
assert.Equal(t, "panic", PanicLevel.String())
|
||||
}
|
||||
|
||||
func TestParseLevel(t *testing.T) {
|
||||
l, err := ParseLevel("panic")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, PanicLevel, l)
|
||||
|
||||
l, err = ParseLevel("PANIC")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, PanicLevel, l)
|
||||
|
||||
l, err = ParseLevel("fatal")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, FatalLevel, l)
|
||||
|
||||
l, err = ParseLevel("FATAL")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, FatalLevel, l)
|
||||
|
||||
l, err = ParseLevel("error")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, ErrorLevel, l)
|
||||
|
||||
l, err = ParseLevel("ERROR")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, ErrorLevel, l)
|
||||
|
||||
l, err = ParseLevel("warn")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("WARN")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("warning")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("WARNING")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("info")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, InfoLevel, l)
|
||||
|
||||
l, err = ParseLevel("INFO")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, InfoLevel, l)
|
||||
|
||||
l, err = ParseLevel("debug")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, DebugLevel, l)
|
||||
|
||||
l, err = ParseLevel("DEBUG")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, DebugLevel, l)
|
||||
|
||||
l, err = ParseLevel("invalid")
|
||||
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
|
||||
}
|
||||
|
||||
func TestGetSetLevelRace(t *testing.T) {
|
||||
wg := sync.WaitGroup{}
|
||||
for i := 0; i < 100; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
if i%2 == 0 {
|
||||
SetLevel(InfoLevel)
|
||||
} else {
|
||||
GetLevel()
|
||||
}
|
||||
}(i)
|
||||
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestLoggingRace(t *testing.T) {
|
||||
logger := New()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(100)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
go func() {
|
||||
logger.Info("info")
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Compile test
|
||||
func TestLogrusInterface(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
fn := func(l FieldLogger) {
|
||||
b := l.WithField("key", "value")
|
||||
b.Debug("Test")
|
||||
}
|
||||
// test logger
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
fn(logger)
|
||||
|
||||
// test Entry
|
||||
e := logger.WithField("another", "value")
|
||||
fn(e)
|
||||
}
|
||||
|
||||
// Implements io.Writer using channels for synchronization, so we can wait on
|
||||
// the Entry.Writer goroutine to write in a non-racey way. This does assume that
|
||||
// there is a single call to Logger.Out for each message.
|
||||
type channelWriter chan []byte
|
||||
|
||||
func (cw channelWriter) Write(p []byte) (int, error) {
|
||||
cw <- p
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func TestEntryWriter(t *testing.T) {
|
||||
cw := channelWriter(make(chan []byte, 1))
|
||||
log := New()
|
||||
log.Out = cw
|
||||
log.Formatter = new(JSONFormatter)
|
||||
log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n"))
|
||||
|
||||
bs := <-cw
|
||||
var fields Fields
|
||||
err := json.Unmarshal(bs, &fields)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, fields["foo"], "bar")
|
||||
assert.Equal(t, fields["level"], "warning")
|
||||
}
|
141
vendor/github.com/Sirupsen/logrus/text_formatter_test.go
generated
vendored
141
vendor/github.com/Sirupsen/logrus/text_formatter_test.go
generated
vendored
|
@ -1,141 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFormatting(t *testing.T) {
|
||||
tf := &TextFormatter{DisableColors: true}
|
||||
|
||||
testCases := []struct {
|
||||
value string
|
||||
expected string
|
||||
}{
|
||||
{`foo`, "time=\"0001-01-01T00:00:00Z\" level=panic test=foo\n"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
b, _ := tf.Format(WithField("test", tc.value))
|
||||
|
||||
if string(b) != tc.expected {
|
||||
t.Errorf("formatting expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuoting(t *testing.T) {
|
||||
tf := &TextFormatter{DisableColors: true}
|
||||
|
||||
checkQuoting := func(q bool, value interface{}) {
|
||||
b, _ := tf.Format(WithField("test", value))
|
||||
idx := bytes.Index(b, ([]byte)("test="))
|
||||
cont := bytes.Contains(b[idx+5:], []byte("\""))
|
||||
if cont != q {
|
||||
if q {
|
||||
t.Errorf("quoting expected for: %#v", value)
|
||||
} else {
|
||||
t.Errorf("quoting not expected for: %#v", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkQuoting(false, "")
|
||||
checkQuoting(false, "abcd")
|
||||
checkQuoting(false, "v1.0")
|
||||
checkQuoting(false, "1234567890")
|
||||
checkQuoting(false, "/foobar")
|
||||
checkQuoting(false, "foo_bar")
|
||||
checkQuoting(false, "foo@bar")
|
||||
checkQuoting(false, "foobar^")
|
||||
checkQuoting(false, "+/-_^@f.oobar")
|
||||
checkQuoting(true, "foobar$")
|
||||
checkQuoting(true, "&foobar")
|
||||
checkQuoting(true, "x y")
|
||||
checkQuoting(true, "x,y")
|
||||
checkQuoting(false, errors.New("invalid"))
|
||||
checkQuoting(true, errors.New("invalid argument"))
|
||||
|
||||
// Test for quoting empty fields.
|
||||
tf.QuoteEmptyFields = true
|
||||
checkQuoting(true, "")
|
||||
checkQuoting(false, "abcd")
|
||||
checkQuoting(true, errors.New("invalid argument"))
|
||||
}
|
||||
|
||||
func TestEscaping(t *testing.T) {
|
||||
tf := &TextFormatter{DisableColors: true}
|
||||
|
||||
testCases := []struct {
|
||||
value string
|
||||
expected string
|
||||
}{
|
||||
{`ba"r`, `ba\"r`},
|
||||
{`ba'r`, `ba'r`},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
b, _ := tf.Format(WithField("test", tc.value))
|
||||
if !bytes.Contains(b, []byte(tc.expected)) {
|
||||
t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEscaping_Interface(t *testing.T) {
|
||||
tf := &TextFormatter{DisableColors: true}
|
||||
|
||||
ts := time.Now()
|
||||
|
||||
testCases := []struct {
|
||||
value interface{}
|
||||
expected string
|
||||
}{
|
||||
{ts, fmt.Sprintf("\"%s\"", ts.String())},
|
||||
{errors.New("error: something went wrong"), "\"error: something went wrong\""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
b, _ := tf.Format(WithField("test", tc.value))
|
||||
if !bytes.Contains(b, []byte(tc.expected)) {
|
||||
t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestampFormat(t *testing.T) {
|
||||
checkTimeStr := func(format string) {
|
||||
customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format}
|
||||
customStr, _ := customFormatter.Format(WithField("test", "test"))
|
||||
timeStart := bytes.Index(customStr, ([]byte)("time="))
|
||||
timeEnd := bytes.Index(customStr, ([]byte)("level="))
|
||||
timeStr := customStr[timeStart+5+len("\"") : timeEnd-1-len("\"")]
|
||||
if format == "" {
|
||||
format = time.RFC3339
|
||||
}
|
||||
_, e := time.Parse(format, (string)(timeStr))
|
||||
if e != nil {
|
||||
t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e)
|
||||
}
|
||||
}
|
||||
|
||||
checkTimeStr("2006-01-02T15:04:05.000000000Z07:00")
|
||||
checkTimeStr("Mon Jan _2 15:04:05 2006")
|
||||
checkTimeStr("")
|
||||
}
|
||||
|
||||
func TestDisableTimestampWithColoredOutput(t *testing.T) {
|
||||
tf := &TextFormatter{DisableTimestamp: true, ForceColors: true}
|
||||
|
||||
b, _ := tf.Format(WithField("test", "test"))
|
||||
if strings.Contains(string(b), "[0000]") {
|
||||
t.Error("timestamp not expected when DisableTimestamp is true")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add tests for sorting etc., this requires a parser for the text
|
||||
// formatter output.
|
11
vendor/github.com/fatih/structs/.travis.yml
generated
vendored
11
vendor/github.com/fatih/structs/.travis.yml
generated
vendored
|
@ -1,11 +0,0 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.7.x
|
||||
- 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
|
163
vendor/github.com/fatih/structs/README.md
generated
vendored
163
vendor/github.com/fatih/structs/README.md
generated
vendored
|
@ -1,163 +0,0 @@
|
|||
# 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
|
141
vendor/github.com/fatih/structs/field.go
generated
vendored
141
vendor/github.com/fatih/structs/field.go
generated
vendored
|
@ -1,141 +0,0 @@
|
|||
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) {
|
||||
value := &f.value
|
||||
// value must be settable so we need to make sure it holds the address of the
|
||||
// variable and not a copy, so we can pass the pointer to strctVal instead of a
|
||||
// copy (which is not assigned to any variable, hence not settable).
|
||||
// see "https://blog.golang.org/laws-of-reflection#TOC_8."
|
||||
if f.value.Kind() != reflect.Ptr {
|
||||
a := f.value.Addr()
|
||||
value = &a
|
||||
}
|
||||
v := strctVal(value.Interface())
|
||||
t := v.Type()
|
||||
|
||||
field, ok := t.FieldByName(name)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &Field{
|
||||
field: field,
|
||||
value: v.FieldByName(name),
|
||||
}, true
|
||||
}
|
397
vendor/github.com/fatih/structs/field_test.go
generated
vendored
397
vendor/github.com/fatih/structs/field_test.go
generated
vendored
|
@ -1,397 +0,0 @@
|
|||
package structs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A test struct that defines all cases
|
||||
type Foo struct {
|
||||
A string
|
||||
B int `structs:"y"`
|
||||
C bool `json:"c"`
|
||||
d string // not exported
|
||||
E *Baz
|
||||
x string `xml:"x"` // not exported, with tag
|
||||
Y []string
|
||||
Z map[string]interface{}
|
||||
*Bar // embedded
|
||||
}
|
||||
|
||||
type Baz struct {
|
||||
A string
|
||||
B int
|
||||
}
|
||||
|
||||
type Bar struct {
|
||||
E string
|
||||
F int
|
||||
g []string
|
||||
}
|
||||
|
||||
func newStruct() *Struct {
|
||||
b := &Bar{
|
||||
E: "example",
|
||||
F: 2,
|
||||
g: []string{"zeynep", "fatih"},
|
||||
}
|
||||
|
||||
// B and x is not initialized for testing
|
||||
f := &Foo{
|
||||
A: "gopher",
|
||||
C: true,
|
||||
d: "small",
|
||||
E: nil,
|
||||
Y: []string{"example"},
|
||||
Z: nil,
|
||||
}
|
||||
f.Bar = b
|
||||
|
||||
return New(f)
|
||||
}
|
||||
|
||||
func TestField_Set(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
f := s.Field("A")
|
||||
err := f.Set("fatih")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if f.Value().(string) != "fatih" {
|
||||
t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih")
|
||||
}
|
||||
|
||||
f = s.Field("Y")
|
||||
err = f.Set([]string{"override", "with", "this"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
sliceLen := len(f.Value().([]string))
|
||||
if sliceLen != 3 {
|
||||
t.Errorf("Setted values slice length is wrong: %d, want: %d", sliceLen, 3)
|
||||
}
|
||||
|
||||
f = s.Field("C")
|
||||
err = f.Set(false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if f.Value().(bool) {
|
||||
t.Errorf("Setted value is wrong: %t want: %t", f.Value().(bool), false)
|
||||
}
|
||||
|
||||
// let's pass a different type
|
||||
f = s.Field("A")
|
||||
err = f.Set(123) // Field A is of type string, but we are going to pass an integer
|
||||
if err == nil {
|
||||
t.Error("Setting a field's value with a different type than the field's type should return an error")
|
||||
}
|
||||
|
||||
// old value should be still there :)
|
||||
if f.Value().(string) != "fatih" {
|
||||
t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih")
|
||||
}
|
||||
|
||||
// let's access an unexported field, which should give an error
|
||||
f = s.Field("d")
|
||||
err = f.Set("large")
|
||||
if err != errNotExported {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// let's set a pointer to struct
|
||||
b := &Bar{
|
||||
E: "gopher",
|
||||
F: 2,
|
||||
}
|
||||
|
||||
f = s.Field("Bar")
|
||||
err = f.Set(b)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
baz := &Baz{
|
||||
A: "helloWorld",
|
||||
B: 42,
|
||||
}
|
||||
|
||||
f = s.Field("E")
|
||||
err = f.Set(baz)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
ba := s.Field("E").Value().(*Baz)
|
||||
|
||||
if ba.A != "helloWorld" {
|
||||
t.Errorf("could not set baz. Got: %s Want: helloWorld", ba.A)
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_NotSettable(t *testing.T) {
|
||||
a := map[int]Baz{
|
||||
4: Baz{
|
||||
A: "value",
|
||||
},
|
||||
}
|
||||
|
||||
s := New(a[4])
|
||||
|
||||
if err := s.Field("A").Set("newValue"); err != errNotSettable {
|
||||
t.Errorf("Trying to set non-settable field should error with %q. Got %q instead.", errNotSettable, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_Zero(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
f := s.Field("A")
|
||||
err := f.Zero()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if f.Value().(string) != "" {
|
||||
t.Errorf("Zeroed value is wrong: %s want: %s", f.Value().(string), "")
|
||||
}
|
||||
|
||||
f = s.Field("Y")
|
||||
err = f.Zero()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
sliceLen := len(f.Value().([]string))
|
||||
if sliceLen != 0 {
|
||||
t.Errorf("Zeroed values slice length is wrong: %d, want: %d", sliceLen, 0)
|
||||
}
|
||||
|
||||
f = s.Field("C")
|
||||
err = f.Zero()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if f.Value().(bool) {
|
||||
t.Errorf("Zeroed value is wrong: %t want: %t", f.Value().(bool), false)
|
||||
}
|
||||
|
||||
// let's access an unexported field, which should give an error
|
||||
f = s.Field("d")
|
||||
err = f.Zero()
|
||||
if err != errNotExported {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
f = s.Field("Bar")
|
||||
err = f.Zero()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
f = s.Field("E")
|
||||
err = f.Zero()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
v := s.Field("E").value
|
||||
if !v.IsNil() {
|
||||
t.Errorf("could not set baz. Got: %s Want: <nil>", v.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
func TestField(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err == nil {
|
||||
t.Error("Retrieveing a non existing field from the struct should panic")
|
||||
}
|
||||
}()
|
||||
|
||||
_ = s.Field("no-field")
|
||||
}
|
||||
|
||||
func TestField_Kind(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
f := s.Field("A")
|
||||
if f.Kind() != reflect.String {
|
||||
t.Errorf("Field A has wrong kind: %s want: %s", f.Kind(), reflect.String)
|
||||
}
|
||||
|
||||
f = s.Field("B")
|
||||
if f.Kind() != reflect.Int {
|
||||
t.Errorf("Field B has wrong kind: %s want: %s", f.Kind(), reflect.Int)
|
||||
}
|
||||
|
||||
// unexported
|
||||
f = s.Field("d")
|
||||
if f.Kind() != reflect.String {
|
||||
t.Errorf("Field d has wrong kind: %s want: %s", f.Kind(), reflect.String)
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_Tag(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
v := s.Field("B").Tag("json")
|
||||
if v != "" {
|
||||
t.Errorf("Field's tag value of a non existing tag should return empty, got: %s", v)
|
||||
}
|
||||
|
||||
v = s.Field("C").Tag("json")
|
||||
if v != "c" {
|
||||
t.Errorf("Field's tag value of the existing field C should return 'c', got: %s", v)
|
||||
}
|
||||
|
||||
v = s.Field("d").Tag("json")
|
||||
if v != "" {
|
||||
t.Errorf("Field's tag value of a non exported field should return empty, got: %s", v)
|
||||
}
|
||||
|
||||
v = s.Field("x").Tag("xml")
|
||||
if v != "x" {
|
||||
t.Errorf("Field's tag value of a non exported field with a tag should return 'x', got: %s", v)
|
||||
}
|
||||
|
||||
v = s.Field("A").Tag("json")
|
||||
if v != "" {
|
||||
t.Errorf("Field's tag value of a existing field without a tag should return empty, got: %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_Value(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
v := s.Field("A").Value()
|
||||
val, ok := v.(string)
|
||||
if !ok {
|
||||
t.Errorf("Field's value of a A should be string")
|
||||
}
|
||||
|
||||
if val != "gopher" {
|
||||
t.Errorf("Field's value of a existing tag should return 'gopher', got: %s", val)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err == nil {
|
||||
t.Error("Value of a non exported field from the field should panic")
|
||||
}
|
||||
}()
|
||||
|
||||
// should panic
|
||||
_ = s.Field("d").Value()
|
||||
}
|
||||
|
||||
func TestField_IsEmbedded(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
if !s.Field("Bar").IsEmbedded() {
|
||||
t.Errorf("Fields 'Bar' field is an embedded field")
|
||||
}
|
||||
|
||||
if s.Field("d").IsEmbedded() {
|
||||
t.Errorf("Fields 'd' field is not an embedded field")
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_IsExported(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
if !s.Field("Bar").IsExported() {
|
||||
t.Errorf("Fields 'Bar' field is an exported field")
|
||||
}
|
||||
|
||||
if !s.Field("A").IsExported() {
|
||||
t.Errorf("Fields 'A' field is an exported field")
|
||||
}
|
||||
|
||||
if s.Field("d").IsExported() {
|
||||
t.Errorf("Fields 'd' field is not an exported field")
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_IsZero(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
if s.Field("A").IsZero() {
|
||||
t.Errorf("Fields 'A' field is an initialized field")
|
||||
}
|
||||
|
||||
if !s.Field("B").IsZero() {
|
||||
t.Errorf("Fields 'B' field is not an initialized field")
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_Name(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
if s.Field("A").Name() != "A" {
|
||||
t.Errorf("Fields 'A' field should have the name 'A'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_Field(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
e := s.Field("Bar").Field("E")
|
||||
|
||||
val, ok := e.Value().(string)
|
||||
if !ok {
|
||||
t.Error("The value of the field 'e' inside 'Bar' struct should be string")
|
||||
}
|
||||
|
||||
if val != "example" {
|
||||
t.Errorf("The value of 'e' should be 'example, got: %s", val)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err == nil {
|
||||
t.Error("Field of a non existing nested struct should panic")
|
||||
}
|
||||
}()
|
||||
|
||||
_ = s.Field("Bar").Field("e")
|
||||
}
|
||||
|
||||
func TestField_Fields(t *testing.T) {
|
||||
s := newStruct()
|
||||
fields := s.Field("Bar").Fields()
|
||||
|
||||
if len(fields) != 3 {
|
||||
t.Errorf("We expect 3 fields in embedded struct, was: %d", len(fields))
|
||||
}
|
||||
}
|
||||
|
||||
func TestField_FieldOk(t *testing.T) {
|
||||
s := newStruct()
|
||||
|
||||
b, ok := s.FieldOk("Bar")
|
||||
if !ok {
|
||||
t.Error("The field 'Bar' should exists.")
|
||||
}
|
||||
|
||||
e, ok := b.FieldOk("E")
|
||||
if !ok {
|
||||
t.Error("The field 'E' should exists.")
|
||||
}
|
||||
|
||||
val, ok := e.Value().(string)
|
||||
if !ok {
|
||||
t.Error("The value of the field 'e' inside 'Bar' struct should be string")
|
||||
}
|
||||
|
||||
if val != "example" {
|
||||
t.Errorf("The value of 'e' should be 'example, got: %s", val)
|
||||
}
|
||||
}
|
586
vendor/github.com/fatih/structs/structs.go
generated
vendored
586
vendor/github.com/fatih/structs/structs.go
generated
vendored
|
@ -1,586 +0,0 @@
|
|||
// 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 !tagOpts.Has("omitnested") {
|
||||
finalVal = s.nested(val)
|
||||
|
||||
v := reflect.ValueOf(val.Interface())
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Map, reflect.Struct:
|
||||
isSubStruct = true
|
||||
}
|
||||
} 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≤
|
||||
for 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()
|
||||
}
|
||||
|
||||
// nested retrieves recursively all types for the given value and returns the
|
||||
// nested value.
|
||||
func (s *Struct) nested(val reflect.Value) interface{} {
|
||||
var finalVal interface{}
|
||||
|
||||
v := reflect.ValueOf(val.Interface())
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
n := New(val.Interface())
|
||||
n.TagName = s.TagName
|
||||
m := n.Map()
|
||||
|
||||
// do not add the converted value if there are no exported fields, ie:
|
||||
// time.Time
|
||||
if len(m) == 0 {
|
||||
finalVal = val.Interface()
|
||||
} else {
|
||||
finalVal = m
|
||||
}
|
||||
case reflect.Map:
|
||||
// get the element type of the map
|
||||
mapElem := val.Type()
|
||||
switch val.Type().Kind() {
|
||||
case reflect.Ptr, reflect.Array, reflect.Map,
|
||||
reflect.Slice, reflect.Chan:
|
||||
mapElem = val.Type().Elem()
|
||||
if mapElem.Kind() == reflect.Ptr {
|
||||
mapElem = mapElem.Elem()
|
||||
}
|
||||
}
|
||||
|
||||
// only iterate over struct types, ie: map[string]StructType,
|
||||
// map[string][]StructType,
|
||||
if mapElem.Kind() == reflect.Struct ||
|
||||
(mapElem.Kind() == reflect.Slice &&
|
||||
mapElem.Elem().Kind() == reflect.Struct) {
|
||||
m := make(map[string]interface{}, val.Len())
|
||||
for _, k := range val.MapKeys() {
|
||||
m[k.String()] = s.nested(val.MapIndex(k))
|
||||
}
|
||||
finalVal = m
|
||||
break
|
||||
}
|
||||
|
||||
// TODO(arslan): should this be optional?
|
||||
finalVal = val.Interface()
|
||||
case reflect.Slice, reflect.Array:
|
||||
if val.Type().Kind() == reflect.Interface {
|
||||
finalVal = val.Interface()
|
||||
break
|
||||
}
|
||||
|
||||
// TODO(arslan): should this be optional?
|
||||
// do not iterate of non struct types, just pass the value. Ie: []int,
|
||||
// []string, co... We only iterate further if it's a struct.
|
||||
// i.e []foo or []*foo
|
||||
if val.Type().Elem().Kind() != reflect.Struct &&
|
||||
!(val.Type().Elem().Kind() == reflect.Ptr &&
|
||||
val.Type().Elem().Elem().Kind() == reflect.Struct) {
|
||||
finalVal = val.Interface()
|
||||
break
|
||||
}
|
||||
|
||||
slices := make([]interface{}, val.Len(), val.Len())
|
||||
for x := 0; x < val.Len(); x++ {
|
||||
slices[x] = s.nested(val.Index(x))
|
||||
}
|
||||
finalVal = slices
|
||||
default:
|
||||
finalVal = val.Interface()
|
||||
}
|
||||
|
||||
return finalVal
|
||||
}
|
351
vendor/github.com/fatih/structs/structs_example_test.go
generated
vendored
351
vendor/github.com/fatih/structs/structs_example_test.go
generated
vendored
|
@ -1,351 +0,0 @@
|
|||
package structs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
type Server struct {
|
||||
Name string
|
||||
ID int32
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
server := &Server{
|
||||
Name: "Arslan",
|
||||
ID: 123456,
|
||||
Enabled: true,
|
||||
}
|
||||
|
||||
s := New(server)
|
||||
|
||||
fmt.Printf("Name : %v\n", s.Name())
|
||||
fmt.Printf("Values : %v\n", s.Values())
|
||||
fmt.Printf("Value of ID : %v\n", s.Field("ID").Value())
|
||||
// Output:
|
||||
// Name : Server
|
||||
// Values : [Arslan 123456 true]
|
||||
// Value of ID : 123456
|
||||
|
||||
}
|
||||
|
||||
func ExampleMap() {
|
||||
type Server struct {
|
||||
Name string
|
||||
ID int32
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
Name: "Arslan",
|
||||
ID: 123456,
|
||||
Enabled: true,
|
||||
}
|
||||
|
||||
m := Map(s)
|
||||
|
||||
fmt.Printf("%#v\n", m["Name"])
|
||||
fmt.Printf("%#v\n", m["ID"])
|
||||
fmt.Printf("%#v\n", m["Enabled"])
|
||||
// Output:
|
||||
// "Arslan"
|
||||
// 123456
|
||||
// true
|
||||
|
||||
}
|
||||
|
||||
func ExampleMap_tags() {
|
||||
// Custom tags can change the map keys instead of using the fields name
|
||||
type Server struct {
|
||||
Name string `structs:"server_name"`
|
||||
ID int32 `structs:"server_id"`
|
||||
Enabled bool `structs:"enabled"`
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
Name: "Zeynep",
|
||||
ID: 789012,
|
||||
}
|
||||
|
||||
m := Map(s)
|
||||
|
||||
// access them by the custom tags defined above
|
||||
fmt.Printf("%#v\n", m["server_name"])
|
||||
fmt.Printf("%#v\n", m["server_id"])
|
||||
fmt.Printf("%#v\n", m["enabled"])
|
||||
// Output:
|
||||
// "Zeynep"
|
||||
// 789012
|
||||
// false
|
||||
|
||||
}
|
||||
|
||||
func ExampleMap_omitNested() {
|
||||
// By default field with struct types are processed too. We can stop
|
||||
// processing them via "omitnested" tag option.
|
||||
type Server struct {
|
||||
Name string `structs:"server_name"`
|
||||
ID int32 `structs:"server_id"`
|
||||
Time time.Time `structs:"time,omitnested"` // do not convert to map[string]interface{}
|
||||
}
|
||||
|
||||
const shortForm = "2006-Jan-02"
|
||||
t, _ := time.Parse("2006-Jan-02", "2013-Feb-03")
|
||||
|
||||
s := &Server{
|
||||
Name: "Zeynep",
|
||||
ID: 789012,
|
||||
Time: t,
|
||||
}
|
||||
|
||||
m := Map(s)
|
||||
|
||||
// access them by the custom tags defined above
|
||||
fmt.Printf("%v\n", m["server_name"])
|
||||
fmt.Printf("%v\n", m["server_id"])
|
||||
fmt.Printf("%v\n", m["time"].(time.Time))
|
||||
// Output:
|
||||
// Zeynep
|
||||
// 789012
|
||||
// 2013-02-03 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleMap_omitEmpty() {
|
||||
// By default field with struct types of zero values are processed too. We
|
||||
// can stop processing them via "omitempty" tag option.
|
||||
type Server struct {
|
||||
Name string `structs:",omitempty"`
|
||||
ID int32 `structs:"server_id,omitempty"`
|
||||
Location string
|
||||
}
|
||||
|
||||
// Only add location
|
||||
s := &Server{
|
||||
Location: "Tokyo",
|
||||
}
|
||||
|
||||
m := Map(s)
|
||||
|
||||
// map contains only the Location field
|
||||
fmt.Printf("%v\n", m)
|
||||
// Output:
|
||||
// map[Location:Tokyo]
|
||||
}
|
||||
|
||||
func ExampleValues() {
|
||||
type Server struct {
|
||||
Name string
|
||||
ID int32
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
Name: "Fatih",
|
||||
ID: 135790,
|
||||
Enabled: false,
|
||||
}
|
||||
|
||||
m := Values(s)
|
||||
|
||||
fmt.Printf("Values: %+v\n", m)
|
||||
// Output:
|
||||
// Values: [Fatih 135790 false]
|
||||
}
|
||||
|
||||
func ExampleValues_omitEmpty() {
|
||||
// By default field with struct types of zero values are processed too. We
|
||||
// can stop processing them via "omitempty" tag option.
|
||||
type Server struct {
|
||||
Name string `structs:",omitempty"`
|
||||
ID int32 `structs:"server_id,omitempty"`
|
||||
Location string
|
||||
}
|
||||
|
||||
// Only add location
|
||||
s := &Server{
|
||||
Location: "Ankara",
|
||||
}
|
||||
|
||||
m := Values(s)
|
||||
|
||||
// values contains only the Location field
|
||||
fmt.Printf("Values: %+v\n", m)
|
||||
// Output:
|
||||
// Values: [Ankara]
|
||||
}
|
||||
|
||||
func ExampleValues_tags() {
|
||||
type Location struct {
|
||||
City string
|
||||
Country string
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Name string
|
||||
ID int32
|
||||
Enabled bool
|
||||
Location Location `structs:"-"` // values from location are not included anymore
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
Name: "Fatih",
|
||||
ID: 135790,
|
||||
Enabled: false,
|
||||
Location: Location{City: "Ankara", Country: "Turkey"},
|
||||
}
|
||||
|
||||
// Let get all values from the struct s. Note that we don't include values
|
||||
// from the Location field
|
||||
m := Values(s)
|
||||
|
||||
fmt.Printf("Values: %+v\n", m)
|
||||
// Output:
|
||||
// Values: [Fatih 135790 false]
|
||||
}
|
||||
|
||||
func ExampleFields() {
|
||||
type Access struct {
|
||||
Name string
|
||||
LastAccessed time.Time
|
||||
Number int
|
||||
}
|
||||
|
||||
s := &Access{
|
||||
Name: "Fatih",
|
||||
LastAccessed: time.Now(),
|
||||
Number: 1234567,
|
||||
}
|
||||
|
||||
fields := Fields(s)
|
||||
|
||||
for i, field := range fields {
|
||||
fmt.Printf("[%d] %+v\n", i, field.Name())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// [0] Name
|
||||
// [1] LastAccessed
|
||||
// [2] Number
|
||||
}
|
||||
|
||||
func ExampleFields_nested() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Number int
|
||||
}
|
||||
|
||||
type Access struct {
|
||||
Person Person
|
||||
HasPermission bool
|
||||
LastAccessed time.Time
|
||||
}
|
||||
|
||||
s := &Access{
|
||||
Person: Person{Name: "fatih", Number: 1234567},
|
||||
LastAccessed: time.Now(),
|
||||
HasPermission: true,
|
||||
}
|
||||
|
||||
// Let's get all fields from the struct s.
|
||||
fields := Fields(s)
|
||||
|
||||
for _, field := range fields {
|
||||
if field.Name() == "Person" {
|
||||
fmt.Printf("Access.Person.Name: %+v\n", field.Field("Name").Value())
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Access.Person.Name: fatih
|
||||
}
|
||||
|
||||
func ExampleField() {
|
||||
type Person struct {
|
||||
Name string
|
||||
Number int
|
||||
}
|
||||
|
||||
type Access struct {
|
||||
Person Person
|
||||
HasPermission bool
|
||||
LastAccessed time.Time
|
||||
}
|
||||
|
||||
access := &Access{
|
||||
Person: Person{Name: "fatih", Number: 1234567},
|
||||
LastAccessed: time.Now(),
|
||||
HasPermission: true,
|
||||
}
|
||||
|
||||
// Create a new Struct type
|
||||
s := New(access)
|
||||
|
||||
// Get the Field type for "Person" field
|
||||
p := s.Field("Person")
|
||||
|
||||
// Get the underlying "Name field" and print the value of it
|
||||
name := p.Field("Name")
|
||||
|
||||
fmt.Printf("Value of Person.Access.Name: %+v\n", name.Value())
|
||||
|
||||
// Output:
|
||||
// Value of Person.Access.Name: fatih
|
||||
|
||||
}
|
||||
|
||||
func ExampleIsZero() {
|
||||
type Server struct {
|
||||
Name string
|
||||
ID int32
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
// Nothing is initalized
|
||||
a := &Server{}
|
||||
isZeroA := IsZero(a)
|
||||
|
||||
// Name and Enabled is initialized, but not ID
|
||||
b := &Server{
|
||||
Name: "Golang",
|
||||
Enabled: true,
|
||||
}
|
||||
isZeroB := IsZero(b)
|
||||
|
||||
fmt.Printf("%#v\n", isZeroA)
|
||||
fmt.Printf("%#v\n", isZeroB)
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleHasZero() {
|
||||
// Let's define an Access struct. Note that the "Enabled" field is not
|
||||
// going to be checked because we added the "structs" tag to the field.
|
||||
type Access struct {
|
||||
Name string
|
||||
LastAccessed time.Time
|
||||
Number int
|
||||
Enabled bool `structs:"-"`
|
||||
}
|
||||
|
||||
// Name and Number is not initialized.
|
||||
a := &Access{
|
||||
LastAccessed: time.Now(),
|
||||
}
|
||||
hasZeroA := HasZero(a)
|
||||
|
||||
// Name and Number is initialized.
|
||||
b := &Access{
|
||||
Name: "Fatih",
|
||||
LastAccessed: time.Now(),
|
||||
Number: 12345,
|
||||
}
|
||||
hasZeroB := HasZero(b)
|
||||
|
||||
fmt.Printf("%#v\n", hasZeroA)
|
||||
fmt.Printf("%#v\n", hasZeroB)
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
1453
vendor/github.com/fatih/structs/structs_test.go
generated
vendored
1453
vendor/github.com/fatih/structs/structs_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
32
vendor/github.com/fatih/structs/tags.go
generated
vendored
32
vendor/github.com/fatih/structs/tags.go
generated
vendored
|
@ -1,32 +0,0 @@
|
|||
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:]
|
||||
}
|
46
vendor/github.com/fatih/structs/tags_test.go
generated
vendored
46
vendor/github.com/fatih/structs/tags_test.go
generated
vendored
|
@ -1,46 +0,0 @@
|
|||
package structs
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestParseTag_Name(t *testing.T) {
|
||||
tags := []struct {
|
||||
tag string
|
||||
has bool
|
||||
}{
|
||||
{"", false},
|
||||
{"name", true},
|
||||
{"name,opt", true},
|
||||
{"name , opt, opt2", false}, // has a single whitespace
|
||||
{", opt, opt2", false},
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
name, _ := parseTag(tag.tag)
|
||||
|
||||
if (name != "name") && tag.has {
|
||||
t.Errorf("Parse tag should return name: %#v", tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTag_Opts(t *testing.T) {
|
||||
tags := []struct {
|
||||
opts string
|
||||
has bool
|
||||
}{
|
||||
{"name", false},
|
||||
{"name,opt", true},
|
||||
{"name , opt, opt2", false}, // has a single whitespace
|
||||
{",opt, opt2", true},
|
||||
{", opt3, opt4", false},
|
||||
}
|
||||
|
||||
// search for "opt"
|
||||
for _, tag := range tags {
|
||||
_, opts := parseTag(tag.opts)
|
||||
|
||||
if opts.Has("opt") != tag.has {
|
||||
t.Errorf("Tag opts should have opt: %#v", tag)
|
||||
}
|
||||
}
|
||||
}
|
5
vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
Normal file
5
vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
6
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
Normal file
6
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Setup a Global .gitignore for OS and editor generated files:
|
||||
# https://help.github.com/articles/ignoring-files
|
||||
# git config --global core.excludesfile ~/.gitignore_global
|
||||
|
||||
.vagrant
|
||||
*.sublime-project
|
30
vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
Normal file
30
vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
fast_finish: true
|
||||
|
||||
before_script:
|
||||
- go get -u github.com/golang/lint/golint
|
||||
|
||||
script:
|
||||
- go test -v --race ./...
|
||||
|
||||
after_script:
|
||||
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
|
||||
- test -z "$(golint ./... | tee /dev/stderr)"
|
||||
- go vet ./...
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
notifications:
|
||||
email: false
|
52
vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
Normal file
52
vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# You can update this list using the following command:
|
||||
#
|
||||
# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Aaron L <aaron@bettercoder.net>
|
||||
Adrien Bustany <adrien@bustany.org>
|
||||
Amit Krishnan <amit.krishnan@oracle.com>
|
||||
Anmol Sethi <me@anmol.io>
|
||||
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
|
||||
Bruno Bigras <bigras.bruno@gmail.com>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Case Nelson <case@teammating.com>
|
||||
Chris Howey <chris@howey.me> <howeyc@gmail.com>
|
||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||
Daniel Wagner-Hall <dawagner@gmail.com>
|
||||
Dave Cheney <dave@cheney.net>
|
||||
Evan Phoenix <evan@fallingsnow.net>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Hari haran <hariharan.uno@gmail.com>
|
||||
John C Barstow
|
||||
Kelvin Fo <vmirage@gmail.com>
|
||||
Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
|
||||
Matt Layher <mdlayher@gmail.com>
|
||||
Nathan Youngman <git@nathany.com>
|
||||
Nickolai Zeldovich <nickolai@csail.mit.edu>
|
||||
Patrick <patrick@dropbox.com>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Pawel Knap <pawelknap88@gmail.com>
|
||||
Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pursuit92 <JoshChase@techpursuit.net>
|
||||
Riku Voipio <riku.voipio@linaro.org>
|
||||
Rob Figueiredo <robfig@gmail.com>
|
||||
Rodrigo Chiossi <rodrigochiossi@gmail.com>
|
||||
Slawek Ligus <root@ooz.ie>
|
||||
Soge Zhang <zhssoge@gmail.com>
|
||||
Tiffany Jernigan <tiffany.jernigan@intel.com>
|
||||
Tilak Sharma <tilaks@google.com>
|
||||
Tom Payne <twpayne@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Vahe Khachikyan <vahe@live.ca>
|
||||
Yukang <moorekang@gmail.com>
|
||||
bronze1man <bronze1man@gmail.com>
|
||||
debrando <denis.brandolini@gmail.com>
|
||||
henrikedwards <henrik.edwards@gmail.com>
|
||||
铁哥 <guotie.9@gmail.com>
|
317
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
Normal file
317
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,317 @@
|
|||
# Changelog
|
||||
|
||||
## v1.4.7 / 2018-01-09
|
||||
|
||||
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
|
||||
* Tests: Fix missing verb on format string (thanks @rchiossi)
|
||||
* Linux: Fix deadlock in Remove (thanks @aarondl)
|
||||
* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne)
|
||||
* Docs: Moved FAQ into the README (thanks @vahe)
|
||||
* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
|
||||
* Docs: replace references to OS X with macOS
|
||||
|
||||
## v1.4.2 / 2016-10-10
|
||||
|
||||
* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
|
||||
|
||||
## v1.4.1 / 2016-10-04
|
||||
|
||||
* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
|
||||
|
||||
## v1.4.0 / 2016-10-01
|
||||
|
||||
* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
|
||||
|
||||
## v1.3.1 / 2016-06-28
|
||||
|
||||
* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
|
||||
|
||||
## v1.3.0 / 2016-04-19
|
||||
|
||||
* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
|
||||
|
||||
## v1.2.10 / 2016-03-02
|
||||
|
||||
* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
|
||||
|
||||
## v1.2.9 / 2016-01-13
|
||||
|
||||
kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
|
||||
|
||||
## v1.2.8 / 2015-12-17
|
||||
|
||||
* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
|
||||
* inotify: fix race in test
|
||||
* enable race detection for continuous integration (Linux, Mac, Windows)
|
||||
|
||||
## v1.2.5 / 2015-10-17
|
||||
|
||||
* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
|
||||
* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
|
||||
* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
|
||||
* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
|
||||
|
||||
## v1.2.1 / 2015-10-14
|
||||
|
||||
* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
|
||||
|
||||
## v1.2.0 / 2015-02-08
|
||||
|
||||
* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
|
||||
* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
|
||||
* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
|
||||
|
||||
## v1.1.1 / 2015-02-05
|
||||
|
||||
* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
|
||||
|
||||
## v1.1.0 / 2014-12-12
|
||||
|
||||
* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
|
||||
* add low-level functions
|
||||
* only need to store flags on directories
|
||||
* less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13)
|
||||
* done can be an unbuffered channel
|
||||
* remove calls to os.NewSyscallError
|
||||
* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher)
|
||||
* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v1.0.4 / 2014-09-07
|
||||
|
||||
* kqueue: add dragonfly to the build tags.
|
||||
* Rename source code files, rearrange code so exported APIs are at the top.
|
||||
* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
|
||||
|
||||
## v1.0.3 / 2014-08-19
|
||||
|
||||
* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
|
||||
|
||||
## v1.0.2 / 2014-08-17
|
||||
|
||||
* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
* [Fix] Make ./path and path equivalent. (thanks @zhsso)
|
||||
|
||||
## v1.0.0 / 2014-08-15
|
||||
|
||||
* [API] Remove AddWatch on Windows, use Add.
|
||||
* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
|
||||
* Minor updates based on feedback from golint.
|
||||
|
||||
## dev / 2014-07-09
|
||||
|
||||
* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify).
|
||||
* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
|
||||
|
||||
## dev / 2014-07-04
|
||||
|
||||
* kqueue: fix incorrect mutex used in Close()
|
||||
* Update example to demonstrate usage of Op.
|
||||
|
||||
## dev / 2014-06-28
|
||||
|
||||
* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4)
|
||||
* Fix for String() method on Event (thanks Alex Brainman)
|
||||
* Don't build on Plan 9 or Solaris (thanks @4ad)
|
||||
|
||||
## dev / 2014-06-21
|
||||
|
||||
* Events channel of type Event rather than *Event.
|
||||
* [internal] use syscall constants directly for inotify and kqueue.
|
||||
* [internal] kqueue: rename events to kevents and fileEvent to event.
|
||||
|
||||
## dev / 2014-06-19
|
||||
|
||||
* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
|
||||
* [internal] remove cookie from Event struct (unused).
|
||||
* [internal] Event struct has the same definition across every OS.
|
||||
* [internal] remove internal watch and removeWatch methods.
|
||||
|
||||
## dev / 2014-06-12
|
||||
|
||||
* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
|
||||
* [API] Pluralized channel names: Events and Errors.
|
||||
* [API] Renamed FileEvent struct to Event.
|
||||
* [API] Op constants replace methods like IsCreate().
|
||||
|
||||
## dev / 2014-06-12
|
||||
|
||||
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||
|
||||
## dev / 2014-05-23
|
||||
|
||||
* [API] Remove current implementation of WatchFlags.
|
||||
* current implementation doesn't take advantage of OS for efficiency
|
||||
* provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes
|
||||
* no tests for the current implementation
|
||||
* not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
|
||||
|
||||
## v0.9.3 / 2014-12-31
|
||||
|
||||
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||
|
||||
## v0.9.2 / 2014-08-17
|
||||
|
||||
* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||
|
||||
## v0.9.1 / 2014-06-12
|
||||
|
||||
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||
|
||||
## v0.9.0 / 2014-01-17
|
||||
|
||||
* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
|
||||
* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
|
||||
* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
|
||||
|
||||
## v0.8.12 / 2013-11-13
|
||||
|
||||
* [API] Remove FD_SET and friends from Linux adapter
|
||||
|
||||
## v0.8.11 / 2013-11-02
|
||||
|
||||
* [Doc] Add Changelog [#72][] (thanks @nathany)
|
||||
* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
|
||||
|
||||
## v0.8.10 / 2013-10-19
|
||||
|
||||
* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
|
||||
* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
|
||||
* [Doc] specify OS-specific limits in README (thanks @debrando)
|
||||
|
||||
## v0.8.9 / 2013-09-08
|
||||
|
||||
* [Doc] Contributing (thanks @nathany)
|
||||
* [Doc] update package path in example code [#63][] (thanks @paulhammond)
|
||||
* [Doc] GoCI badge in README (Linux only) [#60][]
|
||||
* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
|
||||
|
||||
## v0.8.8 / 2013-06-17
|
||||
|
||||
* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
|
||||
|
||||
## v0.8.7 / 2013-06-03
|
||||
|
||||
* [API] Make syscall flags internal
|
||||
* [Fix] inotify: ignore event changes
|
||||
* [Fix] race in symlink test [#45][] (reported by @srid)
|
||||
* [Fix] tests on Windows
|
||||
* lower case error messages
|
||||
|
||||
## v0.8.6 / 2013-05-23
|
||||
|
||||
* kqueue: Use EVT_ONLY flag on Darwin
|
||||
* [Doc] Update README with full example
|
||||
|
||||
## v0.8.5 / 2013-05-09
|
||||
|
||||
* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
|
||||
|
||||
## v0.8.4 / 2013-04-07
|
||||
|
||||
* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
|
||||
|
||||
## v0.8.3 / 2013-03-13
|
||||
|
||||
* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
|
||||
* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
|
||||
|
||||
## v0.8.2 / 2013-02-07
|
||||
|
||||
* [Doc] add Authors
|
||||
* [Fix] fix data races for map access [#29][] (thanks @fsouza)
|
||||
|
||||
## v0.8.1 / 2013-01-09
|
||||
|
||||
* [Fix] Windows path separators
|
||||
* [Doc] BSD License
|
||||
|
||||
## v0.8.0 / 2012-11-09
|
||||
|
||||
* kqueue: directory watching improvements (thanks @vmirage)
|
||||
* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
|
||||
* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
|
||||
|
||||
## v0.7.4 / 2012-10-09
|
||||
|
||||
* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
|
||||
* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
|
||||
* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
|
||||
* [Fix] kqueue: modify after recreation of file
|
||||
|
||||
## v0.7.3 / 2012-09-27
|
||||
|
||||
* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
|
||||
* [Fix] kqueue: no longer get duplicate CREATE events
|
||||
|
||||
## v0.7.2 / 2012-09-01
|
||||
|
||||
* kqueue: events for created directories
|
||||
|
||||
## v0.7.1 / 2012-07-14
|
||||
|
||||
* [Fix] for renaming files
|
||||
|
||||
## v0.7.0 / 2012-07-02
|
||||
|
||||
* [Feature] FSNotify flags
|
||||
* [Fix] inotify: Added file name back to event path
|
||||
|
||||
## v0.6.0 / 2012-06-06
|
||||
|
||||
* kqueue: watch files after directory created (thanks @tmc)
|
||||
|
||||
## v0.5.1 / 2012-05-22
|
||||
|
||||
* [Fix] inotify: remove all watches before Close()
|
||||
|
||||
## v0.5.0 / 2012-05-03
|
||||
|
||||
* [API] kqueue: return errors during watch instead of sending over channel
|
||||
* kqueue: match symlink behavior on Linux
|
||||
* inotify: add `DELETE_SELF` (requested by @taralx)
|
||||
* [Fix] kqueue: handle EINTR (reported by @robfig)
|
||||
* [Doc] Godoc example [#1][] (thanks @davecheney)
|
||||
|
||||
## v0.4.0 / 2012-03-30
|
||||
|
||||
* Go 1 released: build with go tool
|
||||
* [Feature] Windows support using winfsnotify
|
||||
* Windows does not have attribute change notifications
|
||||
* Roll attribute notifications into IsModify
|
||||
|
||||
## v0.3.0 / 2012-02-19
|
||||
|
||||
* kqueue: add files when watch directory
|
||||
|
||||
## v0.2.0 / 2011-12-30
|
||||
|
||||
* update to latest Go weekly code
|
||||
|
||||
## v0.1.0 / 2011-10-19
|
||||
|
||||
* kqueue: add watch on file creation to match inotify
|
||||
* kqueue: create file event
|
||||
* inotify: ignore `IN_IGNORED` events
|
||||
* event String()
|
||||
* linux: common FileEvent functions
|
||||
* initial commit
|
||||
|
||||
[#79]: https://github.com/howeyc/fsnotify/pull/79
|
||||
[#77]: https://github.com/howeyc/fsnotify/pull/77
|
||||
[#72]: https://github.com/howeyc/fsnotify/issues/72
|
||||
[#71]: https://github.com/howeyc/fsnotify/issues/71
|
||||
[#70]: https://github.com/howeyc/fsnotify/issues/70
|
||||
[#63]: https://github.com/howeyc/fsnotify/issues/63
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#60]: https://github.com/howeyc/fsnotify/issues/60
|
||||
[#59]: https://github.com/howeyc/fsnotify/issues/59
|
||||
[#49]: https://github.com/howeyc/fsnotify/issues/49
|
||||
[#45]: https://github.com/howeyc/fsnotify/issues/45
|
||||
[#40]: https://github.com/howeyc/fsnotify/issues/40
|
||||
[#36]: https://github.com/howeyc/fsnotify/issues/36
|
||||
[#33]: https://github.com/howeyc/fsnotify/issues/33
|
||||
[#29]: https://github.com/howeyc/fsnotify/issues/29
|
||||
[#25]: https://github.com/howeyc/fsnotify/issues/25
|
||||
[#24]: https://github.com/howeyc/fsnotify/issues/24
|
||||
[#21]: https://github.com/howeyc/fsnotify/issues/21
|
77
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
Normal file
77
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Contributing
|
||||
|
||||
## Issues
|
||||
|
||||
* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues).
|
||||
* Please indicate the platform you are using fsnotify on.
|
||||
* A code example to reproduce the problem is appreciated.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
### Contributor License Agreement
|
||||
|
||||
fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
|
||||
|
||||
Please indicate that you have signed the CLA in your pull request.
|
||||
|
||||
### How fsnotify is Developed
|
||||
|
||||
* Development is done on feature branches.
|
||||
* Tests are run on BSD, Linux, macOS and Windows.
|
||||
* Pull requests are reviewed and [applied to master][am] using [hub][].
|
||||
* Maintainers may modify or squash commits rather than asking contributors to.
|
||||
* To issue a new release, the maintainers will:
|
||||
* Update the CHANGELOG
|
||||
* Tag a version, which will become available through gopkg.in.
|
||||
|
||||
### How to Fork
|
||||
|
||||
For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
|
||||
|
||||
1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`)
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
3. Ensure everything works and the tests pass (see below)
|
||||
4. Commit your changes (`git commit -am 'Add some feature'`)
|
||||
|
||||
Contribute upstream:
|
||||
|
||||
1. Fork fsnotify on GitHub
|
||||
2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
|
||||
3. Push to the branch (`git push fork my-new-feature`)
|
||||
4. Create a new Pull Request on GitHub
|
||||
|
||||
This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/).
|
||||
|
||||
### Testing
|
||||
|
||||
fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows.
|
||||
|
||||
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
|
||||
|
||||
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
|
||||
|
||||
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
|
||||
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
|
||||
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
|
||||
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
|
||||
* When you're done, you will want to halt or destroy the Vagrant boxes.
|
||||
|
||||
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
|
||||
|
||||
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
|
||||
|
||||
### Maintainers
|
||||
|
||||
Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
|
||||
* Submit a pull request and sign the CLA as above.
|
||||
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||
|
||||
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
|
||||
|
||||
All code changes should be internal pull requests.
|
||||
|
||||
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||
|
||||
[hub]: https://github.com/github/hub
|
||||
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
28
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
Normal file
28
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2012 fsnotify Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
79
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
Normal file
79
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
# File system notifications for Go
|
||||
|
||||
[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
|
||||
|
||||
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
|
||||
|
||||
```console
|
||||
go get -u golang.org/x/sys/...
|
||||
```
|
||||
|
||||
Cross platform: Windows, Linux, BSD and macOS.
|
||||
|
||||
|Adapter |OS |Status |
|
||||
|----------|----------|----------|
|
||||
|inotify |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)|
|
||||
|kqueue |BSD, macOS, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)|
|
||||
|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
|
||||
|FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)|
|
||||
|FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)|
|
||||
|fanotify |Linux 2.6.37+ | |
|
||||
|USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)|
|
||||
|Polling |*All* |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)|
|
||||
|
||||
\* Android and iOS are untested.
|
||||
|
||||
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||
|
||||
## API stability
|
||||
|
||||
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||
|
||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
|
||||
|
||||
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||
|
||||
## Example
|
||||
|
||||
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
|
||||
|
||||
## FAQ
|
||||
|
||||
**When a file is moved to another directory is it still being watched?**
|
||||
|
||||
No (it shouldn't be, unless you are watching where it was moved to).
|
||||
|
||||
**When I watch a directory, are all subdirectories watched as well?**
|
||||
|
||||
No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]).
|
||||
|
||||
**Do I have to watch the Error and Event channels in a separate goroutine?**
|
||||
|
||||
As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7])
|
||||
|
||||
**Why am I receiving multiple events for the same file on OS X?**
|
||||
|
||||
Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]).
|
||||
|
||||
**How many files can be watched at once?**
|
||||
|
||||
There are OS-specific limits as to how many watches can be created:
|
||||
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
|
||||
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
||||
|
||||
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
||||
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
||||
[#7]: https://github.com/howeyc/fsnotify/issues/7
|
||||
|
||||
[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
|
||||
|
||||
## Related Projects
|
||||
|
||||
* [notify](https://github.com/rjeczalik/notify)
|
||||
* [fsevents](https://github.com/fsnotify/fsevents)
|
||||
|
37
vendor/github.com/fsnotify/fsnotify/fen.go
generated
vendored
Normal file
37
vendor/github.com/fsnotify/fsnotify/fen.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build solaris
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
return nil, errors.New("FEN based watcher not yet supported for fsnotify\n")
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
return nil
|
||||
}
|
66
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
Normal file
66
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2012 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 !plan9
|
||||
|
||||
// Package fsnotify provides a platform-independent interface for file system notifications.
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Event represents a single file system notification.
|
||||
type Event struct {
|
||||
Name string // Relative path to the file or directory.
|
||||
Op Op // File operation that triggered the event.
|
||||
}
|
||||
|
||||
// Op describes a set of file operations.
|
||||
type Op uint32
|
||||
|
||||
// These are the generalized file operations that can trigger a notification.
|
||||
const (
|
||||
Create Op = 1 << iota
|
||||
Write
|
||||
Remove
|
||||
Rename
|
||||
Chmod
|
||||
)
|
||||
|
||||
func (op Op) String() string {
|
||||
// Use a buffer for efficient string concatenation
|
||||
var buffer bytes.Buffer
|
||||
|
||||
if op&Create == Create {
|
||||
buffer.WriteString("|CREATE")
|
||||
}
|
||||
if op&Remove == Remove {
|
||||
buffer.WriteString("|REMOVE")
|
||||
}
|
||||
if op&Write == Write {
|
||||
buffer.WriteString("|WRITE")
|
||||
}
|
||||
if op&Rename == Rename {
|
||||
buffer.WriteString("|RENAME")
|
||||
}
|
||||
if op&Chmod == Chmod {
|
||||
buffer.WriteString("|CHMOD")
|
||||
}
|
||||
if buffer.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
return buffer.String()[1:] // Strip leading pipe
|
||||
}
|
||||
|
||||
// String returns a string representation of the event in the form
|
||||
// "file: REMOVE|WRITE|..."
|
||||
func (e Event) String() string {
|
||||
return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
|
||||
}
|
||||
|
||||
// Common errors that can be reported by a watcher
|
||||
var ErrEventOverflow = errors.New("fsnotify queue overflow")
|
337
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
Normal file
337
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
Normal file
|
@ -0,0 +1,337 @@
|
|||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
mu sync.Mutex // Map access
|
||||
fd int
|
||||
poller *fdPoller
|
||||
watches map[string]*watch // Map of inotify watches (key: path)
|
||||
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||
doneResp chan struct{} // Channel to respond to Close
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
// Create inotify fd
|
||||
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC)
|
||||
if fd == -1 {
|
||||
return nil, errno
|
||||
}
|
||||
// Create epoll
|
||||
poller, err := newFdPoller(fd)
|
||||
if err != nil {
|
||||
unix.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
w := &Watcher{
|
||||
fd: fd,
|
||||
poller: poller,
|
||||
watches: make(map[string]*watch),
|
||||
paths: make(map[int]string),
|
||||
Events: make(chan Event),
|
||||
Errors: make(chan error),
|
||||
done: make(chan struct{}),
|
||||
doneResp: make(chan struct{}),
|
||||
}
|
||||
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *Watcher) isClosed() bool {
|
||||
select {
|
||||
case <-w.done:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Send 'close' signal to goroutine, and set the Watcher to closed.
|
||||
close(w.done)
|
||||
|
||||
// Wake up goroutine
|
||||
w.poller.wake()
|
||||
|
||||
// Wait for goroutine to close
|
||||
<-w.doneResp
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
name = filepath.Clean(name)
|
||||
if w.isClosed() {
|
||||
return errors.New("inotify instance already closed")
|
||||
}
|
||||
|
||||
const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
|
||||
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
|
||||
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
|
||||
|
||||
var flags uint32 = agnosticEvents
|
||||
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
watchEntry := w.watches[name]
|
||||
if watchEntry != nil {
|
||||
flags |= watchEntry.flags | unix.IN_MASK_ADD
|
||||
}
|
||||
wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
|
||||
if wd == -1 {
|
||||
return errno
|
||||
}
|
||||
|
||||
if watchEntry == nil {
|
||||
w.watches[name] = &watch{wd: uint32(wd), flags: flags}
|
||||
w.paths[wd] = name
|
||||
} else {
|
||||
watchEntry.wd = uint32(wd)
|
||||
watchEntry.flags = flags
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove stops watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
name = filepath.Clean(name)
|
||||
|
||||
// Fetch the watch.
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
watch, ok := w.watches[name]
|
||||
|
||||
// Remove it from inotify.
|
||||
if !ok {
|
||||
return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
|
||||
}
|
||||
|
||||
// We successfully removed the watch if InotifyRmWatch doesn't return an
|
||||
// error, we need to clean up our internal state to ensure it matches
|
||||
// inotify's kernel state.
|
||||
delete(w.paths, int(watch.wd))
|
||||
delete(w.watches, name)
|
||||
|
||||
// inotify_rm_watch will return EINVAL if the file has been deleted;
|
||||
// the inotify will already have been removed.
|
||||
// watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
|
||||
// by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
|
||||
// so that EINVAL means that the wd is being rm_watch()ed or its file removed
|
||||
// by another thread and we have not received IN_IGNORE event.
|
||||
success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
|
||||
if success == -1 {
|
||||
// TODO: Perhaps it's not helpful to return an error here in every case.
|
||||
// the only two possible errors are:
|
||||
// EBADF, which happens when w.fd is not a valid file descriptor of any kind.
|
||||
// EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
|
||||
// Watch descriptors are invalidated when they are removed explicitly or implicitly;
|
||||
// explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
|
||||
return errno
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
}
|
||||
|
||||
// readEvents reads from the inotify file descriptor, converts the
|
||||
// received events into Event objects and sends them via the Events channel
|
||||
func (w *Watcher) readEvents() {
|
||||
var (
|
||||
buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
||||
n int // Number of bytes read with read()
|
||||
errno error // Syscall errno
|
||||
ok bool // For poller.wait
|
||||
)
|
||||
|
||||
defer close(w.doneResp)
|
||||
defer close(w.Errors)
|
||||
defer close(w.Events)
|
||||
defer unix.Close(w.fd)
|
||||
defer w.poller.close()
|
||||
|
||||
for {
|
||||
// See if we have been closed.
|
||||
if w.isClosed() {
|
||||
return
|
||||
}
|
||||
|
||||
ok, errno = w.poller.wait()
|
||||
if errno != nil {
|
||||
select {
|
||||
case w.Errors <- errno:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
n, errno = unix.Read(w.fd, buf[:])
|
||||
// If a signal interrupted execution, see if we've been asked to close, and try again.
|
||||
// http://man7.org/linux/man-pages/man7/signal.7.html :
|
||||
// "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
|
||||
if errno == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
// unix.Read might have been woken up by Close. If so, we're done.
|
||||
if w.isClosed() {
|
||||
return
|
||||
}
|
||||
|
||||
if n < unix.SizeofInotifyEvent {
|
||||
var err error
|
||||
if n == 0 {
|
||||
// If EOF is received. This should really never happen.
|
||||
err = io.EOF
|
||||
} else if n < 0 {
|
||||
// If an error occurred while reading.
|
||||
err = errno
|
||||
} else {
|
||||
// Read was too short.
|
||||
err = errors.New("notify: short read in readEvents()")
|
||||
}
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var offset uint32
|
||||
// We don't know how many events we just read into the buffer
|
||||
// While the offset points to at least one whole event...
|
||||
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
||||
// Point "raw" to the event in the buffer
|
||||
raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
||||
|
||||
mask := uint32(raw.Mask)
|
||||
nameLen := uint32(raw.Len)
|
||||
|
||||
if mask&unix.IN_Q_OVERFLOW != 0 {
|
||||
select {
|
||||
case w.Errors <- ErrEventOverflow:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If the event happened to the watched directory or the watched file, the kernel
|
||||
// doesn't append the filename to the event, but we would like to always fill the
|
||||
// the "Name" field with a valid filename. We retrieve the path of the watch from
|
||||
// the "paths" map.
|
||||
w.mu.Lock()
|
||||
name, ok := w.paths[int(raw.Wd)]
|
||||
// IN_DELETE_SELF occurs when the file/directory being watched is removed.
|
||||
// This is a sign to clean up the maps, otherwise we are no longer in sync
|
||||
// with the inotify kernel state which has already deleted the watch
|
||||
// automatically.
|
||||
if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
||||
delete(w.paths, int(raw.Wd))
|
||||
delete(w.watches, name)
|
||||
}
|
||||
w.mu.Unlock()
|
||||
|
||||
if nameLen > 0 {
|
||||
// Point "bytes" at the first byte of the filename
|
||||
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
|
||||
// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
||||
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
||||
}
|
||||
|
||||
event := newEvent(name, mask)
|
||||
|
||||
// Send the events that are not ignored on the events channel
|
||||
if !event.ignoreLinux(mask) {
|
||||
select {
|
||||
case w.Events <- event:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
offset += unix.SizeofInotifyEvent + nameLen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Certain types of events can be "ignored" and not sent over the Events
|
||||
// channel. Such as events marked ignore by the kernel, or MODIFY events
|
||||
// against files that do not exist.
|
||||
func (e *Event) ignoreLinux(mask uint32) bool {
|
||||
// Ignore anything the inotify API says to ignore
|
||||
if mask&unix.IN_IGNORED == unix.IN_IGNORED {
|
||||
return true
|
||||
}
|
||||
|
||||
// If the event is not a DELETE or RENAME, the file must exist.
|
||||
// Otherwise the event is ignored.
|
||||
// *Note*: this was put in place because it was seen that a MODIFY
|
||||
// event was sent after the DELETE. This ignores that MODIFY and
|
||||
// assumes a DELETE will come or has come if the file doesn't exist.
|
||||
if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
|
||||
_, statErr := os.Lstat(e.Name)
|
||||
return os.IsNotExist(statErr)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// newEvent returns an platform-independent Event based on an inotify mask.
|
||||
func newEvent(name string, mask uint32) Event {
|
||||
e := Event{Name: name}
|
||||
if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
||||
e.Op |= Create
|
||||
}
|
||||
if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE {
|
||||
e.Op |= Remove
|
||||
}
|
||||
if mask&unix.IN_MODIFY == unix.IN_MODIFY {
|
||||
e.Op |= Write
|
||||
}
|
||||
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
||||
e.Op |= Rename
|
||||
}
|
||||
if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
|
||||
e.Op |= Chmod
|
||||
}
|
||||
return e
|
||||
}
|
187
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
Normal file
187
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2015 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
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type fdPoller struct {
|
||||
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||
epfd int // Epoll file descriptor
|
||||
pipe [2]int // Pipe for waking up
|
||||
}
|
||||
|
||||
func emptyPoller(fd int) *fdPoller {
|
||||
poller := new(fdPoller)
|
||||
poller.fd = fd
|
||||
poller.epfd = -1
|
||||
poller.pipe[0] = -1
|
||||
poller.pipe[1] = -1
|
||||
return poller
|
||||
}
|
||||
|
||||
// Create a new inotify poller.
|
||||
// This creates an inotify handler, and an epoll handler.
|
||||
func newFdPoller(fd int) (*fdPoller, error) {
|
||||
var errno error
|
||||
poller := emptyPoller(fd)
|
||||
defer func() {
|
||||
if errno != nil {
|
||||
poller.close()
|
||||
}
|
||||
}()
|
||||
poller.fd = fd
|
||||
|
||||
// Create epoll fd
|
||||
poller.epfd, errno = unix.EpollCreate1(0)
|
||||
if poller.epfd == -1 {
|
||||
return nil, errno
|
||||
}
|
||||
// Create pipe; pipe[0] is the read end, pipe[1] the write end.
|
||||
errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
// Register inotify fd with epoll
|
||||
event := unix.EpollEvent{
|
||||
Fd: int32(poller.fd),
|
||||
Events: unix.EPOLLIN,
|
||||
}
|
||||
errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
// Register pipe fd with epoll
|
||||
event = unix.EpollEvent{
|
||||
Fd: int32(poller.pipe[0]),
|
||||
Events: unix.EPOLLIN,
|
||||
}
|
||||
errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event)
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
return poller, nil
|
||||
}
|
||||
|
||||
// Wait using epoll.
|
||||
// Returns true if something is ready to be read,
|
||||
// false if there is not.
|
||||
func (poller *fdPoller) wait() (bool, error) {
|
||||
// 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
|
||||
// I don't know whether epoll_wait returns the number of events returned,
|
||||
// or the total number of events ready.
|
||||
// I decided to catch both by making the buffer one larger than the maximum.
|
||||
events := make([]unix.EpollEvent, 7)
|
||||
for {
|
||||
n, errno := unix.EpollWait(poller.epfd, events, -1)
|
||||
if n == -1 {
|
||||
if errno == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
return false, errno
|
||||
}
|
||||
if n == 0 {
|
||||
// If there are no events, try again.
|
||||
continue
|
||||
}
|
||||
if n > 6 {
|
||||
// This should never happen. More events were returned than should be possible.
|
||||
return false, errors.New("epoll_wait returned more events than I know what to do with")
|
||||
}
|
||||
ready := events[:n]
|
||||
epollhup := false
|
||||
epollerr := false
|
||||
epollin := false
|
||||
for _, event := range ready {
|
||||
if event.Fd == int32(poller.fd) {
|
||||
if event.Events&unix.EPOLLHUP != 0 {
|
||||
// This should not happen, but if it does, treat it as a wakeup.
|
||||
epollhup = true
|
||||
}
|
||||
if event.Events&unix.EPOLLERR != 0 {
|
||||
// If an error is waiting on the file descriptor, we should pretend
|
||||
// something is ready to read, and let unix.Read pick up the error.
|
||||
epollerr = true
|
||||
}
|
||||
if event.Events&unix.EPOLLIN != 0 {
|
||||
// There is data to read.
|
||||
epollin = true
|
||||
}
|
||||
}
|
||||
if event.Fd == int32(poller.pipe[0]) {
|
||||
if event.Events&unix.EPOLLHUP != 0 {
|
||||
// Write pipe descriptor was closed, by us. This means we're closing down the
|
||||
// watcher, and we should wake up.
|
||||
}
|
||||
if event.Events&unix.EPOLLERR != 0 {
|
||||
// If an error is waiting on the pipe file descriptor.
|
||||
// This is an absolute mystery, and should never ever happen.
|
||||
return false, errors.New("Error on the pipe descriptor.")
|
||||
}
|
||||
if event.Events&unix.EPOLLIN != 0 {
|
||||
// This is a regular wakeup, so we have to clear the buffer.
|
||||
err := poller.clearWake()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if epollhup || epollerr || epollin {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Close the write end of the poller.
|
||||
func (poller *fdPoller) wake() error {
|
||||
buf := make([]byte, 1)
|
||||
n, errno := unix.Write(poller.pipe[1], buf)
|
||||
if n == -1 {
|
||||
if errno == unix.EAGAIN {
|
||||
// Buffer is full, poller will wake.
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (poller *fdPoller) clearWake() error {
|
||||
// You have to be woken up a LOT in order to get to 100!
|
||||
buf := make([]byte, 100)
|
||||
n, errno := unix.Read(poller.pipe[0], buf)
|
||||
if n == -1 {
|
||||
if errno == unix.EAGAIN {
|
||||
// Buffer is empty, someone else cleared our wake.
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close all poller file descriptors, but not the one passed to it.
|
||||
func (poller *fdPoller) close() {
|
||||
if poller.pipe[1] != -1 {
|
||||
unix.Close(poller.pipe[1])
|
||||
}
|
||||
if poller.pipe[0] != -1 {
|
||||
unix.Close(poller.pipe[0])
|
||||
}
|
||||
if poller.epfd != -1 {
|
||||
unix.Close(poller.epfd)
|
||||
}
|
||||
}
|
521
vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
Normal file
521
vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
Normal file
|
@ -0,0 +1,521 @@
|
|||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build freebsd openbsd netbsd dragonfly darwin
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||
|
||||
kq int // File descriptor (as returned by the kqueue() syscall).
|
||||
|
||||
mu sync.Mutex // Protects access to watcher data
|
||||
watches map[string]int // Map of watched file descriptors (key: path).
|
||||
externalWatches map[string]bool // Map of watches added by user of the library.
|
||||
dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue.
|
||||
paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events.
|
||||
fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events).
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
}
|
||||
|
||||
type pathInfo struct {
|
||||
name string
|
||||
isDir bool
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
kq, err := kqueue()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w := &Watcher{
|
||||
kq: kq,
|
||||
watches: make(map[string]int),
|
||||
dirFlags: make(map[string]uint32),
|
||||
paths: make(map[int]pathInfo),
|
||||
fileExists: make(map[string]bool),
|
||||
externalWatches: make(map[string]bool),
|
||||
Events: make(chan Event),
|
||||
Errors: make(chan error),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
w.mu.Lock()
|
||||
if w.isClosed {
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
|
||||
// copy paths to remove while locked
|
||||
var pathsToRemove = make([]string, 0, len(w.watches))
|
||||
for name := range w.watches {
|
||||
pathsToRemove = append(pathsToRemove, name)
|
||||
}
|
||||
w.mu.Unlock()
|
||||
// unlock before calling Remove, which also locks
|
||||
|
||||
for _, name := range pathsToRemove {
|
||||
w.Remove(name)
|
||||
}
|
||||
|
||||
// send a "quit" message to the reader goroutine
|
||||
close(w.done)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
w.mu.Lock()
|
||||
w.externalWatches[name] = true
|
||||
w.mu.Unlock()
|
||||
_, err := w.addWatch(name, noteAllEvents)
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
name = filepath.Clean(name)
|
||||
w.mu.Lock()
|
||||
watchfd, ok := w.watches[name]
|
||||
w.mu.Unlock()
|
||||
if !ok {
|
||||
return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
|
||||
}
|
||||
|
||||
const registerRemove = unix.EV_DELETE
|
||||
if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
unix.Close(watchfd)
|
||||
|
||||
w.mu.Lock()
|
||||
isDir := w.paths[watchfd].isDir
|
||||
delete(w.watches, name)
|
||||
delete(w.paths, watchfd)
|
||||
delete(w.dirFlags, name)
|
||||
w.mu.Unlock()
|
||||
|
||||
// Find all watched paths that are in this directory that are not external.
|
||||
if isDir {
|
||||
var pathsToRemove []string
|
||||
w.mu.Lock()
|
||||
for _, path := range w.paths {
|
||||
wdir, _ := filepath.Split(path.name)
|
||||
if filepath.Clean(wdir) == name {
|
||||
if !w.externalWatches[path.name] {
|
||||
pathsToRemove = append(pathsToRemove, path.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
w.mu.Unlock()
|
||||
for _, name := range pathsToRemove {
|
||||
// Since these are internal, not much sense in propagating error
|
||||
// to the user, as that will just confuse them with an error about
|
||||
// a path they did not explicitly watch themselves.
|
||||
w.Remove(name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
|
||||
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
|
||||
|
||||
// keventWaitTime to block on each read from kevent
|
||||
var keventWaitTime = durationToTimespec(100 * time.Millisecond)
|
||||
|
||||
// addWatch adds name to the watched file set.
|
||||
// The flags are interpreted as described in kevent(2).
|
||||
// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks.
|
||||
func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
|
||||
var isDir bool
|
||||
// Make ./name and name equivalent
|
||||
name = filepath.Clean(name)
|
||||
|
||||
w.mu.Lock()
|
||||
if w.isClosed {
|
||||
w.mu.Unlock()
|
||||
return "", errors.New("kevent instance already closed")
|
||||
}
|
||||
watchfd, alreadyWatching := w.watches[name]
|
||||
// We already have a watch, but we can still override flags.
|
||||
if alreadyWatching {
|
||||
isDir = w.paths[watchfd].isDir
|
||||
}
|
||||
w.mu.Unlock()
|
||||
|
||||
if !alreadyWatching {
|
||||
fi, err := os.Lstat(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Don't watch sockets.
|
||||
if fi.Mode()&os.ModeSocket == os.ModeSocket {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Don't watch named pipes.
|
||||
if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Follow Symlinks
|
||||
// Unfortunately, Linux can add bogus symlinks to watch list without
|
||||
// issue, and Windows can't do symlinks period (AFAIK). To maintain
|
||||
// consistency, we will act like everything is fine. There will simply
|
||||
// be no file events for broken symlinks.
|
||||
// Hence the returns of nil on errors.
|
||||
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
name, err = filepath.EvalSymlinks(name)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
_, alreadyWatching = w.watches[name]
|
||||
w.mu.Unlock()
|
||||
|
||||
if alreadyWatching {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
fi, err = os.Lstat(name)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
watchfd, err = unix.Open(name, openMode, 0700)
|
||||
if watchfd == -1 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
isDir = fi.IsDir()
|
||||
}
|
||||
|
||||
const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE
|
||||
if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil {
|
||||
unix.Close(watchfd)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !alreadyWatching {
|
||||
w.mu.Lock()
|
||||
w.watches[name] = watchfd
|
||||
w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
if isDir {
|
||||
// Watch the directory if it has not been watched before,
|
||||
// or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
|
||||
w.mu.Lock()
|
||||
|
||||
watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
|
||||
(!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE)
|
||||
// Store flags so this watch can be updated later
|
||||
w.dirFlags[name] = flags
|
||||
w.mu.Unlock()
|
||||
|
||||
if watchDir {
|
||||
if err := w.watchDirectoryFiles(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// readEvents reads from kqueue and converts the received kevents into
|
||||
// Event values that it sends down the Events channel.
|
||||
func (w *Watcher) readEvents() {
|
||||
eventBuffer := make([]unix.Kevent_t, 10)
|
||||
|
||||
loop:
|
||||
for {
|
||||
// See if there is a message on the "done" channel
|
||||
select {
|
||||
case <-w.done:
|
||||
break loop
|
||||
default:
|
||||
}
|
||||
|
||||
// Get new events
|
||||
kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
|
||||
// EINTR is okay, the syscall was interrupted before timeout expired.
|
||||
if err != nil && err != unix.EINTR {
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
case <-w.done:
|
||||
break loop
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Flush the events we received to the Events channel
|
||||
for len(kevents) > 0 {
|
||||
kevent := &kevents[0]
|
||||
watchfd := int(kevent.Ident)
|
||||
mask := uint32(kevent.Fflags)
|
||||
w.mu.Lock()
|
||||
path := w.paths[watchfd]
|
||||
w.mu.Unlock()
|
||||
event := newEvent(path.name, mask)
|
||||
|
||||
if path.isDir && !(event.Op&Remove == Remove) {
|
||||
// Double check to make sure the directory exists. This can happen when
|
||||
// we do a rm -fr on a recursively watched folders and we receive a
|
||||
// modification event first but the folder has been deleted and later
|
||||
// receive the delete event
|
||||
if _, err := os.Lstat(event.Name); os.IsNotExist(err) {
|
||||
// mark is as delete event
|
||||
event.Op |= Remove
|
||||
}
|
||||
}
|
||||
|
||||
if event.Op&Rename == Rename || event.Op&Remove == Remove {
|
||||
w.Remove(event.Name)
|
||||
w.mu.Lock()
|
||||
delete(w.fileExists, event.Name)
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) {
|
||||
w.sendDirectoryChangeEvents(event.Name)
|
||||
} else {
|
||||
// Send the event on the Events channel.
|
||||
select {
|
||||
case w.Events <- event:
|
||||
case <-w.done:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
if event.Op&Remove == Remove {
|
||||
// Look for a file that may have overwritten this.
|
||||
// For example, mv f1 f2 will delete f2, then create f2.
|
||||
if path.isDir {
|
||||
fileDir := filepath.Clean(event.Name)
|
||||
w.mu.Lock()
|
||||
_, found := w.watches[fileDir]
|
||||
w.mu.Unlock()
|
||||
if found {
|
||||
// make sure the directory exists before we watch for changes. When we
|
||||
// do a recursive watch and perform rm -fr, the parent directory might
|
||||
// have gone missing, ignore the missing directory and let the
|
||||
// upcoming delete event remove the watch from the parent directory.
|
||||
if _, err := os.Lstat(fileDir); err == nil {
|
||||
w.sendDirectoryChangeEvents(fileDir)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filePath := filepath.Clean(event.Name)
|
||||
if fileInfo, err := os.Lstat(filePath); err == nil {
|
||||
w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move to next event
|
||||
kevents = kevents[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup
|
||||
err := unix.Close(w.kq)
|
||||
if err != nil {
|
||||
// only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors.
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
default:
|
||||
}
|
||||
}
|
||||
close(w.Events)
|
||||
close(w.Errors)
|
||||
}
|
||||
|
||||
// newEvent returns an platform-independent Event based on kqueue Fflags.
|
||||
func newEvent(name string, mask uint32) Event {
|
||||
e := Event{Name: name}
|
||||
if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
|
||||
e.Op |= Remove
|
||||
}
|
||||
if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
|
||||
e.Op |= Write
|
||||
}
|
||||
if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
|
||||
e.Op |= Rename
|
||||
}
|
||||
if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
|
||||
e.Op |= Chmod
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func newCreateEvent(name string) Event {
|
||||
return Event{Name: name, Op: Create}
|
||||
}
|
||||
|
||||
// watchDirectoryFiles to mimic inotify when adding a watch on a directory
|
||||
func (w *Watcher) watchDirectoryFiles(dirPath string) error {
|
||||
// Get all files
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, fileInfo := range files {
|
||||
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||
filePath, err = w.internalWatch(filePath, fileInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
w.fileExists[filePath] = true
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendDirectoryEvents searches the directory for newly created files
|
||||
// and sends them over the event channel. This functionality is to have
|
||||
// the BSD version of fsnotify match Linux inotify which provides a
|
||||
// create event for files created in a watched directory.
|
||||
func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
|
||||
// Get all files
|
||||
files, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Search for new files
|
||||
for _, fileInfo := range files {
|
||||
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||
err := w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sendFileCreatedEvent sends a create event if the file isn't already being tracked.
|
||||
func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) {
|
||||
w.mu.Lock()
|
||||
_, doesExist := w.fileExists[filePath]
|
||||
w.mu.Unlock()
|
||||
if !doesExist {
|
||||
// Send create event
|
||||
select {
|
||||
case w.Events <- newCreateEvent(filePath):
|
||||
case <-w.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// like watchDirectoryFiles (but without doing another ReadDir)
|
||||
filePath, err = w.internalWatch(filePath, fileInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.mu.Lock()
|
||||
w.fileExists[filePath] = true
|
||||
w.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) {
|
||||
if fileInfo.IsDir() {
|
||||
// mimic Linux providing delete events for subdirectories
|
||||
// but preserve the flags used if currently watching subdirectory
|
||||
w.mu.Lock()
|
||||
flags := w.dirFlags[name]
|
||||
w.mu.Unlock()
|
||||
|
||||
flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
|
||||
return w.addWatch(name, flags)
|
||||
}
|
||||
|
||||
// watch file to mimic Linux inotify
|
||||
return w.addWatch(name, noteAllEvents)
|
||||
}
|
||||
|
||||
// kqueue creates a new kernel event queue and returns a descriptor.
|
||||
func kqueue() (kq int, err error) {
|
||||
kq, err = unix.Kqueue()
|
||||
if kq == -1 {
|
||||
return kq, err
|
||||
}
|
||||
return kq, nil
|
||||
}
|
||||
|
||||
// register events with the queue
|
||||
func register(kq int, fds []int, flags int, fflags uint32) error {
|
||||
changes := make([]unix.Kevent_t, len(fds))
|
||||
|
||||
for i, fd := range fds {
|
||||
// SetKevent converts int to the platform-specific types:
|
||||
unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
|
||||
changes[i].Fflags = fflags
|
||||
}
|
||||
|
||||
// register the events
|
||||
success, err := unix.Kevent(kq, changes, nil, nil)
|
||||
if success == -1 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// read retrieves pending events, or waits until an event occurs.
|
||||
// A timeout of nil blocks indefinitely, while 0 polls the queue.
|
||||
func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) {
|
||||
n, err := unix.Kevent(kq, nil, events, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return events[0:n], nil
|
||||
}
|
||||
|
||||
// durationToTimespec prepares a timeout value
|
||||
func durationToTimespec(d time.Duration) unix.Timespec {
|
||||
return unix.NsecToTimespec(d.Nanoseconds())
|
||||
}
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build dragonfly freebsd netbsd openbsd
|
||||
// +build freebsd openbsd netbsd dragonfly
|
||||
|
||||
package unix
|
||||
package fsnotify
|
||||
|
||||
const ImplementsGetwd = false
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func Getwd() (string, error) { return "", ENOTSUP }
|
||||
const openMode = unix.O_NONBLOCK | unix.O_RDONLY
|
12
vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
generated
vendored
Normal file
12
vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
// 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 darwin
|
||||
|
||||
package fsnotify
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// note: this constant is not defined on BSD
|
||||
const openMode = unix.O_EVTONLY
|
561
vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
Normal file
561
vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
Normal file
|
@ -0,0 +1,561 @@
|
|||
// 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
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct {
|
||||
Events chan Event
|
||||
Errors chan error
|
||||
isClosed bool // Set to true when Close() is first called
|
||||
mu sync.Mutex // Map access
|
||||
port syscall.Handle // Handle to completion port
|
||||
watches watchMap // Map of watches (key: i-number)
|
||||
input chan *input // Inputs to the reader are sent on this channel
|
||||
quit chan chan<- error
|
||||
}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
|
||||
if e != nil {
|
||||
return nil, os.NewSyscallError("CreateIoCompletionPort", e)
|
||||
}
|
||||
w := &Watcher{
|
||||
port: port,
|
||||
watches: make(watchMap),
|
||||
input: make(chan *input, 1),
|
||||
Events: make(chan Event, 50),
|
||||
Errors: make(chan error),
|
||||
quit: make(chan chan<- error, 1),
|
||||
}
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
if w.isClosed {
|
||||
return nil
|
||||
}
|
||||
w.isClosed = true
|
||||
|
||||
// Send "quit" message to the reader goroutine
|
||||
ch := make(chan error)
|
||||
w.quit <- ch
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-ch
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
if w.isClosed {
|
||||
return errors.New("watcher already closed")
|
||||
}
|
||||
in := &input{
|
||||
op: opAddWatch,
|
||||
path: filepath.Clean(name),
|
||||
flags: sysFSALLEVENTS,
|
||||
reply: make(chan error),
|
||||
}
|
||||
w.input <- in
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-in.reply
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
in := &input{
|
||||
op: opRemoveWatch,
|
||||
path: filepath.Clean(name),
|
||||
reply: make(chan error),
|
||||
}
|
||||
w.input <- in
|
||||
if err := w.wakeupReader(); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-in.reply
|
||||
}
|
||||
|
||||
const (
|
||||
// Options for AddWatch
|
||||
sysFSONESHOT = 0x80000000
|
||||
sysFSONLYDIR = 0x1000000
|
||||
|
||||
// Events
|
||||
sysFSACCESS = 0x1
|
||||
sysFSALLEVENTS = 0xfff
|
||||
sysFSATTRIB = 0x4
|
||||
sysFSCLOSE = 0x18
|
||||
sysFSCREATE = 0x100
|
||||
sysFSDELETE = 0x200
|
||||
sysFSDELETESELF = 0x400
|
||||
sysFSMODIFY = 0x2
|
||||
sysFSMOVE = 0xc0
|
||||
sysFSMOVEDFROM = 0x40
|
||||
sysFSMOVEDTO = 0x80
|
||||
sysFSMOVESELF = 0x800
|
||||
|
||||
// Special events
|
||||
sysFSIGNORED = 0x8000
|
||||
sysFSQOVERFLOW = 0x4000
|
||||
)
|
||||
|
||||
func newEvent(name string, mask uint32) Event {
|
||||
e := Event{Name: name}
|
||||
if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
|
||||
e.Op |= Create
|
||||
}
|
||||
if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF {
|
||||
e.Op |= Remove
|
||||
}
|
||||
if mask&sysFSMODIFY == sysFSMODIFY {
|
||||
e.Op |= Write
|
||||
}
|
||||
if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
|
||||
e.Op |= Rename
|
||||
}
|
||||
if mask&sysFSATTRIB == sysFSATTRIB {
|
||||
e.Op |= Chmod
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
const (
|
||||
opAddWatch = iota
|
||||
opRemoveWatch
|
||||
)
|
||||
|
||||
const (
|
||||
provisional uint64 = 1 << (32 + iota)
|
||||
)
|
||||
|
||||
type input struct {
|
||||
op int
|
||||
path string
|
||||
flags uint32
|
||||
reply chan error
|
||||
}
|
||||
|
||||
type inode struct {
|
||||
handle syscall.Handle
|
||||
volume uint32
|
||||
index uint64
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
ov syscall.Overlapped
|
||||
ino *inode // i-number
|
||||
path string // Directory path
|
||||
mask uint64 // Directory itself is being watched with these notify flags
|
||||
names map[string]uint64 // Map of names being watched and their notify flags
|
||||
rename string // Remembers the old name while renaming a file
|
||||
buf [4096]byte
|
||||
}
|
||||
|
||||
type indexMap map[uint64]*watch
|
||||
type watchMap map[uint32]indexMap
|
||||
|
||||
func (w *Watcher) wakeupReader() error {
|
||||
e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
||||
if e != nil {
|
||||
return os.NewSyscallError("PostQueuedCompletionStatus", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDir(pathname string) (dir string, err error) {
|
||||
attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
|
||||
if e != nil {
|
||||
return "", os.NewSyscallError("GetFileAttributes", e)
|
||||
}
|
||||
if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||
dir = pathname
|
||||
} else {
|
||||
dir, _ = filepath.Split(pathname)
|
||||
dir = filepath.Clean(dir)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getIno(path string) (ino *inode, err error) {
|
||||
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
|
||||
syscall.FILE_LIST_DIRECTORY,
|
||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||
nil, syscall.OPEN_EXISTING,
|
||||
syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
|
||||
if e != nil {
|
||||
return nil, os.NewSyscallError("CreateFile", e)
|
||||
}
|
||||
var fi syscall.ByHandleFileInformation
|
||||
if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
|
||||
syscall.CloseHandle(h)
|
||||
return nil, os.NewSyscallError("GetFileInformationByHandle", e)
|
||||
}
|
||||
ino = &inode{
|
||||
handle: h,
|
||||
volume: fi.VolumeSerialNumber,
|
||||
index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
|
||||
}
|
||||
return ino, nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (m watchMap) get(ino *inode) *watch {
|
||||
if i := m[ino.volume]; i != nil {
|
||||
return i[ino.index]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (m watchMap) set(ino *inode, watch *watch) {
|
||||
i := m[ino.volume]
|
||||
if i == nil {
|
||||
i = make(indexMap)
|
||||
m[ino.volume] = i
|
||||
}
|
||||
i[ino.index] = watch
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) addWatch(pathname string, flags uint64) error {
|
||||
dir, err := getDir(pathname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if flags&sysFSONLYDIR != 0 && pathname != dir {
|
||||
return nil
|
||||
}
|
||||
ino, err := getIno(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.mu.Lock()
|
||||
watchEntry := w.watches.get(ino)
|
||||
w.mu.Unlock()
|
||||
if watchEntry == nil {
|
||||
if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
|
||||
syscall.CloseHandle(ino.handle)
|
||||
return os.NewSyscallError("CreateIoCompletionPort", e)
|
||||
}
|
||||
watchEntry = &watch{
|
||||
ino: ino,
|
||||
path: dir,
|
||||
names: make(map[string]uint64),
|
||||
}
|
||||
w.mu.Lock()
|
||||
w.watches.set(ino, watchEntry)
|
||||
w.mu.Unlock()
|
||||
flags |= provisional
|
||||
} else {
|
||||
syscall.CloseHandle(ino.handle)
|
||||
}
|
||||
if pathname == dir {
|
||||
watchEntry.mask |= flags
|
||||
} else {
|
||||
watchEntry.names[filepath.Base(pathname)] |= flags
|
||||
}
|
||||
if err = w.startRead(watchEntry); err != nil {
|
||||
return err
|
||||
}
|
||||
if pathname == dir {
|
||||
watchEntry.mask &= ^provisional
|
||||
} else {
|
||||
watchEntry.names[filepath.Base(pathname)] &= ^provisional
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) remWatch(pathname string) error {
|
||||
dir, err := getDir(pathname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ino, err := getIno(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.mu.Lock()
|
||||
watch := w.watches.get(ino)
|
||||
w.mu.Unlock()
|
||||
if watch == nil {
|
||||
return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
|
||||
}
|
||||
if pathname == dir {
|
||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||
watch.mask = 0
|
||||
} else {
|
||||
name := filepath.Base(pathname)
|
||||
w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
|
||||
delete(watch.names, name)
|
||||
}
|
||||
return w.startRead(watch)
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) deleteWatch(watch *watch) {
|
||||
for name, mask := range watch.names {
|
||||
if mask&provisional == 0 {
|
||||
w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
|
||||
}
|
||||
delete(watch.names, name)
|
||||
}
|
||||
if watch.mask != 0 {
|
||||
if watch.mask&provisional == 0 {
|
||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||
}
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) startRead(watch *watch) error {
|
||||
if e := syscall.CancelIo(watch.ino.handle); e != nil {
|
||||
w.Errors <- os.NewSyscallError("CancelIo", e)
|
||||
w.deleteWatch(watch)
|
||||
}
|
||||
mask := toWindowsFlags(watch.mask)
|
||||
for _, m := range watch.names {
|
||||
mask |= toWindowsFlags(m)
|
||||
}
|
||||
if mask == 0 {
|
||||
if e := syscall.CloseHandle(watch.ino.handle); e != nil {
|
||||
w.Errors <- os.NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
w.mu.Lock()
|
||||
delete(w.watches[watch.ino.volume], watch.ino.index)
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
|
||||
uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
|
||||
if e != nil {
|
||||
err := os.NewSyscallError("ReadDirectoryChanges", e)
|
||||
if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
||||
// Watched directory was probably removed
|
||||
if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) {
|
||||
if watch.mask&sysFSONESHOT != 0 {
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readEvents reads from the I/O completion port, converts the
|
||||
// received events into Event objects and sends them via the Events channel.
|
||||
// Entry point to the I/O thread.
|
||||
func (w *Watcher) readEvents() {
|
||||
var (
|
||||
n, key uint32
|
||||
ov *syscall.Overlapped
|
||||
)
|
||||
runtime.LockOSThread()
|
||||
|
||||
for {
|
||||
e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
|
||||
watch := (*watch)(unsafe.Pointer(ov))
|
||||
|
||||
if watch == nil {
|
||||
select {
|
||||
case ch := <-w.quit:
|
||||
w.mu.Lock()
|
||||
var indexes []indexMap
|
||||
for _, index := range w.watches {
|
||||
indexes = append(indexes, index)
|
||||
}
|
||||
w.mu.Unlock()
|
||||
for _, index := range indexes {
|
||||
for _, watch := range index {
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if e := syscall.CloseHandle(w.port); e != nil {
|
||||
err = os.NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
close(w.Events)
|
||||
close(w.Errors)
|
||||
ch <- err
|
||||
return
|
||||
case in := <-w.input:
|
||||
switch in.op {
|
||||
case opAddWatch:
|
||||
in.reply <- w.addWatch(in.path, uint64(in.flags))
|
||||
case opRemoveWatch:
|
||||
in.reply <- w.remWatch(in.path)
|
||||
}
|
||||
default:
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch e {
|
||||
case syscall.ERROR_MORE_DATA:
|
||||
if watch == nil {
|
||||
w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
|
||||
} else {
|
||||
// The i/o succeeded but the buffer is full.
|
||||
// In theory we should be building up a full packet.
|
||||
// In practice we can get away with just carrying on.
|
||||
n = uint32(unsafe.Sizeof(watch.buf))
|
||||
}
|
||||
case syscall.ERROR_ACCESS_DENIED:
|
||||
// Watched directory was probably removed
|
||||
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
continue
|
||||
case syscall.ERROR_OPERATION_ABORTED:
|
||||
// CancelIo was called on this handle
|
||||
continue
|
||||
default:
|
||||
w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
|
||||
continue
|
||||
case nil:
|
||||
}
|
||||
|
||||
var offset uint32
|
||||
for {
|
||||
if n == 0 {
|
||||
w.Events <- newEvent("", sysFSQOVERFLOW)
|
||||
w.Errors <- errors.New("short read in readEvents()")
|
||||
break
|
||||
}
|
||||
|
||||
// Point "raw" to the event in the buffer
|
||||
raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
|
||||
buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
|
||||
name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
|
||||
fullname := filepath.Join(watch.path, name)
|
||||
|
||||
var mask uint64
|
||||
switch raw.Action {
|
||||
case syscall.FILE_ACTION_REMOVED:
|
||||
mask = sysFSDELETESELF
|
||||
case syscall.FILE_ACTION_MODIFIED:
|
||||
mask = sysFSMODIFY
|
||||
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||
watch.rename = name
|
||||
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||
if watch.names[watch.rename] != 0 {
|
||||
watch.names[name] |= watch.names[watch.rename]
|
||||
delete(watch.names, watch.rename)
|
||||
mask = sysFSMOVESELF
|
||||
}
|
||||
}
|
||||
|
||||
sendNameEvent := func() {
|
||||
if w.sendEvent(fullname, watch.names[name]&mask) {
|
||||
if watch.names[name]&sysFSONESHOT != 0 {
|
||||
delete(watch.names, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
sendNameEvent()
|
||||
}
|
||||
if raw.Action == syscall.FILE_ACTION_REMOVED {
|
||||
w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
|
||||
delete(watch.names, name)
|
||||
}
|
||||
if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
|
||||
if watch.mask&sysFSONESHOT != 0 {
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
fullname = filepath.Join(watch.path, watch.rename)
|
||||
sendNameEvent()
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
if raw.NextEntryOffset == 0 {
|
||||
break
|
||||
}
|
||||
offset += raw.NextEntryOffset
|
||||
|
||||
// Error!
|
||||
if offset >= n {
|
||||
w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := w.startRead(watch); err != nil {
|
||||
w.Errors <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
||||
if mask == 0 {
|
||||
return false
|
||||
}
|
||||
event := newEvent(name, uint32(mask))
|
||||
select {
|
||||
case ch := <-w.quit:
|
||||
w.quit <- ch
|
||||
case w.Events <- event:
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func toWindowsFlags(mask uint64) uint32 {
|
||||
var m uint32
|
||||
if mask&sysFSACCESS != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
|
||||
}
|
||||
if mask&sysFSMODIFY != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||
}
|
||||
if mask&sysFSATTRIB != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
|
||||
}
|
||||
if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
|
||||
m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func toFSnotifyFlags(action uint32) uint64 {
|
||||
switch action {
|
||||
case syscall.FILE_ACTION_ADDED:
|
||||
return sysFSCREATE
|
||||
case syscall.FILE_ACTION_REMOVED:
|
||||
return sysFSDELETE
|
||||
case syscall.FILE_ACTION_MODIFIED:
|
||||
return sysFSMODIFY
|
||||
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||
return sysFSMOVEDFROM
|
||||
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||
return sysFSMOVEDTO
|
||||
}
|
||||
return 0
|
||||
}
|
77
vendor/github.com/golang/snappy/cmd/snappytool/main.cpp
generated
vendored
77
vendor/github.com/golang/snappy/cmd/snappytool/main.cpp
generated
vendored
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
To build the snappytool binary:
|
||||
g++ main.cpp /usr/lib/libsnappy.a -o snappytool
|
||||
or, if you have built the C++ snappy library from source:
|
||||
g++ main.cpp /path/to/your/snappy/.libs/libsnappy.a -o snappytool
|
||||
after running "make" from your snappy checkout directory.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "snappy.h"
|
||||
|
||||
#define N 1000000
|
||||
|
||||
char dst[N];
|
||||
char src[N];
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Parse args.
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "exactly one of -d or -e must be given\n");
|
||||
return 1;
|
||||
}
|
||||
bool decode = strcmp(argv[1], "-d") == 0;
|
||||
bool encode = strcmp(argv[1], "-e") == 0;
|
||||
if (decode == encode) {
|
||||
fprintf(stderr, "exactly one of -d or -e must be given\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read all of stdin into src[:s].
|
||||
size_t s = 0;
|
||||
while (1) {
|
||||
if (s == N) {
|
||||
fprintf(stderr, "input too large\n");
|
||||
return 1;
|
||||
}
|
||||
ssize_t n = read(0, src+s, N-s);
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "read error: %s\n", strerror(errno));
|
||||
// TODO: handle EAGAIN, EINTR?
|
||||
return 1;
|
||||
}
|
||||
s += n;
|
||||
}
|
||||
|
||||
// Encode or decode src[:s] to dst[:d], and write to stdout.
|
||||
size_t d = 0;
|
||||
if (encode) {
|
||||
if (N < snappy::MaxCompressedLength(s)) {
|
||||
fprintf(stderr, "input too large after encoding\n");
|
||||
return 1;
|
||||
}
|
||||
snappy::RawCompress(src, s, dst, &d);
|
||||
} else {
|
||||
if (!snappy::GetUncompressedLength(src, s, &d)) {
|
||||
fprintf(stderr, "could not get uncompressed length\n");
|
||||
return 1;
|
||||
}
|
||||
if (N < d) {
|
||||
fprintf(stderr, "input too large after decoding\n");
|
||||
return 1;
|
||||
}
|
||||
if (!snappy::RawUncompress(src, s, dst)) {
|
||||
fprintf(stderr, "input was not valid Snappy-compressed data\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
write(1, dst, d);
|
||||
return 0;
|
||||
}
|
1965
vendor/github.com/golang/snappy/golden_test.go
generated
vendored
1965
vendor/github.com/golang/snappy/golden_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
1353
vendor/github.com/golang/snappy/snappy_test.go
generated
vendored
1353
vendor/github.com/golang/snappy/snappy_test.go
generated
vendored
File diff suppressed because it is too large
Load diff
396
vendor/github.com/golang/snappy/testdata/Mark.Twain-Tom.Sawyer.txt
generated
vendored
396
vendor/github.com/golang/snappy/testdata/Mark.Twain-Tom.Sawyer.txt
generated
vendored
|
@ -1,396 +0,0 @@
|
|||
Produced by David Widger. The previous edition was updated by Jose
|
||||
Menendez.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
THE ADVENTURES OF TOM SAWYER
|
||||
BY
|
||||
MARK TWAIN
|
||||
(Samuel Langhorne Clemens)
|
||||
|
||||
|
||||
|
||||
|
||||
P R E F A C E
|
||||
|
||||
MOST of the adventures recorded in this book really occurred; one or
|
||||
two were experiences of my own, the rest those of boys who were
|
||||
schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but
|
||||
not from an individual--he is a combination of the characteristics of
|
||||
three boys whom I knew, and therefore belongs to the composite order of
|
||||
architecture.
|
||||
|
||||
The odd superstitions touched upon were all prevalent among children
|
||||
and slaves in the West at the period of this story--that is to say,
|
||||
thirty or forty years ago.
|
||||
|
||||
Although my book is intended mainly for the entertainment of boys and
|
||||
girls, I hope it will not be shunned by men and women on that account,
|
||||
for part of my plan has been to try to pleasantly remind adults of what
|
||||
they once were themselves, and of how they felt and thought and talked,
|
||||
and what queer enterprises they sometimes engaged in.
|
||||
|
||||
THE AUTHOR.
|
||||
|
||||
HARTFORD, 1876.
|
||||
|
||||
|
||||
|
||||
T O M S A W Y E R
|
||||
|
||||
|
||||
|
||||
CHAPTER I
|
||||
|
||||
"TOM!"
|
||||
|
||||
No answer.
|
||||
|
||||
"TOM!"
|
||||
|
||||
No answer.
|
||||
|
||||
"What's gone with that boy, I wonder? You TOM!"
|
||||
|
||||
No answer.
|
||||
|
||||
The old lady pulled her spectacles down and looked over them about the
|
||||
room; then she put them up and looked out under them. She seldom or
|
||||
never looked THROUGH them for so small a thing as a boy; they were her
|
||||
state pair, the pride of her heart, and were built for "style," not
|
||||
service--she could have seen through a pair of stove-lids just as well.
|
||||
She looked perplexed for a moment, and then said, not fiercely, but
|
||||
still loud enough for the furniture to hear:
|
||||
|
||||
"Well, I lay if I get hold of you I'll--"
|
||||
|
||||
She did not finish, for by this time she was bending down and punching
|
||||
under the bed with the broom, and so she needed breath to punctuate the
|
||||
punches with. She resurrected nothing but the cat.
|
||||
|
||||
"I never did see the beat of that boy!"
|
||||
|
||||
She went to the open door and stood in it and looked out among the
|
||||
tomato vines and "jimpson" weeds that constituted the garden. No Tom.
|
||||
So she lifted up her voice at an angle calculated for distance and
|
||||
shouted:
|
||||
|
||||
"Y-o-u-u TOM!"
|
||||
|
||||
There was a slight noise behind her and she turned just in time to
|
||||
seize a small boy by the slack of his roundabout and arrest his flight.
|
||||
|
||||
"There! I might 'a' thought of that closet. What you been doing in
|
||||
there?"
|
||||
|
||||
"Nothing."
|
||||
|
||||
"Nothing! Look at your hands. And look at your mouth. What IS that
|
||||
truck?"
|
||||
|
||||
"I don't know, aunt."
|
||||
|
||||
"Well, I know. It's jam--that's what it is. Forty times I've said if
|
||||
you didn't let that jam alone I'd skin you. Hand me that switch."
|
||||
|
||||
The switch hovered in the air--the peril was desperate--
|
||||
|
||||
"My! Look behind you, aunt!"
|
||||
|
||||
The old lady whirled round, and snatched her skirts out of danger. The
|
||||
lad fled on the instant, scrambled up the high board-fence, and
|
||||
disappeared over it.
|
||||
|
||||
His aunt Polly stood surprised a moment, and then broke into a gentle
|
||||
laugh.
|
||||
|
||||
"Hang the boy, can't I never learn anything? Ain't he played me tricks
|
||||
enough like that for me to be looking out for him by this time? But old
|
||||
fools is the biggest fools there is. Can't learn an old dog new tricks,
|
||||
as the saying is. But my goodness, he never plays them alike, two days,
|
||||
and how is a body to know what's coming? He 'pears to know just how
|
||||
long he can torment me before I get my dander up, and he knows if he
|
||||
can make out to put me off for a minute or make me laugh, it's all down
|
||||
again and I can't hit him a lick. I ain't doing my duty by that boy,
|
||||
and that's the Lord's truth, goodness knows. Spare the rod and spile
|
||||
the child, as the Good Book says. I'm a laying up sin and suffering for
|
||||
us both, I know. He's full of the Old Scratch, but laws-a-me! he's my
|
||||
own dead sister's boy, poor thing, and I ain't got the heart to lash
|
||||
him, somehow. Every time I let him off, my conscience does hurt me so,
|
||||
and every time I hit him my old heart most breaks. Well-a-well, man
|
||||
that is born of woman is of few days and full of trouble, as the
|
||||
Scripture says, and I reckon it's so. He'll play hookey this evening, *
|
||||
and [* Southwestern for "afternoon"] I'll just be obleeged to make him
|
||||
work, to-morrow, to punish him. It's mighty hard to make him work
|
||||
Saturdays, when all the boys is having holiday, but he hates work more
|
||||
than he hates anything else, and I've GOT to do some of my duty by him,
|
||||
or I'll be the ruination of the child."
|
||||
|
||||
Tom did play hookey, and he had a very good time. He got back home
|
||||
barely in season to help Jim, the small colored boy, saw next-day's
|
||||
wood and split the kindlings before supper--at least he was there in
|
||||
time to tell his adventures to Jim while Jim did three-fourths of the
|
||||
work. Tom's younger brother (or rather half-brother) Sid was already
|
||||
through with his part of the work (picking up chips), for he was a
|
||||
quiet boy, and had no adventurous, troublesome ways.
|
||||
|
||||
While Tom was eating his supper, and stealing sugar as opportunity
|
||||
offered, Aunt Polly asked him questions that were full of guile, and
|
||||
very deep--for she wanted to trap him into damaging revealments. Like
|
||||
many other simple-hearted souls, it was her pet vanity to believe she
|
||||
was endowed with a talent for dark and mysterious diplomacy, and she
|
||||
loved to contemplate her most transparent devices as marvels of low
|
||||
cunning. Said she:
|
||||
|
||||
"Tom, it was middling warm in school, warn't it?"
|
||||
|
||||
"Yes'm."
|
||||
|
||||
"Powerful warm, warn't it?"
|
||||
|
||||
"Yes'm."
|
||||
|
||||
"Didn't you want to go in a-swimming, Tom?"
|
||||
|
||||
A bit of a scare shot through Tom--a touch of uncomfortable suspicion.
|
||||
He searched Aunt Polly's face, but it told him nothing. So he said:
|
||||
|
||||
"No'm--well, not very much."
|
||||
|
||||
The old lady reached out her hand and felt Tom's shirt, and said:
|
||||
|
||||
"But you ain't too warm now, though." And it flattered her to reflect
|
||||
that she had discovered that the shirt was dry without anybody knowing
|
||||
that that was what she had in her mind. But in spite of her, Tom knew
|
||||
where the wind lay, now. So he forestalled what might be the next move:
|
||||
|
||||
"Some of us pumped on our heads--mine's damp yet. See?"
|
||||
|
||||
Aunt Polly was vexed to think she had overlooked that bit of
|
||||
circumstantial evidence, and missed a trick. Then she had a new
|
||||
inspiration:
|
||||
|
||||
"Tom, you didn't have to undo your shirt collar where I sewed it, to
|
||||
pump on your head, did you? Unbutton your jacket!"
|
||||
|
||||
The trouble vanished out of Tom's face. He opened his jacket. His
|
||||
shirt collar was securely sewed.
|
||||
|
||||
"Bother! Well, go 'long with you. I'd made sure you'd played hookey
|
||||
and been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a
|
||||
singed cat, as the saying is--better'n you look. THIS time."
|
||||
|
||||
She was half sorry her sagacity had miscarried, and half glad that Tom
|
||||
had stumbled into obedient conduct for once.
|
||||
|
||||
But Sidney said:
|
||||
|
||||
"Well, now, if I didn't think you sewed his collar with white thread,
|
||||
but it's black."
|
||||
|
||||
"Why, I did sew it with white! Tom!"
|
||||
|
||||
But Tom did not wait for the rest. As he went out at the door he said:
|
||||
|
||||
"Siddy, I'll lick you for that."
|
||||
|
||||
In a safe place Tom examined two large needles which were thrust into
|
||||
the lapels of his jacket, and had thread bound about them--one needle
|
||||
carried white thread and the other black. He said:
|
||||
|
||||
"She'd never noticed if it hadn't been for Sid. Confound it! sometimes
|
||||
she sews it with white, and sometimes she sews it with black. I wish to
|
||||
geeminy she'd stick to one or t'other--I can't keep the run of 'em. But
|
||||
I bet you I'll lam Sid for that. I'll learn him!"
|
||||
|
||||
He was not the Model Boy of the village. He knew the model boy very
|
||||
well though--and loathed him.
|
||||
|
||||
Within two minutes, or even less, he had forgotten all his troubles.
|
||||
Not because his troubles were one whit less heavy and bitter to him
|
||||
than a man's are to a man, but because a new and powerful interest bore
|
||||
them down and drove them out of his mind for the time--just as men's
|
||||
misfortunes are forgotten in the excitement of new enterprises. This
|
||||
new interest was a valued novelty in whistling, which he had just
|
||||
acquired from a negro, and he was suffering to practise it undisturbed.
|
||||
It consisted in a peculiar bird-like turn, a sort of liquid warble,
|
||||
produced by touching the tongue to the roof of the mouth at short
|
||||
intervals in the midst of the music--the reader probably remembers how
|
||||
to do it, if he has ever been a boy. Diligence and attention soon gave
|
||||
him the knack of it, and he strode down the street with his mouth full
|
||||
of harmony and his soul full of gratitude. He felt much as an
|
||||
astronomer feels who has discovered a new planet--no doubt, as far as
|
||||
strong, deep, unalloyed pleasure is concerned, the advantage was with
|
||||
the boy, not the astronomer.
|
||||
|
||||
The summer evenings were long. It was not dark, yet. Presently Tom
|
||||
checked his whistle. A stranger was before him--a boy a shade larger
|
||||
than himself. A new-comer of any age or either sex was an impressive
|
||||
curiosity in the poor little shabby village of St. Petersburg. This boy
|
||||
was well dressed, too--well dressed on a week-day. This was simply
|
||||
astounding. His cap was a dainty thing, his close-buttoned blue cloth
|
||||
roundabout was new and natty, and so were his pantaloons. He had shoes
|
||||
on--and it was only Friday. He even wore a necktie, a bright bit of
|
||||
ribbon. He had a citified air about him that ate into Tom's vitals. The
|
||||
more Tom stared at the splendid marvel, the higher he turned up his
|
||||
nose at his finery and the shabbier and shabbier his own outfit seemed
|
||||
to him to grow. Neither boy spoke. If one moved, the other moved--but
|
||||
only sidewise, in a circle; they kept face to face and eye to eye all
|
||||
the time. Finally Tom said:
|
||||
|
||||
"I can lick you!"
|
||||
|
||||
"I'd like to see you try it."
|
||||
|
||||
"Well, I can do it."
|
||||
|
||||
"No you can't, either."
|
||||
|
||||
"Yes I can."
|
||||
|
||||
"No you can't."
|
||||
|
||||
"I can."
|
||||
|
||||
"You can't."
|
||||
|
||||
"Can!"
|
||||
|
||||
"Can't!"
|
||||
|
||||
An uncomfortable pause. Then Tom said:
|
||||
|
||||
"What's your name?"
|
||||
|
||||
"'Tisn't any of your business, maybe."
|
||||
|
||||
"Well I 'low I'll MAKE it my business."
|
||||
|
||||
"Well why don't you?"
|
||||
|
||||
"If you say much, I will."
|
||||
|
||||
"Much--much--MUCH. There now."
|
||||
|
||||
"Oh, you think you're mighty smart, DON'T you? I could lick you with
|
||||
one hand tied behind me, if I wanted to."
|
||||
|
||||
"Well why don't you DO it? You SAY you can do it."
|
||||
|
||||
"Well I WILL, if you fool with me."
|
||||
|
||||
"Oh yes--I've seen whole families in the same fix."
|
||||
|
||||
"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!"
|
||||
|
||||
"You can lump that hat if you don't like it. I dare you to knock it
|
||||
off--and anybody that'll take a dare will suck eggs."
|
||||
|
||||
"You're a liar!"
|
||||
|
||||
"You're another."
|
||||
|
||||
"You're a fighting liar and dasn't take it up."
|
||||
|
||||
"Aw--take a walk!"
|
||||
|
||||
"Say--if you give me much more of your sass I'll take and bounce a
|
||||
rock off'n your head."
|
||||
|
||||
"Oh, of COURSE you will."
|
||||
|
||||
"Well I WILL."
|
||||
|
||||
"Well why don't you DO it then? What do you keep SAYING you will for?
|
||||
Why don't you DO it? It's because you're afraid."
|
||||
|
||||
"I AIN'T afraid."
|
||||
|
||||
"You are."
|
||||
|
||||
"I ain't."
|
||||
|
||||
"You are."
|
||||
|
||||
Another pause, and more eying and sidling around each other. Presently
|
||||
they were shoulder to shoulder. Tom said:
|
||||
|
||||
"Get away from here!"
|
||||
|
||||
"Go away yourself!"
|
||||
|
||||
"I won't."
|
||||
|
||||
"I won't either."
|
||||
|
||||
So they stood, each with a foot placed at an angle as a brace, and
|
||||
both shoving with might and main, and glowering at each other with
|
||||
hate. But neither could get an advantage. After struggling till both
|
||||
were hot and flushed, each relaxed his strain with watchful caution,
|
||||
and Tom said:
|
||||
|
||||
"You're a coward and a pup. I'll tell my big brother on you, and he
|
||||
can thrash you with his little finger, and I'll make him do it, too."
|
||||
|
||||
"What do I care for your big brother? I've got a brother that's bigger
|
||||
than he is--and what's more, he can throw him over that fence, too."
|
||||
[Both brothers were imaginary.]
|
||||
|
||||
"That's a lie."
|
||||
|
||||
"YOUR saying so don't make it so."
|
||||
|
||||
Tom drew a line in the dust with his big toe, and said:
|
||||
|
||||
"I dare you to step over that, and I'll lick you till you can't stand
|
||||
up. Anybody that'll take a dare will steal sheep."
|
||||
|
||||
The new boy stepped over promptly, and said:
|
||||
|
||||
"Now you said you'd do it, now let's see you do it."
|
||||
|
||||
"Don't you crowd me now; you better look out."
|
||||
|
||||
"Well, you SAID you'd do it--why don't you do it?"
|
||||
|
||||
"By jingo! for two cents I WILL do it."
|
||||
|
||||
The new boy took two broad coppers out of his pocket and held them out
|
||||
with derision. Tom struck them to the ground. In an instant both boys
|
||||
were rolling and tumbling in the dirt, gripped together like cats; and
|
||||
for the space of a minute they tugged and tore at each other's hair and
|
||||
clothes, punched and scratched each other's nose, and covered
|
||||
themselves with dust and glory. Presently the confusion took form, and
|
||||
through the fog of battle Tom appeared, seated astride the new boy, and
|
||||
pounding him with his fists. "Holler 'nuff!" said he.
|
||||
|
||||
The boy only struggled to free himself. He was crying--mainly from rage.
|
||||
|
||||
"Holler 'nuff!"--and the pounding went on.
|
||||
|
||||
At last the stranger got out a smothered "'Nuff!" and Tom let him up
|
||||
and said:
|
||||
|
||||
"Now that'll learn you. Better look out who you're fooling with next
|
||||
time."
|
||||
|
||||
The new boy went off brushing the dust from his clothes, sobbing,
|
||||
snuffling, and occasionally looking back and shaking his head and
|
||||
threatening what he would do to Tom the "next time he caught him out."
|
||||
To which Tom responded with jeers, and started off in high feather, and
|
||||
as soon as his back was turned the new boy snatched up a stone, threw
|
||||
it and hit him between the shoulders and then turned tail and ran like
|
||||
an antelope. Tom chased the traitor home, and thus found out where he
|
||||
lived. He then held a position at the gate for some time, daring the
|
||||
enemy to come outside, but the enemy only made faces at him through the
|
||||
window and declined. At last the enemy's mother appeared, and called
|
||||
Tom a bad, vicious, vulgar child, and ordered him away. So he went
|
||||
away; but he said he "'lowed" to "lay" for that boy.
|
||||
|
||||
He got home pretty late that night, and when he climbed cautiously in
|
||||
at the window, he uncovered an ambuscade, in the person of his aunt;
|
||||
and when she saw the state his clothes were in her resolution to turn
|
||||
his Saturday holiday into captivity at hard labor became adamantine in
|
||||
its firmness.
|
BIN
vendor/github.com/golang/snappy/testdata/Mark.Twain-Tom.Sawyer.txt.rawsnappy
generated
vendored
BIN
vendor/github.com/golang/snappy/testdata/Mark.Twain-Tom.Sawyer.txt.rawsnappy
generated
vendored
Binary file not shown.
94
vendor/github.com/hashicorp/errwrap/errwrap_test.go
generated
vendored
94
vendor/github.com/hashicorp/errwrap/errwrap_test.go
generated
vendored
|
@ -1,94 +0,0 @@
|
|||
package errwrap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWrappedError_impl(t *testing.T) {
|
||||
var _ error = new(wrappedError)
|
||||
}
|
||||
|
||||
func TestGetAll(t *testing.T) {
|
||||
cases := []struct {
|
||||
Err error
|
||||
Msg string
|
||||
Len int
|
||||
}{
|
||||
{},
|
||||
{
|
||||
fmt.Errorf("foo"),
|
||||
"foo",
|
||||
1,
|
||||
},
|
||||
{
|
||||
fmt.Errorf("bar"),
|
||||
"foo",
|
||||
0,
|
||||
},
|
||||
{
|
||||
Wrapf("bar", fmt.Errorf("foo")),
|
||||
"foo",
|
||||
1,
|
||||
},
|
||||
{
|
||||
Wrapf("{{err}}", fmt.Errorf("foo")),
|
||||
"foo",
|
||||
2,
|
||||
},
|
||||
{
|
||||
Wrapf("bar", Wrapf("baz", fmt.Errorf("foo"))),
|
||||
"foo",
|
||||
1,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
actual := GetAll(tc.Err, tc.Msg)
|
||||
if len(actual) != tc.Len {
|
||||
t.Fatalf("%d: bad: %#v", i, actual)
|
||||
}
|
||||
for _, v := range actual {
|
||||
if v.Error() != tc.Msg {
|
||||
t.Fatalf("%d: bad: %#v", i, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllType(t *testing.T) {
|
||||
cases := []struct {
|
||||
Err error
|
||||
Type interface{}
|
||||
Len int
|
||||
}{
|
||||
{},
|
||||
{
|
||||
fmt.Errorf("foo"),
|
||||
"foo",
|
||||
0,
|
||||
},
|
||||
{
|
||||
fmt.Errorf("bar"),
|
||||
fmt.Errorf("foo"),
|
||||
1,
|
||||
},
|
||||
{
|
||||
Wrapf("bar", fmt.Errorf("foo")),
|
||||
fmt.Errorf("baz"),
|
||||
2,
|
||||
},
|
||||
{
|
||||
Wrapf("bar", Wrapf("baz", fmt.Errorf("foo"))),
|
||||
Wrapf("", nil),
|
||||
0,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
actual := GetAllType(tc.Err, tc.Type)
|
||||
if len(actual) != tc.Len {
|
||||
t.Fatalf("%d: bad: %#v", i, actual)
|
||||
}
|
||||
}
|
||||
}
|
1
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
1
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
|
@ -26,6 +26,7 @@ func DefaultPooledTransport() *http.Transport {
|
|||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
|
|
43
vendor/github.com/hashicorp/go-cleanhttp/handlers.go
generated
vendored
Normal file
43
vendor/github.com/hashicorp/go-cleanhttp/handlers.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
package cleanhttp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// HandlerInput provides input options to cleanhttp's handlers
|
||||
type HandlerInput struct {
|
||||
ErrStatus int
|
||||
}
|
||||
|
||||
// PrintablePathCheckHandler is a middleware that ensures the request path
|
||||
// contains only printable runes.
|
||||
func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler {
|
||||
// Nil-check on input to make it optional
|
||||
if input == nil {
|
||||
input = &HandlerInput{
|
||||
ErrStatus: http.StatusBadRequest,
|
||||
}
|
||||
}
|
||||
|
||||
// Default to http.StatusBadRequest on error
|
||||
if input.ErrStatus == 0 {
|
||||
input.ErrStatus = http.StatusBadRequest
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Check URL path for non-printable characters
|
||||
idx := strings.IndexFunc(r.URL.Path, func(c rune) bool {
|
||||
return !unicode.IsPrint(c)
|
||||
})
|
||||
|
||||
if idx != -1 {
|
||||
w.WriteHeader(input.ErrStatus)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
})
|
||||
}
|
2
vendor/github.com/hashicorp/go-multierror/.travis.yml
generated
vendored
2
vendor/github.com/hashicorp/go-multierror/.travis.yml
generated
vendored
|
@ -3,7 +3,7 @@ sudo: false
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
- 1.x
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
|
82
vendor/github.com/hashicorp/go-multierror/append_test.go
generated
vendored
82
vendor/github.com/hashicorp/go-multierror/append_test.go
generated
vendored
|
@ -1,82 +0,0 @@
|
|||
package multierror
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppend_Error(t *testing.T) {
|
||||
original := &Error{
|
||||
Errors: []error{errors.New("foo")},
|
||||
}
|
||||
|
||||
result := Append(original, errors.New("bar"))
|
||||
if len(result.Errors) != 2 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
|
||||
original = &Error{}
|
||||
result = Append(original, errors.New("bar"))
|
||||
if len(result.Errors) != 1 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
|
||||
// Test when a typed nil is passed
|
||||
var e *Error
|
||||
result = Append(e, errors.New("baz"))
|
||||
if len(result.Errors) != 1 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
|
||||
// Test flattening
|
||||
original = &Error{
|
||||
Errors: []error{errors.New("foo")},
|
||||
}
|
||||
|
||||
result = Append(original, Append(nil, errors.New("foo"), errors.New("bar")))
|
||||
if len(result.Errors) != 3 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppend_NilError(t *testing.T) {
|
||||
var err error
|
||||
result := Append(err, errors.New("bar"))
|
||||
if len(result.Errors) != 1 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppend_NilErrorArg(t *testing.T) {
|
||||
var err error
|
||||
var nilErr *Error
|
||||
result := Append(err, nilErr)
|
||||
if len(result.Errors) != 0 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppend_NilErrorIfaceArg(t *testing.T) {
|
||||
var err error
|
||||
var nilErr error
|
||||
result := Append(err, nilErr)
|
||||
if len(result.Errors) != 0 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppend_NonError(t *testing.T) {
|
||||
original := errors.New("foo")
|
||||
result := Append(original, errors.New("bar"))
|
||||
if len(result.Errors) != 2 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppend_NonError_Error(t *testing.T) {
|
||||
original := errors.New("foo")
|
||||
result := Append(original, Append(nil, errors.New("bar")))
|
||||
if len(result.Errors) != 2 {
|
||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
||||
}
|
||||
}
|
48
vendor/github.com/hashicorp/go-multierror/flatten_test.go
generated
vendored
48
vendor/github.com/hashicorp/go-multierror/flatten_test.go
generated
vendored
|
@ -1,48 +0,0 @@
|
|||
package multierror
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFlatten(t *testing.T) {
|
||||
original := &Error{
|
||||
Errors: []error{
|
||||
errors.New("one"),
|
||||
&Error{
|
||||
Errors: []error{
|
||||
errors.New("two"),
|
||||
&Error{
|
||||
Errors: []error{
|
||||
errors.New("three"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected := strings.TrimSpace(`
|
||||
3 errors occurred:
|
||||
|
||||
* one
|
||||
* two
|
||||
* three
|
||||
`)
|
||||
actual := fmt.Sprintf("%s", Flatten(original))
|
||||
|
||||
if expected != actual {
|
||||
t.Fatalf("expected: %s, got: %s", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatten_nonError(t *testing.T) {
|
||||
err := errors.New("foo")
|
||||
actual := Flatten(err)
|
||||
if !reflect.DeepEqual(actual, err) {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
38
vendor/github.com/hashicorp/go-multierror/format_test.go
generated
vendored
38
vendor/github.com/hashicorp/go-multierror/format_test.go
generated
vendored
|
@ -1,38 +0,0 @@
|
|||
package multierror
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListFormatFuncSingle(t *testing.T) {
|
||||
expected := `1 error occurred:
|
||||
|
||||
* foo`
|
||||
|
||||
errors := []error{
|
||||
errors.New("foo"),
|
||||
}
|
||||
|
||||
actual := ListFormatFunc(errors)
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListFormatFuncMultiple(t *testing.T) {
|
||||
expected := `2 errors occurred:
|
||||
|
||||
* foo
|
||||
* bar`
|
||||
|
||||
errors := []error{
|
||||
errors.New("foo"),
|
||||
errors.New("bar"),
|
||||
}
|
||||
|
||||
actual := ListFormatFunc(errors)
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
70
vendor/github.com/hashicorp/go-multierror/multierror_test.go
generated
vendored
70
vendor/github.com/hashicorp/go-multierror/multierror_test.go
generated
vendored
|
@ -1,70 +0,0 @@
|
|||
package multierror
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestError_Impl(t *testing.T) {
|
||||
var _ error = new(Error)
|
||||
}
|
||||
|
||||
func TestErrorError_custom(t *testing.T) {
|
||||
errors := []error{
|
||||
errors.New("foo"),
|
||||
errors.New("bar"),
|
||||
}
|
||||
|
||||
fn := func(es []error) string {
|
||||
return "foo"
|
||||
}
|
||||
|
||||
multi := &Error{Errors: errors, ErrorFormat: fn}
|
||||
if multi.Error() != "foo" {
|
||||
t.Fatalf("bad: %s", multi.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorError_default(t *testing.T) {
|
||||
expected := `2 errors occurred:
|
||||
|
||||
* foo
|
||||
* bar`
|
||||
|
||||
errors := []error{
|
||||
errors.New("foo"),
|
||||
errors.New("bar"),
|
||||
}
|
||||
|
||||
multi := &Error{Errors: errors}
|
||||
if multi.Error() != expected {
|
||||
t.Fatalf("bad: %s", multi.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorErrorOrNil(t *testing.T) {
|
||||
err := new(Error)
|
||||
if err.ErrorOrNil() != nil {
|
||||
t.Fatalf("bad: %#v", err.ErrorOrNil())
|
||||
}
|
||||
|
||||
err.Errors = []error{errors.New("foo")}
|
||||
if v := err.ErrorOrNil(); v == nil {
|
||||
t.Fatal("should not be nil")
|
||||
} else if !reflect.DeepEqual(v, err) {
|
||||
t.Fatalf("bad: %#v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorWrappedErrors(t *testing.T) {
|
||||
errors := []error{
|
||||
errors.New("foo"),
|
||||
errors.New("bar"),
|
||||
}
|
||||
|
||||
multi := &Error{Errors: errors}
|
||||
if !reflect.DeepEqual(multi.Errors, multi.WrappedErrors()) {
|
||||
t.Fatalf("bad: %s", multi.WrappedErrors())
|
||||
}
|
||||
}
|
33
vendor/github.com/hashicorp/go-multierror/prefix_test.go
generated
vendored
33
vendor/github.com/hashicorp/go-multierror/prefix_test.go
generated
vendored
|
@ -1,33 +0,0 @@
|
|||
package multierror
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPrefix_Error(t *testing.T) {
|
||||
original := &Error{
|
||||
Errors: []error{errors.New("foo")},
|
||||
}
|
||||
|
||||
result := Prefix(original, "bar")
|
||||
if result.(*Error).Errors[0].Error() != "bar foo" {
|
||||
t.Fatalf("bad: %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrefix_NilError(t *testing.T) {
|
||||
var err error
|
||||
result := Prefix(err, "bar")
|
||||
if result != nil {
|
||||
t.Fatalf("bad: %#v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrefix_NonError(t *testing.T) {
|
||||
original := errors.New("foo")
|
||||
result := Prefix(original, "bar")
|
||||
if result.Error() != "bar foo" {
|
||||
t.Fatalf("bad: %s", result)
|
||||
}
|
||||
}
|
54
vendor/github.com/hashicorp/go-multierror/scripts/deps.sh
generated
vendored
54
vendor/github.com/hashicorp/go-multierror/scripts/deps.sh
generated
vendored
|
@ -1,54 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This script updates dependencies using a temporary directory. This is required
|
||||
# to avoid any auxillary dependencies that sneak into GOPATH.
|
||||
set -e
|
||||
|
||||
# Get the parent directory of where this script is.
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
|
||||
DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
|
||||
|
||||
# Change into that directory
|
||||
cd "$DIR"
|
||||
|
||||
# Get the name from the directory
|
||||
NAME=${NAME:-"$(basename $(pwd))"}
|
||||
|
||||
# Announce
|
||||
echo "==> Updating dependencies..."
|
||||
|
||||
echo "--> Making tmpdir..."
|
||||
tmpdir=$(mktemp -d)
|
||||
function cleanup {
|
||||
rm -rf "${tmpdir}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
export GOPATH="${tmpdir}"
|
||||
export PATH="${tmpdir}/bin:$PATH"
|
||||
|
||||
mkdir -p "${tmpdir}/src/github.com/hashicorp"
|
||||
pushd "${tmpdir}/src/github.com/hashicorp" &>/dev/null
|
||||
|
||||
echo "--> Copying ${NAME}..."
|
||||
cp -R "$DIR" "${tmpdir}/src/github.com/hashicorp/${NAME}"
|
||||
pushd "${tmpdir}/src/github.com/hashicorp/${NAME}" &>/dev/null
|
||||
rm -rf vendor/
|
||||
|
||||
echo "--> Installing dependency manager..."
|
||||
go get -u github.com/kardianos/govendor
|
||||
govendor init
|
||||
|
||||
echo "--> Installing all dependencies (may take some time)..."
|
||||
govendor fetch -v +outside
|
||||
|
||||
echo "--> Vendoring..."
|
||||
govendor add +external
|
||||
|
||||
echo "--> Moving into place..."
|
||||
vpath="${tmpdir}/src/github.com/hashicorp/${NAME}/vendor"
|
||||
popd &>/dev/null
|
||||
popd &>/dev/null
|
||||
rm -rf vendor/
|
||||
cp -R "${vpath}" .
|
17
vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin_test.go
generated
vendored
17
vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin_test.go
generated
vendored
|
@ -1,17 +0,0 @@
|
|||
package rootcerts
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSystemCAsOnDarwin(t *testing.T) {
|
||||
_, err := LoadSystemCAs()
|
||||
if err != nil {
|
||||
t.Fatalf("Got error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertKeychains(t *testing.T) {
|
||||
keychains := certKeychains()
|
||||
if len(keychains) != 3 {
|
||||
t.Fatalf("Expected 3 keychains, got %#v", keychains)
|
||||
}
|
||||
}
|
52
vendor/github.com/hashicorp/go-rootcerts/rootcerts_test.go
generated
vendored
52
vendor/github.com/hashicorp/go-rootcerts/rootcerts_test.go
generated
vendored
|
@ -1,52 +0,0 @@
|
|||
package rootcerts
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const fixturesDir = "./test-fixtures"
|
||||
|
||||
func TestConfigureTLSHandlesNil(t *testing.T) {
|
||||
err := ConfigureTLS(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertsHandlesNil(t *testing.T) {
|
||||
_, err := LoadCACerts(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertsFromFile(t *testing.T) {
|
||||
path := testFixture("cafile", "cacert.pem")
|
||||
_, err := LoadCACerts(&Config{CAFile: path})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertsFromDir(t *testing.T) {
|
||||
path := testFixture("capath")
|
||||
_, err := LoadCACerts(&Config{CAPath: path})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertsFromDirWithSymlinks(t *testing.T) {
|
||||
path := testFixture("capath-with-symlinks")
|
||||
_, err := LoadCACerts(&Config{CAPath: path})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testFixture(n ...string) string {
|
||||
parts := []string{fixturesDir}
|
||||
parts = append(parts, n...)
|
||||
return filepath.Join(parts...)
|
||||
}
|
28
vendor/github.com/hashicorp/go-rootcerts/test-fixtures/cafile/cacert.pem
generated
vendored
28
vendor/github.com/hashicorp/go-rootcerts/test-fixtures/cafile/cacert.pem
generated
vendored
|
@ -1,28 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIExDCCA6ygAwIBAgIJAJ7PV+3kJZqZMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD
|
||||
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xEjAQ
|
||||
BgNVBAoTCUhhc2hpQ29ycDEUMBIGA1UECxMLRW5naW5lZXJpbmcxGzAZBgNVBAMU
|
||||
EiouYXRsYXMucGhpbnplLmNvbTEhMB8GCSqGSIb3DQEJARYScGF1bEBoYXNoaWNv
|
||||
cnAuY29tMB4XDTE2MDQyNzE1MjYyMVoXDTE3MDQyNzE1MjYyMVowgZwxCzAJBgNV
|
||||
BAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczEQMA4GA1UEBxMHQ2hpY2FnbzESMBAG
|
||||
A1UEChMJSGFzaGlDb3JwMRQwEgYDVQQLEwtFbmdpbmVlcmluZzEbMBkGA1UEAxQS
|
||||
Ki5hdGxhcy5waGluemUuY29tMSEwHwYJKoZIhvcNAQkBFhJwYXVsQGhhc2hpY29y
|
||||
cC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWRXdMnsTpxpwZ
|
||||
D2olsun9WO7SnMQ/SIR3DV/fttPIDHSQm2ad4r2pKEuiV+TKEFUgj/Id9bCAfQYs
|
||||
jsa1qX1GmieXz+83OnK3MDEcDczpjGhSplTYGOjlxKLMhMBAOtdV5hJAYz3nwV3c
|
||||
R+IQu/4213+em40shZAQRNZ2apnyE3+QB+gPlEs9Nw0OcbSKLmAiuKPbJpO+94ou
|
||||
n1h0/w/+DPz6yO/fFPoA3vlisGM6B4R9U2JVwWjXrU71fU1i82ulFQdApdfUs1FP
|
||||
wRrZxgX5ldUrRvFr8lJiMehdX8khO7Ue4rT6yxbI6KVM04Q5mNt1ARRLI69rN9My
|
||||
pGXiItcxAgMBAAGjggEFMIIBATAdBgNVHQ4EFgQUjwsj8l0Y9HFQLH0GaJAsOHof
|
||||
PhwwgdEGA1UdIwSByTCBxoAUjwsj8l0Y9HFQLH0GaJAsOHofPhyhgaKkgZ8wgZwx
|
||||
CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczEQMA4GA1UEBxMHQ2hpY2Fn
|
||||
bzESMBAGA1UEChMJSGFzaGlDb3JwMRQwEgYDVQQLEwtFbmdpbmVlcmluZzEbMBkG
|
||||
A1UEAxQSKi5hdGxhcy5waGluemUuY29tMSEwHwYJKoZIhvcNAQkBFhJwYXVsQGhh
|
||||
c2hpY29ycC5jb22CCQCez1ft5CWamTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
|
||||
BQUAA4IBAQC4tFfxpB8xEk9ewb5CNhhac4oKwGths+oq45DjoNtlagDMmIs2bl18
|
||||
q45PIB7fuFkAz/YHcOL0UEOAiw4jbuROp9jacHxBV21lRLLmNlK1Llc3eNVvLJ38
|
||||
ud6/Skilv9XyC4JNk0P5KrghxR6SOGwRuYZNqF+tthf+Bp9wJvLyfqDuJfGBal7C
|
||||
ezobMoh4tp8Dh1JeQlwvJcVt2k0UFJpa57MNr78c684Bq55ow+jd6wFG0XM0MMmy
|
||||
u+QRgJEGfYuYDPFEO8C8IfRyrHuV7Ll9P6eyEEFCneznXY0yJc/Gn3ZcX7ANqJsc
|
||||
ueMOWw/vUnonzxAFKW+I9U9ptyVSNMLY
|
||||
-----END CERTIFICATE-----
|
22
vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath/securetrust.pem
generated
vendored
22
vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath/securetrust.pem
generated
vendored
|
@ -1,22 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
|
||||
MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
|
||||
FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
|
||||
MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv
|
||||
cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz
|
||||
Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO
|
||||
0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao
|
||||
wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj
|
||||
7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS
|
||||
8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT
|
||||
BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg
|
||||
JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC
|
||||
NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
|
||||
6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/
|
||||
3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm
|
||||
D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
|
||||
CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
|
||||
3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
|
||||
-----END CERTIFICATE-----
|
25
vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath/thawte.pem
generated
vendored
25
vendor/github.com/hashicorp/go-rootcerts/test-fixtures/capath/thawte.pem
generated
vendored
|
@ -1,25 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
|
||||
qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
|
||||
Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
|
||||
MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
|
||||
BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
|
||||
NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
|
||||
LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
|
||||
A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
|
||||
IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
|
||||
W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
|
||||
3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
|
||||
6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
|
||||
Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
|
||||
NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
|
||||
r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
|
||||
DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
|
||||
YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
|
||||
xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
|
||||
/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
|
||||
LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
|
||||
jVaMaA==
|
||||
-----END CERTIFICATE-----
|
26
vendor/github.com/hashicorp/go-sockaddr/.gitignore
generated
vendored
Normal file
26
vendor/github.com/hashicorp/go-sockaddr/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
# 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
|
||||
*.prof
|
||||
.cover.out*
|
||||
coverage.html
|
65
vendor/github.com/hashicorp/go-sockaddr/GNUmakefile
generated
vendored
Normal file
65
vendor/github.com/hashicorp/go-sockaddr/GNUmakefile
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
TOOLS= golang.org/x/tools/cover
|
||||
GOCOVER_TMPFILE?= $(GOCOVER_FILE).tmp
|
||||
GOCOVER_FILE?= .cover.out
|
||||
GOCOVERHTML?= coverage.html
|
||||
FIND=`/usr/bin/which 2> /dev/null gfind find | /usr/bin/grep -v ^no | /usr/bin/head -n 1`
|
||||
XARGS=`/usr/bin/which 2> /dev/null gxargs xargs | /usr/bin/grep -v ^no | /usr/bin/head -n 1`
|
||||
|
||||
test:: $(GOCOVER_FILE)
|
||||
@$(MAKE) -C cmd/sockaddr test
|
||||
|
||||
cover:: coverage_report
|
||||
|
||||
$(GOCOVER_FILE)::
|
||||
@${FIND} . -type d ! -path '*cmd*' ! -path '*.git*' -print0 | ${XARGS} -0 -I % sh -ec "cd % && rm -f $(GOCOVER_TMPFILE) && go test -coverprofile=$(GOCOVER_TMPFILE)"
|
||||
|
||||
@echo 'mode: set' > $(GOCOVER_FILE)
|
||||
@${FIND} . -type f ! -path '*cmd*' ! -path '*.git*' -name "$(GOCOVER_TMPFILE)" -print0 | ${XARGS} -0 -n1 cat $(GOCOVER_TMPFILE) | grep -v '^mode: ' >> ${PWD}/$(GOCOVER_FILE)
|
||||
|
||||
$(GOCOVERHTML): $(GOCOVER_FILE)
|
||||
go tool cover -html=$(GOCOVER_FILE) -o $(GOCOVERHTML)
|
||||
|
||||
coverage_report:: $(GOCOVER_FILE)
|
||||
go tool cover -html=$(GOCOVER_FILE)
|
||||
|
||||
audit_tools::
|
||||
@go get -u github.com/golang/lint/golint && echo "Installed golint:"
|
||||
@go get -u github.com/fzipp/gocyclo && echo "Installed gocyclo:"
|
||||
@go get -u github.com/remyoudompheng/go-misc/deadcode && echo "Installed deadcode:"
|
||||
@go get -u github.com/client9/misspell/cmd/misspell && echo "Installed misspell:"
|
||||
@go get -u github.com/gordonklaus/ineffassign && echo "Installed ineffassign:"
|
||||
|
||||
audit::
|
||||
deadcode
|
||||
go tool vet -all *.go
|
||||
go tool vet -shadow=true *.go
|
||||
golint *.go
|
||||
ineffassign .
|
||||
gocyclo -over 65 *.go
|
||||
misspell *.go
|
||||
|
||||
clean::
|
||||
rm -f $(GOCOVER_FILE) $(GOCOVERHTML)
|
||||
|
||||
dev::
|
||||
@go build
|
||||
@$(MAKE) -B -C cmd/sockaddr sockaddr
|
||||
|
||||
install::
|
||||
@go install
|
||||
@$(MAKE) -C cmd/sockaddr install
|
||||
|
||||
doc::
|
||||
@echo Visit: http://127.0.0.1:6161/pkg/github.com/hashicorp/go-sockaddr/
|
||||
godoc -http=:6161 -goroot $GOROOT
|
||||
|
||||
world::
|
||||
@set -e; \
|
||||
for os in solaris darwin freebsd linux windows; do \
|
||||
for arch in amd64; do \
|
||||
printf "Building on %s-%s\n" "$${os}" "$${arch}" ; \
|
||||
env GOOS="$${os}" GOARCH="$${arch}" go build -o /dev/null; \
|
||||
done; \
|
||||
done
|
||||
|
||||
$(MAKE) -C cmd/sockaddr world
|
373
vendor/github.com/hashicorp/go-sockaddr/LICENSE
generated
vendored
Normal file
373
vendor/github.com/hashicorp/go-sockaddr/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,373 @@
|
|||
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.
|
118
vendor/github.com/hashicorp/go-sockaddr/README.md
generated
vendored
Normal file
118
vendor/github.com/hashicorp/go-sockaddr/README.md
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
# go-sockaddr
|
||||
|
||||
## `sockaddr` Library
|
||||
|
||||
Socket address convenience functions for Go. `go-sockaddr` is a convenience
|
||||
library that makes doing the right thing with IP addresses easy. `go-sockaddr`
|
||||
is loosely modeled after the UNIX `sockaddr_t` and creates a union of the family
|
||||
of `sockaddr_t` types (see below for an ascii diagram). Library documentation
|
||||
is available
|
||||
at
|
||||
[https://godoc.org/github.com/hashicorp/go-sockaddr](https://godoc.org/github.com/hashicorp/go-sockaddr).
|
||||
The primary intent of the library was to make it possible to define heuristics
|
||||
for selecting the correct IP addresses when a configuration is evaluated at
|
||||
runtime. See
|
||||
the
|
||||
[docs](https://godoc.org/github.com/hashicorp/go-sockaddr),
|
||||
[`template` package](https://godoc.org/github.com/hashicorp/go-sockaddr/template),
|
||||
tests,
|
||||
and
|
||||
[CLI utility](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
|
||||
for details and hints as to how to use this library.
|
||||
|
||||
For example, with this library it is possible to find an IP address that:
|
||||
|
||||
* is attached to a default route
|
||||
([`GetDefaultInterfaces()`](https://godoc.org/github.com/hashicorp/go-sockaddr#GetDefaultInterfaces))
|
||||
* is contained within a CIDR block ([`IfByNetwork()`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByNetwork))
|
||||
* is an RFC1918 address
|
||||
([`IfByRFC("1918")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
|
||||
* is ordered
|
||||
([`OrderedIfAddrBy(args)`](https://godoc.org/github.com/hashicorp/go-sockaddr#OrderedIfAddrBy) where
|
||||
`args` includes, but is not limited
|
||||
to,
|
||||
[`AscIfType`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscIfType),
|
||||
[`AscNetworkSize`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscNetworkSize))
|
||||
* excludes all IPv6 addresses
|
||||
([`IfByType("^(IPv4)$")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByType))
|
||||
* is larger than a `/32`
|
||||
([`IfByMaskSize(32)`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByMaskSize))
|
||||
* is not on a `down` interface
|
||||
([`ExcludeIfs("flags", "down")`](https://godoc.org/github.com/hashicorp/go-sockaddr#ExcludeIfs))
|
||||
* preferences an IPv6 address over an IPv4 address
|
||||
([`SortIfByType()`](https://godoc.org/github.com/hashicorp/go-sockaddr#SortIfByType) +
|
||||
[`ReverseIfAddrs()`](https://godoc.org/github.com/hashicorp/go-sockaddr#ReverseIfAddrs)); and
|
||||
* excludes any IP in RFC6890 address
|
||||
([`IfByRFC("6890")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
|
||||
|
||||
Or any combination or variation therein.
|
||||
|
||||
There are also a few simple helper functions such as `GetPublicIP` and
|
||||
`GetPrivateIP` which both return strings and select the first public or private
|
||||
IP address on the default interface, respectively. Similarly, there is also a
|
||||
helper function called `GetInterfaceIP` which returns the first usable IP
|
||||
address on the named interface.
|
||||
|
||||
## `sockaddr` CLI
|
||||
|
||||
Given the possible complexity of the `sockaddr` library, there is a CLI utility
|
||||
that accompanies the library, also
|
||||
called
|
||||
[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr).
|
||||
The
|
||||
[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
|
||||
utility exposes nearly all of the functionality of the library and can be used
|
||||
either as an administrative tool or testing tool. To install
|
||||
the
|
||||
[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr),
|
||||
run:
|
||||
|
||||
```text
|
||||
$ go get -u github.com/hashicorp/go-sockaddr/cmd/sockaddr
|
||||
```
|
||||
|
||||
If you're familiar with UNIX's `sockaddr` struct's, the following diagram
|
||||
mapping the C `sockaddr` (top) to `go-sockaddr` structs (bottom) and
|
||||
interfaces will be helpful:
|
||||
|
||||
```
|
||||
+-------------------------------------------------------+
|
||||
| |
|
||||
| sockaddr |
|
||||
| SockAddr |
|
||||
| |
|
||||
| +--------------+ +----------------------------------+ |
|
||||
| | sockaddr_un | | | |
|
||||
| | SockAddrUnix | | sockaddr_in{,6} | |
|
||||
| +--------------+ | IPAddr | |
|
||||
| | | |
|
||||
| | +-------------+ +--------------+ | |
|
||||
| | | sockaddr_in | | sockaddr_in6 | | |
|
||||
| | | IPv4Addr | | IPv6Addr | | |
|
||||
| | +-------------+ +--------------+ | |
|
||||
| | | |
|
||||
| +----------------------------------+ |
|
||||
| |
|
||||
+-------------------------------------------------------+
|
||||
```
|
||||
|
||||
## Inspiration and Design
|
||||
|
||||
There were many subtle inspirations that led to this design, but the most direct
|
||||
inspiration for the filtering syntax was
|
||||
OpenBSD's
|
||||
[`pf.conf(5)`](https://www.freebsd.org/cgi/man.cgi?query=pf.conf&apropos=0&sektion=0&arch=default&format=html#PARAMETERS) firewall
|
||||
syntax that lets you select the first IP address on a given named interface.
|
||||
The original problem stemmed from:
|
||||
|
||||
* needing to create immutable images using [Packer](https://www.packer.io) that
|
||||
ran the [Consul](https://www.consul.io) process (Consul can only use one IP
|
||||
address at a time);
|
||||
* images that may or may not have multiple interfaces or IP addresses at
|
||||
runtime; and
|
||||
* we didn't want to rely on configuration management to render out the correct
|
||||
IP address if the VM image was being used in an auto-scaling group.
|
||||
|
||||
Instead we needed some way to codify a heuristic that would correctly select the
|
||||
right IP address but the input parameters were not known when the image was
|
||||
created.
|
5
vendor/github.com/hashicorp/go-sockaddr/doc.go
generated
vendored
Normal file
5
vendor/github.com/hashicorp/go-sockaddr/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/*
|
||||
Package sockaddr is a Go implementation of the UNIX socket family data types and
|
||||
related helper functions.
|
||||
*/
|
||||
package sockaddr
|
254
vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
generated
vendored
Normal file
254
vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
generated
vendored
Normal file
|
@ -0,0 +1,254 @@
|
|||
package sockaddr
|
||||
|
||||
import "strings"
|
||||
|
||||
// ifAddrAttrMap is a map of the IfAddr type-specific attributes.
|
||||
var ifAddrAttrMap map[AttrName]func(IfAddr) string
|
||||
var ifAddrAttrs []AttrName
|
||||
|
||||
func init() {
|
||||
ifAddrAttrInit()
|
||||
}
|
||||
|
||||
// GetPrivateIP returns a string with a single IP address that is part of RFC
|
||||
// 6890 and has a default route. If the system can't determine its IP address
|
||||
// or find an RFC 6890 IP address, an empty string will be returned instead.
|
||||
// This function is the `eval` equivalent of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetPrivateInterfaces | attr "address"}}'
|
||||
/// ```
|
||||
func GetPrivateIP() (string, error) {
|
||||
privateIfs, err := GetPrivateInterfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(privateIfs) < 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ifAddr := privateIfs[0]
|
||||
ip := *ToIPAddr(ifAddr.SockAddr)
|
||||
return ip.NetIP().String(), nil
|
||||
}
|
||||
|
||||
// GetPrivateIPs returns a string with all IP addresses that are part of RFC
|
||||
// 6890 (regardless of whether or not there is a default route, unlike
|
||||
// GetPublicIP). If the system can't find any RFC 6890 IP addresses, an empty
|
||||
// string will be returned instead. This function is the `eval` equivalent of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}'
|
||||
/// ```
|
||||
func GetPrivateIPs() (string, error) {
|
||||
ifAddrs, err := GetAllInterfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(ifAddrs) < 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP)
|
||||
if len(ifAddrs) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs)
|
||||
|
||||
ifAddrs, _, err = IfByRFC("6890", ifAddrs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(ifAddrs) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
_, ifAddrs, err = IfByRFC(ForwardingBlacklistRFC, ifAddrs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(ifAddrs) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ips := make([]string, 0, len(ifAddrs))
|
||||
for _, ifAddr := range ifAddrs {
|
||||
ip := *ToIPAddr(ifAddr.SockAddr)
|
||||
s := ip.NetIP().String()
|
||||
ips = append(ips, s)
|
||||
}
|
||||
|
||||
return strings.Join(ips, " "), nil
|
||||
}
|
||||
|
||||
// GetPublicIP returns a string with a single IP address that is NOT part of RFC
|
||||
// 6890 and has a default route. If the system can't determine its IP address
|
||||
// or find a non RFC 6890 IP address, an empty string will be returned instead.
|
||||
// This function is the `eval` equivalent of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetPublicInterfaces | attr "address"}}'
|
||||
/// ```
|
||||
func GetPublicIP() (string, error) {
|
||||
publicIfs, err := GetPublicInterfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(publicIfs) < 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ifAddr := publicIfs[0]
|
||||
ip := *ToIPAddr(ifAddr.SockAddr)
|
||||
return ip.NetIP().String(), nil
|
||||
}
|
||||
|
||||
// GetPublicIPs returns a string with all IP addresses that are NOT part of RFC
|
||||
// 6890 (regardless of whether or not there is a default route, unlike
|
||||
// GetPublicIP). If the system can't find any non RFC 6890 IP addresses, an
|
||||
// empty string will be returned instead. This function is the `eval`
|
||||
// equivalent of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}'
|
||||
/// ```
|
||||
func GetPublicIPs() (string, error) {
|
||||
ifAddrs, err := GetAllInterfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(ifAddrs) < 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP)
|
||||
if len(ifAddrs) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs)
|
||||
|
||||
_, ifAddrs, err = IfByRFC("6890", ifAddrs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(ifAddrs) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ips := make([]string, 0, len(ifAddrs))
|
||||
for _, ifAddr := range ifAddrs {
|
||||
ip := *ToIPAddr(ifAddr.SockAddr)
|
||||
s := ip.NetIP().String()
|
||||
ips = append(ips, s)
|
||||
}
|
||||
|
||||
return strings.Join(ips, " "), nil
|
||||
}
|
||||
|
||||
// GetInterfaceIP returns a string with a single IP address sorted by the size
|
||||
// of the network (i.e. IP addresses with a smaller netmask, larger network
|
||||
// size, are sorted first). This function is the `eval` equivalent of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <<ARG>> | sort "type,size" | include "flag" "forwardable" | attr "address" }}'
|
||||
/// ```
|
||||
func GetInterfaceIP(namedIfRE string) (string, error) {
|
||||
ifAddrs, err := GetAllInterfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ifAddrs, _, err = IfByName(namedIfRE, ifAddrs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ifAddrs, _, err = IfByFlag("forwardable", ifAddrs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(ifAddrs) == 0 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ip := ToIPAddr(ifAddrs[0].SockAddr)
|
||||
if ip == nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return IPAddrAttr(*ip, "address"), nil
|
||||
}
|
||||
|
||||
// GetInterfaceIPs returns a string with all IPs, sorted by the size of the
|
||||
// network (i.e. IP addresses with a smaller netmask, larger network size, are
|
||||
// sorted first), on a named interface. This function is the `eval` equivalent
|
||||
// of:
|
||||
//
|
||||
// ```
|
||||
// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <<ARG>> | sort "type,size" | join "address" " "}}'
|
||||
/// ```
|
||||
func GetInterfaceIPs(namedIfRE string) (string, error) {
|
||||
ifAddrs, err := GetAllInterfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ifAddrs, _, err = IfByName(namedIfRE, ifAddrs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(ifAddrs) == 0 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ips := make([]string, 0, len(ifAddrs))
|
||||
for _, ifAddr := range ifAddrs {
|
||||
ip := *ToIPAddr(ifAddr.SockAddr)
|
||||
s := ip.NetIP().String()
|
||||
ips = append(ips, s)
|
||||
}
|
||||
|
||||
return strings.Join(ips, " "), nil
|
||||
}
|
||||
|
||||
// IfAddrAttrs returns a list of attributes supported by the IfAddr type
|
||||
func IfAddrAttrs() []AttrName {
|
||||
return ifAddrAttrs
|
||||
}
|
||||
|
||||
// IfAddrAttr returns a string representation of an attribute for the given
|
||||
// IfAddr.
|
||||
func IfAddrAttr(ifAddr IfAddr, attrName AttrName) string {
|
||||
fn, found := ifAddrAttrMap[attrName]
|
||||
if !found {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fn(ifAddr)
|
||||
}
|
||||
|
||||
// ifAddrAttrInit is called once at init()
|
||||
func ifAddrAttrInit() {
|
||||
// Sorted for human readability
|
||||
ifAddrAttrs = []AttrName{
|
||||
"flags",
|
||||
"name",
|
||||
}
|
||||
|
||||
ifAddrAttrMap = map[AttrName]func(ifAddr IfAddr) string{
|
||||
"flags": func(ifAddr IfAddr) string {
|
||||
return ifAddr.Interface.Flags.String()
|
||||
},
|
||||
"name": func(ifAddr IfAddr) string {
|
||||
return ifAddr.Interface.Name
|
||||
},
|
||||
}
|
||||
}
|
1281
vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
generated
vendored
Normal file
1281
vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
65
vendor/github.com/hashicorp/go-sockaddr/ifattr.go
generated
vendored
Normal file
65
vendor/github.com/hashicorp/go-sockaddr/ifattr.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
package sockaddr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// IfAddr is a union of a SockAddr and a net.Interface.
|
||||
type IfAddr struct {
|
||||
SockAddr
|
||||
net.Interface
|
||||
}
|
||||
|
||||
// Attr returns the named attribute as a string
|
||||
func (ifAddr IfAddr) Attr(attrName AttrName) (string, error) {
|
||||
val := IfAddrAttr(ifAddr, attrName)
|
||||
if val != "" {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
return Attr(ifAddr.SockAddr, attrName)
|
||||
}
|
||||
|
||||
// Attr returns the named attribute as a string
|
||||
func Attr(sa SockAddr, attrName AttrName) (string, error) {
|
||||
switch sockType := sa.Type(); {
|
||||
case sockType&TypeIP != 0:
|
||||
ip := *ToIPAddr(sa)
|
||||
attrVal := IPAddrAttr(ip, attrName)
|
||||
if attrVal != "" {
|
||||
return attrVal, nil
|
||||
}
|
||||
|
||||
if sockType == TypeIPv4 {
|
||||
ipv4 := *ToIPv4Addr(sa)
|
||||
attrVal := IPv4AddrAttr(ipv4, attrName)
|
||||
if attrVal != "" {
|
||||
return attrVal, nil
|
||||
}
|
||||
} else if sockType == TypeIPv6 {
|
||||
ipv6 := *ToIPv6Addr(sa)
|
||||
attrVal := IPv6AddrAttr(ipv6, attrName)
|
||||
if attrVal != "" {
|
||||
return attrVal, nil
|
||||
}
|
||||
}
|
||||
|
||||
case sockType == TypeUnix:
|
||||
us := *ToUnixSock(sa)
|
||||
attrVal := UnixSockAttr(us, attrName)
|
||||
if attrVal != "" {
|
||||
return attrVal, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Non type-specific attributes
|
||||
switch attrName {
|
||||
case "string":
|
||||
return sa.String(), nil
|
||||
case "type":
|
||||
return sa.Type().String(), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unsupported attribute name %q", attrName)
|
||||
}
|
169
vendor/github.com/hashicorp/go-sockaddr/ipaddr.go
generated
vendored
Normal file
169
vendor/github.com/hashicorp/go-sockaddr/ipaddr.go
generated
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
package sockaddr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Constants for the sizes of IPv3, IPv4, and IPv6 address types.
|
||||
const (
|
||||
IPv3len = 6
|
||||
IPv4len = 4
|
||||
IPv6len = 16
|
||||
)
|
||||
|
||||
// IPAddr is a generic IP address interface for IPv4 and IPv6 addresses,
|
||||
// networks, and socket endpoints.
|
||||
type IPAddr interface {
|
||||
SockAddr
|
||||
AddressBinString() string
|
||||
AddressHexString() string
|
||||
Cmp(SockAddr) int
|
||||
CmpAddress(SockAddr) int
|
||||
CmpPort(SockAddr) int
|
||||
FirstUsable() IPAddr
|
||||
Host() IPAddr
|
||||
IPPort() IPPort
|
||||
LastUsable() IPAddr
|
||||
Maskbits() int
|
||||
NetIP() *net.IP
|
||||
NetIPMask() *net.IPMask
|
||||
NetIPNet() *net.IPNet
|
||||
Network() IPAddr
|
||||
Octets() []int
|
||||
}
|
||||
|
||||
// IPPort is the type for an IP port number for the TCP and UDP IP transports.
|
||||
type IPPort uint16
|
||||
|
||||
// IPPrefixLen is a typed integer representing the prefix length for a given
|
||||
// IPAddr.
|
||||
type IPPrefixLen byte
|
||||
|
||||
// ipAddrAttrMap is a map of the IPAddr type-specific attributes.
|
||||
var ipAddrAttrMap map[AttrName]func(IPAddr) string
|
||||
var ipAddrAttrs []AttrName
|
||||
|
||||
func init() {
|
||||
ipAddrInit()
|
||||
}
|
||||
|
||||
// NewIPAddr creates a new IPAddr from a string. Returns nil if the string is
|
||||
// not an IPv4 or an IPv6 address.
|
||||
func NewIPAddr(addr string) (IPAddr, error) {
|
||||
ipv4Addr, err := NewIPv4Addr(addr)
|
||||
if err == nil {
|
||||
return ipv4Addr, nil
|
||||
}
|
||||
|
||||
ipv6Addr, err := NewIPv6Addr(addr)
|
||||
if err == nil {
|
||||
return ipv6Addr, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid IPAddr %v", addr)
|
||||
}
|
||||
|
||||
// IPAddrAttr returns a string representation of an attribute for the given
|
||||
// IPAddr.
|
||||
func IPAddrAttr(ip IPAddr, selector AttrName) string {
|
||||
fn, found := ipAddrAttrMap[selector]
|
||||
if !found {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fn(ip)
|
||||
}
|
||||
|
||||
// IPAttrs returns a list of attributes supported by the IPAddr type
|
||||
func IPAttrs() []AttrName {
|
||||
return ipAddrAttrs
|
||||
}
|
||||
|
||||
// MustIPAddr is a helper method that must return an IPAddr or panic on invalid
|
||||
// input.
|
||||
func MustIPAddr(addr string) IPAddr {
|
||||
ip, err := NewIPAddr(addr)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Unable to create an IPAddr from %+q: %v", addr, err))
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
// ipAddrInit is called once at init()
|
||||
func ipAddrInit() {
|
||||
// Sorted for human readability
|
||||
ipAddrAttrs = []AttrName{
|
||||
"host",
|
||||
"address",
|
||||
"port",
|
||||
"netmask",
|
||||
"network",
|
||||
"mask_bits",
|
||||
"binary",
|
||||
"hex",
|
||||
"first_usable",
|
||||
"last_usable",
|
||||
"octets",
|
||||
}
|
||||
|
||||
ipAddrAttrMap = map[AttrName]func(ip IPAddr) string{
|
||||
"address": func(ip IPAddr) string {
|
||||
return ip.NetIP().String()
|
||||
},
|
||||
"binary": func(ip IPAddr) string {
|
||||
return ip.AddressBinString()
|
||||
},
|
||||
"first_usable": func(ip IPAddr) string {
|
||||
return ip.FirstUsable().String()
|
||||
},
|
||||
"hex": func(ip IPAddr) string {
|
||||
return ip.AddressHexString()
|
||||
},
|
||||
"host": func(ip IPAddr) string {
|
||||
return ip.Host().String()
|
||||
},
|
||||
"last_usable": func(ip IPAddr) string {
|
||||
return ip.LastUsable().String()
|
||||
},
|
||||
"mask_bits": func(ip IPAddr) string {
|
||||
return fmt.Sprintf("%d", ip.Maskbits())
|
||||
},
|
||||
"netmask": func(ip IPAddr) string {
|
||||
switch v := ip.(type) {
|
||||
case IPv4Addr:
|
||||
ipv4Mask := IPv4Addr{
|
||||
Address: IPv4Address(v.Mask),
|
||||
Mask: IPv4HostMask,
|
||||
}
|
||||
return ipv4Mask.String()
|
||||
case IPv6Addr:
|
||||
ipv6Mask := new(big.Int)
|
||||
ipv6Mask.Set(v.Mask)
|
||||
ipv6MaskAddr := IPv6Addr{
|
||||
Address: IPv6Address(ipv6Mask),
|
||||
Mask: ipv6HostMask,
|
||||
}
|
||||
return ipv6MaskAddr.String()
|
||||
default:
|
||||
return fmt.Sprintf("<unsupported type: %T>", ip)
|
||||
}
|
||||
},
|
||||
"network": func(ip IPAddr) string {
|
||||
return ip.Network().NetIP().String()
|
||||
},
|
||||
"octets": func(ip IPAddr) string {
|
||||
octets := ip.Octets()
|
||||
octetStrs := make([]string, 0, len(octets))
|
||||
for _, octet := range octets {
|
||||
octetStrs = append(octetStrs, fmt.Sprintf("%d", octet))
|
||||
}
|
||||
return strings.Join(octetStrs, " ")
|
||||
},
|
||||
"port": func(ip IPAddr) string {
|
||||
return fmt.Sprintf("%d", ip.IPPort())
|
||||
},
|
||||
}
|
||||
}
|
98
vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go
generated
vendored
Normal file
98
vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
package sockaddr
|
||||
|
||||
import "bytes"
|
||||
|
||||
type IPAddrs []IPAddr
|
||||
|
||||
func (s IPAddrs) Len() int { return len(s) }
|
||||
func (s IPAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// // SortIPAddrsByCmp is a type that satisfies sort.Interface and can be used
|
||||
// // by the routines in this package. The SortIPAddrsByCmp type is used to
|
||||
// // sort IPAddrs by Cmp()
|
||||
// type SortIPAddrsByCmp struct{ IPAddrs }
|
||||
|
||||
// // Less reports whether the element with index i should sort before the
|
||||
// // element with index j.
|
||||
// func (s SortIPAddrsByCmp) Less(i, j int) bool {
|
||||
// // Sort by Type, then address, then port number.
|
||||
// return Less(s.IPAddrs[i], s.IPAddrs[j])
|
||||
// }
|
||||
|
||||
// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
|
||||
// can be used by the routines in this package. The
|
||||
// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
|
||||
// network (most specific to largest network).
|
||||
type SortIPAddrsByNetworkSize struct{ IPAddrs }
|
||||
|
||||
// Less reports whether the element with index i should sort before the
|
||||
// element with index j.
|
||||
func (s SortIPAddrsByNetworkSize) Less(i, j int) bool {
|
||||
// Sort masks with a larger binary value (i.e. fewer hosts per network
|
||||
// prefix) after masks with a smaller value (larger number of hosts per
|
||||
// prefix).
|
||||
switch bytes.Compare([]byte(*s.IPAddrs[i].NetIPMask()), []byte(*s.IPAddrs[j].NetIPMask())) {
|
||||
case 0:
|
||||
// Fall through to the second test if the net.IPMasks are the
|
||||
// same.
|
||||
break
|
||||
case 1:
|
||||
return true
|
||||
case -1:
|
||||
return false
|
||||
default:
|
||||
panic("bad, m'kay?")
|
||||
}
|
||||
|
||||
// Sort IPs based on the length (i.e. prefer IPv4 over IPv6).
|
||||
iLen := len(*s.IPAddrs[i].NetIP())
|
||||
jLen := len(*s.IPAddrs[j].NetIP())
|
||||
if iLen != jLen {
|
||||
return iLen > jLen
|
||||
}
|
||||
|
||||
// Sort IPs based on their network address from lowest to highest.
|
||||
switch bytes.Compare(s.IPAddrs[i].NetIPNet().IP, s.IPAddrs[j].NetIPNet().IP) {
|
||||
case 0:
|
||||
break
|
||||
case 1:
|
||||
return false
|
||||
case -1:
|
||||
return true
|
||||
default:
|
||||
panic("lol wut?")
|
||||
}
|
||||
|
||||
// If a host does not have a port set, it always sorts after hosts
|
||||
// that have a port (e.g. a host with a /32 and port number is more
|
||||
// specific and should sort first over a host with a /32 but no port
|
||||
// set).
|
||||
if s.IPAddrs[i].IPPort() == 0 || s.IPAddrs[j].IPPort() == 0 {
|
||||
return false
|
||||
}
|
||||
return s.IPAddrs[i].IPPort() < s.IPAddrs[j].IPPort()
|
||||
}
|
||||
|
||||
// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
|
||||
// can be used by the routines in this package. The
|
||||
// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
|
||||
// network (most specific to largest network).
|
||||
type SortIPAddrsBySpecificMaskLen struct{ IPAddrs }
|
||||
|
||||
// Less reports whether the element with index i should sort before the
|
||||
// element with index j.
|
||||
func (s SortIPAddrsBySpecificMaskLen) Less(i, j int) bool {
|
||||
return s.IPAddrs[i].Maskbits() > s.IPAddrs[j].Maskbits()
|
||||
}
|
||||
|
||||
// SortIPAddrsByBroadMaskLen is a type that satisfies sort.Interface and can
|
||||
// be used by the routines in this package. The SortIPAddrsByBroadMaskLen
|
||||
// type is used to sort IPAddrs by largest network (i.e. largest subnets
|
||||
// first).
|
||||
type SortIPAddrsByBroadMaskLen struct{ IPAddrs }
|
||||
|
||||
// Less reports whether the element with index i should sort before the
|
||||
// element with index j.
|
||||
func (s SortIPAddrsByBroadMaskLen) Less(i, j int) bool {
|
||||
return s.IPAddrs[i].Maskbits() < s.IPAddrs[j].Maskbits()
|
||||
}
|
516
vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
generated
vendored
Normal file
516
vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
generated
vendored
Normal file
|
@ -0,0 +1,516 @@
|
|||
package sockaddr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// IPv4Address is a named type representing an IPv4 address.
|
||||
IPv4Address uint32
|
||||
|
||||
// IPv4Network is a named type representing an IPv4 network.
|
||||
IPv4Network uint32
|
||||
|
||||
// IPv4Mask is a named type representing an IPv4 network mask.
|
||||
IPv4Mask uint32
|
||||
)
|
||||
|
||||
// IPv4HostMask is a constant represents a /32 IPv4 Address
|
||||
// (i.e. 255.255.255.255).
|
||||
const IPv4HostMask = IPv4Mask(0xffffffff)
|
||||
|
||||
// ipv4AddrAttrMap is a map of the IPv4Addr type-specific attributes.
|
||||
var ipv4AddrAttrMap map[AttrName]func(IPv4Addr) string
|
||||
var ipv4AddrAttrs []AttrName
|
||||
var trailingHexNetmaskRE *regexp.Regexp
|
||||
|
||||
// IPv4Addr implements a convenience wrapper around the union of Go's
|
||||
// built-in net.IP and net.IPNet types. In UNIX-speak, IPv4Addr implements
|
||||
// `sockaddr` when the the address family is set to AF_INET
|
||||
// (i.e. `sockaddr_in`).
|
||||
type IPv4Addr struct {
|
||||
IPAddr
|
||||
Address IPv4Address
|
||||
Mask IPv4Mask
|
||||
Port IPPort
|
||||
}
|
||||
|
||||
func init() {
|
||||
ipv4AddrInit()
|
||||
trailingHexNetmaskRE = regexp.MustCompile(`/([0f]{8})$`)
|
||||
}
|
||||
|
||||
// NewIPv4Addr creates an IPv4Addr from a string. String can be in the form
|
||||
// of either an IPv4:port (e.g. `1.2.3.4:80`, in which case the mask is
|
||||
// assumed to be a `/32`), an IPv4 address (e.g. `1.2.3.4`, also with a `/32`
|
||||
// mask), or an IPv4 CIDR (e.g. `1.2.3.4/24`, which has its IP port
|
||||
// initialized to zero). ipv4Str can not be a hostname.
|
||||
//
|
||||
// NOTE: Many net.*() routines will initialize and return an IPv6 address.
|
||||
// To create uint32 values from net.IP, always test to make sure the address
|
||||
// returned can be converted to a 4 byte array using To4().
|
||||
func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) {
|
||||
// Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go. In
|
||||
// particular, clients with the Barracuda VPN client will see something like:
|
||||
// `192.168.3.51/00ffffff` as their IP address.
|
||||
trailingHexNetmaskRe := trailingHexNetmaskRE.Copy()
|
||||
if match := trailingHexNetmaskRe.FindStringIndex(ipv4Str); match != nil {
|
||||
ipv4Str = ipv4Str[:match[0]]
|
||||
}
|
||||
|
||||
// Parse as an IPv4 CIDR
|
||||
ipAddr, network, err := net.ParseCIDR(ipv4Str)
|
||||
if err == nil {
|
||||
ipv4 := ipAddr.To4()
|
||||
if ipv4 == nil {
|
||||
return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address", ipv4Str)
|
||||
}
|
||||
|
||||
// If we see an IPv6 netmask, convert it to an IPv4 mask.
|
||||
netmaskSepPos := strings.LastIndexByte(ipv4Str, '/')
|
||||
if netmaskSepPos != -1 && netmaskSepPos+1 < len(ipv4Str) {
|
||||
netMask, err := strconv.ParseUint(ipv4Str[netmaskSepPos+1:], 10, 8)
|
||||
if err != nil {
|
||||
return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: unable to parse CIDR netmask: %v", ipv4Str, err)
|
||||
} else if netMask > 128 {
|
||||
return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: invalid CIDR netmask", ipv4Str)
|
||||
}
|
||||
|
||||
if netMask >= 96 {
|
||||
// Convert the IPv6 netmask to an IPv4 netmask
|
||||
network.Mask = net.CIDRMask(int(netMask-96), IPv4len*8)
|
||||
}
|
||||
}
|
||||
ipv4Addr := IPv4Addr{
|
||||
Address: IPv4Address(binary.BigEndian.Uint32(ipv4)),
|
||||
Mask: IPv4Mask(binary.BigEndian.Uint32(network.Mask)),
|
||||
}
|
||||
return ipv4Addr, nil
|
||||
}
|
||||
|
||||
// Attempt to parse ipv4Str as a /32 host with a port number.
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp4", ipv4Str)
|
||||
if err == nil {
|
||||
ipv4 := tcpAddr.IP.To4()
|
||||
if ipv4 == nil {
|
||||
return IPv4Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv4 address", ipv4Str)
|
||||
}
|
||||
|
||||
ipv4Uint32 := binary.BigEndian.Uint32(ipv4)
|
||||
ipv4Addr := IPv4Addr{
|
||||
Address: IPv4Address(ipv4Uint32),
|
||||
Mask: IPv4HostMask,
|
||||
Port: IPPort(tcpAddr.Port),
|
||||
}
|
||||
|
||||
return ipv4Addr, nil
|
||||
}
|
||||
|
||||
// Parse as a naked IPv4 address
|
||||
ip := net.ParseIP(ipv4Str)
|
||||
if ip != nil {
|
||||
ipv4 := ip.To4()
|
||||
if ipv4 == nil {
|
||||
return IPv4Addr{}, fmt.Errorf("Unable to string convert %+q to an IPv4 address", ipv4Str)
|
||||
}
|
||||
|
||||
ipv4Uint32 := binary.BigEndian.Uint32(ipv4)
|
||||
ipv4Addr := IPv4Addr{
|
||||
Address: IPv4Address(ipv4Uint32),
|
||||
Mask: IPv4HostMask,
|
||||
}
|
||||
return ipv4Addr, nil
|
||||
}
|
||||
|
||||
return IPv4Addr{}, fmt.Errorf("Unable to parse %+q to an IPv4 address: %v", ipv4Str, err)
|
||||
}
|
||||
|
||||
// AddressBinString returns a string with the IPv4Addr's Address represented
|
||||
// as a sequence of '0' and '1' characters. This method is useful for
|
||||
// debugging or by operators who want to inspect an address.
|
||||
func (ipv4 IPv4Addr) AddressBinString() string {
|
||||
return fmt.Sprintf("%032s", strconv.FormatUint(uint64(ipv4.Address), 2))
|
||||
}
|
||||
|
||||
// AddressHexString returns a string with the IPv4Addr address represented as
|
||||
// a sequence of hex characters. This method is useful for debugging or by
|
||||
// operators who want to inspect an address.
|
||||
func (ipv4 IPv4Addr) AddressHexString() string {
|
||||
return fmt.Sprintf("%08s", strconv.FormatUint(uint64(ipv4.Address), 16))
|
||||
}
|
||||
|
||||
// Broadcast is an IPv4Addr-only method that returns the broadcast address of
|
||||
// the network.
|
||||
//
|
||||
// NOTE: IPv6 only supports multicast, so this method only exists for
|
||||
// IPv4Addr.
|
||||
func (ipv4 IPv4Addr) Broadcast() IPAddr {
|
||||
// Nothing should listen on a broadcast address.
|
||||
return IPv4Addr{
|
||||
Address: IPv4Address(ipv4.BroadcastAddress()),
|
||||
Mask: IPv4HostMask,
|
||||
}
|
||||
}
|
||||
|
||||
// BroadcastAddress returns a IPv4Network of the IPv4Addr's broadcast
|
||||
// address.
|
||||
func (ipv4 IPv4Addr) BroadcastAddress() IPv4Network {
|
||||
return IPv4Network(uint32(ipv4.Address)&uint32(ipv4.Mask) | ^uint32(ipv4.Mask))
|
||||
}
|
||||
|
||||
// CmpAddress follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its address is lower than arg
|
||||
// - 0 if the SockAddr arg is equal to the receiving IPv4Addr or the argument is
|
||||
// of a different type.
|
||||
// - 1 If the argument should sort first.
|
||||
func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int {
|
||||
ipv4b, ok := sa.(IPv4Addr)
|
||||
if !ok {
|
||||
return sortDeferDecision
|
||||
}
|
||||
|
||||
switch {
|
||||
case ipv4.Address == ipv4b.Address:
|
||||
return sortDeferDecision
|
||||
case ipv4.Address < ipv4b.Address:
|
||||
return sortReceiverBeforeArg
|
||||
default:
|
||||
return sortArgBeforeReceiver
|
||||
}
|
||||
}
|
||||
|
||||
// CmpPort follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its port is lower than arg
|
||||
// - 0 if the SockAddr arg's port number is equal to the receiving IPv4Addr,
|
||||
// regardless of type.
|
||||
// - 1 If the argument should sort first.
|
||||
func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int {
|
||||
var saPort IPPort
|
||||
switch v := sa.(type) {
|
||||
case IPv4Addr:
|
||||
saPort = v.Port
|
||||
case IPv6Addr:
|
||||
saPort = v.Port
|
||||
default:
|
||||
return sortDeferDecision
|
||||
}
|
||||
|
||||
switch {
|
||||
case ipv4.Port == saPort:
|
||||
return sortDeferDecision
|
||||
case ipv4.Port < saPort:
|
||||
return sortReceiverBeforeArg
|
||||
default:
|
||||
return sortArgBeforeReceiver
|
||||
}
|
||||
}
|
||||
|
||||
// CmpRFC follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because it belongs to the RFC and its
|
||||
// arg does not
|
||||
// - 0 if the receiver and arg both belong to the same RFC or neither do.
|
||||
// - 1 If the arg belongs to the RFC but receiver does not.
|
||||
func (ipv4 IPv4Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
|
||||
recvInRFC := IsRFC(rfcNum, ipv4)
|
||||
ipv4b, ok := sa.(IPv4Addr)
|
||||
if !ok {
|
||||
// If the receiver is part of the desired RFC and the SockAddr
|
||||
// argument is not, return -1 so that the receiver sorts before
|
||||
// the non-IPv4 SockAddr. Conversely, if the receiver is not
|
||||
// part of the RFC, punt on sorting and leave it for the next
|
||||
// sorter.
|
||||
if recvInRFC {
|
||||
return sortReceiverBeforeArg
|
||||
} else {
|
||||
return sortDeferDecision
|
||||
}
|
||||
}
|
||||
|
||||
argInRFC := IsRFC(rfcNum, ipv4b)
|
||||
switch {
|
||||
case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
|
||||
// If a and b both belong to the RFC, or neither belong to
|
||||
// rfcNum, defer sorting to the next sorter.
|
||||
return sortDeferDecision
|
||||
case recvInRFC && !argInRFC:
|
||||
return sortReceiverBeforeArg
|
||||
default:
|
||||
return sortArgBeforeReceiver
|
||||
}
|
||||
}
|
||||
|
||||
// Contains returns true if the SockAddr is contained within the receiver.
|
||||
func (ipv4 IPv4Addr) Contains(sa SockAddr) bool {
|
||||
ipv4b, ok := sa.(IPv4Addr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return ipv4.ContainsNetwork(ipv4b)
|
||||
}
|
||||
|
||||
// ContainsAddress returns true if the IPv4Address is contained within the
|
||||
// receiver.
|
||||
func (ipv4 IPv4Addr) ContainsAddress(x IPv4Address) bool {
|
||||
return IPv4Address(ipv4.NetworkAddress()) <= x &&
|
||||
IPv4Address(ipv4.BroadcastAddress()) >= x
|
||||
}
|
||||
|
||||
// ContainsNetwork returns true if the network from IPv4Addr is contained
|
||||
// within the receiver.
|
||||
func (ipv4 IPv4Addr) ContainsNetwork(x IPv4Addr) bool {
|
||||
return ipv4.NetworkAddress() <= x.NetworkAddress() &&
|
||||
ipv4.BroadcastAddress() >= x.BroadcastAddress()
|
||||
}
|
||||
|
||||
// DialPacketArgs returns the arguments required to be passed to
|
||||
// net.DialUDP(). If the Mask of ipv4 is not a /32 or the Port is 0,
|
||||
// DialPacketArgs() will fail. See Host() to create an IPv4Addr with its
|
||||
// mask set to /32.
|
||||
func (ipv4 IPv4Addr) DialPacketArgs() (network, dialArgs string) {
|
||||
if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 {
|
||||
return "udp4", ""
|
||||
}
|
||||
return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
|
||||
}
|
||||
|
||||
// DialStreamArgs returns the arguments required to be passed to
|
||||
// net.DialTCP(). If the Mask of ipv4 is not a /32 or the Port is 0,
|
||||
// DialStreamArgs() will fail. See Host() to create an IPv4Addr with its
|
||||
// mask set to /32.
|
||||
func (ipv4 IPv4Addr) DialStreamArgs() (network, dialArgs string) {
|
||||
if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 {
|
||||
return "tcp4", ""
|
||||
}
|
||||
return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
|
||||
}
|
||||
|
||||
// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
|
||||
func (ipv4 IPv4Addr) Equal(sa SockAddr) bool {
|
||||
ipv4b, ok := sa.(IPv4Addr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if ipv4.Port != ipv4b.Port {
|
||||
return false
|
||||
}
|
||||
|
||||
if ipv4.Address != ipv4b.Address {
|
||||
return false
|
||||
}
|
||||
|
||||
if ipv4.NetIPNet().String() != ipv4b.NetIPNet().String() {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// FirstUsable returns an IPv4Addr set to the first address following the
|
||||
// network prefix. The first usable address in a network is normally the
|
||||
// gateway and should not be used except by devices forwarding packets
|
||||
// between two administratively distinct networks (i.e. a router). This
|
||||
// function does not discriminate against first usable vs "first address that
|
||||
// should be used." For example, FirstUsable() on "192.168.1.10/24" would
|
||||
// return the address "192.168.1.1/24".
|
||||
func (ipv4 IPv4Addr) FirstUsable() IPAddr {
|
||||
addr := ipv4.NetworkAddress()
|
||||
|
||||
// If /32, return the address itself. If /31 assume a point-to-point
|
||||
// link and return the lower address.
|
||||
if ipv4.Maskbits() < 31 {
|
||||
addr++
|
||||
}
|
||||
|
||||
return IPv4Addr{
|
||||
Address: IPv4Address(addr),
|
||||
Mask: IPv4HostMask,
|
||||
}
|
||||
}
|
||||
|
||||
// Host returns a copy of ipv4 with its mask set to /32 so that it can be
|
||||
// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
|
||||
// ListenStreamArgs().
|
||||
func (ipv4 IPv4Addr) Host() IPAddr {
|
||||
// Nothing should listen on a broadcast address.
|
||||
return IPv4Addr{
|
||||
Address: ipv4.Address,
|
||||
Mask: IPv4HostMask,
|
||||
Port: ipv4.Port,
|
||||
}
|
||||
}
|
||||
|
||||
// IPPort returns the Port number attached to the IPv4Addr
|
||||
func (ipv4 IPv4Addr) IPPort() IPPort {
|
||||
return ipv4.Port
|
||||
}
|
||||
|
||||
// LastUsable returns the last address before the broadcast address in a
|
||||
// given network.
|
||||
func (ipv4 IPv4Addr) LastUsable() IPAddr {
|
||||
addr := ipv4.BroadcastAddress()
|
||||
|
||||
// If /32, return the address itself. If /31 assume a point-to-point
|
||||
// link and return the upper address.
|
||||
if ipv4.Maskbits() < 31 {
|
||||
addr--
|
||||
}
|
||||
|
||||
return IPv4Addr{
|
||||
Address: IPv4Address(addr),
|
||||
Mask: IPv4HostMask,
|
||||
}
|
||||
}
|
||||
|
||||
// ListenPacketArgs returns the arguments required to be passed to
|
||||
// net.ListenUDP(). If the Mask of ipv4 is not a /32, ListenPacketArgs()
|
||||
// will fail. See Host() to create an IPv4Addr with its mask set to /32.
|
||||
func (ipv4 IPv4Addr) ListenPacketArgs() (network, listenArgs string) {
|
||||
if ipv4.Mask != IPv4HostMask {
|
||||
return "udp4", ""
|
||||
}
|
||||
return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
|
||||
}
|
||||
|
||||
// ListenStreamArgs returns the arguments required to be passed to
|
||||
// net.ListenTCP(). If the Mask of ipv4 is not a /32, ListenStreamArgs()
|
||||
// will fail. See Host() to create an IPv4Addr with its mask set to /32.
|
||||
func (ipv4 IPv4Addr) ListenStreamArgs() (network, listenArgs string) {
|
||||
if ipv4.Mask != IPv4HostMask {
|
||||
return "tcp4", ""
|
||||
}
|
||||
return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
|
||||
}
|
||||
|
||||
// Maskbits returns the number of network mask bits in a given IPv4Addr. For
|
||||
// example, the Maskbits() of "192.168.1.1/24" would return 24.
|
||||
func (ipv4 IPv4Addr) Maskbits() int {
|
||||
mask := make(net.IPMask, IPv4len)
|
||||
binary.BigEndian.PutUint32(mask, uint32(ipv4.Mask))
|
||||
maskOnes, _ := mask.Size()
|
||||
return maskOnes
|
||||
}
|
||||
|
||||
// MustIPv4Addr is a helper method that must return an IPv4Addr or panic on
|
||||
// invalid input.
|
||||
func MustIPv4Addr(addr string) IPv4Addr {
|
||||
ipv4, err := NewIPv4Addr(addr)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Unable to create an IPv4Addr from %+q: %v", addr, err))
|
||||
}
|
||||
return ipv4
|
||||
}
|
||||
|
||||
// NetIP returns the address as a net.IP (address is always presized to
|
||||
// IPv4).
|
||||
func (ipv4 IPv4Addr) NetIP() *net.IP {
|
||||
x := make(net.IP, IPv4len)
|
||||
binary.BigEndian.PutUint32(x, uint32(ipv4.Address))
|
||||
return &x
|
||||
}
|
||||
|
||||
// NetIPMask create a new net.IPMask from the IPv4Addr.
|
||||
func (ipv4 IPv4Addr) NetIPMask() *net.IPMask {
|
||||
ipv4Mask := net.IPMask{}
|
||||
ipv4Mask = make(net.IPMask, IPv4len)
|
||||
binary.BigEndian.PutUint32(ipv4Mask, uint32(ipv4.Mask))
|
||||
return &ipv4Mask
|
||||
}
|
||||
|
||||
// NetIPNet create a new net.IPNet from the IPv4Addr.
|
||||
func (ipv4 IPv4Addr) NetIPNet() *net.IPNet {
|
||||
ipv4net := &net.IPNet{}
|
||||
ipv4net.IP = make(net.IP, IPv4len)
|
||||
binary.BigEndian.PutUint32(ipv4net.IP, uint32(ipv4.NetworkAddress()))
|
||||
ipv4net.Mask = *ipv4.NetIPMask()
|
||||
return ipv4net
|
||||
}
|
||||
|
||||
// Network returns the network prefix or network address for a given network.
|
||||
func (ipv4 IPv4Addr) Network() IPAddr {
|
||||
return IPv4Addr{
|
||||
Address: IPv4Address(ipv4.NetworkAddress()),
|
||||
Mask: ipv4.Mask,
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkAddress returns an IPv4Network of the IPv4Addr's network address.
|
||||
func (ipv4 IPv4Addr) NetworkAddress() IPv4Network {
|
||||
return IPv4Network(uint32(ipv4.Address) & uint32(ipv4.Mask))
|
||||
}
|
||||
|
||||
// Octets returns a slice of the four octets in an IPv4Addr's Address. The
|
||||
// order of the bytes is big endian.
|
||||
func (ipv4 IPv4Addr) Octets() []int {
|
||||
return []int{
|
||||
int(ipv4.Address >> 24),
|
||||
int((ipv4.Address >> 16) & 0xff),
|
||||
int((ipv4.Address >> 8) & 0xff),
|
||||
int(ipv4.Address & 0xff),
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of the IPv4Addr
|
||||
func (ipv4 IPv4Addr) String() string {
|
||||
if ipv4.Port != 0 {
|
||||
return fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
|
||||
}
|
||||
|
||||
if ipv4.Maskbits() == 32 {
|
||||
return ipv4.NetIP().String()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s/%d", ipv4.NetIP().String(), ipv4.Maskbits())
|
||||
}
|
||||
|
||||
// Type is used as a type switch and returns TypeIPv4
|
||||
func (IPv4Addr) Type() SockAddrType {
|
||||
return TypeIPv4
|
||||
}
|
||||
|
||||
// IPv4AddrAttr returns a string representation of an attribute for the given
|
||||
// IPv4Addr.
|
||||
func IPv4AddrAttr(ipv4 IPv4Addr, selector AttrName) string {
|
||||
fn, found := ipv4AddrAttrMap[selector]
|
||||
if !found {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fn(ipv4)
|
||||
}
|
||||
|
||||
// IPv4Attrs returns a list of attributes supported by the IPv4Addr type
|
||||
func IPv4Attrs() []AttrName {
|
||||
return ipv4AddrAttrs
|
||||
}
|
||||
|
||||
// ipv4AddrInit is called once at init()
|
||||
func ipv4AddrInit() {
|
||||
// Sorted for human readability
|
||||
ipv4AddrAttrs = []AttrName{
|
||||
"size", // Same position as in IPv6 for output consistency
|
||||
"broadcast",
|
||||
"uint32",
|
||||
}
|
||||
|
||||
ipv4AddrAttrMap = map[AttrName]func(ipv4 IPv4Addr) string{
|
||||
"broadcast": func(ipv4 IPv4Addr) string {
|
||||
return ipv4.Broadcast().String()
|
||||
},
|
||||
"size": func(ipv4 IPv4Addr) string {
|
||||
return fmt.Sprintf("%d", 1<<uint(IPv4len*8-ipv4.Maskbits()))
|
||||
},
|
||||
"uint32": func(ipv4 IPv4Addr) string {
|
||||
return fmt.Sprintf("%d", uint32(ipv4.Address))
|
||||
},
|
||||
}
|
||||
}
|
591
vendor/github.com/hashicorp/go-sockaddr/ipv6addr.go
generated
vendored
Normal file
591
vendor/github.com/hashicorp/go-sockaddr/ipv6addr.go
generated
vendored
Normal file
|
@ -0,0 +1,591 @@
|
|||
package sockaddr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
)
|
||||
|
||||
type (
|
||||
// IPv6Address is a named type representing an IPv6 address.
|
||||
IPv6Address *big.Int
|
||||
|
||||
// IPv6Network is a named type representing an IPv6 network.
|
||||
IPv6Network *big.Int
|
||||
|
||||
// IPv6Mask is a named type representing an IPv6 network mask.
|
||||
IPv6Mask *big.Int
|
||||
)
|
||||
|
||||
// IPv6HostPrefix is a constant represents a /128 IPv6 Prefix.
|
||||
const IPv6HostPrefix = IPPrefixLen(128)
|
||||
|
||||
// ipv6HostMask is an unexported big.Int representing a /128 IPv6 address.
|
||||
// This value must be a constant and always set to all ones.
|
||||
var ipv6HostMask IPv6Mask
|
||||
|
||||
// ipv6AddrAttrMap is a map of the IPv6Addr type-specific attributes.
|
||||
var ipv6AddrAttrMap map[AttrName]func(IPv6Addr) string
|
||||
var ipv6AddrAttrs []AttrName
|
||||
|
||||
func init() {
|
||||
biMask := new(big.Int)
|
||||
biMask.SetBytes([]byte{
|
||||
0xff, 0xff,
|
||||
0xff, 0xff,
|
||||
0xff, 0xff,
|
||||
0xff, 0xff,
|
||||
0xff, 0xff,
|
||||
0xff, 0xff,
|
||||
0xff, 0xff,
|
||||
0xff, 0xff,
|
||||
},
|
||||
)
|
||||
ipv6HostMask = IPv6Mask(biMask)
|
||||
|
||||
ipv6AddrInit()
|
||||
}
|
||||
|
||||
// IPv6Addr implements a convenience wrapper around the union of Go's
|
||||
// built-in net.IP and net.IPNet types. In UNIX-speak, IPv6Addr implements
|
||||
// `sockaddr` when the the address family is set to AF_INET6
|
||||
// (i.e. `sockaddr_in6`).
|
||||
type IPv6Addr struct {
|
||||
IPAddr
|
||||
Address IPv6Address
|
||||
Mask IPv6Mask
|
||||
Port IPPort
|
||||
}
|
||||
|
||||
// NewIPv6Addr creates an IPv6Addr from a string. String can be in the form of
|
||||
// an an IPv6:port (e.g. `[2001:4860:0:2001::68]:80`, in which case the mask is
|
||||
// assumed to be a /128), an IPv6 address (e.g. `2001:4860:0:2001::68`, also
|
||||
// with a `/128` mask), an IPv6 CIDR (e.g. `2001:4860:0:2001::68/64`, which has
|
||||
// its IP port initialized to zero). ipv6Str can not be a hostname.
|
||||
//
|
||||
// NOTE: Many net.*() routines will initialize and return an IPv4 address.
|
||||
// Always test to make sure the address returned cannot be converted to a 4 byte
|
||||
// array using To4().
|
||||
func NewIPv6Addr(ipv6Str string) (IPv6Addr, error) {
|
||||
v6Addr := false
|
||||
LOOP:
|
||||
for i := 0; i < len(ipv6Str); i++ {
|
||||
switch ipv6Str[i] {
|
||||
case '.':
|
||||
break LOOP
|
||||
case ':':
|
||||
v6Addr = true
|
||||
break LOOP
|
||||
}
|
||||
}
|
||||
|
||||
if !v6Addr {
|
||||
return IPv6Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv6 address, appears to be an IPv4 address", ipv6Str)
|
||||
}
|
||||
|
||||
// Attempt to parse ipv6Str as a /128 host with a port number.
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp6", ipv6Str)
|
||||
if err == nil {
|
||||
ipv6 := tcpAddr.IP.To16()
|
||||
if ipv6 == nil {
|
||||
return IPv6Addr{}, fmt.Errorf("Unable to resolve %+q as a 16byte IPv6 address", ipv6Str)
|
||||
}
|
||||
|
||||
ipv6BigIntAddr := new(big.Int)
|
||||
ipv6BigIntAddr.SetBytes(ipv6)
|
||||
|
||||
ipv6BigIntMask := new(big.Int)
|
||||
ipv6BigIntMask.Set(ipv6HostMask)
|
||||
|
||||
ipv6Addr := IPv6Addr{
|
||||
Address: IPv6Address(ipv6BigIntAddr),
|
||||
Mask: IPv6Mask(ipv6BigIntMask),
|
||||
Port: IPPort(tcpAddr.Port),
|
||||
}
|
||||
|
||||
return ipv6Addr, nil
|
||||
}
|
||||
|
||||
// Parse as a naked IPv6 address. Trim square brackets if present.
|
||||
if len(ipv6Str) > 2 && ipv6Str[0] == '[' && ipv6Str[len(ipv6Str)-1] == ']' {
|
||||
ipv6Str = ipv6Str[1 : len(ipv6Str)-1]
|
||||
}
|
||||
ip := net.ParseIP(ipv6Str)
|
||||
if ip != nil {
|
||||
ipv6 := ip.To16()
|
||||
if ipv6 == nil {
|
||||
return IPv6Addr{}, fmt.Errorf("Unable to string convert %+q to a 16byte IPv6 address", ipv6Str)
|
||||
}
|
||||
|
||||
ipv6BigIntAddr := new(big.Int)
|
||||
ipv6BigIntAddr.SetBytes(ipv6)
|
||||
|
||||
ipv6BigIntMask := new(big.Int)
|
||||
ipv6BigIntMask.Set(ipv6HostMask)
|
||||
|
||||
return IPv6Addr{
|
||||
Address: IPv6Address(ipv6BigIntAddr),
|
||||
Mask: IPv6Mask(ipv6BigIntMask),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Parse as an IPv6 CIDR
|
||||
ipAddr, network, err := net.ParseCIDR(ipv6Str)
|
||||
if err == nil {
|
||||
ipv6 := ipAddr.To16()
|
||||
if ipv6 == nil {
|
||||
return IPv6Addr{}, fmt.Errorf("Unable to convert %+q to a 16byte IPv6 address", ipv6Str)
|
||||
}
|
||||
|
||||
ipv6BigIntAddr := new(big.Int)
|
||||
ipv6BigIntAddr.SetBytes(ipv6)
|
||||
|
||||
ipv6BigIntMask := new(big.Int)
|
||||
ipv6BigIntMask.SetBytes(network.Mask)
|
||||
|
||||
ipv6Addr := IPv6Addr{
|
||||
Address: IPv6Address(ipv6BigIntAddr),
|
||||
Mask: IPv6Mask(ipv6BigIntMask),
|
||||
}
|
||||
return ipv6Addr, nil
|
||||
}
|
||||
|
||||
return IPv6Addr{}, fmt.Errorf("Unable to parse %+q to an IPv6 address: %v", ipv6Str, err)
|
||||
}
|
||||
|
||||
// AddressBinString returns a string with the IPv6Addr's Address represented
|
||||
// as a sequence of '0' and '1' characters. This method is useful for
|
||||
// debugging or by operators who want to inspect an address.
|
||||
func (ipv6 IPv6Addr) AddressBinString() string {
|
||||
bi := big.Int(*ipv6.Address)
|
||||
return fmt.Sprintf("%0128s", bi.Text(2))
|
||||
}
|
||||
|
||||
// AddressHexString returns a string with the IPv6Addr address represented as
|
||||
// a sequence of hex characters. This method is useful for debugging or by
|
||||
// operators who want to inspect an address.
|
||||
func (ipv6 IPv6Addr) AddressHexString() string {
|
||||
bi := big.Int(*ipv6.Address)
|
||||
return fmt.Sprintf("%032s", bi.Text(16))
|
||||
}
|
||||
|
||||
// CmpAddress follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its address is lower than arg
|
||||
// - 0 if the SockAddr arg equal to the receiving IPv6Addr or the argument is of a
|
||||
// different type.
|
||||
// - 1 If the argument should sort first.
|
||||
func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int {
|
||||
ipv6b, ok := sa.(IPv6Addr)
|
||||
if !ok {
|
||||
return sortDeferDecision
|
||||
}
|
||||
|
||||
ipv6aBigInt := new(big.Int)
|
||||
ipv6aBigInt.Set(ipv6.Address)
|
||||
ipv6bBigInt := new(big.Int)
|
||||
ipv6bBigInt.Set(ipv6b.Address)
|
||||
|
||||
return ipv6aBigInt.Cmp(ipv6bBigInt)
|
||||
}
|
||||
|
||||
// CmpPort follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because its port is lower than arg
|
||||
// - 0 if the SockAddr arg's port number is equal to the receiving IPv6Addr,
|
||||
// regardless of type.
|
||||
// - 1 If the argument should sort first.
|
||||
func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int {
|
||||
var saPort IPPort
|
||||
switch v := sa.(type) {
|
||||
case IPv4Addr:
|
||||
saPort = v.Port
|
||||
case IPv6Addr:
|
||||
saPort = v.Port
|
||||
default:
|
||||
return sortDeferDecision
|
||||
}
|
||||
|
||||
switch {
|
||||
case ipv6.Port == saPort:
|
||||
return sortDeferDecision
|
||||
case ipv6.Port < saPort:
|
||||
return sortReceiverBeforeArg
|
||||
default:
|
||||
return sortArgBeforeReceiver
|
||||
}
|
||||
}
|
||||
|
||||
// CmpRFC follows the Cmp() standard protocol and returns:
|
||||
//
|
||||
// - -1 If the receiver should sort first because it belongs to the RFC and its
|
||||
// arg does not
|
||||
// - 0 if the receiver and arg both belong to the same RFC or neither do.
|
||||
// - 1 If the arg belongs to the RFC but receiver does not.
|
||||
func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
|
||||
recvInRFC := IsRFC(rfcNum, ipv6)
|
||||
ipv6b, ok := sa.(IPv6Addr)
|
||||
if !ok {
|
||||
// If the receiver is part of the desired RFC and the SockAddr
|
||||
// argument is not, sort receiver before the non-IPv6 SockAddr.
|
||||
// Conversely, if the receiver is not part of the RFC, punt on
|
||||
// sorting and leave it for the next sorter.
|
||||
if recvInRFC {
|
||||
return sortReceiverBeforeArg
|
||||
} else {
|
||||
return sortDeferDecision
|
||||
}
|
||||
}
|
||||
|
||||
argInRFC := IsRFC(rfcNum, ipv6b)
|
||||
switch {
|
||||
case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
|
||||
// If a and b both belong to the RFC, or neither belong to
|
||||
// rfcNum, defer sorting to the next sorter.
|
||||
return sortDeferDecision
|
||||
case recvInRFC && !argInRFC:
|
||||
return sortReceiverBeforeArg
|
||||
default:
|
||||
return sortArgBeforeReceiver
|
||||
}
|
||||
}
|
||||
|
||||
// Contains returns true if the SockAddr is contained within the receiver.
|
||||
func (ipv6 IPv6Addr) Contains(sa SockAddr) bool {
|
||||
ipv6b, ok := sa.(IPv6Addr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return ipv6.ContainsNetwork(ipv6b)
|
||||
}
|
||||
|
||||
// ContainsAddress returns true if the IPv6Address is contained within the
|
||||
// receiver.
|
||||
func (ipv6 IPv6Addr) ContainsAddress(x IPv6Address) bool {
|
||||
xAddr := IPv6Addr{
|
||||
Address: x,
|
||||
Mask: ipv6HostMask,
|
||||
}
|
||||
|
||||
{
|
||||
xIPv6 := xAddr.FirstUsable().(IPv6Addr)
|
||||
yIPv6 := ipv6.FirstUsable().(IPv6Addr)
|
||||
if xIPv6.CmpAddress(yIPv6) >= 1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
xIPv6 := xAddr.LastUsable().(IPv6Addr)
|
||||
yIPv6 := ipv6.LastUsable().(IPv6Addr)
|
||||
if xIPv6.CmpAddress(yIPv6) <= -1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ContainsNetwork returns true if the network from IPv6Addr is contained within
|
||||
// the receiver.
|
||||
func (x IPv6Addr) ContainsNetwork(y IPv6Addr) bool {
|
||||
{
|
||||
xIPv6 := x.FirstUsable().(IPv6Addr)
|
||||
yIPv6 := y.FirstUsable().(IPv6Addr)
|
||||
if ret := xIPv6.CmpAddress(yIPv6); ret >= 1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
xIPv6 := x.LastUsable().(IPv6Addr)
|
||||
yIPv6 := y.LastUsable().(IPv6Addr)
|
||||
if ret := xIPv6.CmpAddress(yIPv6); ret <= -1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// DialPacketArgs returns the arguments required to be passed to
|
||||
// net.DialUDP(). If the Mask of ipv6 is not a /128 or the Port is 0,
|
||||
// DialPacketArgs() will fail. See Host() to create an IPv6Addr with its
|
||||
// mask set to /128.
|
||||
func (ipv6 IPv6Addr) DialPacketArgs() (network, dialArgs string) {
|
||||
ipv6Mask := big.Int(*ipv6.Mask)
|
||||
if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
|
||||
return "udp6", ""
|
||||
}
|
||||
return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
|
||||
}
|
||||
|
||||
// DialStreamArgs returns the arguments required to be passed to
|
||||
// net.DialTCP(). If the Mask of ipv6 is not a /128 or the Port is 0,
|
||||
// DialStreamArgs() will fail. See Host() to create an IPv6Addr with its
|
||||
// mask set to /128.
|
||||
func (ipv6 IPv6Addr) DialStreamArgs() (network, dialArgs string) {
|
||||
ipv6Mask := big.Int(*ipv6.Mask)
|
||||
if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
|
||||
return "tcp6", ""
|
||||
}
|
||||
return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
|
||||
}
|
||||
|
||||
// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
|
||||
func (ipv6a IPv6Addr) Equal(sa SockAddr) bool {
|
||||
ipv6b, ok := sa.(IPv6Addr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if ipv6a.NetIP().String() != ipv6b.NetIP().String() {
|
||||
return false
|
||||
}
|
||||
|
||||
if ipv6a.NetIPNet().String() != ipv6b.NetIPNet().String() {
|
||||
return false
|
||||
}
|
||||
|
||||
if ipv6a.Port != ipv6b.Port {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// FirstUsable returns an IPv6Addr set to the first address following the
|
||||
// network prefix. The first usable address in a network is normally the
|
||||
// gateway and should not be used except by devices forwarding packets
|
||||
// between two administratively distinct networks (i.e. a router). This
|
||||
// function does not discriminate against first usable vs "first address that
|
||||
// should be used." For example, FirstUsable() on "2001:0db8::0003/64" would
|
||||
// return "2001:0db8::00011".
|
||||
func (ipv6 IPv6Addr) FirstUsable() IPAddr {
|
||||
return IPv6Addr{
|
||||
Address: IPv6Address(ipv6.NetworkAddress()),
|
||||
Mask: ipv6HostMask,
|
||||
}
|
||||
}
|
||||
|
||||
// Host returns a copy of ipv6 with its mask set to /128 so that it can be
|
||||
// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
|
||||
// ListenStreamArgs().
|
||||
func (ipv6 IPv6Addr) Host() IPAddr {
|
||||
// Nothing should listen on a broadcast address.
|
||||
return IPv6Addr{
|
||||
Address: ipv6.Address,
|
||||
Mask: ipv6HostMask,
|
||||
Port: ipv6.Port,
|
||||
}
|
||||
}
|
||||
|
||||
// IPPort returns the Port number attached to the IPv6Addr
|
||||
func (ipv6 IPv6Addr) IPPort() IPPort {
|
||||
return ipv6.Port
|
||||
}
|
||||
|
||||
// LastUsable returns the last address in a given network.
|
||||
func (ipv6 IPv6Addr) LastUsable() IPAddr {
|
||||
addr := new(big.Int)
|
||||
addr.Set(ipv6.Address)
|
||||
|
||||
mask := new(big.Int)
|
||||
mask.Set(ipv6.Mask)
|
||||
|
||||
negMask := new(big.Int)
|
||||
negMask.Xor(ipv6HostMask, mask)
|
||||
|
||||
lastAddr := new(big.Int)
|
||||
lastAddr.And(addr, mask)
|
||||
lastAddr.Or(lastAddr, negMask)
|
||||
|
||||
return IPv6Addr{
|
||||
Address: IPv6Address(lastAddr),
|
||||
Mask: ipv6HostMask,
|
||||
}
|
||||
}
|
||||
|
||||
// ListenPacketArgs returns the arguments required to be passed to
|
||||
// net.ListenUDP(). If the Mask of ipv6 is not a /128, ListenPacketArgs()
|
||||
// will fail. See Host() to create an IPv6Addr with its mask set to /128.
|
||||
func (ipv6 IPv6Addr) ListenPacketArgs() (network, listenArgs string) {
|
||||
ipv6Mask := big.Int(*ipv6.Mask)
|
||||
if ipv6Mask.Cmp(ipv6HostMask) != 0 {
|
||||
return "udp6", ""
|
||||
}
|
||||
return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
|
||||
}
|
||||
|
||||
// ListenStreamArgs returns the arguments required to be passed to
|
||||
// net.ListenTCP(). If the Mask of ipv6 is not a /128, ListenStreamArgs()
|
||||
// will fail. See Host() to create an IPv6Addr with its mask set to /128.
|
||||
func (ipv6 IPv6Addr) ListenStreamArgs() (network, listenArgs string) {
|
||||
ipv6Mask := big.Int(*ipv6.Mask)
|
||||
if ipv6Mask.Cmp(ipv6HostMask) != 0 {
|
||||
return "tcp6", ""
|
||||
}
|
||||
return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
|
||||
}
|
||||
|
||||
// Maskbits returns the number of network mask bits in a given IPv6Addr. For
|
||||
// example, the Maskbits() of "2001:0db8::0003/64" would return 64.
|
||||
func (ipv6 IPv6Addr) Maskbits() int {
|
||||
maskOnes, _ := ipv6.NetIPNet().Mask.Size()
|
||||
|
||||
return maskOnes
|
||||
}
|
||||
|
||||
// MustIPv6Addr is a helper method that must return an IPv6Addr or panic on
|
||||
// invalid input.
|
||||
func MustIPv6Addr(addr string) IPv6Addr {
|
||||
ipv6, err := NewIPv6Addr(addr)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Unable to create an IPv6Addr from %+q: %v", addr, err))
|
||||
}
|
||||
return ipv6
|
||||
}
|
||||
|
||||
// NetIP returns the address as a net.IP.
|
||||
func (ipv6 IPv6Addr) NetIP() *net.IP {
|
||||
return bigIntToNetIPv6(ipv6.Address)
|
||||
}
|
||||
|
||||
// NetIPMask create a new net.IPMask from the IPv6Addr.
|
||||
func (ipv6 IPv6Addr) NetIPMask() *net.IPMask {
|
||||
ipv6Mask := make(net.IPMask, IPv6len)
|
||||
m := big.Int(*ipv6.Mask)
|
||||
copy(ipv6Mask, m.Bytes())
|
||||
return &ipv6Mask
|
||||
}
|
||||
|
||||
// Network returns a pointer to the net.IPNet within IPv4Addr receiver.
|
||||
func (ipv6 IPv6Addr) NetIPNet() *net.IPNet {
|
||||
ipv6net := &net.IPNet{}
|
||||
ipv6net.IP = make(net.IP, IPv6len)
|
||||
copy(ipv6net.IP, *ipv6.NetIP())
|
||||
ipv6net.Mask = *ipv6.NetIPMask()
|
||||
return ipv6net
|
||||
}
|
||||
|
||||
// Network returns the network prefix or network address for a given network.
|
||||
func (ipv6 IPv6Addr) Network() IPAddr {
|
||||
return IPv6Addr{
|
||||
Address: IPv6Address(ipv6.NetworkAddress()),
|
||||
Mask: ipv6.Mask,
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkAddress returns an IPv6Network of the IPv6Addr's network address.
|
||||
func (ipv6 IPv6Addr) NetworkAddress() IPv6Network {
|
||||
addr := new(big.Int)
|
||||
addr.SetBytes((*ipv6.Address).Bytes())
|
||||
|
||||
mask := new(big.Int)
|
||||
mask.SetBytes(*ipv6.NetIPMask())
|
||||
|
||||
netAddr := new(big.Int)
|
||||
netAddr.And(addr, mask)
|
||||
|
||||
return IPv6Network(netAddr)
|
||||
}
|
||||
|
||||
// Octets returns a slice of the 16 octets in an IPv6Addr's Address. The
|
||||
// order of the bytes is big endian.
|
||||
func (ipv6 IPv6Addr) Octets() []int {
|
||||
x := make([]int, IPv6len)
|
||||
for i, b := range *bigIntToNetIPv6(ipv6.Address) {
|
||||
x[i] = int(b)
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
// String returns a string representation of the IPv6Addr
|
||||
func (ipv6 IPv6Addr) String() string {
|
||||
if ipv6.Port != 0 {
|
||||
return fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
|
||||
}
|
||||
|
||||
if ipv6.Maskbits() == 128 {
|
||||
return ipv6.NetIP().String()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s/%d", ipv6.NetIP().String(), ipv6.Maskbits())
|
||||
}
|
||||
|
||||
// Type is used as a type switch and returns TypeIPv6
|
||||
func (IPv6Addr) Type() SockAddrType {
|
||||
return TypeIPv6
|
||||
}
|
||||
|
||||
// IPv6Attrs returns a list of attributes supported by the IPv6Addr type
|
||||
func IPv6Attrs() []AttrName {
|
||||
return ipv6AddrAttrs
|
||||
}
|
||||
|
||||
// IPv6AddrAttr returns a string representation of an attribute for the given
|
||||
// IPv6Addr.
|
||||
func IPv6AddrAttr(ipv6 IPv6Addr, selector AttrName) string {
|
||||
fn, found := ipv6AddrAttrMap[selector]
|
||||
if !found {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fn(ipv6)
|
||||
}
|
||||
|
||||
// ipv6AddrInit is called once at init()
|
||||
func ipv6AddrInit() {
|
||||
// Sorted for human readability
|
||||
ipv6AddrAttrs = []AttrName{
|
||||
"size", // Same position as in IPv6 for output consistency
|
||||
"uint128",
|
||||
}
|
||||
|
||||
ipv6AddrAttrMap = map[AttrName]func(ipv6 IPv6Addr) string{
|
||||
"size": func(ipv6 IPv6Addr) string {
|
||||
netSize := big.NewInt(1)
|
||||
netSize = netSize.Lsh(netSize, uint(IPv6len*8-ipv6.Maskbits()))
|
||||
return netSize.Text(10)
|
||||
},
|
||||
"uint128": func(ipv6 IPv6Addr) string {
|
||||
b := big.Int(*ipv6.Address)
|
||||
return b.Text(10)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// bigIntToNetIPv6 is a helper function that correctly returns a net.IP with the
|
||||
// correctly padded values.
|
||||
func bigIntToNetIPv6(bi *big.Int) *net.IP {
|
||||
x := make(net.IP, IPv6len)
|
||||
ipv6Bytes := bi.Bytes()
|
||||
|
||||
// It's possibe for ipv6Bytes to be less than IPv6len bytes in size. If
|
||||
// they are different sizes we to pad the size of response.
|
||||
if len(ipv6Bytes) < IPv6len {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Grow(IPv6len)
|
||||
|
||||
for i := len(ipv6Bytes); i < IPv6len; i++ {
|
||||
if err := binary.Write(buf, binary.BigEndian, byte(0)); err != nil {
|
||||
panic(fmt.Sprintf("Unable to pad byte %d of input %v: %v", i, bi, err))
|
||||
}
|
||||
}
|
||||
|
||||
for _, b := range ipv6Bytes {
|
||||
if err := binary.Write(buf, binary.BigEndian, b); err != nil {
|
||||
panic(fmt.Sprintf("Unable to preserve endianness of input %v: %v", bi, err))
|
||||
}
|
||||
}
|
||||
|
||||
ipv6Bytes = buf.Bytes()
|
||||
}
|
||||
i := copy(x, ipv6Bytes)
|
||||
if i != IPv6len {
|
||||
panic("IPv6 wrong size")
|
||||
}
|
||||
return &x
|
||||
}
|
948
vendor/github.com/hashicorp/go-sockaddr/rfc.go
generated
vendored
Normal file
948
vendor/github.com/hashicorp/go-sockaddr/rfc.go
generated
vendored
Normal file
|
@ -0,0 +1,948 @@
|
|||
package sockaddr
|
||||
|
||||
// ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP
|
||||
// blocks.
|
||||
const ForwardingBlacklist = 4294967295
|
||||
const ForwardingBlacklistRFC = "4294967295"
|
||||
|
||||
// IsRFC tests to see if an SockAddr matches the specified RFC
|
||||
func IsRFC(rfcNum uint, sa SockAddr) bool {
|
||||
rfcNetMap := KnownRFCs()
|
||||
rfcNets, ok := rfcNetMap[rfcNum]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
var contained bool
|
||||
for _, rfcNet := range rfcNets {
|
||||
if rfcNet.Contains(sa) {
|
||||
contained = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return contained
|
||||
}
|
||||
|
||||
// KnownRFCs returns an initial set of known RFCs.
|
||||
//
|
||||
// NOTE (sean@): As this list evolves over time, please submit patches to keep
|
||||
// this list current. If something isn't right, inquire, as it may just be a
|
||||
// bug on my part. Some of the inclusions were based on my judgement as to what
|
||||
// would be a useful value (e.g. RFC3330).
|
||||
//
|
||||
// Useful resources:
|
||||
//
|
||||
// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
|
||||
// * https://www.iana.org/assignments/ipv6-unicast-address-assignments/ipv6-unicast-address-assignments.xhtml
|
||||
// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
|
||||
func KnownRFCs() map[uint]SockAddrs {
|
||||
// NOTE(sean@): Multiple SockAddrs per RFC lend themselves well to a
|
||||
// RADIX tree, but `ENOTIME`. Patches welcome.
|
||||
return map[uint]SockAddrs{
|
||||
919: {
|
||||
// [RFC919] Broadcasting Internet Datagrams
|
||||
MustIPv4Addr("255.255.255.255/32"), // [RFC1122], §7 Broadcast IP Addressing - Proposed Standards
|
||||
},
|
||||
1122: {
|
||||
// [RFC1122] Requirements for Internet Hosts -- Communication Layers
|
||||
MustIPv4Addr("0.0.0.0/8"), // [RFC1122], §3.2.1.3
|
||||
MustIPv4Addr("127.0.0.0/8"), // [RFC1122], §3.2.1.3
|
||||
},
|
||||
1112: {
|
||||
// [RFC1112] Host Extensions for IP Multicasting
|
||||
MustIPv4Addr("224.0.0.0/4"), // [RFC1112], §4 Host Group Addresses
|
||||
},
|
||||
1918: {
|
||||
// [RFC1918] Address Allocation for Private Internets
|
||||
MustIPv4Addr("10.0.0.0/8"),
|
||||
MustIPv4Addr("172.16.0.0/12"),
|
||||
MustIPv4Addr("192.168.0.0/16"),
|
||||
},
|
||||
2544: {
|
||||
// [RFC2544] Benchmarking Methodology for Network
|
||||
// Interconnect Devices
|
||||
MustIPv4Addr("198.18.0.0/15"),
|
||||
},
|
||||
2765: {
|
||||
// [RFC2765] Stateless IP/ICMP Translation Algorithm
|
||||
// (SIIT) (obsoleted by RFCs 6145, which itself was
|
||||
// later obsoleted by 7915).
|
||||
|
||||
// [RFC2765], §2.1 Addresses
|
||||
MustIPv6Addr("0:0:0:0:0:ffff:0:0/96"),
|
||||
},
|
||||
2928: {
|
||||
// [RFC2928] Initial IPv6 Sub-TLA ID Assignments
|
||||
MustIPv6Addr("2001::/16"), // Superblock
|
||||
//MustIPv6Addr("2001:0000::/23"), // IANA
|
||||
//MustIPv6Addr("2001:0200::/23"), // APNIC
|
||||
//MustIPv6Addr("2001:0400::/23"), // ARIN
|
||||
//MustIPv6Addr("2001:0600::/23"), // RIPE NCC
|
||||
//MustIPv6Addr("2001:0800::/23"), // (future assignment)
|
||||
// ...
|
||||
//MustIPv6Addr("2001:FE00::/23"), // (future assignment)
|
||||
},
|
||||
3056: { // 6to4 address
|
||||
// [RFC3056] Connection of IPv6 Domains via IPv4 Clouds
|
||||
|
||||
// [RFC3056], §2 IPv6 Prefix Allocation
|
||||
MustIPv6Addr("2002::/16"),
|
||||
},
|
||||
3068: {
|
||||
// [RFC3068] An Anycast Prefix for 6to4 Relay Routers
|
||||
// (obsolete by RFC7526)
|
||||
|
||||
// [RFC3068], § 6to4 Relay anycast address
|
||||
MustIPv4Addr("192.88.99.0/24"),
|
||||
|
||||
// [RFC3068], §2.5 6to4 IPv6 relay anycast address
|
||||
//
|
||||
// NOTE: /120 == 128-(32-24)
|
||||
MustIPv6Addr("2002:c058:6301::/120"),
|
||||
},
|
||||
3171: {
|
||||
// [RFC3171] IANA Guidelines for IPv4 Multicast Address Assignments
|
||||
MustIPv4Addr("224.0.0.0/4"),
|
||||
},
|
||||
3330: {
|
||||
// [RFC3330] Special-Use IPv4 Addresses
|
||||
|
||||
// Addresses in this block refer to source hosts on
|
||||
// "this" network. Address 0.0.0.0/32 may be used as a
|
||||
// source address for this host on this network; other
|
||||
// addresses within 0.0.0.0/8 may be used to refer to
|
||||
// specified hosts on this network [RFC1700, page 4].
|
||||
MustIPv4Addr("0.0.0.0/8"),
|
||||
|
||||
// 10.0.0.0/8 - This block is set aside for use in
|
||||
// private networks. Its intended use is documented in
|
||||
// [RFC1918]. Addresses within this block should not
|
||||
// appear on the public Internet.
|
||||
MustIPv4Addr("10.0.0.0/8"),
|
||||
|
||||
// 14.0.0.0/8 - This block is set aside for assignments
|
||||
// to the international system of Public Data Networks
|
||||
// [RFC1700, page 181]. The registry of assignments
|
||||
// within this block can be accessed from the "Public
|
||||
// Data Network Numbers" link on the web page at
|
||||
// http://www.iana.org/numbers.html. Addresses within
|
||||
// this block are assigned to users and should be
|
||||
// treated as such.
|
||||
|
||||
// 24.0.0.0/8 - This block was allocated in early 1996
|
||||
// for use in provisioning IP service over cable
|
||||
// television systems. Although the IANA initially was
|
||||
// involved in making assignments to cable operators,
|
||||
// this responsibility was transferred to American
|
||||
// Registry for Internet Numbers (ARIN) in May 2001.
|
||||
// Addresses within this block are assigned in the
|
||||
// normal manner and should be treated as such.
|
||||
|
||||
// 39.0.0.0/8 - This block was used in the "Class A
|
||||
// Subnet Experiment" that commenced in May 1995, as
|
||||
// documented in [RFC1797]. The experiment has been
|
||||
// completed and this block has been returned to the
|
||||
// pool of addresses reserved for future allocation or
|
||||
// assignment. This block therefore no longer has a
|
||||
// special use and is subject to allocation to a
|
||||
// Regional Internet Registry for assignment in the
|
||||
// normal manner.
|
||||
|
||||
// 127.0.0.0/8 - This block is assigned for use as the Internet host
|
||||
// loopback address. A datagram sent by a higher level protocol to an
|
||||
// address anywhere within this block should loop back inside the host.
|
||||
// This is ordinarily implemented using only 127.0.0.1/32 for loopback,
|
||||
// but no addresses within this block should ever appear on any network
|
||||
// anywhere [RFC1700, page 5].
|
||||
MustIPv4Addr("127.0.0.0/8"),
|
||||
|
||||
// 128.0.0.0/16 - This block, corresponding to the
|
||||
// numerically lowest of the former Class B addresses,
|
||||
// was initially and is still reserved by the IANA.
|
||||
// Given the present classless nature of the IP address
|
||||
// space, the basis for the reservation no longer
|
||||
// applies and addresses in this block are subject to
|
||||
// future allocation to a Regional Internet Registry for
|
||||
// assignment in the normal manner.
|
||||
|
||||
// 169.254.0.0/16 - This is the "link local" block. It
|
||||
// is allocated for communication between hosts on a
|
||||
// single link. Hosts obtain these addresses by
|
||||
// auto-configuration, such as when a DHCP server may
|
||||
// not be found.
|
||||
MustIPv4Addr("169.254.0.0/16"),
|
||||
|
||||
// 172.16.0.0/12 - This block is set aside for use in
|
||||
// private networks. Its intended use is documented in
|
||||
// [RFC1918]. Addresses within this block should not
|
||||
// appear on the public Internet.
|
||||
MustIPv4Addr("172.16.0.0/12"),
|
||||
|
||||
// 191.255.0.0/16 - This block, corresponding to the numerically highest
|
||||
// to the former Class B addresses, was initially and is still reserved
|
||||
// by the IANA. Given the present classless nature of the IP address
|
||||
// space, the basis for the reservation no longer applies and addresses
|
||||
// in this block are subject to future allocation to a Regional Internet
|
||||
// Registry for assignment in the normal manner.
|
||||
|
||||
// 192.0.0.0/24 - This block, corresponding to the
|
||||
// numerically lowest of the former Class C addresses,
|
||||
// was initially and is still reserved by the IANA.
|
||||
// Given the present classless nature of the IP address
|
||||
// space, the basis for the reservation no longer
|
||||
// applies and addresses in this block are subject to
|
||||
// future allocation to a Regional Internet Registry for
|
||||
// assignment in the normal manner.
|
||||
|
||||
// 192.0.2.0/24 - This block is assigned as "TEST-NET" for use in
|
||||
// documentation and example code. It is often used in conjunction with
|
||||
// domain names example.com or example.net in vendor and protocol
|
||||
// documentation. Addresses within this block should not appear on the
|
||||
// public Internet.
|
||||
MustIPv4Addr("192.0.2.0/24"),
|
||||
|
||||
// 192.88.99.0/24 - This block is allocated for use as 6to4 relay
|
||||
// anycast addresses, according to [RFC3068].
|
||||
MustIPv4Addr("192.88.99.0/24"),
|
||||
|
||||
// 192.168.0.0/16 - This block is set aside for use in private networks.
|
||||
// Its intended use is documented in [RFC1918]. Addresses within this
|
||||
// block should not appear on the public Internet.
|
||||
MustIPv4Addr("192.168.0.0/16"),
|
||||
|
||||
// 198.18.0.0/15 - This block has been allocated for use
|
||||
// in benchmark tests of network interconnect devices.
|
||||
// Its use is documented in [RFC2544].
|
||||
MustIPv4Addr("198.18.0.0/15"),
|
||||
|
||||
// 223.255.255.0/24 - This block, corresponding to the
|
||||
// numerically highest of the former Class C addresses,
|
||||
// was initially and is still reserved by the IANA.
|
||||
// Given the present classless nature of the IP address
|
||||
// space, the basis for the reservation no longer
|
||||
// applies and addresses in this block are subject to
|
||||
// future allocation to a Regional Internet Registry for
|
||||
// assignment in the normal manner.
|
||||
|
||||
// 224.0.0.0/4 - This block, formerly known as the Class
|
||||
// D address space, is allocated for use in IPv4
|
||||
// multicast address assignments. The IANA guidelines
|
||||
// for assignments from this space are described in
|
||||
// [RFC3171].
|
||||
MustIPv4Addr("224.0.0.0/4"),
|
||||
|
||||
// 240.0.0.0/4 - This block, formerly known as the Class E address
|
||||
// space, is reserved. The "limited broadcast" destination address
|
||||
// 255.255.255.255 should never be forwarded outside the (sub-)net of
|
||||
// the source. The remainder of this space is reserved
|
||||
// for future use. [RFC1700, page 4]
|
||||
MustIPv4Addr("240.0.0.0/4"),
|
||||
},
|
||||
3849: {
|
||||
// [RFC3849] IPv6 Address Prefix Reserved for Documentation
|
||||
MustIPv6Addr("2001:db8::/32"), // [RFC3849], §4 IANA Considerations
|
||||
},
|
||||
3927: {
|
||||
// [RFC3927] Dynamic Configuration of IPv4 Link-Local Addresses
|
||||
MustIPv4Addr("169.254.0.0/16"), // [RFC3927], §2.1 Link-Local Address Selection
|
||||
},
|
||||
4038: {
|
||||
// [RFC4038] Application Aspects of IPv6 Transition
|
||||
|
||||
// [RFC4038], §4.2. IPv6 Applications in a Dual-Stack Node
|
||||
MustIPv6Addr("0:0:0:0:0:ffff::/96"),
|
||||
},
|
||||
4193: {
|
||||
// [RFC4193] Unique Local IPv6 Unicast Addresses
|
||||
MustIPv6Addr("fc00::/7"),
|
||||
},
|
||||
4291: {
|
||||
// [RFC4291] IP Version 6 Addressing Architecture
|
||||
|
||||
// [RFC4291], §2.5.2 The Unspecified Address
|
||||
MustIPv6Addr("::/128"),
|
||||
|
||||
// [RFC4291], §2.5.3 The Loopback Address
|
||||
MustIPv6Addr("::1/128"),
|
||||
|
||||
// [RFC4291], §2.5.5.1. IPv4-Compatible IPv6 Address
|
||||
MustIPv6Addr("::/96"),
|
||||
|
||||
// [RFC4291], §2.5.5.2. IPv4-Mapped IPv6 Address
|
||||
MustIPv6Addr("::ffff:0:0/96"),
|
||||
|
||||
// [RFC4291], §2.5.6 Link-Local IPv6 Unicast Addresses
|
||||
MustIPv6Addr("fe80::/10"),
|
||||
|
||||
// [RFC4291], §2.5.7 Site-Local IPv6 Unicast Addresses
|
||||
// (depreciated)
|
||||
MustIPv6Addr("fec0::/10"),
|
||||
|
||||
// [RFC4291], §2.7 Multicast Addresses
|
||||
MustIPv6Addr("ff00::/8"),
|
||||
|
||||
// IPv6 Multicast Information.
|
||||
//
|
||||
// In the following "table" below, `ff0x` is replaced
|
||||
// with the following values depending on the scope of
|
||||
// the query:
|
||||
//
|
||||
// IPv6 Multicast Scopes:
|
||||
// * ff00/9 // reserved
|
||||
// * ff01/9 // interface-local
|
||||
// * ff02/9 // link-local
|
||||
// * ff03/9 // realm-local
|
||||
// * ff04/9 // admin-local
|
||||
// * ff05/9 // site-local
|
||||
// * ff08/9 // organization-local
|
||||
// * ff0e/9 // global
|
||||
// * ff0f/9 // reserved
|
||||
//
|
||||
// IPv6 Multicast Addresses:
|
||||
// * ff0x::2 // All routers
|
||||
// * ff02::5 // OSPFIGP
|
||||
// * ff02::6 // OSPFIGP Designated Routers
|
||||
// * ff02::9 // RIP Routers
|
||||
// * ff02::a // EIGRP Routers
|
||||
// * ff02::d // All PIM Routers
|
||||
// * ff02::1a // All RPL Routers
|
||||
// * ff0x::fb // mDNSv6
|
||||
// * ff0x::101 // All Network Time Protocol (NTP) servers
|
||||
// * ff02::1:1 // Link Name
|
||||
// * ff02::1:2 // All-dhcp-agents
|
||||
// * ff02::1:3 // Link-local Multicast Name Resolution
|
||||
// * ff05::1:3 // All-dhcp-servers
|
||||
// * ff02::1:ff00:0/104 // Solicited-node multicast address.
|
||||
// * ff02::2:ff00:0/104 // Node Information Queries
|
||||
},
|
||||
4380: {
|
||||
// [RFC4380] Teredo: Tunneling IPv6 over UDP through
|
||||
// Network Address Translations (NATs)
|
||||
|
||||
// [RFC4380], §2.6 Global Teredo IPv6 Service Prefix
|
||||
MustIPv6Addr("2001:0000::/32"),
|
||||
},
|
||||
4773: {
|
||||
// [RFC4773] Administration of the IANA Special Purpose IPv6 Address Block
|
||||
MustIPv6Addr("2001:0000::/23"), // IANA
|
||||
},
|
||||
4843: {
|
||||
// [RFC4843] An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers (ORCHID)
|
||||
MustIPv6Addr("2001:10::/28"), // [RFC4843], §7 IANA Considerations
|
||||
},
|
||||
5180: {
|
||||
// [RFC5180] IPv6 Benchmarking Methodology for Network Interconnect Devices
|
||||
MustIPv6Addr("2001:0200::/48"), // [RFC5180], §8 IANA Considerations
|
||||
},
|
||||
5735: {
|
||||
// [RFC5735] Special Use IPv4 Addresses
|
||||
MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
|
||||
MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
|
||||
MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
|
||||
MustIPv4Addr("198.18.0.0/15"), // Benchmarks
|
||||
},
|
||||
5737: {
|
||||
// [RFC5737] IPv4 Address Blocks Reserved for Documentation
|
||||
MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
|
||||
MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
|
||||
MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
|
||||
},
|
||||
6052: {
|
||||
// [RFC6052] IPv6 Addressing of IPv4/IPv6 Translators
|
||||
MustIPv6Addr("64:ff9b::/96"), // [RFC6052], §2.1. Well-Known Prefix
|
||||
},
|
||||
6333: {
|
||||
// [RFC6333] Dual-Stack Lite Broadband Deployments Following IPv4 Exhaustion
|
||||
MustIPv4Addr("192.0.0.0/29"), // [RFC6333], §5.7 Well-Known IPv4 Address
|
||||
},
|
||||
6598: {
|
||||
// [RFC6598] IANA-Reserved IPv4 Prefix for Shared Address Space
|
||||
MustIPv4Addr("100.64.0.0/10"),
|
||||
},
|
||||
6666: {
|
||||
// [RFC6666] A Discard Prefix for IPv6
|
||||
MustIPv6Addr("0100::/64"),
|
||||
},
|
||||
6890: {
|
||||
// [RFC6890] Special-Purpose IP Address Registries
|
||||
|
||||
// From "RFC6890 §2.2.1 Information Requirements":
|
||||
/*
|
||||
The IPv4 and IPv6 Special-Purpose Address Registries maintain the
|
||||
following information regarding each entry:
|
||||
|
||||
o Address Block - A block of IPv4 or IPv6 addresses that has been
|
||||
registered for a special purpose.
|
||||
|
||||
o Name - A descriptive name for the special-purpose address block.
|
||||
|
||||
o RFC - The RFC through which the special-purpose address block was
|
||||
requested.
|
||||
|
||||
o Allocation Date - The date upon which the special-purpose address
|
||||
block was allocated.
|
||||
|
||||
o Termination Date - The date upon which the allocation is to be
|
||||
terminated. This field is applicable for limited-use allocations
|
||||
only.
|
||||
|
||||
o Source - A boolean value indicating whether an address from the
|
||||
allocated special-purpose address block is valid when used as the
|
||||
source address of an IP datagram that transits two devices.
|
||||
|
||||
o Destination - A boolean value indicating whether an address from
|
||||
the allocated special-purpose address block is valid when used as
|
||||
the destination address of an IP datagram that transits two
|
||||
devices.
|
||||
|
||||
o Forwardable - A boolean value indicating whether a router may
|
||||
forward an IP datagram whose destination address is drawn from the
|
||||
allocated special-purpose address block between external
|
||||
interfaces.
|
||||
|
||||
o Global - A boolean value indicating whether an IP datagram whose
|
||||
destination address is drawn from the allocated special-purpose
|
||||
address block is forwardable beyond a specified administrative
|
||||
domain.
|
||||
|
||||
o Reserved-by-Protocol - A boolean value indicating whether the
|
||||
special-purpose address block is reserved by IP, itself. This
|
||||
value is "TRUE" if the RFC that created the special-purpose
|
||||
address block requires all compliant IP implementations to behave
|
||||
in a special way when processing packets either to or from
|
||||
addresses contained by the address block.
|
||||
|
||||
If the value of "Destination" is FALSE, the values of "Forwardable"
|
||||
and "Global" must also be false.
|
||||
*/
|
||||
|
||||
/*+----------------------+----------------------------+
|
||||
* | Attribute | Value |
|
||||
* +----------------------+----------------------------+
|
||||
* | Address Block | 0.0.0.0/8 |
|
||||
* | Name | "This host on this network"|
|
||||
* | RFC | [RFC1122], Section 3.2.1.3 |
|
||||
* | Allocation Date | September 1981 |
|
||||
* | Termination Date | N/A |
|
||||
* | Source | True |
|
||||
* | Destination | False |
|
||||
* | Forwardable | False |
|
||||
* | Global | False |
|
||||
* | Reserved-by-Protocol | True |
|
||||
* +----------------------+----------------------------+*/
|
||||
MustIPv4Addr("0.0.0.0/8"),
|
||||
|
||||
/*+----------------------+---------------+
|
||||
* | Attribute | Value |
|
||||
* +----------------------+---------------+
|
||||
* | Address Block | 10.0.0.0/8 |
|
||||
* | Name | Private-Use |
|
||||
* | RFC | [RFC1918] |
|
||||
* | Allocation Date | February 1996 |
|
||||
* | Termination Date | N/A |
|
||||
* | Source | True |
|
||||
* | Destination | True |
|
||||
* | Forwardable | True |
|
||||
* | Global | False |
|
||||
* | Reserved-by-Protocol | False |
|
||||
* +----------------------+---------------+ */
|
||||
MustIPv4Addr("10.0.0.0/8"),
|
||||
|
||||
/*+----------------------+----------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------------+
|
||||
| Address Block | 100.64.0.0/10 |
|
||||
| Name | Shared Address Space |
|
||||
| RFC | [RFC6598] |
|
||||
| Allocation Date | April 2012 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------------+*/
|
||||
MustIPv4Addr("100.64.0.0/10"),
|
||||
|
||||
/*+----------------------+----------------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------------------+
|
||||
| Address Block | 127.0.0.0/8 |
|
||||
| Name | Loopback |
|
||||
| RFC | [RFC1122], Section 3.2.1.3 |
|
||||
| Allocation Date | September 1981 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False [1] |
|
||||
| Destination | False [1] |
|
||||
| Forwardable | False [1] |
|
||||
| Global | False [1] |
|
||||
| Reserved-by-Protocol | True |
|
||||
+----------------------+----------------------------+*/
|
||||
// [1] Several protocols have been granted exceptions to
|
||||
// this rule. For examples, see [RFC4379] and
|
||||
// [RFC5884].
|
||||
MustIPv4Addr("127.0.0.0/8"),
|
||||
|
||||
/*+----------------------+----------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------+
|
||||
| Address Block | 169.254.0.0/16 |
|
||||
| Name | Link Local |
|
||||
| RFC | [RFC3927] |
|
||||
| Allocation Date | May 2005 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | True |
|
||||
+----------------------+----------------+*/
|
||||
MustIPv4Addr("169.254.0.0/16"),
|
||||
|
||||
/*+----------------------+---------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------+
|
||||
| Address Block | 172.16.0.0/12 |
|
||||
| Name | Private-Use |
|
||||
| RFC | [RFC1918] |
|
||||
| Allocation Date | February 1996 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+---------------+*/
|
||||
MustIPv4Addr("172.16.0.0/12"),
|
||||
|
||||
/*+----------------------+---------------------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------------------------+
|
||||
| Address Block | 192.0.0.0/24 [2] |
|
||||
| Name | IETF Protocol Assignments |
|
||||
| RFC | Section 2.1 of this document |
|
||||
| Allocation Date | January 2010 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+---------------------------------+*/
|
||||
// [2] Not usable unless by virtue of a more specific
|
||||
// reservation.
|
||||
MustIPv4Addr("192.0.0.0/24"),
|
||||
|
||||
/*+----------------------+--------------------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+--------------------------------+
|
||||
| Address Block | 192.0.0.0/29 |
|
||||
| Name | IPv4 Service Continuity Prefix |
|
||||
| RFC | [RFC6333], [RFC7335] |
|
||||
| Allocation Date | June 2011 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+--------------------------------+*/
|
||||
MustIPv4Addr("192.0.0.0/29"),
|
||||
|
||||
/*+----------------------+----------------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------------------+
|
||||
| Address Block | 192.0.2.0/24 |
|
||||
| Name | Documentation (TEST-NET-1) |
|
||||
| RFC | [RFC5737] |
|
||||
| Allocation Date | January 2010 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------------------+*/
|
||||
MustIPv4Addr("192.0.2.0/24"),
|
||||
|
||||
/*+----------------------+--------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+--------------------+
|
||||
| Address Block | 192.88.99.0/24 |
|
||||
| Name | 6to4 Relay Anycast |
|
||||
| RFC | [RFC3068] |
|
||||
| Allocation Date | June 2001 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | True |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+--------------------+*/
|
||||
MustIPv4Addr("192.88.99.0/24"),
|
||||
|
||||
/*+----------------------+----------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------+
|
||||
| Address Block | 192.168.0.0/16 |
|
||||
| Name | Private-Use |
|
||||
| RFC | [RFC1918] |
|
||||
| Allocation Date | February 1996 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------+*/
|
||||
MustIPv4Addr("192.168.0.0/16"),
|
||||
|
||||
/*+----------------------+---------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------+
|
||||
| Address Block | 198.18.0.0/15 |
|
||||
| Name | Benchmarking |
|
||||
| RFC | [RFC2544] |
|
||||
| Allocation Date | March 1999 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+---------------+*/
|
||||
MustIPv4Addr("198.18.0.0/15"),
|
||||
|
||||
/*+----------------------+----------------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------------------+
|
||||
| Address Block | 198.51.100.0/24 |
|
||||
| Name | Documentation (TEST-NET-2) |
|
||||
| RFC | [RFC5737] |
|
||||
| Allocation Date | January 2010 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------------------+*/
|
||||
MustIPv4Addr("198.51.100.0/24"),
|
||||
|
||||
/*+----------------------+----------------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------------------+
|
||||
| Address Block | 203.0.113.0/24 |
|
||||
| Name | Documentation (TEST-NET-3) |
|
||||
| RFC | [RFC5737] |
|
||||
| Allocation Date | January 2010 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------------------+*/
|
||||
MustIPv4Addr("203.0.113.0/24"),
|
||||
|
||||
/*+----------------------+----------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------------+
|
||||
| Address Block | 240.0.0.0/4 |
|
||||
| Name | Reserved |
|
||||
| RFC | [RFC1112], Section 4 |
|
||||
| Allocation Date | August 1989 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | True |
|
||||
+----------------------+----------------------+*/
|
||||
MustIPv4Addr("240.0.0.0/4"),
|
||||
|
||||
/*+----------------------+----------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------------+
|
||||
| Address Block | 255.255.255.255/32 |
|
||||
| Name | Limited Broadcast |
|
||||
| RFC | [RFC0919], Section 7 |
|
||||
| Allocation Date | October 1984 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | True |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------------+*/
|
||||
MustIPv4Addr("255.255.255.255/32"),
|
||||
|
||||
/*+----------------------+------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+------------------+
|
||||
| Address Block | ::1/128 |
|
||||
| Name | Loopback Address |
|
||||
| RFC | [RFC4291] |
|
||||
| Allocation Date | February 2006 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | True |
|
||||
+----------------------+------------------+*/
|
||||
MustIPv6Addr("::1/128"),
|
||||
|
||||
/*+----------------------+---------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------------+
|
||||
| Address Block | ::/128 |
|
||||
| Name | Unspecified Address |
|
||||
| RFC | [RFC4291] |
|
||||
| Allocation Date | February 2006 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | True |
|
||||
+----------------------+---------------------+*/
|
||||
MustIPv6Addr("::/128"),
|
||||
|
||||
/*+----------------------+---------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------------+
|
||||
| Address Block | 64:ff9b::/96 |
|
||||
| Name | IPv4-IPv6 Translat. |
|
||||
| RFC | [RFC6052] |
|
||||
| Allocation Date | October 2010 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | True |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+---------------------+*/
|
||||
MustIPv6Addr("64:ff9b::/96"),
|
||||
|
||||
/*+----------------------+---------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------------+
|
||||
| Address Block | ::ffff:0:0/96 |
|
||||
| Name | IPv4-mapped Address |
|
||||
| RFC | [RFC4291] |
|
||||
| Allocation Date | February 2006 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | True |
|
||||
+----------------------+---------------------+*/
|
||||
MustIPv6Addr("::ffff:0:0/96"),
|
||||
|
||||
/*+----------------------+----------------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------------------+
|
||||
| Address Block | 100::/64 |
|
||||
| Name | Discard-Only Address Block |
|
||||
| RFC | [RFC6666] |
|
||||
| Allocation Date | June 2012 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------------------+*/
|
||||
MustIPv6Addr("100::/64"),
|
||||
|
||||
/*+----------------------+---------------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------------------+
|
||||
| Address Block | 2001::/23 |
|
||||
| Name | IETF Protocol Assignments |
|
||||
| RFC | [RFC2928] |
|
||||
| Allocation Date | September 2000 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False[1] |
|
||||
| Destination | False[1] |
|
||||
| Forwardable | False[1] |
|
||||
| Global | False[1] |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+---------------------------+*/
|
||||
// [1] Unless allowed by a more specific allocation.
|
||||
MustIPv6Addr("2001::/16"),
|
||||
|
||||
/*+----------------------+----------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------+
|
||||
| Address Block | 2001::/32 |
|
||||
| Name | TEREDO |
|
||||
| RFC | [RFC4380] |
|
||||
| Allocation Date | January 2006 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------+*/
|
||||
// Covered by previous entry, included for completeness.
|
||||
//
|
||||
// MustIPv6Addr("2001::/16"),
|
||||
|
||||
/*+----------------------+----------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+----------------+
|
||||
| Address Block | 2001:2::/48 |
|
||||
| Name | Benchmarking |
|
||||
| RFC | [RFC5180] |
|
||||
| Allocation Date | April 2008 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+----------------+*/
|
||||
// Covered by previous entry, included for completeness.
|
||||
//
|
||||
// MustIPv6Addr("2001:2::/48"),
|
||||
|
||||
/*+----------------------+---------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------+
|
||||
| Address Block | 2001:db8::/32 |
|
||||
| Name | Documentation |
|
||||
| RFC | [RFC3849] |
|
||||
| Allocation Date | July 2004 |
|
||||
| Termination Date | N/A |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+---------------+*/
|
||||
// Covered by previous entry, included for completeness.
|
||||
//
|
||||
// MustIPv6Addr("2001:db8::/32"),
|
||||
|
||||
/*+----------------------+--------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+--------------+
|
||||
| Address Block | 2001:10::/28 |
|
||||
| Name | ORCHID |
|
||||
| RFC | [RFC4843] |
|
||||
| Allocation Date | March 2007 |
|
||||
| Termination Date | March 2014 |
|
||||
| Source | False |
|
||||
| Destination | False |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+--------------+*/
|
||||
// Covered by previous entry, included for completeness.
|
||||
//
|
||||
// MustIPv6Addr("2001:10::/28"),
|
||||
|
||||
/*+----------------------+---------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+---------------+
|
||||
| Address Block | 2002::/16 [2] |
|
||||
| Name | 6to4 |
|
||||
| RFC | [RFC3056] |
|
||||
| Allocation Date | February 2001 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | N/A [2] |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+---------------+*/
|
||||
// [2] See [RFC3056] for details.
|
||||
MustIPv6Addr("2002::/16"),
|
||||
|
||||
/*+----------------------+--------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+--------------+
|
||||
| Address Block | fc00::/7 |
|
||||
| Name | Unique-Local |
|
||||
| RFC | [RFC4193] |
|
||||
| Allocation Date | October 2005 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | True |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | False |
|
||||
+----------------------+--------------+*/
|
||||
MustIPv6Addr("fc00::/7"),
|
||||
|
||||
/*+----------------------+-----------------------+
|
||||
| Attribute | Value |
|
||||
+----------------------+-----------------------+
|
||||
| Address Block | fe80::/10 |
|
||||
| Name | Linked-Scoped Unicast |
|
||||
| RFC | [RFC4291] |
|
||||
| Allocation Date | February 2006 |
|
||||
| Termination Date | N/A |
|
||||
| Source | True |
|
||||
| Destination | True |
|
||||
| Forwardable | False |
|
||||
| Global | False |
|
||||
| Reserved-by-Protocol | True |
|
||||
+----------------------+-----------------------+*/
|
||||
MustIPv6Addr("fe80::/10"),
|
||||
},
|
||||
7335: {
|
||||
// [RFC7335] IPv4 Service Continuity Prefix
|
||||
MustIPv4Addr("192.0.0.0/29"), // [RFC7335], §6 IANA Considerations
|
||||
},
|
||||
ForwardingBlacklist: { // Pseudo-RFC
|
||||
// Blacklist of non-forwardable IP blocks taken from RFC6890
|
||||
//
|
||||
// TODO: the attributes for forwardable should be
|
||||
// searcahble and embedded in the main list of RFCs
|
||||
// above.
|
||||
MustIPv4Addr("0.0.0.0/8"),
|
||||
MustIPv4Addr("127.0.0.0/8"),
|
||||
MustIPv4Addr("169.254.0.0/16"),
|
||||
MustIPv4Addr("192.0.0.0/24"),
|
||||
MustIPv4Addr("192.0.2.0/24"),
|
||||
MustIPv4Addr("198.51.100.0/24"),
|
||||
MustIPv4Addr("203.0.113.0/24"),
|
||||
MustIPv4Addr("240.0.0.0/4"),
|
||||
MustIPv4Addr("255.255.255.255/32"),
|
||||
MustIPv6Addr("::1/128"),
|
||||
MustIPv6Addr("::/128"),
|
||||
MustIPv6Addr("::ffff:0:0/96"),
|
||||
|
||||
// There is no way of expressing a whitelist per RFC2928
|
||||
// atm without creating a negative mask, which I don't
|
||||
// want to do atm.
|
||||
//MustIPv6Addr("2001::/23"),
|
||||
|
||||
MustIPv6Addr("2001:db8::/32"),
|
||||
MustIPv6Addr("2001:10::/28"),
|
||||
MustIPv6Addr("fe80::/10"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// VisitAllRFCs iterates over all known RFCs and calls the visitor
|
||||
func VisitAllRFCs(fn func(rfcNum uint, sockaddrs SockAddrs)) {
|
||||
rfcNetMap := KnownRFCs()
|
||||
|
||||
// Blacklist of faux-RFCs. Don't show the world that we're abusing the
|
||||
// RFC system in this library.
|
||||
rfcBlacklist := map[uint]struct{}{
|
||||
ForwardingBlacklist: {},
|
||||
}
|
||||
|
||||
for rfcNum, sas := range rfcNetMap {
|
||||
if _, found := rfcBlacklist[rfcNum]; !found {
|
||||
fn(rfcNum, sas)
|
||||
}
|
||||
}
|
||||
}
|
19
vendor/github.com/hashicorp/go-sockaddr/route_info.go
generated
vendored
Normal file
19
vendor/github.com/hashicorp/go-sockaddr/route_info.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
package sockaddr
|
||||
|
||||
// RouteInterface specifies an interface for obtaining memoized route table and
|
||||
// network information from a given OS.
|
||||
type RouteInterface interface {
|
||||
// GetDefaultInterfaceName returns the name of the interface that has a
|
||||
// default route or an error and an empty string if a problem was
|
||||
// encountered.
|
||||
GetDefaultInterfaceName() (string, error)
|
||||
}
|
||||
|
||||
// VisitCommands visits each command used by the platform-specific RouteInfo
|
||||
// implementation.
|
||||
func (ri routeInfo) VisitCommands(fn func(name string, cmd []string)) {
|
||||
for k, v := range ri.cmds {
|
||||
cmds := append([]string(nil), v...)
|
||||
fn(k, cmds)
|
||||
}
|
||||
}
|
36
vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go
generated
vendored
Normal file
36
vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
// +build darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package sockaddr
|
||||
|
||||
import "os/exec"
|
||||
|
||||
var cmds map[string][]string = map[string][]string{
|
||||
"route": {"/sbin/route", "-n", "get", "default"},
|
||||
}
|
||||
|
||||
type routeInfo struct {
|
||||
cmds map[string][]string
|
||||
}
|
||||
|
||||
// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
|
||||
// interface.
|
||||
func NewRouteInfo() (routeInfo, error) {
|
||||
return routeInfo{
|
||||
cmds: cmds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetDefaultInterfaceName returns the interface name attached to the default
|
||||
// route on the default interface.
|
||||
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
|
||||
out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var ifName string
|
||||
if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ifName, nil
|
||||
}
|
10
vendor/github.com/hashicorp/go-sockaddr/route_info_default.go
generated
vendored
Normal file
10
vendor/github.com/hashicorp/go-sockaddr/route_info_default.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
// +build android nacl plan9
|
||||
|
||||
package sockaddr
|
||||
|
||||
import "errors"
|
||||
|
||||
// getDefaultIfName is the default interface function for unsupported platforms.
|
||||
func getDefaultIfName() (string, error) {
|
||||
return "", errors.New("No default interface found (unsupported platform)")
|
||||
}
|
40
vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
generated
vendored
Normal file
40
vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
package sockaddr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type routeInfo struct {
|
||||
cmds map[string][]string
|
||||
}
|
||||
|
||||
// NewRouteInfo returns a Linux-specific implementation of the RouteInfo
|
||||
// interface.
|
||||
func NewRouteInfo() (routeInfo, error) {
|
||||
// CoreOS Container Linux moved ip to /usr/bin/ip, so look it up on
|
||||
// $PATH and fallback to /sbin/ip on error.
|
||||
path, _ := exec.LookPath("ip")
|
||||
if path == "" {
|
||||
path = "/sbin/ip"
|
||||
}
|
||||
|
||||
return routeInfo{
|
||||
cmds: map[string][]string{"ip": {path, "route"}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetDefaultInterfaceName returns the interface name attached to the default
|
||||
// route on the default interface.
|
||||
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
|
||||
out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var ifName string
|
||||
if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil {
|
||||
return "", errors.New("No default interface found")
|
||||
}
|
||||
return ifName, nil
|
||||
}
|
37
vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go
generated
vendored
Normal file
37
vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package sockaddr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
var cmds map[string][]string = map[string][]string{
|
||||
"route": {"/usr/sbin/route", "-n", "get", "default"},
|
||||
}
|
||||
|
||||
type routeInfo struct {
|
||||
cmds map[string][]string
|
||||
}
|
||||
|
||||
// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
|
||||
// interface.
|
||||
func NewRouteInfo() (routeInfo, error) {
|
||||
return routeInfo{
|
||||
cmds: cmds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetDefaultInterfaceName returns the interface name attached to the default
|
||||
// route on the default interface.
|
||||
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
|
||||
out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var ifName string
|
||||
if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
|
||||
return "", errors.New("No default interface found")
|
||||
}
|
||||
return ifName, nil
|
||||
}
|
41
vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go
generated
vendored
Normal file
41
vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
package sockaddr
|
||||
|
||||
import "os/exec"
|
||||
|
||||
var cmds map[string][]string = map[string][]string{
|
||||
"netstat": {"netstat", "-rn"},
|
||||
"ipconfig": {"ipconfig"},
|
||||
}
|
||||
|
||||
type routeInfo struct {
|
||||
cmds map[string][]string
|
||||
}
|
||||
|
||||
// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
|
||||
// interface.
|
||||
func NewRouteInfo() (routeInfo, error) {
|
||||
return routeInfo{
|
||||
cmds: cmds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetDefaultInterfaceName returns the interface name attached to the default
|
||||
// route on the default interface.
|
||||
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
|
||||
ifNameOut, err := exec.Command(cmds["netstat"][0], cmds["netstat"][1:]...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ipconfigOut, err := exec.Command(cmds["ipconfig"][0], cmds["ipconfig"][1:]...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ifName, nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue