Update dependencies
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
efb89cf600
commit
3acde1749b
314 changed files with 47573 additions and 15095 deletions
53
Gopkg.lock
generated
53
Gopkg.lock
generated
|
@ -5,10 +5,11 @@
|
||||||
name = "github.com/Luzifer/go_helpers"
|
name = "github.com/Luzifer/go_helpers"
|
||||||
packages = [
|
packages = [
|
||||||
"accessLogger",
|
"accessLogger",
|
||||||
"http"
|
"http",
|
||||||
|
"str"
|
||||||
]
|
]
|
||||||
revision = "e31c3a2659d3f4901f696692cfe98bd0eb5168f9"
|
revision = "94b91ff63a5db8e22c4d121e6c5c17b44135be4d"
|
||||||
version = "v2.2.0"
|
version = "v2.5.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/Luzifer/rconfig"
|
name = "github.com/Luzifer/rconfig"
|
||||||
|
@ -19,12 +20,14 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/context"
|
name = "github.com/gorilla/context"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "1c83b3eabd45b6d76072b66b746c20815fb2872d"
|
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
|
||||||
|
version = "v1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/mux"
|
name = "github.com/gorilla/mux"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "49c024275504f0341e5a9971eb7ba7fa3dc7af40"
|
revision = "53c1911da2b537f792e7cafcb446b05ffe33b996"
|
||||||
|
version = "v1.6.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/nicksnyder/go-i18n"
|
name = "github.com/nicksnyder/go-i18n"
|
||||||
|
@ -34,49 +37,65 @@
|
||||||
"i18n/language",
|
"i18n/language",
|
||||||
"i18n/translation"
|
"i18n/translation"
|
||||||
]
|
]
|
||||||
revision = "3e70a1a463008cea6726380c908b1a6a8bdf7b24"
|
revision = "0dc1626d56435e9d605a29875701721c54bc9bbd"
|
||||||
version = "v1.8.1"
|
version = "v1.10.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/pelletier/go-toml"
|
name = "github.com/pelletier/go-toml"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "69d355db5304c0f7f809a2edc054553e7142f016"
|
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/satori/uuid"
|
name = "github.com/satori/uuid"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "5bf94b69c6b68ee1b541973bb8e1144db23a194b"
|
revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
|
||||||
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/sirupsen/logrus"
|
name = "github.com/sirupsen/logrus"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "59d0ca41e5faad81cac03f7a7d84ba80d9cc9673"
|
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
||||||
|
version = "v1.0.5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/spf13/pflag"
|
name = "github.com/spf13/pflag"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||||
version = "v1.0.0"
|
version = "v1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/xuyu/goredis"
|
name = "github.com/xuyu/goredis"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "300f7e8cf453e2ea44337b3969d3aecf1a92ebe3"
|
revision = "89fbe9474b3758ff3adf0b7b29c95aeed115fb7b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/crypto"
|
||||||
|
packages = ["ssh/terminal"]
|
||||||
|
revision = "4ec37c66abab2c7e02ae775328b2ff001c3f025a"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["unix"]
|
packages = [
|
||||||
revision = "739734461d1c916b6c72a63d7efda2b27edb369f"
|
"unix",
|
||||||
|
"windows"
|
||||||
|
]
|
||||||
|
revision = "6f686a352de66814cdd080d970febae7767857a3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
name = "gopkg.in/validator.v2"
|
name = "gopkg.in/validator.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "07ffaad256c8e957050ad83d6472eb97d785013d"
|
revision = "59c90c7046f643cbe0d4e7c8776c42a84ce75910"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b"
|
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||||
|
version = "v2.2.1"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
|
|
2
vendor/github.com/Luzifer/go_helpers/accessLogger/accessLogger.go
generated
vendored
2
vendor/github.com/Luzifer/go_helpers/accessLogger/accessLogger.go
generated
vendored
|
@ -33,5 +33,5 @@ func (a *AccessLogResponseWriter) WriteHeader(code int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AccessLogResponseWriter) HTTPResponseType() string {
|
func (a *AccessLogResponseWriter) HTTPResponseType() string {
|
||||||
return fmt.Sprintf("%sxx", strconv.FormatInt(int64(a.StatusCode), 10)[0])
|
return fmt.Sprintf("%cxx", strconv.FormatInt(int64(a.StatusCode), 10)[0])
|
||||||
}
|
}
|
||||||
|
|
55
vendor/github.com/Luzifer/go_helpers/http/digest.go
generated
vendored
Normal file
55
vendor/github.com/Luzifer/go_helpers/http/digest.go
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Luzifer/go_helpers/str"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetDigestAuth(resp *http.Response, method, requestPath, user, password string) string {
|
||||||
|
params := map[string]string{}
|
||||||
|
for _, part := range strings.Split(resp.Header.Get("Www-Authenticate"), " ") {
|
||||||
|
if !strings.Contains(part, `="`) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
spl := strings.Split(strings.Trim(part, " ,"), "=")
|
||||||
|
if !str.StringInSlice(spl[0], []string{"nonce", "realm", "qop"}) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
params[spl[0]] = strings.Trim(spl[1], `"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, 8)
|
||||||
|
io.ReadFull(rand.Reader, b)
|
||||||
|
|
||||||
|
params["cnonce"] = fmt.Sprintf("%x", b)
|
||||||
|
params["nc"] = "1"
|
||||||
|
params["uri"] = requestPath
|
||||||
|
params["username"] = user
|
||||||
|
params["response"] = getMD5([]string{
|
||||||
|
getMD5([]string{params["username"], params["realm"], password}),
|
||||||
|
params["nonce"],
|
||||||
|
params["nc"],
|
||||||
|
params["cnonce"],
|
||||||
|
params["qop"],
|
||||||
|
getMD5([]string{method, requestPath}),
|
||||||
|
})
|
||||||
|
|
||||||
|
authParts := []string{}
|
||||||
|
for k, v := range params {
|
||||||
|
authParts = append(authParts, fmt.Sprintf("%s=%q", k, v))
|
||||||
|
}
|
||||||
|
return "Digest " + strings.Join(authParts, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMD5(in []string) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write([]byte(strings.Join(in, ":")))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
21
vendor/github.com/Luzifer/go_helpers/http/logHandler.go
generated
vendored
21
vendor/github.com/Luzifer/go_helpers/http/logHandler.go
generated
vendored
|
@ -3,6 +3,7 @@ package http
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Luzifer/go_helpers/accessLogger"
|
"github.com/Luzifer/go_helpers/accessLogger"
|
||||||
|
@ -10,10 +11,14 @@ import (
|
||||||
|
|
||||||
type HTTPLogHandler struct {
|
type HTTPLogHandler struct {
|
||||||
Handler http.Handler
|
Handler http.Handler
|
||||||
|
TrustedIPHeaders []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPLogHandler(h http.Handler) http.Handler {
|
func NewHTTPLogHandler(h http.Handler) http.Handler {
|
||||||
return HTTPLogHandler{Handler: h}
|
return HTTPLogHandler{
|
||||||
|
Handler: h,
|
||||||
|
TrustedIPHeaders: []string{"X-Forwarded-For", "RemoteAddr", "X-Real-IP"},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l HTTPLogHandler) ServeHTTP(res http.ResponseWriter, r *http.Request) {
|
func (l HTTPLogHandler) ServeHTTP(res http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -23,7 +28,7 @@ func (l HTTPLogHandler) ServeHTTP(res http.ResponseWriter, r *http.Request) {
|
||||||
l.Handler.ServeHTTP(ares, r)
|
l.Handler.ServeHTTP(ares, r)
|
||||||
|
|
||||||
log.Printf("%s - \"%s %s\" %d %d \"%s\" \"%s\" %s",
|
log.Printf("%s - \"%s %s\" %d %d \"%s\" \"%s\" %s",
|
||||||
r.RemoteAddr,
|
l.findIP(r),
|
||||||
r.Method,
|
r.Method,
|
||||||
r.URL.Path,
|
r.URL.Path,
|
||||||
ares.StatusCode,
|
ares.StatusCode,
|
||||||
|
@ -33,3 +38,15 @@ func (l HTTPLogHandler) ServeHTTP(res http.ResponseWriter, r *http.Request) {
|
||||||
time.Since(start),
|
time.Since(start),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l HTTPLogHandler) findIP(r *http.Request) string {
|
||||||
|
remoteAddr := strings.SplitN(r.RemoteAddr, ":", 2)[0]
|
||||||
|
|
||||||
|
for _, hdr := range l.TrustedIPHeaders {
|
||||||
|
if value := r.Header.Get(hdr); value != "" {
|
||||||
|
return strings.SplitN(value, ",", 2)[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return remoteAddr
|
||||||
|
}
|
||||||
|
|
21
vendor/github.com/Luzifer/go_helpers/str/slice.go
generated
vendored
Normal file
21
vendor/github.com/Luzifer/go_helpers/str/slice.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package str
|
||||||
|
|
||||||
|
// AppendIfMissing adds a string to a slice when it's not present yet
|
||||||
|
func AppendIfMissing(slice []string, s string) []string {
|
||||||
|
for _, e := range slice {
|
||||||
|
if e == s {
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(slice, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringInSlice checks for the existence of a string in the slice
|
||||||
|
func StringInSlice(a string, list []string) bool {
|
||||||
|
for _, b := range list {
|
||||||
|
if b == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
21
vendor/github.com/gorilla/context/.travis.yml
generated
vendored
21
vendor/github.com/gorilla/context/.travis.yml
generated
vendored
|
@ -1,8 +1,19 @@
|
||||||
language: go
|
language: go
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
go:
|
matrix:
|
||||||
- 1.3
|
include:
|
||||||
- 1.4
|
- go: 1.3
|
||||||
- 1.5
|
- go: 1.4
|
||||||
- tip
|
- go: 1.5
|
||||||
|
- go: 1.6
|
||||||
|
- go: tip
|
||||||
|
|
||||||
|
install:
|
||||||
|
- go get golang.org/x/tools/cmd/vet
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go get -t -v ./...
|
||||||
|
- diff -u <(echo -n) <(gofmt -d .)
|
||||||
|
- go tool vet .
|
||||||
|
- go test -v -race ./...
|
||||||
|
|
24
vendor/github.com/gorilla/mux/.travis.yml
generated
vendored
24
vendor/github.com/gorilla/mux/.travis.yml
generated
vendored
|
@ -1,8 +1,22 @@
|
||||||
language: go
|
language: go
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
go:
|
matrix:
|
||||||
- 1.3
|
include:
|
||||||
- 1.4
|
- go: 1.5
|
||||||
- 1.5
|
- go: 1.6
|
||||||
- tip
|
- go: 1.7
|
||||||
|
- go: 1.8
|
||||||
|
- go: 1.9
|
||||||
|
- go: tip
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
|
|
||||||
|
install:
|
||||||
|
- # Skip
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go get -t -v ./...
|
||||||
|
- diff -u <(echo -n) <(gofmt -d .)
|
||||||
|
- go tool vet .
|
||||||
|
- go test -v -race ./...
|
||||||
|
|
11
vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md
generated
vendored
Normal file
11
vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
**What version of Go are you running?** (Paste the output of `go version`)
|
||||||
|
|
||||||
|
|
||||||
|
**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`)
|
||||||
|
|
||||||
|
|
||||||
|
**Describe your problem** (and what you have tried so far)
|
||||||
|
|
||||||
|
|
||||||
|
**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it)
|
||||||
|
|
469
vendor/github.com/gorilla/mux/README.md
generated
vendored
469
vendor/github.com/gorilla/mux/README.md
generated
vendored
|
@ -1,30 +1,51 @@
|
||||||
mux
|
gorilla/mux
|
||||||
===
|
===
|
||||||
[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
|
[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
|
||||||
[![Build Status](https://travis-ci.org/gorilla/mux.png?branch=master)](https://travis-ci.org/gorilla/mux)
|
[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
|
||||||
|
[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)
|
||||||
|
|
||||||
Package gorilla/mux implements a request router and dispatcher.
|
![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)
|
||||||
|
|
||||||
The name mux stands for "HTTP request multiplexer". Like the standard
|
http://www.gorillatoolkit.org/pkg/mux
|
||||||
http.ServeMux, mux.Router matches incoming requests against a list of
|
|
||||||
registered routes and calls a handler for the route that matches the URL
|
|
||||||
or other conditions. The main features are:
|
|
||||||
|
|
||||||
* Requests can be matched based on URL host, path, path prefix, schemes,
|
Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to
|
||||||
header and query values, HTTP methods or using custom matchers.
|
their respective handler.
|
||||||
* URL hosts and paths can have variables with an optional regular
|
|
||||||
expression.
|
The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:
|
||||||
* Registered URLs can be built, or "reversed", which helps maintaining
|
|
||||||
references to resources.
|
* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
|
||||||
* Routes can be used as subrouters: nested routes are only tested if the
|
* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
|
||||||
parent route matches. This is useful to define groups of routes that
|
* URL hosts, paths and query values can have variables with an optional regular expression.
|
||||||
share common conditions like a host, a path prefix or other repeated
|
* Registered URLs can be built, or "reversed", which helps maintaining references to resources.
|
||||||
attributes. As a bonus, this optimizes request matching.
|
* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
|
||||||
* It implements the http.Handler interface so it is compatible with the
|
|
||||||
standard http.ServeMux.
|
---
|
||||||
|
|
||||||
|
* [Install](#install)
|
||||||
|
* [Examples](#examples)
|
||||||
|
* [Matching Routes](#matching-routes)
|
||||||
|
* [Static Files](#static-files)
|
||||||
|
* [Registered URLs](#registered-urls)
|
||||||
|
* [Walking Routes](#walking-routes)
|
||||||
|
* [Graceful Shutdown](#graceful-shutdown)
|
||||||
|
* [Middleware](#middleware)
|
||||||
|
* [Full Example](#full-example)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go get -u github.com/gorilla/mux
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
Let's start registering a couple of URL paths and handlers:
|
Let's start registering a couple of URL paths and handlers:
|
||||||
|
|
||||||
|
```go
|
||||||
func main() {
|
func main() {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/", HomeHandler)
|
r.HandleFunc("/", HomeHandler)
|
||||||
|
@ -32,101 +53,122 @@ Let's start registering a couple of URL paths and handlers:
|
||||||
r.HandleFunc("/articles", ArticlesHandler)
|
r.HandleFunc("/articles", ArticlesHandler)
|
||||||
http.Handle("/", r)
|
http.Handle("/", r)
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Here we register three routes mapping URL paths to handlers. This is
|
Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters.
|
||||||
equivalent to how http.HandleFunc() works: if an incoming request URL matches
|
|
||||||
one of the paths, the corresponding handler is called passing
|
|
||||||
(http.ResponseWriter, *http.Request) as parameters.
|
|
||||||
|
|
||||||
Paths can have variables. They are defined using the format {name} or
|
Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example:
|
||||||
{name:pattern}. If a regular expression pattern is not defined, the matched
|
|
||||||
variable will be anything until the next slash. For example:
|
|
||||||
|
|
||||||
|
```go
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/products/{key}", ProductHandler)
|
r.HandleFunc("/products/{key}", ProductHandler)
|
||||||
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
|
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
|
||||||
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
|
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
|
||||||
|
```
|
||||||
|
|
||||||
The names are used to create a map of route variables which can be retrieved
|
The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:
|
||||||
calling mux.Vars():
|
|
||||||
|
|
||||||
vars := mux.Vars(request)
|
```go
|
||||||
category := vars["category"]
|
func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintf(w, "Category: %v\n", vars["category"])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
And this is all you need to know about the basic usage. More advanced options
|
And this is all you need to know about the basic usage. More advanced options are explained below.
|
||||||
are explained below.
|
|
||||||
|
|
||||||
Routes can also be restricted to a domain or subdomain. Just define a host
|
### Matching Routes
|
||||||
pattern to be matched. They can also have variables:
|
|
||||||
|
|
||||||
|
Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:
|
||||||
|
|
||||||
|
```go
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
// Only matches if domain is "www.example.com".
|
// Only matches if domain is "www.example.com".
|
||||||
r.Host("www.example.com")
|
r.Host("www.example.com")
|
||||||
// Matches a dynamic subdomain.
|
// Matches a dynamic subdomain.
|
||||||
r.Host("{subdomain:[a-z]+}.domain.com")
|
r.Host("{subdomain:[a-z]+}.domain.com")
|
||||||
|
```
|
||||||
|
|
||||||
There are several other matchers that can be added. To match path prefixes:
|
There are several other matchers that can be added. To match path prefixes:
|
||||||
|
|
||||||
|
```go
|
||||||
r.PathPrefix("/products/")
|
r.PathPrefix("/products/")
|
||||||
|
```
|
||||||
|
|
||||||
...or HTTP methods:
|
...or HTTP methods:
|
||||||
|
|
||||||
|
```go
|
||||||
r.Methods("GET", "POST")
|
r.Methods("GET", "POST")
|
||||||
|
```
|
||||||
|
|
||||||
...or URL schemes:
|
...or URL schemes:
|
||||||
|
|
||||||
|
```go
|
||||||
r.Schemes("https")
|
r.Schemes("https")
|
||||||
|
```
|
||||||
|
|
||||||
...or header values:
|
...or header values:
|
||||||
|
|
||||||
|
```go
|
||||||
r.Headers("X-Requested-With", "XMLHttpRequest")
|
r.Headers("X-Requested-With", "XMLHttpRequest")
|
||||||
|
```
|
||||||
|
|
||||||
...or query values:
|
...or query values:
|
||||||
|
|
||||||
|
```go
|
||||||
r.Queries("key", "value")
|
r.Queries("key", "value")
|
||||||
|
```
|
||||||
|
|
||||||
...or to use a custom matcher function:
|
...or to use a custom matcher function:
|
||||||
|
|
||||||
|
```go
|
||||||
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
|
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
|
||||||
return r.ProtoMajor == 0
|
return r.ProtoMajor == 0
|
||||||
})
|
})
|
||||||
|
```
|
||||||
|
|
||||||
...and finally, it is possible to combine several matchers in a single route:
|
...and finally, it is possible to combine several matchers in a single route:
|
||||||
|
|
||||||
|
```go
|
||||||
r.HandleFunc("/products", ProductsHandler).
|
r.HandleFunc("/products", ProductsHandler).
|
||||||
Host("www.example.com").
|
Host("www.example.com").
|
||||||
Methods("GET").
|
Methods("GET").
|
||||||
Schemes("http")
|
Schemes("http")
|
||||||
|
```
|
||||||
|
|
||||||
Setting the same matching conditions again and again can be boring, so we have
|
Routes are tested in the order they were added to the router. If two routes match, the first one wins:
|
||||||
a way to group several routes that share the same requirements.
|
|
||||||
We call it "subrouting".
|
|
||||||
|
|
||||||
For example, let's say we have several URLs that should only match when the
|
```go
|
||||||
host is `www.example.com`. Create a route for that host and get a "subrouter"
|
r := mux.NewRouter()
|
||||||
from it:
|
r.HandleFunc("/specific", specificHandler)
|
||||||
|
r.PathPrefix("/").Handler(catchAllHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
|
||||||
|
|
||||||
|
For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
|
||||||
|
|
||||||
|
```go
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
s := r.Host("www.example.com").Subrouter()
|
s := r.Host("www.example.com").Subrouter()
|
||||||
|
```
|
||||||
|
|
||||||
Then register routes in the subrouter:
|
Then register routes in the subrouter:
|
||||||
|
|
||||||
|
```go
|
||||||
s.HandleFunc("/products/", ProductsHandler)
|
s.HandleFunc("/products/", ProductsHandler)
|
||||||
s.HandleFunc("/products/{key}", ProductHandler)
|
s.HandleFunc("/products/{key}", ProductHandler)
|
||||||
s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
|
||||||
|
```
|
||||||
|
|
||||||
The three URL paths we registered above will only be tested if the domain is
|
The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.
|
||||||
`www.example.com`, because the subrouter is tested first. This is not
|
|
||||||
only convenient, but also optimizes request matching. You can create
|
|
||||||
subrouters combining any attribute matchers accepted by a route.
|
|
||||||
|
|
||||||
Subrouters can be used to create domain or path "namespaces": you define
|
Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter.
|
||||||
subrouters in a central place and then parts of the app can register its
|
|
||||||
paths relatively to a given subrouter.
|
|
||||||
|
|
||||||
There's one more thing about subroutes. When a subrouter has a path prefix,
|
There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths:
|
||||||
the inner routes use it as base for their paths:
|
|
||||||
|
|
||||||
|
```go
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
s := r.PathPrefix("/products").Subrouter()
|
s := r.PathPrefix("/products").Subrouter()
|
||||||
// "/products/"
|
// "/products/"
|
||||||
|
@ -135,63 +177,159 @@ the inner routes use it as base for their paths:
|
||||||
s.HandleFunc("/{key}/", ProductHandler)
|
s.HandleFunc("/{key}/", ProductHandler)
|
||||||
// "/products/{key}/details"
|
// "/products/{key}/details"
|
||||||
s.HandleFunc("/{key}/details", ProductDetailsHandler)
|
s.HandleFunc("/{key}/details", ProductDetailsHandler)
|
||||||
|
```
|
||||||
|
### Listing Routes
|
||||||
|
|
||||||
|
Routes on a mux can be listed using the Router.Walk method—useful for generating documentation:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/", handler)
|
||||||
|
r.HandleFunc("/products", handler).Methods("POST")
|
||||||
|
r.HandleFunc("/articles", handler).Methods("GET")
|
||||||
|
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
|
||||||
|
r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
|
||||||
|
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
|
||||||
|
t, err := route.GetPathTemplate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
qt, err := route.GetQueriesTemplates()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// p will contain regular expression is compatible with regular expression in Perl, Python, and other languages.
|
||||||
|
// for instance the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'
|
||||||
|
p, err := route.GetPathRegexp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
|
||||||
|
// just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
|
||||||
|
// {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
|
||||||
|
qr, err := route.GetQueriesRegexp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m, err := route.GetMethods()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
http.Handle("/", r)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Static Files
|
||||||
|
|
||||||
|
Note that the path provided to `PathPrefix()` represents a "wildcard": calling
|
||||||
|
`PathPrefix("/static/").Handler(...)` means that the handler will be passed any
|
||||||
|
request that matches "/static/*". This makes it easy to serve static files with mux:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
var dir string
|
||||||
|
|
||||||
|
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
|
||||||
|
flag.Parse()
|
||||||
|
r := mux.NewRouter()
|
||||||
|
|
||||||
|
// This will serve files under http://localhost:8000/static/<filename>
|
||||||
|
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Handler: r,
|
||||||
|
Addr: "127.0.0.1:8000",
|
||||||
|
// Good practice: enforce timeouts for servers you create!
|
||||||
|
WriteTimeout: 15 * time.Second,
|
||||||
|
ReadTimeout: 15 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(srv.ListenAndServe())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Registered URLs
|
||||||
|
|
||||||
Now let's see how to build registered URLs.
|
Now let's see how to build registered URLs.
|
||||||
|
|
||||||
Routes can be named. All routes that define a name can have their URLs built,
|
Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example:
|
||||||
or "reversed". We define a name calling Name() on a route. For example:
|
|
||||||
|
|
||||||
|
```go
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
||||||
Name("article")
|
Name("article")
|
||||||
|
```
|
||||||
|
|
||||||
To build a URL, get the route and call the URL() method, passing a sequence of
|
To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do:
|
||||||
key/value pairs for the route variables. For the previous route, we would do:
|
|
||||||
|
|
||||||
|
```go
|
||||||
url, err := r.Get("article").URL("category", "technology", "id", "42")
|
url, err := r.Get("article").URL("category", "technology", "id", "42")
|
||||||
|
```
|
||||||
|
|
||||||
...and the result will be a url.URL with the following path:
|
...and the result will be a `url.URL` with the following path:
|
||||||
|
|
||||||
|
```
|
||||||
"/articles/technology/42"
|
"/articles/technology/42"
|
||||||
|
```
|
||||||
|
|
||||||
This also works for host variables:
|
This also works for host and query value variables:
|
||||||
|
|
||||||
|
```go
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.Host("{subdomain}.domain.com").
|
r.Host("{subdomain}.domain.com").
|
||||||
Path("/articles/{category}/{id:[0-9]+}").
|
Path("/articles/{category}/{id:[0-9]+}").
|
||||||
|
Queries("filter", "{filter}").
|
||||||
HandlerFunc(ArticleHandler).
|
HandlerFunc(ArticleHandler).
|
||||||
Name("article")
|
Name("article")
|
||||||
|
|
||||||
// url.String() will be "http://news.domain.com/articles/technology/42"
|
// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
|
||||||
url, err := r.Get("article").URL("subdomain", "news",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42",
|
||||||
|
"filter", "gorilla")
|
||||||
|
```
|
||||||
|
|
||||||
All variables defined in the route are required, and their values must
|
All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
|
||||||
conform to the corresponding patterns. These requirements guarantee that a
|
|
||||||
generated URL will always match a registered route -- the only exception is
|
|
||||||
for explicitly defined "build-only" routes which never match.
|
|
||||||
|
|
||||||
Regex support also exists for matching Headers within a route. For example, we could do:
|
Regex support also exists for matching Headers within a route. For example, we could do:
|
||||||
|
|
||||||
|
```go
|
||||||
r.HeadersRegexp("Content-Type", "application/(text|json)")
|
r.HeadersRegexp("Content-Type", "application/(text|json)")
|
||||||
|
```
|
||||||
|
|
||||||
...and the route will match both requests with a Content-Type of `application/json` as well as
|
...and the route will match both requests with a Content-Type of `application/json` as well as `application/text`
|
||||||
`application/text`
|
|
||||||
|
|
||||||
There's also a way to build only the URL host or path for a route:
|
There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:
|
||||||
use the methods URLHost() or URLPath() instead. For the previous route,
|
|
||||||
we would do:
|
|
||||||
|
|
||||||
|
```go
|
||||||
// "http://news.domain.com/"
|
// "http://news.domain.com/"
|
||||||
host, err := r.Get("article").URLHost("subdomain", "news")
|
host, err := r.Get("article").URLHost("subdomain", "news")
|
||||||
|
|
||||||
// "/articles/technology/42"
|
// "/articles/technology/42"
|
||||||
path, err := r.Get("article").URLPath("category", "technology", "id", "42")
|
path, err := r.Get("article").URLPath("category", "technology", "id", "42")
|
||||||
|
```
|
||||||
|
|
||||||
And if you use subrouters, host and path defined separately can be built
|
And if you use subrouters, host and path defined separately can be built as well:
|
||||||
as well:
|
|
||||||
|
|
||||||
|
```go
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
s := r.Host("{subdomain}.domain.com").Subrouter()
|
s := r.Host("{subdomain}.domain.com").Subrouter()
|
||||||
s.Path("/articles/{category}/{id:[0-9]+}").
|
s.Path("/articles/{category}/{id:[0-9]+}").
|
||||||
|
@ -202,17 +340,204 @@ as well:
|
||||||
url, err := r.Get("article").URL("subdomain", "news",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Walking Routes
|
||||||
|
|
||||||
|
The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
|
||||||
|
the following prints all of the registered routes:
|
||||||
|
|
||||||
|
```go
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/", handler)
|
||||||
|
r.HandleFunc("/products", handler).Methods("POST")
|
||||||
|
r.HandleFunc("/articles", handler).Methods("GET")
|
||||||
|
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
|
||||||
|
r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
|
||||||
|
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
|
||||||
|
t, err := route.GetPathTemplate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
qt, err := route.GetQueriesTemplates()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages.
|
||||||
|
// For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'.
|
||||||
|
p, err := route.GetPathRegexp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
|
||||||
|
// just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
|
||||||
|
// {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
|
||||||
|
qr, err := route.GetQueriesRegexp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m, err := route.GetMethods()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Graceful Shutdown
|
||||||
|
|
||||||
|
Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var wait time.Duration
|
||||||
|
flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
r := mux.NewRouter()
|
||||||
|
// Add your routes as needed
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: "0.0.0.0:8080",
|
||||||
|
// Good practice to set timeouts to avoid Slowloris attacks.
|
||||||
|
WriteTimeout: time.Second * 15,
|
||||||
|
ReadTimeout: time.Second * 15,
|
||||||
|
IdleTimeout: time.Second * 60,
|
||||||
|
Handler: r, // Pass our instance of gorilla/mux in.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run our server in a goroutine so that it doesn't block.
|
||||||
|
go func() {
|
||||||
|
if err := srv.ListenAndServe(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
|
||||||
|
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
|
||||||
|
signal.Notify(c, os.Interrupt)
|
||||||
|
|
||||||
|
// Block until we receive our signal.
|
||||||
|
<-c
|
||||||
|
|
||||||
|
// Create a deadline to wait for.
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, wait)
|
||||||
|
// Doesn't block if no connections, but will otherwise wait
|
||||||
|
// until the timeout deadline.
|
||||||
|
srv.Shutdown(ctx)
|
||||||
|
// Optionally, you could run srv.Shutdown in a goroutine and block on
|
||||||
|
// <-ctx.Done() if your application should wait for other services
|
||||||
|
// to finalize based on context cancellation.
|
||||||
|
log.Println("shutting down")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Middleware
|
||||||
|
|
||||||
|
Mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters.
|
||||||
|
Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking.
|
||||||
|
|
||||||
|
Mux middlewares are defined using the de facto standard type:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MiddlewareFunc func(http.Handler) http.Handler
|
||||||
|
```
|
||||||
|
|
||||||
|
Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers.
|
||||||
|
|
||||||
|
A very basic middleware which logs the URI of the request being handled could be written as:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func simpleMw(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Do stuff here
|
||||||
|
log.Println(r.RequestURI)
|
||||||
|
// Call the next handler, which can be another middleware in the chain, or the final handler.
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Middlewares can be added to a router using `Router.AddMiddlewareFunc()`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/", handler)
|
||||||
|
r.AddMiddleware(simpleMw)
|
||||||
|
```
|
||||||
|
|
||||||
|
A more complex authentication middleware, which maps session token to users, could be written as:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Define our struct
|
||||||
|
type authenticationMiddleware struct {
|
||||||
|
tokenUsers map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize it somewhere
|
||||||
|
func (amw *authenticationMiddleware) Populate() {
|
||||||
|
amw.tokenUsers["00000000"] = "user0"
|
||||||
|
amw.tokenUsers["aaaaaaaa"] = "userA"
|
||||||
|
amw.tokenUsers["05f717e5"] = "randomUser"
|
||||||
|
amw.tokenUsers["deadbeef"] = "user0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Middleware function, which will be called for each request
|
||||||
|
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
token := r.Header.Get("X-Session-Token")
|
||||||
|
|
||||||
|
if user, found := amw.tokenUsers[token]; found {
|
||||||
|
// We found the token in our map
|
||||||
|
log.Printf("Authenticated user %s\n", user)
|
||||||
|
// Pass down the request to the next middleware (or final handler)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
} else {
|
||||||
|
// Write an error and stop the handler chain
|
||||||
|
http.Error(w, "Forbidden", 403)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/", handler)
|
||||||
|
|
||||||
|
amw := authenticationMiddleware{}
|
||||||
|
amw.Populate()
|
||||||
|
|
||||||
|
r.AddMiddlewareFunc(amw.Middleware)
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares *should* write to `ResponseWriter` if they *are* going to terminate the request, and they *should not* write to `ResponseWriter` if they *are not* going to terminate it.
|
||||||
|
|
||||||
## Full Example
|
## Full Example
|
||||||
|
|
||||||
Here's a complete, runnable example of a small mux based server:
|
Here's a complete, runnable example of a small `mux` based server:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"log"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -226,7 +551,7 @@ func main() {
|
||||||
r.HandleFunc("/", YourHandler)
|
r.HandleFunc("/", YourHandler)
|
||||||
|
|
||||||
// Bind to a port and pass our router in
|
// Bind to a port and pass our router in
|
||||||
http.ListenAndServe(":8000", r)
|
log.Fatal(http.ListenAndServe(":8000", r))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
26
vendor/github.com/gorilla/mux/context_gorilla.go
generated
vendored
Normal file
26
vendor/github.com/gorilla/mux/context_gorilla.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func contextGet(r *http.Request, key interface{}) interface{} {
|
||||||
|
return context.Get(r, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextSet(r *http.Request, key, val interface{}) *http.Request {
|
||||||
|
if val == nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Set(r, key, val)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextClear(r *http.Request) {
|
||||||
|
context.Clear(r)
|
||||||
|
}
|
24
vendor/github.com/gorilla/mux/context_native.go
generated
vendored
Normal file
24
vendor/github.com/gorilla/mux/context_native.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func contextGet(r *http.Request, key interface{}) interface{} {
|
||||||
|
return r.Context().Value(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextSet(r *http.Request, key, val interface{}) *http.Request {
|
||||||
|
if val == nil {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.WithContext(context.WithValue(r.Context(), key, val))
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextClear(r *http.Request) {
|
||||||
|
return
|
||||||
|
}
|
113
vendor/github.com/gorilla/mux/doc.go
generated
vendored
113
vendor/github.com/gorilla/mux/doc.go
generated
vendored
|
@ -3,7 +3,7 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package gorilla/mux implements a request router and dispatcher.
|
Package mux implements a request router and dispatcher.
|
||||||
|
|
||||||
The name mux stands for "HTTP request multiplexer". Like the standard
|
The name mux stands for "HTTP request multiplexer". Like the standard
|
||||||
http.ServeMux, mux.Router matches incoming requests against a list of
|
http.ServeMux, mux.Router matches incoming requests against a list of
|
||||||
|
@ -12,8 +12,8 @@ or other conditions. The main features are:
|
||||||
|
|
||||||
* Requests can be matched based on URL host, path, path prefix, schemes,
|
* Requests can be matched based on URL host, path, path prefix, schemes,
|
||||||
header and query values, HTTP methods or using custom matchers.
|
header and query values, HTTP methods or using custom matchers.
|
||||||
* URL hosts and paths can have variables with an optional regular
|
* URL hosts, paths and query values can have variables with an optional
|
||||||
expression.
|
regular expression.
|
||||||
* Registered URLs can be built, or "reversed", which helps maintaining
|
* Registered URLs can be built, or "reversed", which helps maintaining
|
||||||
references to resources.
|
references to resources.
|
||||||
* Routes can be used as subrouters: nested routes are only tested if the
|
* Routes can be used as subrouters: nested routes are only tested if the
|
||||||
|
@ -47,12 +47,21 @@ variable will be anything until the next slash. For example:
|
||||||
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
|
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
|
||||||
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
|
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
|
||||||
|
|
||||||
|
Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
|
||||||
|
|
||||||
|
r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
|
||||||
|
|
||||||
The names are used to create a map of route variables which can be retrieved
|
The names are used to create a map of route variables which can be retrieved
|
||||||
calling mux.Vars():
|
calling mux.Vars():
|
||||||
|
|
||||||
vars := mux.Vars(request)
|
vars := mux.Vars(request)
|
||||||
category := vars["category"]
|
category := vars["category"]
|
||||||
|
|
||||||
|
Note that if any capturing groups are present, mux will panic() during parsing. To prevent
|
||||||
|
this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
|
||||||
|
"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
|
||||||
|
when capturing groups were present.
|
||||||
|
|
||||||
And this is all you need to know about the basic usage. More advanced options
|
And this is all you need to know about the basic usage. More advanced options
|
||||||
are explained below.
|
are explained below.
|
||||||
|
|
||||||
|
@ -136,6 +145,31 @@ the inner routes use it as base for their paths:
|
||||||
// "/products/{key}/details"
|
// "/products/{key}/details"
|
||||||
s.HandleFunc("/{key}/details", ProductDetailsHandler)
|
s.HandleFunc("/{key}/details", ProductDetailsHandler)
|
||||||
|
|
||||||
|
Note that the path provided to PathPrefix() represents a "wildcard": calling
|
||||||
|
PathPrefix("/static/").Handler(...) means that the handler will be passed any
|
||||||
|
request that matches "/static/*". This makes it easy to serve static files with mux:
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var dir string
|
||||||
|
|
||||||
|
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
|
||||||
|
flag.Parse()
|
||||||
|
r := mux.NewRouter()
|
||||||
|
|
||||||
|
// This will serve files under http://localhost:8000/static/<filename>
|
||||||
|
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Handler: r,
|
||||||
|
Addr: "127.0.0.1:8000",
|
||||||
|
// Good practice: enforce timeouts for servers you create!
|
||||||
|
WriteTimeout: 15 * time.Second,
|
||||||
|
ReadTimeout: 15 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(srv.ListenAndServe())
|
||||||
|
}
|
||||||
|
|
||||||
Now let's see how to build registered URLs.
|
Now let's see how to build registered URLs.
|
||||||
|
|
||||||
Routes can be named. All routes that define a name can have their URLs built,
|
Routes can be named. All routes that define a name can have their URLs built,
|
||||||
|
@ -154,18 +188,20 @@ key/value pairs for the route variables. For the previous route, we would do:
|
||||||
|
|
||||||
"/articles/technology/42"
|
"/articles/technology/42"
|
||||||
|
|
||||||
This also works for host variables:
|
This also works for host and query value variables:
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.Host("{subdomain}.domain.com").
|
r.Host("{subdomain}.domain.com").
|
||||||
Path("/articles/{category}/{id:[0-9]+}").
|
Path("/articles/{category}/{id:[0-9]+}").
|
||||||
|
Queries("filter", "{filter}").
|
||||||
HandlerFunc(ArticleHandler).
|
HandlerFunc(ArticleHandler).
|
||||||
Name("article")
|
Name("article")
|
||||||
|
|
||||||
// url.String() will be "http://news.domain.com/articles/technology/42"
|
// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
|
||||||
url, err := r.Get("article").URL("subdomain", "news",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42",
|
||||||
|
"filter", "gorilla")
|
||||||
|
|
||||||
All variables defined in the route are required, and their values must
|
All variables defined in the route are required, and their values must
|
||||||
conform to the corresponding patterns. These requirements guarantee that a
|
conform to the corresponding patterns. These requirements guarantee that a
|
||||||
|
@ -202,5 +238,70 @@ as well:
|
||||||
url, err := r.Get("article").URL("subdomain", "news",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42")
|
||||||
|
|
||||||
|
Since **vX.Y.Z**, mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed if a
|
||||||
|
match is found (including subrouters). Middlewares are defined using the de facto standard type:
|
||||||
|
|
||||||
|
type MiddlewareFunc func(http.Handler) http.Handler
|
||||||
|
|
||||||
|
Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created).
|
||||||
|
|
||||||
|
A very basic middleware which logs the URI of the request being handled could be written as:
|
||||||
|
|
||||||
|
func simpleMw(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Do stuff here
|
||||||
|
log.Println(r.RequestURI)
|
||||||
|
// Call the next handler, which can be another middleware in the chain, or the final handler.
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Middlewares can be added to a router using `Router.Use()`:
|
||||||
|
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/", handler)
|
||||||
|
r.AddMiddleware(simpleMw)
|
||||||
|
|
||||||
|
A more complex authentication middleware, which maps session token to users, could be written as:
|
||||||
|
|
||||||
|
// Define our struct
|
||||||
|
type authenticationMiddleware struct {
|
||||||
|
tokenUsers map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize it somewhere
|
||||||
|
func (amw *authenticationMiddleware) Populate() {
|
||||||
|
amw.tokenUsers["00000000"] = "user0"
|
||||||
|
amw.tokenUsers["aaaaaaaa"] = "userA"
|
||||||
|
amw.tokenUsers["05f717e5"] = "randomUser"
|
||||||
|
amw.tokenUsers["deadbeef"] = "user0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Middleware function, which will be called for each request
|
||||||
|
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
token := r.Header.Get("X-Session-Token")
|
||||||
|
|
||||||
|
if user, found := amw.tokenUsers[token]; found {
|
||||||
|
// We found the token in our map
|
||||||
|
log.Printf("Authenticated user %s\n", user)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
} else {
|
||||||
|
http.Error(w, "Forbidden", 403)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/", handler)
|
||||||
|
|
||||||
|
amw := authenticationMiddleware{}
|
||||||
|
amw.Populate()
|
||||||
|
|
||||||
|
r.Use(amw.Middleware)
|
||||||
|
|
||||||
|
Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package mux
|
package mux
|
||||||
|
|
28
vendor/github.com/gorilla/mux/middleware.go
generated
vendored
Normal file
28
vendor/github.com/gorilla/mux/middleware.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package mux
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler.
|
||||||
|
// Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed
|
||||||
|
// to it, and then calls the handler passed as parameter to the MiddlewareFunc.
|
||||||
|
type MiddlewareFunc func(http.Handler) http.Handler
|
||||||
|
|
||||||
|
// middleware interface is anything which implements a MiddlewareFunc named Middleware.
|
||||||
|
type middleware interface {
|
||||||
|
Middleware(handler http.Handler) http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// MiddlewareFunc also implements the middleware interface.
|
||||||
|
func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler {
|
||||||
|
return mw(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
|
||||||
|
func (r *Router) Use(mwf MiddlewareFunc) {
|
||||||
|
r.middlewares = append(r.middlewares, mwf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
|
||||||
|
func (r *Router) useInterface(mw middleware) {
|
||||||
|
r.middlewares = append(r.middlewares, mw)
|
||||||
|
}
|
166
vendor/github.com/gorilla/mux/mux.go
generated
vendored
166
vendor/github.com/gorilla/mux/mux.go
generated
vendored
|
@ -10,8 +10,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
"github.com/gorilla/context"
|
var (
|
||||||
|
ErrMethodMismatch = errors.New("method is not allowed")
|
||||||
|
ErrNotFound = errors.New("no matching route was found")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRouter returns a new router instance.
|
// NewRouter returns a new router instance.
|
||||||
|
@ -40,6 +43,10 @@ func NewRouter() *Router {
|
||||||
type Router struct {
|
type Router struct {
|
||||||
// Configurable Handler to be used when no route matches.
|
// Configurable Handler to be used when no route matches.
|
||||||
NotFoundHandler http.Handler
|
NotFoundHandler http.Handler
|
||||||
|
|
||||||
|
// Configurable Handler to be used when the request method does not match the route.
|
||||||
|
MethodNotAllowedHandler http.Handler
|
||||||
|
|
||||||
// Parent route, if this is a subrouter.
|
// Parent route, if this is a subrouter.
|
||||||
parent parentRoute
|
parent parentRoute
|
||||||
// Routes to be matched, in order.
|
// Routes to be matched, in order.
|
||||||
|
@ -48,17 +55,59 @@ type Router struct {
|
||||||
namedRoutes map[string]*Route
|
namedRoutes map[string]*Route
|
||||||
// See Router.StrictSlash(). This defines the flag for new routes.
|
// See Router.StrictSlash(). This defines the flag for new routes.
|
||||||
strictSlash bool
|
strictSlash bool
|
||||||
// If true, do not clear the request context after handling the request
|
// See Router.SkipClean(). This defines the flag for new routes.
|
||||||
|
skipClean bool
|
||||||
|
// If true, do not clear the request context after handling the request.
|
||||||
|
// This has no effect when go1.7+ is used, since the context is stored
|
||||||
|
// on the request itself.
|
||||||
KeepContext bool
|
KeepContext bool
|
||||||
|
// see Router.UseEncodedPath(). This defines a flag for all routes.
|
||||||
|
useEncodedPath bool
|
||||||
|
// Slice of middlewares to be called after a match is found
|
||||||
|
middlewares []middleware
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match matches registered routes against the request.
|
// Match attempts to match the given request against the router's registered routes.
|
||||||
|
//
|
||||||
|
// If the request matches a route of this router or one of its subrouters the Route,
|
||||||
|
// Handler, and Vars fields of the the match argument are filled and this function
|
||||||
|
// returns true.
|
||||||
|
//
|
||||||
|
// If the request does not match any of this router's or its subrouters' routes
|
||||||
|
// then this function returns false. If available, a reason for the match failure
|
||||||
|
// will be filled in the match argument's MatchErr field. If the match failure type
|
||||||
|
// (eg: not found) has a registered handler, the handler is assigned to the Handler
|
||||||
|
// field of the match argument.
|
||||||
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
|
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
for _, route := range r.routes {
|
for _, route := range r.routes {
|
||||||
if route.Match(req, match) {
|
if route.Match(req, match) {
|
||||||
|
// Build middleware chain if no error was found
|
||||||
|
if match.MatchErr == nil {
|
||||||
|
for i := len(r.middlewares) - 1; i >= 0; i-- {
|
||||||
|
match.Handler = r.middlewares[i].Middleware(match.Handler)
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if match.MatchErr == ErrMethodMismatch {
|
||||||
|
if r.MethodNotAllowedHandler != nil {
|
||||||
|
match.Handler = r.MethodNotAllowedHandler
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closest match for a router (includes sub-routers)
|
||||||
|
if r.NotFoundHandler != nil {
|
||||||
|
match.Handler = r.NotFoundHandler
|
||||||
|
match.MatchErr = ErrNotFound
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
match.MatchErr = ErrNotFound
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +116,15 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
// When there is a match, the route variables can be retrieved calling
|
// When there is a match, the route variables can be retrieved calling
|
||||||
// mux.Vars(request).
|
// mux.Vars(request).
|
||||||
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if !r.skipClean {
|
||||||
|
path := req.URL.Path
|
||||||
|
if r.useEncodedPath {
|
||||||
|
path = req.URL.EscapedPath()
|
||||||
|
}
|
||||||
// Clean path to canonical form and redirect.
|
// Clean path to canonical form and redirect.
|
||||||
if p := cleanPath(req.URL.Path); p != req.URL.Path {
|
if p := cleanPath(path); p != path {
|
||||||
|
|
||||||
// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
|
// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
|
||||||
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
|
// This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
|
||||||
// http://code.google.com/p/go/issues/detail?id=5252
|
// http://code.google.com/p/go/issues/detail?id=5252
|
||||||
url := *req.URL
|
url := *req.URL
|
||||||
|
@ -81,22 +135,27 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
w.WriteHeader(http.StatusMovedPermanently)
|
w.WriteHeader(http.StatusMovedPermanently)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var match RouteMatch
|
var match RouteMatch
|
||||||
var handler http.Handler
|
var handler http.Handler
|
||||||
if r.Match(req, &match) {
|
if r.Match(req, &match) {
|
||||||
handler = match.Handler
|
handler = match.Handler
|
||||||
setVars(req, match.Vars)
|
req = setVars(req, match.Vars)
|
||||||
setCurrentRoute(req, match.Route)
|
req = setCurrentRoute(req, match.Route)
|
||||||
}
|
}
|
||||||
if handler == nil {
|
|
||||||
handler = r.NotFoundHandler
|
if handler == nil && match.MatchErr == ErrMethodMismatch {
|
||||||
|
handler = methodNotAllowedHandler()
|
||||||
|
}
|
||||||
|
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
handler = http.NotFoundHandler()
|
handler = http.NotFoundHandler()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if !r.KeepContext {
|
if !r.KeepContext {
|
||||||
defer context.Clear(req)
|
defer contextClear(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,13 +173,18 @@ func (r *Router) GetRoute(name string) *Route {
|
||||||
// StrictSlash defines the trailing slash behavior for new routes. The initial
|
// StrictSlash defines the trailing slash behavior for new routes. The initial
|
||||||
// value is false.
|
// value is false.
|
||||||
//
|
//
|
||||||
// When true, if the route path is "/path/", accessing "/path" will redirect
|
// When true, if the route path is "/path/", accessing "/path" will perform a redirect
|
||||||
// to the former and vice versa. In other words, your application will always
|
// to the former and vice versa. In other words, your application will always
|
||||||
// see the path as specified in the route.
|
// see the path as specified in the route.
|
||||||
//
|
//
|
||||||
// When false, if the route path is "/path", accessing "/path/" will not match
|
// When false, if the route path is "/path", accessing "/path/" will not match
|
||||||
// this route and vice versa.
|
// this route and vice versa.
|
||||||
//
|
//
|
||||||
|
// The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for
|
||||||
|
// routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed
|
||||||
|
// request will be made as a GET by most clients. Use middleware or client settings
|
||||||
|
// to modify this behaviour as needed.
|
||||||
|
//
|
||||||
// Special case: when a route sets a path prefix using the PathPrefix() method,
|
// Special case: when a route sets a path prefix using the PathPrefix() method,
|
||||||
// strict slash is ignored for that route because the redirect behavior can't
|
// strict slash is ignored for that route because the redirect behavior can't
|
||||||
// be determined from a prefix alone. However, any subrouters created from that
|
// be determined from a prefix alone. However, any subrouters created from that
|
||||||
|
@ -130,10 +194,41 @@ func (r *Router) StrictSlash(value bool) *Router {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SkipClean defines the path cleaning behaviour for new routes. The initial
|
||||||
|
// value is false. Users should be careful about which routes are not cleaned
|
||||||
|
//
|
||||||
|
// When true, if the route path is "/path//to", it will remain with the double
|
||||||
|
// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
|
||||||
|
//
|
||||||
|
// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will
|
||||||
|
// become /fetch/http/xkcd.com/534
|
||||||
|
func (r *Router) SkipClean(value bool) *Router {
|
||||||
|
r.skipClean = value
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseEncodedPath tells the router to match the encoded original path
|
||||||
|
// to the routes.
|
||||||
|
// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
|
||||||
|
//
|
||||||
|
// If not called, the router will match the unencoded path to the routes.
|
||||||
|
// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
|
||||||
|
func (r *Router) UseEncodedPath() *Router {
|
||||||
|
r.useEncodedPath = true
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// parentRoute
|
// parentRoute
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (r *Router) getBuildScheme() string {
|
||||||
|
if r.parent != nil {
|
||||||
|
return r.parent.getBuildScheme()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// getNamedRoutes returns the map where named routes are registered.
|
// getNamedRoutes returns the map where named routes are registered.
|
||||||
func (r *Router) getNamedRoutes() map[string]*Route {
|
func (r *Router) getNamedRoutes() map[string]*Route {
|
||||||
if r.namedRoutes == nil {
|
if r.namedRoutes == nil {
|
||||||
|
@ -167,7 +262,7 @@ func (r *Router) buildVars(m map[string]string) map[string]string {
|
||||||
|
|
||||||
// NewRoute registers an empty route.
|
// NewRoute registers an empty route.
|
||||||
func (r *Router) NewRoute() *Route {
|
func (r *Router) NewRoute() *Route {
|
||||||
route := &Route{parent: r, strictSlash: r.strictSlash}
|
route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath}
|
||||||
r.routes = append(r.routes, route)
|
r.routes = append(r.routes, route)
|
||||||
return route
|
return route
|
||||||
}
|
}
|
||||||
|
@ -233,7 +328,7 @@ func (r *Router) Schemes(schemes ...string) *Route {
|
||||||
return r.NewRoute().Schemes(schemes...)
|
return r.NewRoute().Schemes(schemes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildVars registers a new route with a custom function for modifying
|
// BuildVarsFunc registers a new route with a custom function for modifying
|
||||||
// route variables before building a URL.
|
// route variables before building a URL.
|
||||||
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
|
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
|
||||||
return r.NewRoute().BuildVarsFunc(f)
|
return r.NewRoute().BuildVarsFunc(f)
|
||||||
|
@ -257,20 +352,21 @@ type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
|
||||||
|
|
||||||
func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
|
func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
|
||||||
for _, t := range r.routes {
|
for _, t := range r.routes {
|
||||||
if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err := walkFn(t, r, ancestors)
|
err := walkFn(t, r, ancestors)
|
||||||
if err == SkipRouter {
|
if err == SkipRouter {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
for _, sr := range t.matchers {
|
for _, sr := range t.matchers {
|
||||||
if h, ok := sr.(*Router); ok {
|
if h, ok := sr.(*Router); ok {
|
||||||
|
ancestors = append(ancestors, t)
|
||||||
err := h.walk(walkFn, ancestors)
|
err := h.walk(walkFn, ancestors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
ancestors = ancestors[:len(ancestors)-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h, ok := t.handler.(*Router); ok {
|
if h, ok := t.handler.(*Router); ok {
|
||||||
|
@ -294,6 +390,11 @@ type RouteMatch struct {
|
||||||
Route *Route
|
Route *Route
|
||||||
Handler http.Handler
|
Handler http.Handler
|
||||||
Vars map[string]string
|
Vars map[string]string
|
||||||
|
|
||||||
|
// MatchErr is set to appropriate matching error
|
||||||
|
// It is set to ErrMethodMismatch if there is a mismatch in
|
||||||
|
// the request method and route method
|
||||||
|
MatchErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
type contextKey int
|
type contextKey int
|
||||||
|
@ -305,7 +406,7 @@ const (
|
||||||
|
|
||||||
// Vars returns the route variables for the current request, if any.
|
// Vars returns the route variables for the current request, if any.
|
||||||
func Vars(r *http.Request) map[string]string {
|
func Vars(r *http.Request) map[string]string {
|
||||||
if rv := context.Get(r, varsKey); rv != nil {
|
if rv := contextGet(r, varsKey); rv != nil {
|
||||||
return rv.(map[string]string)
|
return rv.(map[string]string)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -317,18 +418,18 @@ func Vars(r *http.Request) map[string]string {
|
||||||
// after the handler returns, unless the KeepContext option is set on the
|
// after the handler returns, unless the KeepContext option is set on the
|
||||||
// Router.
|
// Router.
|
||||||
func CurrentRoute(r *http.Request) *Route {
|
func CurrentRoute(r *http.Request) *Route {
|
||||||
if rv := context.Get(r, routeKey); rv != nil {
|
if rv := contextGet(r, routeKey); rv != nil {
|
||||||
return rv.(*Route)
|
return rv.(*Route)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setVars(r *http.Request, val interface{}) {
|
func setVars(r *http.Request, val interface{}) *http.Request {
|
||||||
context.Set(r, varsKey, val)
|
return contextSet(r, varsKey, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCurrentRoute(r *http.Request, val interface{}) {
|
func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
|
||||||
context.Set(r, routeKey, val)
|
return contextSet(r, routeKey, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -350,6 +451,7 @@ func cleanPath(p string) string {
|
||||||
if p[len(p)-1] == '/' && np != "/" {
|
if p[len(p)-1] == '/' && np != "/" {
|
||||||
np += "/"
|
np += "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
return np
|
return np
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,6 +467,8 @@ func uniqueVars(s1, s2 []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkPairs returns the count of strings passed in, and an error if
|
||||||
|
// the count is not an even number.
|
||||||
func checkPairs(pairs ...string) (int, error) {
|
func checkPairs(pairs ...string) (int, error) {
|
||||||
length := len(pairs)
|
length := len(pairs)
|
||||||
if length%2 != 0 {
|
if length%2 != 0 {
|
||||||
|
@ -374,7 +478,8 @@ func checkPairs(pairs ...string) (int, error) {
|
||||||
return length, nil
|
return length, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mapFromPairs converts variadic string parameters to a string map.
|
// mapFromPairsToString converts variadic string parameters to a
|
||||||
|
// string to string map.
|
||||||
func mapFromPairsToString(pairs ...string) (map[string]string, error) {
|
func mapFromPairsToString(pairs ...string) (map[string]string, error) {
|
||||||
length, err := checkPairs(pairs...)
|
length, err := checkPairs(pairs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -387,6 +492,8 @@ func mapFromPairsToString(pairs ...string) (map[string]string, error) {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mapFromPairsToRegex converts variadic string parameters to a
|
||||||
|
// string to regex map.
|
||||||
func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
|
func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
|
||||||
length, err := checkPairs(pairs...)
|
length, err := checkPairs(pairs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -467,3 +574,12 @@ func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]s
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// methodNotAllowed replies to the request with an HTTP status code 405.
|
||||||
|
func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// methodNotAllowedHandler returns a simple request handler
|
||||||
|
// that replies to each request with a status code 405.
|
||||||
|
func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }
|
||||||
|
|
143
vendor/github.com/gorilla/mux/regexp.go
generated
vendored
143
vendor/github.com/gorilla/mux/regexp.go
generated
vendored
|
@ -14,6 +14,20 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type routeRegexpOptions struct {
|
||||||
|
strictSlash bool
|
||||||
|
useEncodedPath bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type regexpType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
regexpTypePath regexpType = 0
|
||||||
|
regexpTypeHost regexpType = 1
|
||||||
|
regexpTypePrefix regexpType = 2
|
||||||
|
regexpTypeQuery regexpType = 3
|
||||||
|
)
|
||||||
|
|
||||||
// newRouteRegexp parses a route template and returns a routeRegexp,
|
// newRouteRegexp parses a route template and returns a routeRegexp,
|
||||||
// used to match a host, a path or a query string.
|
// used to match a host, a path or a query string.
|
||||||
//
|
//
|
||||||
|
@ -24,7 +38,7 @@ import (
|
||||||
// Previously we accepted only Python-like identifiers for variable
|
// Previously we accepted only Python-like identifiers for variable
|
||||||
// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
|
// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
|
||||||
// name and pattern can't be empty, and names can't contain a colon.
|
// name and pattern can't be empty, and names can't contain a colon.
|
||||||
func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash bool) (*routeRegexp, error) {
|
func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*routeRegexp, error) {
|
||||||
// Check if it is well-formed.
|
// Check if it is well-formed.
|
||||||
idxs, errBraces := braceIndices(tpl)
|
idxs, errBraces := braceIndices(tpl)
|
||||||
if errBraces != nil {
|
if errBraces != nil {
|
||||||
|
@ -34,19 +48,18 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
template := tpl
|
template := tpl
|
||||||
// Now let's parse it.
|
// Now let's parse it.
|
||||||
defaultPattern := "[^/]+"
|
defaultPattern := "[^/]+"
|
||||||
if matchQuery {
|
if typ == regexpTypeQuery {
|
||||||
defaultPattern = "[^?&]*"
|
defaultPattern = ".*"
|
||||||
} else if matchHost {
|
} else if typ == regexpTypeHost {
|
||||||
defaultPattern = "[^.]+"
|
defaultPattern = "[^.]+"
|
||||||
matchPrefix = false
|
|
||||||
}
|
}
|
||||||
// Only match strict slash if not matching
|
// Only match strict slash if not matching
|
||||||
if matchPrefix || matchHost || matchQuery {
|
if typ != regexpTypePath {
|
||||||
strictSlash = false
|
options.strictSlash = false
|
||||||
}
|
}
|
||||||
// Set a flag for strictSlash.
|
// Set a flag for strictSlash.
|
||||||
endSlash := false
|
endSlash := false
|
||||||
if strictSlash && strings.HasSuffix(tpl, "/") {
|
if options.strictSlash && strings.HasSuffix(tpl, "/") {
|
||||||
tpl = tpl[:len(tpl)-1]
|
tpl = tpl[:len(tpl)-1]
|
||||||
endSlash = true
|
endSlash = true
|
||||||
}
|
}
|
||||||
|
@ -73,14 +86,14 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
tpl[idxs[i]:end])
|
tpl[idxs[i]:end])
|
||||||
}
|
}
|
||||||
// Build the regexp pattern.
|
// Build the regexp pattern.
|
||||||
varIdx := i / 2
|
fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt)
|
||||||
fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(varIdx), patt)
|
|
||||||
// Build the reverse template.
|
// Build the reverse template.
|
||||||
fmt.Fprintf(reverse, "%s%%s", raw)
|
fmt.Fprintf(reverse, "%s%%s", raw)
|
||||||
|
|
||||||
// Append variable name and compiled pattern.
|
// Append variable name and compiled pattern.
|
||||||
varsN[varIdx] = name
|
varsN[i/2] = name
|
||||||
varsR[varIdx], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
|
varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -88,16 +101,16 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
// Add the remaining.
|
// Add the remaining.
|
||||||
raw := tpl[end:]
|
raw := tpl[end:]
|
||||||
pattern.WriteString(regexp.QuoteMeta(raw))
|
pattern.WriteString(regexp.QuoteMeta(raw))
|
||||||
if strictSlash {
|
if options.strictSlash {
|
||||||
pattern.WriteString("[/]?")
|
pattern.WriteString("[/]?")
|
||||||
}
|
}
|
||||||
if matchQuery {
|
if typ == regexpTypeQuery {
|
||||||
// Add the default pattern if the query value is empty
|
// Add the default pattern if the query value is empty
|
||||||
if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
|
if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
|
||||||
pattern.WriteString(defaultPattern)
|
pattern.WriteString(defaultPattern)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !matchPrefix {
|
if typ != regexpTypePrefix {
|
||||||
pattern.WriteByte('$')
|
pattern.WriteByte('$')
|
||||||
}
|
}
|
||||||
reverse.WriteString(raw)
|
reverse.WriteString(raw)
|
||||||
|
@ -109,12 +122,18 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
if errCompile != nil {
|
if errCompile != nil {
|
||||||
return nil, errCompile
|
return nil, errCompile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for capturing groups which used to work in older versions
|
||||||
|
if reg.NumSubexp() != len(idxs)/2 {
|
||||||
|
panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) +
|
||||||
|
"Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)")
|
||||||
|
}
|
||||||
|
|
||||||
// Done!
|
// Done!
|
||||||
return &routeRegexp{
|
return &routeRegexp{
|
||||||
template: template,
|
template: template,
|
||||||
matchHost: matchHost,
|
regexpType: typ,
|
||||||
matchQuery: matchQuery,
|
options: options,
|
||||||
strictSlash: strictSlash,
|
|
||||||
regexp: reg,
|
regexp: reg,
|
||||||
reverse: reverse.String(),
|
reverse: reverse.String(),
|
||||||
varsN: varsN,
|
varsN: varsN,
|
||||||
|
@ -127,12 +146,10 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
type routeRegexp struct {
|
type routeRegexp struct {
|
||||||
// The unmodified template.
|
// The unmodified template.
|
||||||
template string
|
template string
|
||||||
// True for host match, false for path or query string match.
|
// The type of match
|
||||||
matchHost bool
|
regexpType regexpType
|
||||||
// True for query string match, false for path and host match.
|
// Options for matching
|
||||||
matchQuery bool
|
options routeRegexpOptions
|
||||||
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
|
|
||||||
strictSlash bool
|
|
||||||
// Expanded regexp.
|
// Expanded regexp.
|
||||||
regexp *regexp.Regexp
|
regexp *regexp.Regexp
|
||||||
// Reverse template.
|
// Reverse template.
|
||||||
|
@ -145,13 +162,17 @@ type routeRegexp struct {
|
||||||
|
|
||||||
// Match matches the regexp against the URL host or path.
|
// Match matches the regexp against the URL host or path.
|
||||||
func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
if !r.matchHost {
|
if r.regexpType != regexpTypeHost {
|
||||||
if r.matchQuery {
|
if r.regexpType == regexpTypeQuery {
|
||||||
return r.matchQueryString(req)
|
return r.matchQueryString(req)
|
||||||
} else {
|
|
||||||
return r.regexp.MatchString(req.URL.Path)
|
|
||||||
}
|
}
|
||||||
|
path := req.URL.Path
|
||||||
|
if r.options.useEncodedPath {
|
||||||
|
path = req.URL.EscapedPath()
|
||||||
}
|
}
|
||||||
|
return r.regexp.MatchString(path)
|
||||||
|
}
|
||||||
|
|
||||||
return r.regexp.MatchString(getHost(req))
|
return r.regexp.MatchString(getHost(req))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +184,9 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("mux: missing route variable %q", v)
|
return "", fmt.Errorf("mux: missing route variable %q", v)
|
||||||
}
|
}
|
||||||
|
if r.regexpType == regexpTypeQuery {
|
||||||
|
value = url.QueryEscape(value)
|
||||||
|
}
|
||||||
urlValues[k] = value
|
urlValues[k] = value
|
||||||
}
|
}
|
||||||
rv := fmt.Sprintf(r.reverse, urlValues...)
|
rv := fmt.Sprintf(r.reverse, urlValues...)
|
||||||
|
@ -181,11 +205,11 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
|
||||||
return rv, nil
|
return rv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getUrlQuery returns a single query parameter from a request URL.
|
// getURLQuery returns a single query parameter from a request URL.
|
||||||
// For a URL with foo=bar&baz=ding, we return only the relevant key
|
// For a URL with foo=bar&baz=ding, we return only the relevant key
|
||||||
// value pair for the routeRegexp.
|
// value pair for the routeRegexp.
|
||||||
func (r *routeRegexp) getUrlQuery(req *http.Request) string {
|
func (r *routeRegexp) getURLQuery(req *http.Request) string {
|
||||||
if !r.matchQuery {
|
if r.regexpType != regexpTypeQuery {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
templateKey := strings.SplitN(r.template, "=", 2)[0]
|
templateKey := strings.SplitN(r.template, "=", 2)[0]
|
||||||
|
@ -198,14 +222,14 @@ func (r *routeRegexp) getUrlQuery(req *http.Request) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *routeRegexp) matchQueryString(req *http.Request) bool {
|
func (r *routeRegexp) matchQueryString(req *http.Request) bool {
|
||||||
return r.regexp.MatchString(r.getUrlQuery(req))
|
return r.regexp.MatchString(r.getURLQuery(req))
|
||||||
}
|
}
|
||||||
|
|
||||||
// braceIndices returns the first level curly brace indices from a string.
|
// braceIndices returns the first level curly brace indices from a string.
|
||||||
// It returns an error in case of unbalanced braces.
|
// It returns an error in case of unbalanced braces.
|
||||||
func braceIndices(s string) ([]int, error) {
|
func braceIndices(s string) ([]int, error) {
|
||||||
var level, idx int
|
var level, idx int
|
||||||
idxs := make([]int, 0)
|
var idxs []int
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
switch s[i] {
|
switch s[i] {
|
||||||
case '{':
|
case '{':
|
||||||
|
@ -246,33 +270,24 @@ type routeRegexpGroup struct {
|
||||||
func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
|
func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
|
||||||
// Store host variables.
|
// Store host variables.
|
||||||
if v.host != nil {
|
if v.host != nil {
|
||||||
hostVars := v.host.regexp.FindStringSubmatch(getHost(req))
|
host := getHost(req)
|
||||||
if hostVars != nil {
|
matches := v.host.regexp.FindStringSubmatchIndex(host)
|
||||||
subexpNames := v.host.regexp.SubexpNames()
|
if len(matches) > 0 {
|
||||||
varName := 0
|
extractVars(host, matches, v.host.varsN, m.Vars)
|
||||||
for i, name := range subexpNames[1:] {
|
|
||||||
if name != "" && name == varGroupName(varName) {
|
|
||||||
m.Vars[v.host.varsN[varName]] = hostVars[i+1]
|
|
||||||
varName++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
path := req.URL.Path
|
||||||
|
if r.useEncodedPath {
|
||||||
|
path = req.URL.EscapedPath()
|
||||||
}
|
}
|
||||||
// Store path variables.
|
// Store path variables.
|
||||||
if v.path != nil {
|
if v.path != nil {
|
||||||
pathVars := v.path.regexp.FindStringSubmatch(req.URL.Path)
|
matches := v.path.regexp.FindStringSubmatchIndex(path)
|
||||||
if pathVars != nil {
|
if len(matches) > 0 {
|
||||||
subexpNames := v.path.regexp.SubexpNames()
|
extractVars(path, matches, v.path.varsN, m.Vars)
|
||||||
varName := 0
|
|
||||||
for i, name := range subexpNames[1:] {
|
|
||||||
if name != "" && name == varGroupName(varName) {
|
|
||||||
m.Vars[v.path.varsN[varName]] = pathVars[i+1]
|
|
||||||
varName++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check if we should redirect.
|
// Check if we should redirect.
|
||||||
if v.path.strictSlash {
|
if v.path.options.strictSlash {
|
||||||
p1 := strings.HasSuffix(req.URL.Path, "/")
|
p1 := strings.HasSuffix(path, "/")
|
||||||
p2 := strings.HasSuffix(v.path.template, "/")
|
p2 := strings.HasSuffix(v.path.template, "/")
|
||||||
if p1 != p2 {
|
if p1 != p2 {
|
||||||
u, _ := url.Parse(req.URL.String())
|
u, _ := url.Parse(req.URL.String())
|
||||||
|
@ -288,16 +303,10 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
|
||||||
}
|
}
|
||||||
// Store query string variables.
|
// Store query string variables.
|
||||||
for _, q := range v.queries {
|
for _, q := range v.queries {
|
||||||
queryVars := q.regexp.FindStringSubmatch(q.getUrlQuery(req))
|
queryURL := q.getURLQuery(req)
|
||||||
if queryVars != nil {
|
matches := q.regexp.FindStringSubmatchIndex(queryURL)
|
||||||
subexpNames := q.regexp.SubexpNames()
|
if len(matches) > 0 {
|
||||||
varName := 0
|
extractVars(queryURL, matches, q.varsN, m.Vars)
|
||||||
for i, name := range subexpNames[1:] {
|
|
||||||
if name != "" && name == varGroupName(varName) {
|
|
||||||
m.Vars[q.varsN[varName]] = queryVars[i+1]
|
|
||||||
varName++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,3 +324,9 @@ func getHost(r *http.Request) string {
|
||||||
return host
|
return host
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractVars(input string, matches []int, names []string, output map[string]string) {
|
||||||
|
for i, name := range names {
|
||||||
|
output[name] = input[matches[2*i+2]:matches[2*i+3]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
200
vendor/github.com/gorilla/mux/route.go
generated
vendored
200
vendor/github.com/gorilla/mux/route.go
generated
vendored
|
@ -26,6 +26,13 @@ type Route struct {
|
||||||
// If true, when the path pattern is "/path/", accessing "/path" will
|
// If true, when the path pattern is "/path/", accessing "/path" will
|
||||||
// redirect to the former and vice versa.
|
// redirect to the former and vice versa.
|
||||||
strictSlash bool
|
strictSlash bool
|
||||||
|
// If true, when the path pattern is "/path//to", accessing "/path//to"
|
||||||
|
// will not redirect
|
||||||
|
skipClean bool
|
||||||
|
// If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
|
||||||
|
useEncodedPath bool
|
||||||
|
// The scheme used when building URLs.
|
||||||
|
buildScheme string
|
||||||
// If true, this route never matches: it is only used to build URLs.
|
// If true, this route never matches: it is only used to build URLs.
|
||||||
buildOnly bool
|
buildOnly bool
|
||||||
// The name used to build URLs.
|
// The name used to build URLs.
|
||||||
|
@ -36,17 +43,42 @@ type Route struct {
|
||||||
buildVarsFunc BuildVarsFunc
|
buildVarsFunc BuildVarsFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Route) SkipClean() bool {
|
||||||
|
return r.skipClean
|
||||||
|
}
|
||||||
|
|
||||||
// Match matches the route against the request.
|
// Match matches the route against the request.
|
||||||
func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
|
func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
if r.buildOnly || r.err != nil {
|
if r.buildOnly || r.err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var matchErr error
|
||||||
|
|
||||||
// Match everything.
|
// Match everything.
|
||||||
for _, m := range r.matchers {
|
for _, m := range r.matchers {
|
||||||
if matched := m.Match(req, match); !matched {
|
if matched := m.Match(req, match); !matched {
|
||||||
|
if _, ok := m.(methodMatcher); ok {
|
||||||
|
matchErr = ErrMethodMismatch
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
matchErr = nil
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if matchErr != nil {
|
||||||
|
match.MatchErr = matchErr
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if match.MatchErr == ErrMethodMismatch {
|
||||||
|
// We found a route which matches request method, clear MatchErr
|
||||||
|
match.MatchErr = nil
|
||||||
|
// Then override the mis-matched handler
|
||||||
|
match.Handler = r.handler
|
||||||
|
}
|
||||||
|
|
||||||
// Yay, we have a match. Let's collect some info about it.
|
// Yay, we have a match. Let's collect some info about it.
|
||||||
if match.Route == nil {
|
if match.Route == nil {
|
||||||
match.Route = r
|
match.Route = r
|
||||||
|
@ -57,6 +89,7 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
if match.Vars == nil {
|
if match.Vars == nil {
|
||||||
match.Vars = make(map[string]string)
|
match.Vars = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set variables.
|
// Set variables.
|
||||||
if r.regexp != nil {
|
if r.regexp != nil {
|
||||||
r.regexp.setMatch(req, match, r)
|
r.regexp.setMatch(req, match, r)
|
||||||
|
@ -138,20 +171,23 @@ func (r *Route) addMatcher(m matcher) *Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
// addRegexpMatcher adds a host or path matcher and builder to a route.
|
// addRegexpMatcher adds a host or path matcher and builder to a route.
|
||||||
func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery bool) error {
|
func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {
|
||||||
if r.err != nil {
|
if r.err != nil {
|
||||||
return r.err
|
return r.err
|
||||||
}
|
}
|
||||||
r.regexp = r.getRegexpGroup()
|
r.regexp = r.getRegexpGroup()
|
||||||
if !matchHost && !matchQuery {
|
if typ == regexpTypePath || typ == regexpTypePrefix {
|
||||||
if len(tpl) == 0 || tpl[0] != '/' {
|
if len(tpl) > 0 && tpl[0] != '/' {
|
||||||
return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
|
return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
|
||||||
}
|
}
|
||||||
if r.regexp.path != nil {
|
if r.regexp.path != nil {
|
||||||
tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
|
tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash)
|
rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{
|
||||||
|
strictSlash: r.strictSlash,
|
||||||
|
useEncodedPath: r.useEncodedPath,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -160,7 +196,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matchHost {
|
if typ == regexpTypeHost {
|
||||||
if r.regexp.path != nil {
|
if r.regexp.path != nil {
|
||||||
if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
|
if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -173,7 +209,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matchQuery {
|
if typ == regexpTypeQuery {
|
||||||
r.regexp.queries = append(r.regexp.queries, rr)
|
r.regexp.queries = append(r.regexp.queries, rr)
|
||||||
} else {
|
} else {
|
||||||
r.regexp.path = rr
|
r.regexp.path = rr
|
||||||
|
@ -217,14 +253,16 @@ func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
||||||
return matchMapWithRegex(m, r.Header, true)
|
return matchMapWithRegex(m, r.Header, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regular expressions can be used with headers as well.
|
// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
|
||||||
// It accepts a sequence of key/value pairs, where the value has regex support. For example
|
// support. For example:
|
||||||
|
//
|
||||||
// r := mux.NewRouter()
|
// r := mux.NewRouter()
|
||||||
// r.HeadersRegexp("Content-Type", "application/(text|json)",
|
// r.HeadersRegexp("Content-Type", "application/(text|json)",
|
||||||
// "X-Requested-With", "XMLHttpRequest")
|
// "X-Requested-With", "XMLHttpRequest")
|
||||||
//
|
//
|
||||||
// The above route will only match if both the request header matches both regular expressions.
|
// The above route will only match if both the request header matches both regular expressions.
|
||||||
// It the value is an empty string, it will match any value if the key is set.
|
// If the value is an empty string, it will match any value if the key is set.
|
||||||
|
// Use the start and end of string anchors (^ and $) to match an exact value.
|
||||||
func (r *Route) HeadersRegexp(pairs ...string) *Route {
|
func (r *Route) HeadersRegexp(pairs ...string) *Route {
|
||||||
if r.err == nil {
|
if r.err == nil {
|
||||||
var headers map[string]*regexp.Regexp
|
var headers map[string]*regexp.Regexp
|
||||||
|
@ -254,7 +292,7 @@ func (r *Route) HeadersRegexp(pairs ...string) *Route {
|
||||||
// Variable names must be unique in a given route. They can be retrieved
|
// Variable names must be unique in a given route. They can be retrieved
|
||||||
// calling mux.Vars(request).
|
// calling mux.Vars(request).
|
||||||
func (r *Route) Host(tpl string) *Route {
|
func (r *Route) Host(tpl string) *Route {
|
||||||
r.err = r.addRegexpMatcher(tpl, true, false, false)
|
r.err = r.addRegexpMatcher(tpl, regexpTypeHost)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +301,7 @@ func (r *Route) Host(tpl string) *Route {
|
||||||
// MatcherFunc is the function signature used by custom matchers.
|
// MatcherFunc is the function signature used by custom matchers.
|
||||||
type MatcherFunc func(*http.Request, *RouteMatch) bool
|
type MatcherFunc func(*http.Request, *RouteMatch) bool
|
||||||
|
|
||||||
|
// Match returns the match for a given request.
|
||||||
func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
|
func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
|
||||||
return m(r, match)
|
return m(r, match)
|
||||||
}
|
}
|
||||||
|
@ -313,7 +352,7 @@ func (r *Route) Methods(methods ...string) *Route {
|
||||||
// Variable names must be unique in a given route. They can be retrieved
|
// Variable names must be unique in a given route. They can be retrieved
|
||||||
// calling mux.Vars(request).
|
// calling mux.Vars(request).
|
||||||
func (r *Route) Path(tpl string) *Route {
|
func (r *Route) Path(tpl string) *Route {
|
||||||
r.err = r.addRegexpMatcher(tpl, false, false, false)
|
r.err = r.addRegexpMatcher(tpl, regexpTypePath)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +368,7 @@ func (r *Route) Path(tpl string) *Route {
|
||||||
// Also note that the setting of Router.StrictSlash() has no effect on routes
|
// Also note that the setting of Router.StrictSlash() has no effect on routes
|
||||||
// with a PathPrefix matcher.
|
// with a PathPrefix matcher.
|
||||||
func (r *Route) PathPrefix(tpl string) *Route {
|
func (r *Route) PathPrefix(tpl string) *Route {
|
||||||
r.err = r.addRegexpMatcher(tpl, false, true, false)
|
r.err = r.addRegexpMatcher(tpl, regexpTypePrefix)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +399,7 @@ func (r *Route) Queries(pairs ...string) *Route {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for i := 0; i < length; i += 2 {
|
for i := 0; i < length; i += 2 {
|
||||||
if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil {
|
if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -383,6 +422,9 @@ func (r *Route) Schemes(schemes ...string) *Route {
|
||||||
for k, v := range schemes {
|
for k, v := range schemes {
|
||||||
schemes[k] = strings.ToLower(v)
|
schemes[k] = strings.ToLower(v)
|
||||||
}
|
}
|
||||||
|
if r.buildScheme == "" && len(schemes) > 0 {
|
||||||
|
r.buildScheme = schemes[0]
|
||||||
|
}
|
||||||
return r.addMatcher(schemeMatcher(schemes))
|
return r.addMatcher(schemeMatcher(schemes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,22 +508,33 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var scheme, host, path string
|
var scheme, host, path string
|
||||||
|
queries := make([]string, 0, len(r.regexp.queries))
|
||||||
if r.regexp.host != nil {
|
if r.regexp.host != nil {
|
||||||
// Set a default scheme.
|
|
||||||
scheme = "http"
|
|
||||||
if host, err = r.regexp.host.url(values); err != nil {
|
if host, err = r.regexp.host.url(values); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
scheme = "http"
|
||||||
|
if s := r.getBuildScheme(); s != "" {
|
||||||
|
scheme = s
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if r.regexp.path != nil {
|
if r.regexp.path != nil {
|
||||||
if path, err = r.regexp.path.url(values); err != nil {
|
if path, err = r.regexp.path.url(values); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, q := range r.regexp.queries {
|
||||||
|
var query string
|
||||||
|
if query, err = q.url(values); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
queries = append(queries, query)
|
||||||
|
}
|
||||||
return &url.URL{
|
return &url.URL{
|
||||||
Scheme: scheme,
|
Scheme: scheme,
|
||||||
Host: host,
|
Host: host,
|
||||||
Path: path,
|
Path: path,
|
||||||
|
RawQuery: strings.Join(queries, "&"),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,10 +556,14 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
Host: host,
|
Host: host,
|
||||||
}, nil
|
}
|
||||||
|
if s := r.getBuildScheme(); s != "" {
|
||||||
|
u.Scheme = s
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// URLPath builds the path part of the URL for a route. See Route.URL().
|
// URLPath builds the path part of the URL for a route. See Route.URL().
|
||||||
|
@ -532,6 +589,104 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPathTemplate returns the template used to build the
|
||||||
|
// route match.
|
||||||
|
// This is useful for building simple REST API documentation and for instrumentation
|
||||||
|
// against third-party services.
|
||||||
|
// An error will be returned if the route does not define a path.
|
||||||
|
func (r *Route) GetPathTemplate() (string, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return "", r.err
|
||||||
|
}
|
||||||
|
if r.regexp == nil || r.regexp.path == nil {
|
||||||
|
return "", errors.New("mux: route doesn't have a path")
|
||||||
|
}
|
||||||
|
return r.regexp.path.template, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPathRegexp returns the expanded regular expression used to match route path.
|
||||||
|
// This is useful for building simple REST API documentation and for instrumentation
|
||||||
|
// against third-party services.
|
||||||
|
// An error will be returned if the route does not define a path.
|
||||||
|
func (r *Route) GetPathRegexp() (string, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return "", r.err
|
||||||
|
}
|
||||||
|
if r.regexp == nil || r.regexp.path == nil {
|
||||||
|
return "", errors.New("mux: route does not have a path")
|
||||||
|
}
|
||||||
|
return r.regexp.path.regexp.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetQueriesRegexp returns the expanded regular expressions used to match the
|
||||||
|
// route queries.
|
||||||
|
// This is useful for building simple REST API documentation and for instrumentation
|
||||||
|
// against third-party services.
|
||||||
|
// An empty list will be returned if the route does not have queries.
|
||||||
|
func (r *Route) GetQueriesRegexp() ([]string, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return nil, r.err
|
||||||
|
}
|
||||||
|
if r.regexp == nil || r.regexp.queries == nil {
|
||||||
|
return nil, errors.New("mux: route doesn't have queries")
|
||||||
|
}
|
||||||
|
var queries []string
|
||||||
|
for _, query := range r.regexp.queries {
|
||||||
|
queries = append(queries, query.regexp.String())
|
||||||
|
}
|
||||||
|
return queries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetQueriesTemplates returns the templates used to build the
|
||||||
|
// query matching.
|
||||||
|
// This is useful for building simple REST API documentation and for instrumentation
|
||||||
|
// against third-party services.
|
||||||
|
// An empty list will be returned if the route does not define queries.
|
||||||
|
func (r *Route) GetQueriesTemplates() ([]string, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return nil, r.err
|
||||||
|
}
|
||||||
|
if r.regexp == nil || r.regexp.queries == nil {
|
||||||
|
return nil, errors.New("mux: route doesn't have queries")
|
||||||
|
}
|
||||||
|
var queries []string
|
||||||
|
for _, query := range r.regexp.queries {
|
||||||
|
queries = append(queries, query.template)
|
||||||
|
}
|
||||||
|
return queries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMethods returns the methods the route matches against
|
||||||
|
// This is useful for building simple REST API documentation and for instrumentation
|
||||||
|
// against third-party services.
|
||||||
|
// An empty list will be returned if route does not have methods.
|
||||||
|
func (r *Route) GetMethods() ([]string, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return nil, r.err
|
||||||
|
}
|
||||||
|
for _, m := range r.matchers {
|
||||||
|
if methods, ok := m.(methodMatcher); ok {
|
||||||
|
return []string(methods), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHostTemplate returns the template used to build the
|
||||||
|
// route match.
|
||||||
|
// This is useful for building simple REST API documentation and for instrumentation
|
||||||
|
// against third-party services.
|
||||||
|
// An error will be returned if the route does not define a host.
|
||||||
|
func (r *Route) GetHostTemplate() (string, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return "", r.err
|
||||||
|
}
|
||||||
|
if r.regexp == nil || r.regexp.host == nil {
|
||||||
|
return "", errors.New("mux: route doesn't have a host")
|
||||||
|
}
|
||||||
|
return r.regexp.host.template, nil
|
||||||
|
}
|
||||||
|
|
||||||
// prepareVars converts the route variable pairs into a map. If the route has a
|
// prepareVars converts the route variable pairs into a map. If the route has a
|
||||||
// BuildVarsFunc, it is invoked.
|
// BuildVarsFunc, it is invoked.
|
||||||
func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
|
func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
|
||||||
|
@ -558,11 +713,22 @@ func (r *Route) buildVars(m map[string]string) map[string]string {
|
||||||
|
|
||||||
// parentRoute allows routes to know about parent host and path definitions.
|
// parentRoute allows routes to know about parent host and path definitions.
|
||||||
type parentRoute interface {
|
type parentRoute interface {
|
||||||
|
getBuildScheme() string
|
||||||
getNamedRoutes() map[string]*Route
|
getNamedRoutes() map[string]*Route
|
||||||
getRegexpGroup() *routeRegexpGroup
|
getRegexpGroup() *routeRegexpGroup
|
||||||
buildVars(map[string]string) map[string]string
|
buildVars(map[string]string) map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Route) getBuildScheme() string {
|
||||||
|
if r.buildScheme != "" {
|
||||||
|
return r.buildScheme
|
||||||
|
}
|
||||||
|
if r.parent != nil {
|
||||||
|
return r.parent.getBuildScheme()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// getNamedRoutes returns the map where named routes are registered.
|
// getNamedRoutes returns the map where named routes are registered.
|
||||||
func (r *Route) getNamedRoutes() map[string]*Route {
|
func (r *Route) getNamedRoutes() map[string]*Route {
|
||||||
if r.parent == nil {
|
if r.parent == nil {
|
||||||
|
|
18
vendor/github.com/gorilla/mux/test_helpers.go
generated
vendored
Normal file
18
vendor/github.com/gorilla/mux/test_helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2012 The Gorilla Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package mux
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// SetURLVars sets the URL variables for the given request, to be accessed via
|
||||||
|
// mux.Vars for testing route behaviour.
|
||||||
|
//
|
||||||
|
// This API should only be used for testing purposes; it provides a way to
|
||||||
|
// inject variables into the request context. Alternatively, URL variables
|
||||||
|
// can be set by making a route that captures the required variables,
|
||||||
|
// starting a server and sending the request to that server.
|
||||||
|
func SetURLVars(r *http.Request, val map[string]string) *http.Request {
|
||||||
|
return setVars(r, val)
|
||||||
|
}
|
6
vendor/github.com/nicksnyder/go-i18n/i18n/language/language.go
generated
vendored
6
vendor/github.com/nicksnyder/go-i18n/i18n/language/language.go
generated
vendored
|
@ -45,7 +45,7 @@ func Parse(src string) []*Language {
|
||||||
switch chr {
|
switch chr {
|
||||||
case ',', ';', '.':
|
case ',', ';', '.':
|
||||||
tag := strings.TrimSpace(src[start:end])
|
tag := strings.TrimSpace(src[start:end])
|
||||||
if spec := getPluralSpec(tag); spec != nil {
|
if spec := GetPluralSpec(tag); spec != nil {
|
||||||
langs = append(langs, &Language{NormalizeTag(tag), spec})
|
langs = append(langs, &Language{NormalizeTag(tag), spec})
|
||||||
}
|
}
|
||||||
start = end + 1
|
start = end + 1
|
||||||
|
@ -53,12 +53,12 @@ func Parse(src string) []*Language {
|
||||||
}
|
}
|
||||||
if start > 0 {
|
if start > 0 {
|
||||||
tag := strings.TrimSpace(src[start:])
|
tag := strings.TrimSpace(src[start:])
|
||||||
if spec := getPluralSpec(tag); spec != nil {
|
if spec := GetPluralSpec(tag); spec != nil {
|
||||||
langs = append(langs, &Language{NormalizeTag(tag), spec})
|
langs = append(langs, &Language{NormalizeTag(tag), spec})
|
||||||
}
|
}
|
||||||
return dedupe(langs)
|
return dedupe(langs)
|
||||||
}
|
}
|
||||||
if spec := getPluralSpec(src); spec != nil {
|
if spec := GetPluralSpec(src); spec != nil {
|
||||||
langs = append(langs, &Language{NormalizeTag(src), spec})
|
langs = append(langs, &Language{NormalizeTag(src), spec})
|
||||||
}
|
}
|
||||||
return langs
|
return langs
|
||||||
|
|
20
vendor/github.com/nicksnyder/go-i18n/i18n/language/operands.go
generated
vendored
20
vendor/github.com/nicksnyder/go-i18n/i18n/language/operands.go
generated
vendored
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
|
// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
|
||||||
type operands struct {
|
type Operands struct {
|
||||||
N float64 // absolute value of the source number (integer and decimals)
|
N float64 // absolute value of the source number (integer and decimals)
|
||||||
I int64 // integer digits of n
|
I int64 // integer digits of n
|
||||||
V int64 // number of visible fraction digits in n, with trailing zeros
|
V int64 // number of visible fraction digits in n, with trailing zeros
|
||||||
|
@ -17,7 +17,7 @@ type operands struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NmodEqualAny returns true if o represents an integer equal to any of the arguments.
|
// NmodEqualAny returns true if o represents an integer equal to any of the arguments.
|
||||||
func (o *operands) NequalsAny(any ...int64) bool {
|
func (o *Operands) NequalsAny(any ...int64) bool {
|
||||||
for _, i := range any {
|
for _, i := range any {
|
||||||
if o.I == i && o.T == 0 {
|
if o.I == i && o.T == 0 {
|
||||||
return true
|
return true
|
||||||
|
@ -27,7 +27,7 @@ func (o *operands) NequalsAny(any ...int64) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NmodEqualAny returns true if o represents an integer equal to any of the arguments modulo mod.
|
// NmodEqualAny returns true if o represents an integer equal to any of the arguments modulo mod.
|
||||||
func (o *operands) NmodEqualsAny(mod int64, any ...int64) bool {
|
func (o *Operands) NmodEqualsAny(mod int64, any ...int64) bool {
|
||||||
modI := o.I % mod
|
modI := o.I % mod
|
||||||
for _, i := range any {
|
for _, i := range any {
|
||||||
if modI == i && o.T == 0 {
|
if modI == i && o.T == 0 {
|
||||||
|
@ -38,17 +38,17 @@ func (o *operands) NmodEqualsAny(mod int64, any ...int64) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NmodInRange returns true if o represents an integer in the closed interval [from, to].
|
// NmodInRange returns true if o represents an integer in the closed interval [from, to].
|
||||||
func (o *operands) NinRange(from, to int64) bool {
|
func (o *Operands) NinRange(from, to int64) bool {
|
||||||
return o.T == 0 && from <= o.I && o.I <= to
|
return o.T == 0 && from <= o.I && o.I <= to
|
||||||
}
|
}
|
||||||
|
|
||||||
// NmodInRange returns true if o represents an integer in the closed interval [from, to] modulo mod.
|
// NmodInRange returns true if o represents an integer in the closed interval [from, to] modulo mod.
|
||||||
func (o *operands) NmodInRange(mod, from, to int64) bool {
|
func (o *Operands) NmodInRange(mod, from, to int64) bool {
|
||||||
modI := o.I % mod
|
modI := o.I % mod
|
||||||
return o.T == 0 && from <= modI && modI <= to
|
return o.T == 0 && from <= modI && modI <= to
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOperands(v interface{}) (*operands, error) {
|
func newOperands(v interface{}) (*Operands, error) {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
case int:
|
case int:
|
||||||
return newOperandsInt64(int64(v)), nil
|
return newOperandsInt64(int64(v)), nil
|
||||||
|
@ -69,14 +69,14 @@ func newOperands(v interface{}) (*operands, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOperandsInt64(i int64) *operands {
|
func newOperandsInt64(i int64) *Operands {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = -i
|
i = -i
|
||||||
}
|
}
|
||||||
return &operands{float64(i), i, 0, 0, 0, 0}
|
return &Operands{float64(i), i, 0, 0, 0, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOperandsString(s string) (*operands, error) {
|
func newOperandsString(s string) (*Operands, error) {
|
||||||
if s[0] == '-' {
|
if s[0] == '-' {
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ func newOperandsString(s string) (*operands, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ops := &operands{N: n}
|
ops := &Operands{N: n}
|
||||||
parts := strings.SplitN(s, ".", 2)
|
parts := strings.SplitN(s, ".", 2)
|
||||||
ops.I, err = strconv.ParseInt(parts[0], 10, 64)
|
ops.I, err = strconv.ParseInt(parts[0], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
9
vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec.go
generated
vendored
9
vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec.go
generated
vendored
|
@ -7,7 +7,7 @@ import "strings"
|
||||||
// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
|
// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
|
||||||
type PluralSpec struct {
|
type PluralSpec struct {
|
||||||
Plurals map[Plural]struct{}
|
Plurals map[Plural]struct{}
|
||||||
PluralFunc func(*operands) Plural
|
PluralFunc func(*Operands) Plural
|
||||||
}
|
}
|
||||||
|
|
||||||
var pluralSpecs = make(map[string]*PluralSpec)
|
var pluralSpecs = make(map[string]*PluralSpec)
|
||||||
|
@ -18,7 +18,8 @@ func normalizePluralSpecID(id string) string {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerPluralSpec(ids []string, ps *PluralSpec) {
|
// RegisterPluralSpec registers a new plural spec for the language ids.
|
||||||
|
func RegisterPluralSpec(ids []string, ps *PluralSpec) {
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
id = normalizePluralSpecID(id)
|
id = normalizePluralSpecID(id)
|
||||||
pluralSpecs[id] = ps
|
pluralSpecs[id] = ps
|
||||||
|
@ -35,9 +36,9 @@ func (ps *PluralSpec) Plural(number interface{}) (Plural, error) {
|
||||||
return ps.PluralFunc(ops), nil
|
return ps.PluralFunc(ops), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPluralSpec returns the PluralSpec that matches the longest prefix of tag.
|
// GetPluralSpec returns the PluralSpec that matches the longest prefix of tag.
|
||||||
// It returns nil if no PluralSpec matches tag.
|
// It returns nil if no PluralSpec matches tag.
|
||||||
func getPluralSpec(tag string) *PluralSpec {
|
func GetPluralSpec(tag string) *PluralSpec {
|
||||||
tag = NormalizeTag(tag)
|
tag = NormalizeTag(tag)
|
||||||
subtag := tag
|
subtag := tag
|
||||||
for {
|
for {
|
||||||
|
|
166
vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen.go
generated
vendored
166
vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen.go
generated
vendored
|
@ -4,15 +4,15 @@ package language
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
||||||
registerPluralSpec([]string{"bm", "bo", "dz", "id", "ig", "ii", "in", "ja", "jbo", "jv", "jw", "kde", "kea", "km", "ko", "lkt", "lo", "ms", "my", "nqo", "root", "sah", "ses", "sg", "th", "to", "vi", "wo", "yo", "zh"}, &PluralSpec{
|
RegisterPluralSpec([]string{"bm", "bo", "dz", "id", "ig", "ii", "in", "ja", "jbo", "jv", "jw", "kde", "kea", "km", "ko", "lkt", "lo", "ms", "my", "nqo", "root", "sah", "ses", "sg", "th", "to", "vi", "wo", "yo", "yue", "zh"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(Other),
|
Plurals: newPluralSet(Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"am", "as", "bn", "fa", "gu", "hi", "kn", "mr", "zu"}, &PluralSpec{
|
RegisterPluralSpec([]string{"am", "as", "bn", "fa", "gu", "hi", "kn", "mr", "zu"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// i = 0 or n = 1
|
// i = 0 or n = 1
|
||||||
if intEqualsAny(ops.I, 0) ||
|
if intEqualsAny(ops.I, 0) ||
|
||||||
ops.NequalsAny(1) {
|
ops.NequalsAny(1) {
|
||||||
|
@ -21,9 +21,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"ff", "fr", "hy", "kab"}, &PluralSpec{
|
RegisterPluralSpec([]string{"ff", "fr", "hy", "kab"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// i = 0,1
|
// i = 0,1
|
||||||
if intEqualsAny(ops.I, 0, 1) {
|
if intEqualsAny(ops.I, 0, 1) {
|
||||||
return One
|
return One
|
||||||
|
@ -31,9 +31,19 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"ast", "ca", "de", "en", "et", "fi", "fy", "gl", "it", "ji", "nl", "sv", "sw", "ur", "yi"}, &PluralSpec{
|
RegisterPluralSpec([]string{"pt"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
|
// i = 0..1
|
||||||
|
if intInRange(ops.I, 0, 1) {
|
||||||
|
return One
|
||||||
|
}
|
||||||
|
return Other
|
||||||
|
},
|
||||||
|
})
|
||||||
|
RegisterPluralSpec([]string{"ast", "ca", "de", "en", "et", "fi", "fy", "gl", "it", "ji", "nl", "sv", "sw", "ur", "yi"}, &PluralSpec{
|
||||||
|
Plurals: newPluralSet(One, Other),
|
||||||
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// i = 1 and v = 0
|
// i = 1 and v = 0
|
||||||
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
||||||
return One
|
return One
|
||||||
|
@ -41,9 +51,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"si"}, &PluralSpec{
|
RegisterPluralSpec([]string{"si"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 0,1 or i = 0 and f = 1
|
// n = 0,1 or i = 0 and f = 1
|
||||||
if ops.NequalsAny(0, 1) ||
|
if ops.NequalsAny(0, 1) ||
|
||||||
intEqualsAny(ops.I, 0) && intEqualsAny(ops.F, 1) {
|
intEqualsAny(ops.I, 0) && intEqualsAny(ops.F, 1) {
|
||||||
|
@ -52,9 +62,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"ak", "bh", "guw", "ln", "mg", "nso", "pa", "ti", "wa"}, &PluralSpec{
|
RegisterPluralSpec([]string{"ak", "bh", "guw", "ln", "mg", "nso", "pa", "ti", "wa"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 0..1
|
// n = 0..1
|
||||||
if ops.NinRange(0, 1) {
|
if ops.NinRange(0, 1) {
|
||||||
return One
|
return One
|
||||||
|
@ -62,9 +72,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"tzm"}, &PluralSpec{
|
RegisterPluralSpec([]string{"tzm"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 0..1 or n = 11..99
|
// n = 0..1 or n = 11..99
|
||||||
if ops.NinRange(0, 1) ||
|
if ops.NinRange(0, 1) ||
|
||||||
ops.NinRange(11, 99) {
|
ops.NinRange(11, 99) {
|
||||||
|
@ -73,19 +83,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"pt"}, &PluralSpec{
|
RegisterPluralSpec([]string{"af", "asa", "az", "bem", "bez", "bg", "brx", "ce", "cgg", "chr", "ckb", "dv", "ee", "el", "eo", "es", "eu", "fo", "fur", "gsw", "ha", "haw", "hu", "jgo", "jmc", "ka", "kaj", "kcg", "kk", "kkj", "kl", "ks", "ksb", "ku", "ky", "lb", "lg", "mas", "mgo", "ml", "mn", "nah", "nb", "nd", "ne", "nn", "nnh", "no", "nr", "ny", "nyn", "om", "or", "os", "pap", "ps", "rm", "rof", "rwk", "saq", "sdh", "seh", "sn", "so", "sq", "ss", "ssy", "st", "syr", "ta", "te", "teo", "tig", "tk", "tn", "tr", "ts", "ug", "uz", "ve", "vo", "vun", "wae", "xh", "xog"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 0..2 and n != 2
|
|
||||||
if ops.NinRange(0, 2) && !ops.NequalsAny(2) {
|
|
||||||
return One
|
|
||||||
}
|
|
||||||
return Other
|
|
||||||
},
|
|
||||||
})
|
|
||||||
registerPluralSpec([]string{"af", "asa", "az", "bem", "bez", "bg", "brx", "ce", "cgg", "chr", "ckb", "dv", "ee", "el", "eo", "es", "eu", "fo", "fur", "gsw", "ha", "haw", "hu", "jgo", "jmc", "ka", "kaj", "kcg", "kk", "kkj", "kl", "ks", "ksb", "ku", "ky", "lb", "lg", "mas", "mgo", "ml", "mn", "nah", "nb", "nd", "ne", "nn", "nnh", "no", "nr", "ny", "nyn", "om", "or", "os", "pap", "ps", "rm", "rof", "rwk", "saq", "sdh", "seh", "sn", "so", "sq", "ss", "ssy", "st", "syr", "ta", "te", "teo", "tig", "tk", "tn", "tr", "ts", "ug", "uz", "ve", "vo", "vun", "wae", "xh", "xog"}, &PluralSpec{
|
|
||||||
Plurals: newPluralSet(One, Other),
|
|
||||||
PluralFunc: func(ops *operands) Plural {
|
|
||||||
// n = 1
|
// n = 1
|
||||||
if ops.NequalsAny(1) {
|
if ops.NequalsAny(1) {
|
||||||
return One
|
return One
|
||||||
|
@ -93,19 +93,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"pt_PT"}, &PluralSpec{
|
RegisterPluralSpec([]string{"da"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 1 and v = 0
|
|
||||||
if ops.NequalsAny(1) && intEqualsAny(ops.V, 0) {
|
|
||||||
return One
|
|
||||||
}
|
|
||||||
return Other
|
|
||||||
},
|
|
||||||
})
|
|
||||||
registerPluralSpec([]string{"da"}, &PluralSpec{
|
|
||||||
Plurals: newPluralSet(One, Other),
|
|
||||||
PluralFunc: func(ops *operands) Plural {
|
|
||||||
// n = 1 or t != 0 and i = 0,1
|
// n = 1 or t != 0 and i = 0,1
|
||||||
if ops.NequalsAny(1) ||
|
if ops.NequalsAny(1) ||
|
||||||
!intEqualsAny(ops.T, 0) && intEqualsAny(ops.I, 0, 1) {
|
!intEqualsAny(ops.T, 0) && intEqualsAny(ops.I, 0, 1) {
|
||||||
|
@ -114,9 +104,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"is"}, &PluralSpec{
|
RegisterPluralSpec([]string{"is"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// t = 0 and i % 10 = 1 and i % 100 != 11 or t != 0
|
// t = 0 and i % 10 = 1 and i % 100 != 11 or t != 0
|
||||||
if intEqualsAny(ops.T, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) ||
|
if intEqualsAny(ops.T, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) ||
|
||||||
!intEqualsAny(ops.T, 0) {
|
!intEqualsAny(ops.T, 0) {
|
||||||
|
@ -125,9 +115,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"mk"}, &PluralSpec{
|
RegisterPluralSpec([]string{"mk"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// v = 0 and i % 10 = 1 or f % 10 = 1
|
// v = 0 and i % 10 = 1 or f % 10 = 1
|
||||||
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) ||
|
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) ||
|
||||||
intEqualsAny(ops.F%10, 1) {
|
intEqualsAny(ops.F%10, 1) {
|
||||||
|
@ -136,9 +126,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"fil", "tl"}, &PluralSpec{
|
RegisterPluralSpec([]string{"fil", "tl"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Other),
|
Plurals: newPluralSet(One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// v = 0 and i = 1,2,3 or v = 0 and i % 10 != 4,6,9 or v != 0 and f % 10 != 4,6,9
|
// v = 0 and i = 1,2,3 or v = 0 and i % 10 != 4,6,9 or v != 0 and f % 10 != 4,6,9
|
||||||
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I, 1, 2, 3) ||
|
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I, 1, 2, 3) ||
|
||||||
intEqualsAny(ops.V, 0) && !intEqualsAny(ops.I%10, 4, 6, 9) ||
|
intEqualsAny(ops.V, 0) && !intEqualsAny(ops.I%10, 4, 6, 9) ||
|
||||||
|
@ -148,9 +138,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"lv", "prg"}, &PluralSpec{
|
RegisterPluralSpec([]string{"lv", "prg"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(Zero, One, Other),
|
Plurals: newPluralSet(Zero, One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19
|
// n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19
|
||||||
if ops.NmodEqualsAny(10, 0) ||
|
if ops.NmodEqualsAny(10, 0) ||
|
||||||
ops.NmodInRange(100, 11, 19) ||
|
ops.NmodInRange(100, 11, 19) ||
|
||||||
|
@ -166,9 +156,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"lag"}, &PluralSpec{
|
RegisterPluralSpec([]string{"lag"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(Zero, One, Other),
|
Plurals: newPluralSet(Zero, One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 0
|
// n = 0
|
||||||
if ops.NequalsAny(0) {
|
if ops.NequalsAny(0) {
|
||||||
return Zero
|
return Zero
|
||||||
|
@ -180,9 +170,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"ksh"}, &PluralSpec{
|
RegisterPluralSpec([]string{"ksh"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(Zero, One, Other),
|
Plurals: newPluralSet(Zero, One, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 0
|
// n = 0
|
||||||
if ops.NequalsAny(0) {
|
if ops.NequalsAny(0) {
|
||||||
return Zero
|
return Zero
|
||||||
|
@ -194,9 +184,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"iu", "kw", "naq", "se", "sma", "smi", "smj", "smn", "sms"}, &PluralSpec{
|
RegisterPluralSpec([]string{"iu", "kw", "naq", "se", "sma", "smi", "smj", "smn", "sms"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Two, Other),
|
Plurals: newPluralSet(One, Two, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 1
|
// n = 1
|
||||||
if ops.NequalsAny(1) {
|
if ops.NequalsAny(1) {
|
||||||
return One
|
return One
|
||||||
|
@ -208,9 +198,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"shi"}, &PluralSpec{
|
RegisterPluralSpec([]string{"shi"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Other),
|
Plurals: newPluralSet(One, Few, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// i = 0 or n = 1
|
// i = 0 or n = 1
|
||||||
if intEqualsAny(ops.I, 0) ||
|
if intEqualsAny(ops.I, 0) ||
|
||||||
ops.NequalsAny(1) {
|
ops.NequalsAny(1) {
|
||||||
|
@ -223,9 +213,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"mo", "ro"}, &PluralSpec{
|
RegisterPluralSpec([]string{"mo", "ro"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Other),
|
Plurals: newPluralSet(One, Few, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// i = 1 and v = 0
|
// i = 1 and v = 0
|
||||||
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
||||||
return One
|
return One
|
||||||
|
@ -239,9 +229,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"bs", "hr", "sh", "sr"}, &PluralSpec{
|
RegisterPluralSpec([]string{"bs", "hr", "sh", "sr"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Other),
|
Plurals: newPluralSet(One, Few, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11
|
// v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11
|
||||||
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) ||
|
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) ||
|
||||||
intEqualsAny(ops.F%10, 1) && !intEqualsAny(ops.F%100, 11) {
|
intEqualsAny(ops.F%10, 1) && !intEqualsAny(ops.F%100, 11) {
|
||||||
|
@ -255,9 +245,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"gd"}, &PluralSpec{
|
RegisterPluralSpec([]string{"gd"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Two, Few, Other),
|
Plurals: newPluralSet(One, Two, Few, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 1,11
|
// n = 1,11
|
||||||
if ops.NequalsAny(1, 11) {
|
if ops.NequalsAny(1, 11) {
|
||||||
return One
|
return One
|
||||||
|
@ -273,9 +263,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"sl"}, &PluralSpec{
|
RegisterPluralSpec([]string{"sl"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Two, Few, Other),
|
Plurals: newPluralSet(One, Two, Few, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// v = 0 and i % 100 = 1
|
// v = 0 and i % 100 = 1
|
||||||
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 1) {
|
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 1) {
|
||||||
return One
|
return One
|
||||||
|
@ -292,9 +282,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"dsb", "hsb"}, &PluralSpec{
|
RegisterPluralSpec([]string{"dsb", "hsb"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Two, Few, Other),
|
Plurals: newPluralSet(One, Two, Few, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// v = 0 and i % 100 = 1 or f % 100 = 1
|
// v = 0 and i % 100 = 1 or f % 100 = 1
|
||||||
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 1) ||
|
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%100, 1) ||
|
||||||
intEqualsAny(ops.F%100, 1) {
|
intEqualsAny(ops.F%100, 1) {
|
||||||
|
@ -313,9 +303,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"he", "iw"}, &PluralSpec{
|
RegisterPluralSpec([]string{"he", "iw"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Two, Many, Other),
|
Plurals: newPluralSet(One, Two, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// i = 1 and v = 0
|
// i = 1 and v = 0
|
||||||
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
||||||
return One
|
return One
|
||||||
|
@ -331,9 +321,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"cs", "sk"}, &PluralSpec{
|
RegisterPluralSpec([]string{"cs", "sk"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Many, Other),
|
Plurals: newPluralSet(One, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// i = 1 and v = 0
|
// i = 1 and v = 0
|
||||||
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
||||||
return One
|
return One
|
||||||
|
@ -349,9 +339,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"pl"}, &PluralSpec{
|
RegisterPluralSpec([]string{"pl"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Many, Other),
|
Plurals: newPluralSet(One, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// i = 1 and v = 0
|
// i = 1 and v = 0
|
||||||
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
if intEqualsAny(ops.I, 1) && intEqualsAny(ops.V, 0) {
|
||||||
return One
|
return One
|
||||||
|
@ -369,9 +359,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"be"}, &PluralSpec{
|
RegisterPluralSpec([]string{"be"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Many, Other),
|
Plurals: newPluralSet(One, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n % 10 = 1 and n % 100 != 11
|
// n % 10 = 1 and n % 100 != 11
|
||||||
if ops.NmodEqualsAny(10, 1) && !ops.NmodEqualsAny(100, 11) {
|
if ops.NmodEqualsAny(10, 1) && !ops.NmodEqualsAny(100, 11) {
|
||||||
return One
|
return One
|
||||||
|
@ -389,9 +379,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"lt"}, &PluralSpec{
|
RegisterPluralSpec([]string{"lt"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Many, Other),
|
Plurals: newPluralSet(One, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n % 10 = 1 and n % 100 != 11..19
|
// n % 10 = 1 and n % 100 != 11..19
|
||||||
if ops.NmodEqualsAny(10, 1) && !ops.NmodInRange(100, 11, 19) {
|
if ops.NmodEqualsAny(10, 1) && !ops.NmodInRange(100, 11, 19) {
|
||||||
return One
|
return One
|
||||||
|
@ -407,9 +397,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"mt"}, &PluralSpec{
|
RegisterPluralSpec([]string{"mt"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Many, Other),
|
Plurals: newPluralSet(One, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 1
|
// n = 1
|
||||||
if ops.NequalsAny(1) {
|
if ops.NequalsAny(1) {
|
||||||
return One
|
return One
|
||||||
|
@ -426,9 +416,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"ru", "uk"}, &PluralSpec{
|
RegisterPluralSpec([]string{"ru", "uk"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Few, Many, Other),
|
Plurals: newPluralSet(One, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// v = 0 and i % 10 = 1 and i % 100 != 11
|
// v = 0 and i % 10 = 1 and i % 100 != 11
|
||||||
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) {
|
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) && !intEqualsAny(ops.I%100, 11) {
|
||||||
return One
|
return One
|
||||||
|
@ -446,9 +436,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"br"}, &PluralSpec{
|
RegisterPluralSpec([]string{"br"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Two, Few, Many, Other),
|
Plurals: newPluralSet(One, Two, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n % 10 = 1 and n % 100 != 11,71,91
|
// n % 10 = 1 and n % 100 != 11,71,91
|
||||||
if ops.NmodEqualsAny(10, 1) && !ops.NmodEqualsAny(100, 11, 71, 91) {
|
if ops.NmodEqualsAny(10, 1) && !ops.NmodEqualsAny(100, 11, 71, 91) {
|
||||||
return One
|
return One
|
||||||
|
@ -468,9 +458,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"ga"}, &PluralSpec{
|
RegisterPluralSpec([]string{"ga"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Two, Few, Many, Other),
|
Plurals: newPluralSet(One, Two, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 1
|
// n = 1
|
||||||
if ops.NequalsAny(1) {
|
if ops.NequalsAny(1) {
|
||||||
return One
|
return One
|
||||||
|
@ -490,9 +480,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"gv"}, &PluralSpec{
|
RegisterPluralSpec([]string{"gv"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(One, Two, Few, Many, Other),
|
Plurals: newPluralSet(One, Two, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// v = 0 and i % 10 = 1
|
// v = 0 and i % 10 = 1
|
||||||
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) {
|
if intEqualsAny(ops.V, 0) && intEqualsAny(ops.I%10, 1) {
|
||||||
return One
|
return One
|
||||||
|
@ -512,9 +502,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"ar"}, &PluralSpec{
|
RegisterPluralSpec([]string{"ar", "ars"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(Zero, One, Two, Few, Many, Other),
|
Plurals: newPluralSet(Zero, One, Two, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 0
|
// n = 0
|
||||||
if ops.NequalsAny(0) {
|
if ops.NequalsAny(0) {
|
||||||
return Zero
|
return Zero
|
||||||
|
@ -538,9 +528,9 @@ func init() {
|
||||||
return Other
|
return Other
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
registerPluralSpec([]string{"cy"}, &PluralSpec{
|
RegisterPluralSpec([]string{"cy"}, &PluralSpec{
|
||||||
Plurals: newPluralSet(Zero, One, Two, Few, Many, Other),
|
Plurals: newPluralSet(Zero, One, Two, Few, Many, Other),
|
||||||
PluralFunc: func(ops *operands) Plural {
|
PluralFunc: func(ops *Operands) Plural {
|
||||||
// n = 0
|
// n = 0
|
||||||
if ops.NequalsAny(0) {
|
if ops.NequalsAny(0) {
|
||||||
return Zero
|
return Zero
|
||||||
|
|
2
vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation.go
generated
vendored
2
vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation.go
generated
vendored
|
@ -50,7 +50,7 @@ func (pt *pluralTranslation) Normalize(l *language.Language) Translation {
|
||||||
|
|
||||||
func (pt *pluralTranslation) Backfill(src Translation) Translation {
|
func (pt *pluralTranslation) Backfill(src Translation) Translation {
|
||||||
for pc, t := range pt.templates {
|
for pc, t := range pt.templates {
|
||||||
if t == nil || t.src == "" {
|
if (t == nil || t.src == "") && src != nil {
|
||||||
pt.templates[pc] = src.Template(language.Other)
|
pt.templates[pc] = src.Template(language.Other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/nicksnyder/go-i18n/i18n/translation/single_translation.go
generated
vendored
2
vendor/github.com/nicksnyder/go-i18n/i18n/translation/single_translation.go
generated
vendored
|
@ -37,7 +37,7 @@ func (st *singleTranslation) Normalize(language *language.Language) Translation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *singleTranslation) Backfill(src Translation) Translation {
|
func (st *singleTranslation) Backfill(src Translation) Translation {
|
||||||
if st.template == nil || st.template.src == "" {
|
if (st.template == nil || st.template.src == "") && src != nil {
|
||||||
st.template = src.Template(language.Other)
|
st.template = src.Template(language.Other)
|
||||||
}
|
}
|
||||||
return st
|
return st
|
||||||
|
|
1
vendor/github.com/pelletier/go-toml/.gitignore
generated
vendored
1
vendor/github.com/pelletier/go-toml/.gitignore
generated
vendored
|
@ -1 +1,2 @@
|
||||||
test_program/test_program_bin
|
test_program/test_program_bin
|
||||||
|
fuzz/
|
||||||
|
|
5
vendor/github.com/pelletier/go-toml/.travis.yml
generated
vendored
5
vendor/github.com/pelletier/go-toml/.travis.yml
generated
vendored
|
@ -1,9 +1,8 @@
|
||||||
sudo: false
|
sudo: false
|
||||||
language: go
|
language: go
|
||||||
go:
|
go:
|
||||||
- 1.6.4
|
- 1.8.5
|
||||||
- 1.7.6
|
- 1.9.2
|
||||||
- 1.8.3
|
|
||||||
- tip
|
- tip
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
|
|
27
vendor/github.com/pelletier/go-toml/README.md
generated
vendored
27
vendor/github.com/pelletier/go-toml/README.md
generated
vendored
|
@ -33,7 +33,7 @@ import "github.com/pelletier/go-toml"
|
||||||
Read a TOML document:
|
Read a TOML document:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
config, _ := toml.LoadString(`
|
config, _ := toml.Load(`
|
||||||
[postgres]
|
[postgres]
|
||||||
user = "pelletier"
|
user = "pelletier"
|
||||||
password = "mypassword"`)
|
password = "mypassword"`)
|
||||||
|
@ -42,7 +42,7 @@ user := config.Get("postgres.user").(string)
|
||||||
|
|
||||||
// or using an intermediate object
|
// or using an intermediate object
|
||||||
postgresConfig := config.Get("postgres").(*toml.Tree)
|
postgresConfig := config.Get("postgres").(*toml.Tree)
|
||||||
password = postgresConfig.Get("password").(string)
|
password := postgresConfig.Get("password").(string)
|
||||||
```
|
```
|
||||||
|
|
||||||
Or use Unmarshal:
|
Or use Unmarshal:
|
||||||
|
@ -57,12 +57,12 @@ type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
doc := []byte(`
|
doc := []byte(`
|
||||||
[postgres]
|
[Postgres]
|
||||||
user = "pelletier"
|
User = "pelletier"
|
||||||
password = "mypassword"`)
|
Password = "mypassword"`)
|
||||||
|
|
||||||
config := Config{}
|
config := Config{}
|
||||||
Unmarshal(doc, &config)
|
toml.Unmarshal(doc, &config)
|
||||||
fmt.Println("user=", config.Postgres.User)
|
fmt.Println("user=", config.Postgres.User)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -70,7 +70,8 @@ Or use a query:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// use a query to gather elements without walking the tree
|
// use a query to gather elements without walking the tree
|
||||||
results, _ := config.Query("$..[user,password]")
|
q, _ := query.Compile("$..[user,password]")
|
||||||
|
results := q.Execute(config)
|
||||||
for ii, item := range results.Values() {
|
for ii, item := range results.Values() {
|
||||||
fmt.Println("Query result %d: %v", ii, item)
|
fmt.Println("Query result %d: %v", ii, item)
|
||||||
}
|
}
|
||||||
|
@ -113,6 +114,18 @@ You have to make sure two kind of tests run:
|
||||||
|
|
||||||
You can run both of them using `./test.sh`.
|
You can run both of them using `./test.sh`.
|
||||||
|
|
||||||
|
### Fuzzing
|
||||||
|
|
||||||
|
The script `./fuzz.sh` is available to
|
||||||
|
run [go-fuzz](https://github.com/dvyukov/go-fuzz) on go-toml.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
Go-toml follows [Semantic Versioning](http://semver.org/). The supported version
|
||||||
|
of [TOML](https://github.com/toml-lang/toml) is indicated at the beginning of
|
||||||
|
this document. The last two major versions of Go are supported
|
||||||
|
(see [Go Release Policy](https://golang.org/doc/devel/release.html#policy)).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The MIT License (MIT). Read [LICENSE](LICENSE).
|
The MIT License (MIT). Read [LICENSE](LICENSE).
|
||||||
|
|
2
vendor/github.com/pelletier/go-toml/doc.go
generated
vendored
2
vendor/github.com/pelletier/go-toml/doc.go
generated
vendored
|
@ -17,7 +17,7 @@
|
||||||
// JSONPath-like queries
|
// JSONPath-like queries
|
||||||
//
|
//
|
||||||
// The package github.com/pelletier/go-toml/query implements a system
|
// The package github.com/pelletier/go-toml/query implements a system
|
||||||
// similar to JSONPath to quickly retrive elements of a TOML document using a
|
// similar to JSONPath to quickly retrieve elements of a TOML document using a
|
||||||
// single expression. See the package documentation for more information.
|
// single expression. See the package documentation for more information.
|
||||||
//
|
//
|
||||||
package toml
|
package toml
|
||||||
|
|
31
vendor/github.com/pelletier/go-toml/fuzz.go
generated
vendored
Normal file
31
vendor/github.com/pelletier/go-toml/fuzz.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// +build gofuzz
|
||||||
|
|
||||||
|
package toml
|
||||||
|
|
||||||
|
func Fuzz(data []byte) int {
|
||||||
|
tree, err := LoadBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
if tree != nil {
|
||||||
|
panic("tree must be nil if there is an error")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
str, err := tree.ToTomlString()
|
||||||
|
if err != nil {
|
||||||
|
if str != "" {
|
||||||
|
panic(`str must be "" if there is an error`)
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tree, err = Load(str)
|
||||||
|
if err != nil {
|
||||||
|
if tree != nil {
|
||||||
|
panic("tree must be nil if there is an error")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
15
vendor/github.com/pelletier/go-toml/fuzz.sh
generated
vendored
Executable file
15
vendor/github.com/pelletier/go-toml/fuzz.sh
generated
vendored
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
#! /bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
go get github.com/dvyukov/go-fuzz/go-fuzz
|
||||||
|
go get github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||||
|
|
||||||
|
if [ ! -e toml-fuzz.zip ]; then
|
||||||
|
go-fuzz-build github.com/pelletier/go-toml
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -fr fuzz
|
||||||
|
mkdir -p fuzz/corpus
|
||||||
|
cp *.toml fuzz/corpus
|
||||||
|
|
||||||
|
go-fuzz -bin=toml-fuzz.zip -workdir=fuzz
|
15
vendor/github.com/pelletier/go-toml/keysparsing.go
generated
vendored
15
vendor/github.com/pelletier/go-toml/keysparsing.go
generated
vendored
|
@ -9,12 +9,14 @@ import (
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Convert the bare key group string to an array.
|
||||||
|
// The input supports double quotation to allow "." inside the key name,
|
||||||
|
// but escape sequences are not supported. Lexers must unescape them beforehand.
|
||||||
func parseKey(key string) ([]string, error) {
|
func parseKey(key string) ([]string, error) {
|
||||||
groups := []string{}
|
groups := []string{}
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
inQuotes := false
|
inQuotes := false
|
||||||
wasInQuotes := false
|
wasInQuotes := false
|
||||||
escapeNext := false
|
|
||||||
ignoreSpace := true
|
ignoreSpace := true
|
||||||
expectDot := false
|
expectDot := false
|
||||||
|
|
||||||
|
@ -25,15 +27,7 @@ func parseKey(key string) ([]string, error) {
|
||||||
}
|
}
|
||||||
ignoreSpace = false
|
ignoreSpace = false
|
||||||
}
|
}
|
||||||
if escapeNext {
|
|
||||||
buffer.WriteRune(char)
|
|
||||||
escapeNext = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch char {
|
switch char {
|
||||||
case '\\':
|
|
||||||
escapeNext = true
|
|
||||||
continue
|
|
||||||
case '"':
|
case '"':
|
||||||
if inQuotes {
|
if inQuotes {
|
||||||
groups = append(groups, buffer.String())
|
groups = append(groups, buffer.String())
|
||||||
|
@ -77,9 +71,6 @@ func parseKey(key string) ([]string, error) {
|
||||||
if inQuotes {
|
if inQuotes {
|
||||||
return nil, errors.New("mismatched quotes")
|
return nil, errors.New("mismatched quotes")
|
||||||
}
|
}
|
||||||
if escapeNext {
|
|
||||||
return nil, errors.New("unfinished escape sequence")
|
|
||||||
}
|
|
||||||
if buffer.Len() > 0 {
|
if buffer.Len() > 0 {
|
||||||
groups = append(groups, buffer.String())
|
groups = append(groups, buffer.String())
|
||||||
}
|
}
|
||||||
|
|
103
vendor/github.com/pelletier/go-toml/lexer.go
generated
vendored
103
vendor/github.com/pelletier/go-toml/lexer.go
generated
vendored
|
@ -204,6 +204,14 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
|
||||||
return l.lexFalse
|
return l.lexFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if l.follow("inf") {
|
||||||
|
return l.lexInf
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.follow("nan") {
|
||||||
|
return l.lexNan
|
||||||
|
}
|
||||||
|
|
||||||
if isSpace(next) {
|
if isSpace(next) {
|
||||||
l.skip()
|
l.skip()
|
||||||
continue
|
continue
|
||||||
|
@ -265,6 +273,18 @@ func (l *tomlLexer) lexFalse() tomlLexStateFn {
|
||||||
return l.lexRvalue
|
return l.lexRvalue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexInf() tomlLexStateFn {
|
||||||
|
l.fastForward(3)
|
||||||
|
l.emit(tokenInf)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tomlLexer) lexNan() tomlLexStateFn {
|
||||||
|
l.fastForward(3)
|
||||||
|
l.emit(tokenNan)
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
|
||||||
func (l *tomlLexer) lexEqual() tomlLexStateFn {
|
func (l *tomlLexer) lexEqual() tomlLexStateFn {
|
||||||
l.next()
|
l.next()
|
||||||
l.emit(tokenEqual)
|
l.emit(tokenEqual)
|
||||||
|
@ -277,6 +297,8 @@ func (l *tomlLexer) lexComma() tomlLexStateFn {
|
||||||
return l.lexRvalue
|
return l.lexRvalue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the key and emits its value without escape sequences.
|
||||||
|
// bare keys, basic string keys and literal string keys are supported.
|
||||||
func (l *tomlLexer) lexKey() tomlLexStateFn {
|
func (l *tomlLexer) lexKey() tomlLexStateFn {
|
||||||
growingString := ""
|
growingString := ""
|
||||||
|
|
||||||
|
@ -287,7 +309,16 @@ func (l *tomlLexer) lexKey() tomlLexStateFn {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return l.errorf(err.Error())
|
return l.errorf(err.Error())
|
||||||
}
|
}
|
||||||
growingString += `"` + str + `"`
|
growingString += str
|
||||||
|
l.next()
|
||||||
|
continue
|
||||||
|
} else if r == '\'' {
|
||||||
|
l.next()
|
||||||
|
str, err := l.lexLiteralStringAsString(`'`, false)
|
||||||
|
if err != nil {
|
||||||
|
return l.errorf(err.Error())
|
||||||
|
}
|
||||||
|
growingString += str
|
||||||
l.next()
|
l.next()
|
||||||
continue
|
continue
|
||||||
} else if r == '\n' {
|
} else if r == '\n' {
|
||||||
|
@ -527,6 +558,7 @@ func (l *tomlLexer) lexTableKey() tomlLexStateFn {
|
||||||
return l.lexInsideTableKey
|
return l.lexInsideTableKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the key till "]]", but only bare keys are supported
|
||||||
func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
|
func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
|
||||||
for r := l.peek(); r != eof; r = l.peek() {
|
for r := l.peek(); r != eof; r = l.peek() {
|
||||||
switch r {
|
switch r {
|
||||||
|
@ -550,6 +582,7 @@ func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
|
||||||
return l.errorf("unclosed table array key")
|
return l.errorf("unclosed table array key")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the key till "]" but only bare keys are supported
|
||||||
func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn {
|
func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn {
|
||||||
for r := l.peek(); r != eof; r = l.peek() {
|
for r := l.peek(); r != eof; r = l.peek() {
|
||||||
switch r {
|
switch r {
|
||||||
|
@ -575,11 +608,77 @@ func (l *tomlLexer) lexRightBracket() tomlLexStateFn {
|
||||||
return l.lexRvalue
|
return l.lexRvalue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type validRuneFn func(r rune) bool
|
||||||
|
|
||||||
|
func isValidHexRune(r rune) bool {
|
||||||
|
return r >= 'a' && r <= 'f' ||
|
||||||
|
r >= 'A' && r <= 'F' ||
|
||||||
|
r >= '0' && r <= '9' ||
|
||||||
|
r == '_'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidOctalRune(r rune) bool {
|
||||||
|
return r >= '0' && r <= '7' || r == '_'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidBinaryRune(r rune) bool {
|
||||||
|
return r == '0' || r == '1' || r == '_'
|
||||||
|
}
|
||||||
|
|
||||||
func (l *tomlLexer) lexNumber() tomlLexStateFn {
|
func (l *tomlLexer) lexNumber() tomlLexStateFn {
|
||||||
r := l.peek()
|
r := l.peek()
|
||||||
if r == '+' || r == '-' {
|
|
||||||
|
if r == '0' {
|
||||||
|
follow := l.peekString(2)
|
||||||
|
if len(follow) == 2 {
|
||||||
|
var isValidRune validRuneFn
|
||||||
|
switch follow[1] {
|
||||||
|
case 'x':
|
||||||
|
isValidRune = isValidHexRune
|
||||||
|
case 'o':
|
||||||
|
isValidRune = isValidOctalRune
|
||||||
|
case 'b':
|
||||||
|
isValidRune = isValidBinaryRune
|
||||||
|
default:
|
||||||
|
if follow[1] >= 'a' && follow[1] <= 'z' || follow[1] >= 'A' && follow[1] <= 'Z' {
|
||||||
|
return l.errorf("unknown number base: %s. possible options are x (hex) o (octal) b (binary)", string(follow[1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isValidRune != nil {
|
||||||
|
l.next()
|
||||||
|
l.next()
|
||||||
|
digitSeen := false
|
||||||
|
for {
|
||||||
|
next := l.peek()
|
||||||
|
if !isValidRune(next) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
digitSeen = true
|
||||||
l.next()
|
l.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !digitSeen {
|
||||||
|
return l.errorf("number needs at least one digit")
|
||||||
|
}
|
||||||
|
|
||||||
|
l.emit(tokenInteger)
|
||||||
|
|
||||||
|
return l.lexRvalue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r == '+' || r == '-' {
|
||||||
|
l.next()
|
||||||
|
if l.follow("inf") {
|
||||||
|
return l.lexInf
|
||||||
|
}
|
||||||
|
if l.follow("nan") {
|
||||||
|
return l.lexNan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pointSeen := false
|
pointSeen := false
|
||||||
expSeen := false
|
expSeen := false
|
||||||
digitSeen := false
|
digitSeen := false
|
||||||
|
|
381
vendor/github.com/pelletier/go-toml/marshal.go
generated
vendored
381
vendor/github.com/pelletier/go-toml/marshal.go
generated
vendored
|
@ -4,17 +4,30 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tomlOpts struct {
|
type tomlOpts struct {
|
||||||
name string
|
name string
|
||||||
|
comment string
|
||||||
|
commented bool
|
||||||
include bool
|
include bool
|
||||||
omitempty bool
|
omitempty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type encOpts struct {
|
||||||
|
quoteMapKeys bool
|
||||||
|
arraysOneElementPerLine bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var encOptsDefaults = encOpts{
|
||||||
|
quoteMapKeys: false,
|
||||||
|
}
|
||||||
|
|
||||||
var timeType = reflect.TypeOf(time.Time{})
|
var timeType = reflect.TypeOf(time.Time{})
|
||||||
var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
|
var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
|
||||||
|
|
||||||
|
@ -94,8 +107,15 @@ encoder, except that there is no concept of a Marshaler interface or MarshalTOML
|
||||||
function for sub-structs, and currently only definite types can be marshaled
|
function for sub-structs, and currently only definite types can be marshaled
|
||||||
(i.e. no `interface{}`).
|
(i.e. no `interface{}`).
|
||||||
|
|
||||||
|
The following struct annotations are supported:
|
||||||
|
|
||||||
|
toml:"Field" Overrides the field's name to output.
|
||||||
|
omitempty When set, empty values and groups are not emitted.
|
||||||
|
comment:"comment" Emits a # comment on the same line. This supports new lines.
|
||||||
|
commented:"true" Emits the value as commented.
|
||||||
|
|
||||||
Note that pointers are automatically assigned the "omitempty" option, as TOML
|
Note that pointers are automatically assigned the "omitempty" option, as TOML
|
||||||
explicity does not handle null values (saying instead the label should be
|
explicitly does not handle null values (saying instead the label should be
|
||||||
dropped).
|
dropped).
|
||||||
|
|
||||||
Tree structural types and corresponding marshal types:
|
Tree structural types and corresponding marshal types:
|
||||||
|
@ -115,6 +135,66 @@ Tree primitive types and corresponding marshal types:
|
||||||
time.Time time.Time{}, pointers to same
|
time.Time time.Time{}, pointers to same
|
||||||
*/
|
*/
|
||||||
func Marshal(v interface{}) ([]byte, error) {
|
func Marshal(v interface{}) ([]byte, error) {
|
||||||
|
return NewEncoder(nil).marshal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoder writes TOML values to an output stream.
|
||||||
|
type Encoder struct {
|
||||||
|
w io.Writer
|
||||||
|
encOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns a new encoder that writes to w.
|
||||||
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
|
return &Encoder{
|
||||||
|
w: w,
|
||||||
|
encOpts: encOptsDefaults,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode writes the TOML encoding of v to the stream.
|
||||||
|
//
|
||||||
|
// See the documentation for Marshal for details.
|
||||||
|
func (e *Encoder) Encode(v interface{}) error {
|
||||||
|
b, err := e.marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := e.w.Write(b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QuoteMapKeys sets up the encoder to encode
|
||||||
|
// maps with string type keys with quoted TOML keys.
|
||||||
|
//
|
||||||
|
// This relieves the character limitations on map keys.
|
||||||
|
func (e *Encoder) QuoteMapKeys(v bool) *Encoder {
|
||||||
|
e.quoteMapKeys = v
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArraysWithOneElementPerLine sets up the encoder to encode arrays
|
||||||
|
// with more than one element on multiple lines instead of one.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// A = [1,2,3]
|
||||||
|
//
|
||||||
|
// Becomes
|
||||||
|
//
|
||||||
|
// A = [
|
||||||
|
// 1,
|
||||||
|
// 2,
|
||||||
|
// 3
|
||||||
|
// ]
|
||||||
|
func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder {
|
||||||
|
e.arraysOneElementPerLine = v
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) marshal(v interface{}) ([]byte, error) {
|
||||||
mtype := reflect.TypeOf(v)
|
mtype := reflect.TypeOf(v)
|
||||||
if mtype.Kind() != reflect.Struct {
|
if mtype.Kind() != reflect.Struct {
|
||||||
return []byte{}, errors.New("Only a struct can be marshaled to TOML")
|
return []byte{}, errors.New("Only a struct can be marshaled to TOML")
|
||||||
|
@ -123,18 +203,21 @@ func Marshal(v interface{}) ([]byte, error) {
|
||||||
if isCustomMarshaler(mtype) {
|
if isCustomMarshaler(mtype) {
|
||||||
return callCustomMarshaler(sval)
|
return callCustomMarshaler(sval)
|
||||||
}
|
}
|
||||||
t, err := valueToTree(mtype, sval)
|
t, err := e.valueToTree(mtype, sval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
s, err := t.ToTomlString()
|
|
||||||
return []byte(s), err
|
var buf bytes.Buffer
|
||||||
|
_, err = t.writeTo(&buf, "", "", 0, e.arraysOneElementPerLine)
|
||||||
|
|
||||||
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert given marshal struct or map value to toml tree
|
// Convert given marshal struct or map value to toml tree
|
||||||
func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
|
func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
|
||||||
if mtype.Kind() == reflect.Ptr {
|
if mtype.Kind() == reflect.Ptr {
|
||||||
return valueToTree(mtype.Elem(), mval.Elem())
|
return e.valueToTree(mtype.Elem(), mval.Elem())
|
||||||
}
|
}
|
||||||
tval := newTree()
|
tval := newTree()
|
||||||
switch mtype.Kind() {
|
switch mtype.Kind() {
|
||||||
|
@ -143,31 +226,39 @@ func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
|
||||||
mtypef, mvalf := mtype.Field(i), mval.Field(i)
|
mtypef, mvalf := mtype.Field(i), mval.Field(i)
|
||||||
opts := tomlOptions(mtypef)
|
opts := tomlOptions(mtypef)
|
||||||
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
|
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
|
||||||
val, err := valueToToml(mtypef.Type, mvalf)
|
val, err := e.valueToToml(mtypef.Type, mvalf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tval.Set(opts.name, val)
|
tval.SetWithComment(opts.name, opts.comment, opts.commented, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
for _, key := range mval.MapKeys() {
|
for _, key := range mval.MapKeys() {
|
||||||
mvalf := mval.MapIndex(key)
|
mvalf := mval.MapIndex(key)
|
||||||
val, err := valueToToml(mtype.Elem(), mvalf)
|
val, err := e.valueToToml(mtype.Elem(), mvalf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if e.quoteMapKeys {
|
||||||
|
keyStr, err := tomlValueStringRepresentation(key.String(), "", e.arraysOneElementPerLine)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tval.SetPath([]string{keyStr}, val)
|
||||||
|
} else {
|
||||||
tval.Set(key.String(), val)
|
tval.Set(key.String(), val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return tval, nil
|
return tval, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert given marshal slice to slice of Toml trees
|
// Convert given marshal slice to slice of Toml trees
|
||||||
func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
|
func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
|
||||||
tval := make([]*Tree, mval.Len(), mval.Len())
|
tval := make([]*Tree, mval.Len(), mval.Len())
|
||||||
for i := 0; i < mval.Len(); i++ {
|
for i := 0; i < mval.Len(); i++ {
|
||||||
val, err := valueToTree(mtype.Elem(), mval.Index(i))
|
val, err := e.valueToTree(mtype.Elem(), mval.Index(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -177,10 +268,10 @@ func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert given marshal slice to slice of toml values
|
// Convert given marshal slice to slice of toml values
|
||||||
func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
|
func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
|
||||||
tval := make([]interface{}, mval.Len(), mval.Len())
|
tval := make([]interface{}, mval.Len(), mval.Len())
|
||||||
for i := 0; i < mval.Len(); i++ {
|
for i := 0; i < mval.Len(); i++ {
|
||||||
val, err := valueToToml(mtype.Elem(), mval.Index(i))
|
val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -190,19 +281,19 @@ func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert given marshal value to toml value
|
// Convert given marshal value to toml value
|
||||||
func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
|
func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
|
||||||
if mtype.Kind() == reflect.Ptr {
|
if mtype.Kind() == reflect.Ptr {
|
||||||
return valueToToml(mtype.Elem(), mval.Elem())
|
return e.valueToToml(mtype.Elem(), mval.Elem())
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case isCustomMarshaler(mtype):
|
case isCustomMarshaler(mtype):
|
||||||
return callCustomMarshaler(mval)
|
return callCustomMarshaler(mval)
|
||||||
case isTree(mtype):
|
case isTree(mtype):
|
||||||
return valueToTree(mtype, mval)
|
return e.valueToTree(mtype, mval)
|
||||||
case isTreeSlice(mtype):
|
case isTreeSlice(mtype):
|
||||||
return valueToTreeSlice(mtype, mval)
|
return e.valueToTreeSlice(mtype, mval)
|
||||||
case isOtherSlice(mtype):
|
case isOtherSlice(mtype):
|
||||||
return valueToOtherSlice(mtype, mval)
|
return e.valueToOtherSlice(mtype, mval)
|
||||||
default:
|
default:
|
||||||
switch mtype.Kind() {
|
switch mtype.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
|
@ -227,17 +318,16 @@ func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
|
||||||
// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
|
// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
|
||||||
// sub-structs, and only definite types can be unmarshaled.
|
// sub-structs, and only definite types can be unmarshaled.
|
||||||
func (t *Tree) Unmarshal(v interface{}) error {
|
func (t *Tree) Unmarshal(v interface{}) error {
|
||||||
mtype := reflect.TypeOf(v)
|
d := Decoder{tval: t}
|
||||||
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
|
return d.unmarshal(v)
|
||||||
return errors.New("Only a pointer to struct can be unmarshaled from TOML")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sval, err := valueFromTree(mtype.Elem(), t)
|
// Marshal returns the TOML encoding of Tree.
|
||||||
if err != nil {
|
// See Marshal() documentation for types mapping table.
|
||||||
return err
|
func (t *Tree) Marshal() ([]byte, error) {
|
||||||
}
|
var buf bytes.Buffer
|
||||||
reflect.ValueOf(v).Elem().Set(sval)
|
err := NewEncoder(&buf).Encode(t)
|
||||||
return nil
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal parses the TOML-encoded data and stores the result in the value
|
// Unmarshal parses the TOML-encoded data and stores the result in the value
|
||||||
|
@ -246,6 +336,10 @@ func (t *Tree) Unmarshal(v interface{}) error {
|
||||||
// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
|
// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
|
||||||
// `interface{}`).
|
// `interface{}`).
|
||||||
//
|
//
|
||||||
|
// The following struct annotations are supported:
|
||||||
|
//
|
||||||
|
// toml:"Field" Overrides the field's name to map to.
|
||||||
|
//
|
||||||
// See Marshal() documentation for types mapping table.
|
// See Marshal() documentation for types mapping table.
|
||||||
func Unmarshal(data []byte, v interface{}) error {
|
func Unmarshal(data []byte, v interface{}) error {
|
||||||
t, err := LoadReader(bytes.NewReader(data))
|
t, err := LoadReader(bytes.NewReader(data))
|
||||||
|
@ -255,10 +349,52 @@ func Unmarshal(data []byte, v interface{}) error {
|
||||||
return t.Unmarshal(v)
|
return t.Unmarshal(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decoder reads and decodes TOML values from an input stream.
|
||||||
|
type Decoder struct {
|
||||||
|
r io.Reader
|
||||||
|
tval *Tree
|
||||||
|
encOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a new decoder that reads from r.
|
||||||
|
func NewDecoder(r io.Reader) *Decoder {
|
||||||
|
return &Decoder{
|
||||||
|
r: r,
|
||||||
|
encOpts: encOptsDefaults,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode reads a TOML-encoded value from it's input
|
||||||
|
// and unmarshals it in the value pointed at by v.
|
||||||
|
//
|
||||||
|
// See the documentation for Marshal for details.
|
||||||
|
func (d *Decoder) Decode(v interface{}) error {
|
||||||
|
var err error
|
||||||
|
d.tval, err = LoadReader(d.r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return d.unmarshal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) unmarshal(v interface{}) error {
|
||||||
|
mtype := reflect.TypeOf(v)
|
||||||
|
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
|
||||||
|
return errors.New("Only a pointer to struct can be unmarshaled from TOML")
|
||||||
|
}
|
||||||
|
|
||||||
|
sval, err := d.valueFromTree(mtype.Elem(), d.tval)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reflect.ValueOf(v).Elem().Set(sval)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Convert toml tree to marshal struct or map, using marshal type
|
// Convert toml tree to marshal struct or map, using marshal type
|
||||||
func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
|
func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
|
||||||
if mtype.Kind() == reflect.Ptr {
|
if mtype.Kind() == reflect.Ptr {
|
||||||
return unwrapPointer(mtype, tval)
|
return d.unwrapPointer(mtype, tval)
|
||||||
}
|
}
|
||||||
var mval reflect.Value
|
var mval reflect.Value
|
||||||
switch mtype.Kind() {
|
switch mtype.Kind() {
|
||||||
|
@ -276,7 +412,7 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val := tval.Get(key)
|
val := tval.Get(key)
|
||||||
mvalf, err := valueFromToml(mtypef.Type, val)
|
mvalf, err := d.valueFromToml(mtypef.Type, val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mval, formatError(err, tval.GetPosition(key))
|
return mval, formatError(err, tval.GetPosition(key))
|
||||||
}
|
}
|
||||||
|
@ -288,8 +424,9 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
mval = reflect.MakeMap(mtype)
|
mval = reflect.MakeMap(mtype)
|
||||||
for _, key := range tval.Keys() {
|
for _, key := range tval.Keys() {
|
||||||
val := tval.Get(key)
|
// TODO: path splits key
|
||||||
mvalf, err := valueFromToml(mtype.Elem(), val)
|
val := tval.GetPath([]string{key})
|
||||||
|
mvalf, err := d.valueFromToml(mtype.Elem(), val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mval, formatError(err, tval.GetPosition(key))
|
return mval, formatError(err, tval.GetPosition(key))
|
||||||
}
|
}
|
||||||
|
@ -300,10 +437,10 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert toml value to marshal struct/map slice, using marshal type
|
// Convert toml value to marshal struct/map slice, using marshal type
|
||||||
func valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
|
func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
|
||||||
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
|
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
|
||||||
for i := 0; i < len(tval); i++ {
|
for i := 0; i < len(tval); i++ {
|
||||||
val, err := valueFromTree(mtype.Elem(), tval[i])
|
val, err := d.valueFromTree(mtype.Elem(), tval[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mval, err
|
return mval, err
|
||||||
}
|
}
|
||||||
|
@ -313,10 +450,10 @@ func valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert toml value to marshal primitive slice, using marshal type
|
// Convert toml value to marshal primitive slice, using marshal type
|
||||||
func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
|
func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
|
||||||
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
|
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
|
||||||
for i := 0; i < len(tval); i++ {
|
for i := 0; i < len(tval); i++ {
|
||||||
val, err := valueFromToml(mtype.Elem(), tval[i])
|
val, err := d.valueFromToml(mtype.Elem(), tval[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mval, err
|
return mval, err
|
||||||
}
|
}
|
||||||
|
@ -326,117 +463,86 @@ func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert toml value to marshal value, using marshal type
|
// Convert toml value to marshal value, using marshal type
|
||||||
func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
|
func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
|
||||||
if mtype.Kind() == reflect.Ptr {
|
if mtype.Kind() == reflect.Ptr {
|
||||||
return unwrapPointer(mtype, tval)
|
return d.unwrapPointer(mtype, tval)
|
||||||
}
|
}
|
||||||
switch {
|
|
||||||
case isTree(mtype):
|
switch tval.(type) {
|
||||||
return valueFromTree(mtype, tval.(*Tree))
|
case *Tree:
|
||||||
case isTreeSlice(mtype):
|
if isTree(mtype) {
|
||||||
return valueFromTreeSlice(mtype, tval.([]*Tree))
|
return d.valueFromTree(mtype, tval.(*Tree))
|
||||||
case isOtherSlice(mtype):
|
}
|
||||||
return valueFromOtherSlice(mtype, tval.([]interface{}))
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
|
||||||
|
case []*Tree:
|
||||||
|
if isTreeSlice(mtype) {
|
||||||
|
return d.valueFromTreeSlice(mtype, tval.([]*Tree))
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
|
||||||
|
case []interface{}:
|
||||||
|
if isOtherSlice(mtype) {
|
||||||
|
return d.valueFromOtherSlice(mtype, tval.([]interface{}))
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
|
||||||
default:
|
default:
|
||||||
switch mtype.Kind() {
|
switch mtype.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool, reflect.Struct:
|
||||||
val, ok := tval.(bool)
|
val := reflect.ValueOf(tval)
|
||||||
if !ok {
|
// if this passes for when mtype is reflect.Struct, tval is a time.Time
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to bool", tval, tval)
|
if !val.Type().ConvertibleTo(mtype) {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
|
||||||
}
|
}
|
||||||
return reflect.ValueOf(val), nil
|
|
||||||
case reflect.Int:
|
return val.Convert(mtype), nil
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(int(val)), nil
|
|
||||||
case reflect.Int8:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(int8(val)), nil
|
|
||||||
case reflect.Int16:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(int16(val)), nil
|
|
||||||
case reflect.Int32:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(int32(val)), nil
|
|
||||||
case reflect.Int64:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(val), nil
|
|
||||||
case reflect.Uint:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(uint(val)), nil
|
|
||||||
case reflect.Uint8:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(uint8(val)), nil
|
|
||||||
case reflect.Uint16:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(uint16(val)), nil
|
|
||||||
case reflect.Uint32:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(uint32(val)), nil
|
|
||||||
case reflect.Uint64:
|
|
||||||
val, ok := tval.(int64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(uint64(val)), nil
|
|
||||||
case reflect.Float32:
|
|
||||||
val, ok := tval.(float64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(float32(val)), nil
|
|
||||||
case reflect.Float64:
|
|
||||||
val, ok := tval.(float64)
|
|
||||||
if !ok {
|
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(val), nil
|
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
val, ok := tval.(string)
|
val := reflect.ValueOf(tval)
|
||||||
if !ok {
|
// stupidly, int64 is convertible to string. So special case this.
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to string", tval, tval)
|
if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Int64 {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
|
||||||
}
|
}
|
||||||
return reflect.ValueOf(val), nil
|
|
||||||
case reflect.Struct:
|
return val.Convert(mtype), nil
|
||||||
val, ok := tval.(time.Time)
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
if !ok {
|
val := reflect.ValueOf(tval)
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to time", tval, tval)
|
if !val.Type().ConvertibleTo(mtype) {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
|
||||||
}
|
}
|
||||||
return reflect.ValueOf(val), nil
|
if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Int()) {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return val.Convert(mtype), nil
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
val := reflect.ValueOf(tval)
|
||||||
|
if !val.Type().ConvertibleTo(mtype) {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
|
||||||
|
}
|
||||||
|
if val.Int() < 0 {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String())
|
||||||
|
}
|
||||||
|
if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Int())) {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return val.Convert(mtype), nil
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
val := reflect.ValueOf(tval)
|
||||||
|
if !val.Type().ConvertibleTo(mtype) {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
|
||||||
|
}
|
||||||
|
if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Float()) {
|
||||||
|
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return val.Convert(mtype), nil
|
||||||
default:
|
default:
|
||||||
return reflect.ValueOf(nil), fmt.Errorf("Unmarshal can't handle %v(%v)", mtype, mtype.Kind())
|
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
|
func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
|
||||||
val, err := valueFromToml(mtype.Elem(), tval)
|
val, err := d.valueFromToml(mtype.Elem(), tval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reflect.ValueOf(nil), err
|
return reflect.ValueOf(nil), err
|
||||||
}
|
}
|
||||||
|
@ -448,7 +554,12 @@ func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error)
|
||||||
func tomlOptions(vf reflect.StructField) tomlOpts {
|
func tomlOptions(vf reflect.StructField) tomlOpts {
|
||||||
tag := vf.Tag.Get("toml")
|
tag := vf.Tag.Get("toml")
|
||||||
parse := strings.Split(tag, ",")
|
parse := strings.Split(tag, ",")
|
||||||
result := tomlOpts{vf.Name, true, false}
|
var comment string
|
||||||
|
if c := vf.Tag.Get("comment"); c != "" {
|
||||||
|
comment = c
|
||||||
|
}
|
||||||
|
commented, _ := strconv.ParseBool(vf.Tag.Get("commented"))
|
||||||
|
result := tomlOpts{name: vf.Name, comment: comment, commented: commented, include: true, omitempty: false}
|
||||||
if parse[0] != "" {
|
if parse[0] != "" {
|
||||||
if parse[0] == "-" && len(parse) == 1 {
|
if parse[0] == "-" && len(parse) == 1 {
|
||||||
result.include = false
|
result.include = false
|
||||||
|
|
73
vendor/github.com/pelletier/go-toml/parser.go
generated
vendored
73
vendor/github.com/pelletier/go-toml/parser.go
generated
vendored
|
@ -5,6 +5,7 @@ package toml
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -185,10 +186,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign value to the found table
|
// assign value to the found table
|
||||||
keyVals, err := parseKey(key.val)
|
keyVals := []string{key.val}
|
||||||
if err != nil {
|
|
||||||
p.raiseError(key, "%s", err)
|
|
||||||
}
|
|
||||||
if len(keyVals) != 1 {
|
if len(keyVals) != 1 {
|
||||||
p.raiseError(key, "Invalid key")
|
p.raiseError(key, "Invalid key")
|
||||||
}
|
}
|
||||||
|
@ -205,20 +203,32 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
|
||||||
case *Tree, []*Tree:
|
case *Tree, []*Tree:
|
||||||
toInsert = value
|
toInsert = value
|
||||||
default:
|
default:
|
||||||
toInsert = &tomlValue{value, key.Position}
|
toInsert = &tomlValue{value: value, position: key.Position}
|
||||||
}
|
}
|
||||||
targetNode.values[keyVal] = toInsert
|
targetNode.values[keyVal] = toInsert
|
||||||
return p.parseStart
|
return p.parseStart
|
||||||
}
|
}
|
||||||
|
|
||||||
var numberUnderscoreInvalidRegexp *regexp.Regexp
|
var numberUnderscoreInvalidRegexp *regexp.Regexp
|
||||||
|
var hexNumberUnderscoreInvalidRegexp *regexp.Regexp
|
||||||
|
|
||||||
func cleanupNumberToken(value string) (string, error) {
|
func numberContainsInvalidUnderscore(value string) error {
|
||||||
if numberUnderscoreInvalidRegexp.MatchString(value) {
|
if numberUnderscoreInvalidRegexp.MatchString(value) {
|
||||||
return "", errors.New("invalid use of _ in number")
|
return errors.New("invalid use of _ in number")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexNumberContainsInvalidUnderscore(value string) error {
|
||||||
|
if hexNumberUnderscoreInvalidRegexp.MatchString(value) {
|
||||||
|
return errors.New("invalid use of _ in hex number")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupNumberToken(value string) string {
|
||||||
cleanedVal := strings.Replace(value, "_", "", -1)
|
cleanedVal := strings.Replace(value, "_", "", -1)
|
||||||
return cleanedVal, nil
|
return cleanedVal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *tomlParser) parseRvalue() interface{} {
|
func (p *tomlParser) parseRvalue() interface{} {
|
||||||
|
@ -234,21 +244,57 @@ func (p *tomlParser) parseRvalue() interface{} {
|
||||||
return true
|
return true
|
||||||
case tokenFalse:
|
case tokenFalse:
|
||||||
return false
|
return false
|
||||||
|
case tokenInf:
|
||||||
|
if tok.val[0] == '-' {
|
||||||
|
return math.Inf(-1)
|
||||||
|
}
|
||||||
|
return math.Inf(1)
|
||||||
|
case tokenNan:
|
||||||
|
return math.NaN()
|
||||||
case tokenInteger:
|
case tokenInteger:
|
||||||
cleanedVal, err := cleanupNumberToken(tok.val)
|
cleanedVal := cleanupNumberToken(tok.val)
|
||||||
|
var err error
|
||||||
|
var val int64
|
||||||
|
if len(cleanedVal) >= 3 && cleanedVal[0] == '0' {
|
||||||
|
switch cleanedVal[1] {
|
||||||
|
case 'x':
|
||||||
|
err = hexNumberContainsInvalidUnderscore(tok.val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.raiseError(tok, "%s", err)
|
p.raiseError(tok, "%s", err)
|
||||||
}
|
}
|
||||||
val, err := strconv.ParseInt(cleanedVal, 10, 64)
|
val, err = strconv.ParseInt(cleanedVal[2:], 16, 64)
|
||||||
|
case 'o':
|
||||||
|
err = numberContainsInvalidUnderscore(tok.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
val, err = strconv.ParseInt(cleanedVal[2:], 8, 64)
|
||||||
|
case 'b':
|
||||||
|
err = numberContainsInvalidUnderscore(tok.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
val, err = strconv.ParseInt(cleanedVal[2:], 2, 64)
|
||||||
|
default:
|
||||||
|
panic("invalid base") // the lexer should catch this first
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = numberContainsInvalidUnderscore(tok.val)
|
||||||
|
if err != nil {
|
||||||
|
p.raiseError(tok, "%s", err)
|
||||||
|
}
|
||||||
|
val, err = strconv.ParseInt(cleanedVal, 10, 64)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.raiseError(tok, "%s", err)
|
p.raiseError(tok, "%s", err)
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
case tokenFloat:
|
case tokenFloat:
|
||||||
cleanedVal, err := cleanupNumberToken(tok.val)
|
err := numberContainsInvalidUnderscore(tok.val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.raiseError(tok, "%s", err)
|
p.raiseError(tok, "%s", err)
|
||||||
}
|
}
|
||||||
|
cleanedVal := cleanupNumberToken(tok.val)
|
||||||
val, err := strconv.ParseFloat(cleanedVal, 64)
|
val, err := strconv.ParseFloat(cleanedVal, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.raiseError(tok, "%s", err)
|
p.raiseError(tok, "%s", err)
|
||||||
|
@ -309,7 +355,7 @@ Loop:
|
||||||
}
|
}
|
||||||
p.getToken()
|
p.getToken()
|
||||||
default:
|
default:
|
||||||
p.raiseError(follow, "unexpected token type in inline table: %s", follow.typ.String())
|
p.raiseError(follow, "unexpected token type in inline table: %s", follow.String())
|
||||||
}
|
}
|
||||||
previous = follow
|
previous = follow
|
||||||
}
|
}
|
||||||
|
@ -379,5 +425,6 @@ func parseToml(flow []token) *Tree {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d]|_$|^_)`)
|
numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d])|_$|^_`)
|
||||||
|
hexNumberUnderscoreInvalidRegexp = regexp.MustCompile(`(^0x_)|([^\da-f]_|_[^\da-f])|_$|^_`)
|
||||||
}
|
}
|
||||||
|
|
1
vendor/github.com/pelletier/go-toml/test.sh
generated
vendored
1
vendor/github.com/pelletier/go-toml/test.sh
generated
vendored
|
@ -1,6 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# fail out of the script if anything here fails
|
# fail out of the script if anything here fails
|
||||||
set -e
|
set -e
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
# set the path to the present working directory
|
# set the path to the present working directory
|
||||||
export GOPATH=`pwd`
|
export GOPATH=`pwd`
|
||||||
|
|
4
vendor/github.com/pelletier/go-toml/token.go
generated
vendored
4
vendor/github.com/pelletier/go-toml/token.go
generated
vendored
|
@ -23,6 +23,8 @@ const (
|
||||||
tokenTrue
|
tokenTrue
|
||||||
tokenFalse
|
tokenFalse
|
||||||
tokenFloat
|
tokenFloat
|
||||||
|
tokenInf
|
||||||
|
tokenNan
|
||||||
tokenEqual
|
tokenEqual
|
||||||
tokenLeftBracket
|
tokenLeftBracket
|
||||||
tokenRightBracket
|
tokenRightBracket
|
||||||
|
@ -55,6 +57,8 @@ var tokenTypeNames = []string{
|
||||||
"True",
|
"True",
|
||||||
"False",
|
"False",
|
||||||
"Float",
|
"Float",
|
||||||
|
"Inf",
|
||||||
|
"NaN",
|
||||||
"=",
|
"=",
|
||||||
"[",
|
"[",
|
||||||
"]",
|
"]",
|
||||||
|
|
35
vendor/github.com/pelletier/go-toml/toml.go
generated
vendored
35
vendor/github.com/pelletier/go-toml/toml.go
generated
vendored
|
@ -12,12 +12,16 @@ import (
|
||||||
|
|
||||||
type tomlValue struct {
|
type tomlValue struct {
|
||||||
value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
|
value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
|
||||||
|
comment string
|
||||||
|
commented bool
|
||||||
position Position
|
position Position
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tree is the result of the parsing of a TOML file.
|
// Tree is the result of the parsing of a TOML file.
|
||||||
type Tree struct {
|
type Tree struct {
|
||||||
values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
|
values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
|
||||||
|
comment string
|
||||||
|
commented bool
|
||||||
position Position
|
position Position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,18 +71,15 @@ func (t *Tree) Keys() []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the value at key in the Tree.
|
// Get the value at key in the Tree.
|
||||||
// Key is a dot-separated path (e.g. a.b.c).
|
// Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
|
||||||
|
// If you need to retrieve non-bare keys, use GetPath.
|
||||||
// Returns nil if the path does not exist in the tree.
|
// Returns nil if the path does not exist in the tree.
|
||||||
// If keys is of length zero, the current tree is returned.
|
// If keys is of length zero, the current tree is returned.
|
||||||
func (t *Tree) Get(key string) interface{} {
|
func (t *Tree) Get(key string) interface{} {
|
||||||
if key == "" {
|
if key == "" {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
comps, err := parseKey(key)
|
return t.GetPath(strings.Split(key, "."))
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return t.GetPath(comps)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPath returns the element in the tree indicated by 'keys'.
|
// GetPath returns the element in the tree indicated by 'keys'.
|
||||||
|
@ -178,13 +179,25 @@ func (t *Tree) GetDefault(key string, def interface{}) interface{} {
|
||||||
// Key is a dot-separated path (e.g. a.b.c).
|
// Key is a dot-separated path (e.g. a.b.c).
|
||||||
// Creates all necessary intermediate trees, if needed.
|
// Creates all necessary intermediate trees, if needed.
|
||||||
func (t *Tree) Set(key string, value interface{}) {
|
func (t *Tree) Set(key string, value interface{}) {
|
||||||
t.SetPath(strings.Split(key, "."), value)
|
t.SetWithComment(key, "", false, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWithComment is the same as Set, but allows you to provide comment
|
||||||
|
// information to the key, that will be reused by Marshal().
|
||||||
|
func (t *Tree) SetWithComment(key string, comment string, commented bool, value interface{}) {
|
||||||
|
t.SetPathWithComment(strings.Split(key, "."), comment, commented, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPath sets an element in the tree.
|
// SetPath sets an element in the tree.
|
||||||
// Keys is an array of path elements (e.g. {"a","b","c"}).
|
// Keys is an array of path elements (e.g. {"a","b","c"}).
|
||||||
// Creates all necessary intermediate trees, if needed.
|
// Creates all necessary intermediate trees, if needed.
|
||||||
func (t *Tree) SetPath(keys []string, value interface{}) {
|
func (t *Tree) SetPath(keys []string, value interface{}) {
|
||||||
|
t.SetPathWithComment(keys, "", false, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPathWithComment is the same as SetPath, but allows you to provide comment
|
||||||
|
// information to the key, that will be reused by Marshal().
|
||||||
|
func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool, value interface{}) {
|
||||||
subtree := t
|
subtree := t
|
||||||
for _, intermediateKey := range keys[:len(keys)-1] {
|
for _, intermediateKey := range keys[:len(keys)-1] {
|
||||||
nextTree, exists := subtree.values[intermediateKey]
|
nextTree, exists := subtree.values[intermediateKey]
|
||||||
|
@ -209,13 +222,17 @@ func (t *Tree) SetPath(keys []string, value interface{}) {
|
||||||
|
|
||||||
switch value.(type) {
|
switch value.(type) {
|
||||||
case *Tree:
|
case *Tree:
|
||||||
|
tt := value.(*Tree)
|
||||||
|
tt.comment = comment
|
||||||
toInsert = value
|
toInsert = value
|
||||||
case []*Tree:
|
case []*Tree:
|
||||||
toInsert = value
|
toInsert = value
|
||||||
case *tomlValue:
|
case *tomlValue:
|
||||||
toInsert = value
|
tt := value.(*tomlValue)
|
||||||
|
tt.comment = comment
|
||||||
|
toInsert = tt
|
||||||
default:
|
default:
|
||||||
toInsert = &tomlValue{value: value}
|
toInsert = &tomlValue{value: value, comment: comment, commented: commented}
|
||||||
}
|
}
|
||||||
|
|
||||||
subtree.values[keys[len(keys)-1]] = toInsert
|
subtree.values[keys[len(keys)-1]] = toInsert
|
||||||
|
|
6
vendor/github.com/pelletier/go-toml/tomltree_create.go
generated
vendored
6
vendor/github.com/pelletier/go-toml/tomltree_create.go
generated
vendored
|
@ -104,7 +104,7 @@ func sliceToTree(object interface{}) (interface{}, error) {
|
||||||
}
|
}
|
||||||
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
|
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
|
||||||
}
|
}
|
||||||
return &tomlValue{arrayValue.Interface(), Position{}}, nil
|
return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toTree(object interface{}) (interface{}, error) {
|
func toTree(object interface{}) (interface{}, error) {
|
||||||
|
@ -127,7 +127,7 @@ func toTree(object interface{}) (interface{}, error) {
|
||||||
}
|
}
|
||||||
values[key.String()] = newValue
|
values[key.String()] = newValue
|
||||||
}
|
}
|
||||||
return &Tree{values, Position{}}, nil
|
return &Tree{values: values, position: Position{}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
|
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
|
||||||
|
@ -138,5 +138,5 @@ func toTree(object interface{}) (interface{}, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &tomlValue{simpleValue, Position{}}, nil
|
return &tomlValue{value: simpleValue, position: Position{}}, nil
|
||||||
}
|
}
|
||||||
|
|
84
vendor/github.com/pelletier/go-toml/tomltree_write.go
generated
vendored
84
vendor/github.com/pelletier/go-toml/tomltree_write.go
generated
vendored
|
@ -44,7 +44,7 @@ func encodeTomlString(value string) string {
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func tomlValueStringRepresentation(v interface{}) (string, error) {
|
func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElementPerLine bool) (string, error) {
|
||||||
switch value := v.(type) {
|
switch value := v.(type) {
|
||||||
case uint64:
|
case uint64:
|
||||||
return strconv.FormatUint(value, 10), nil
|
return strconv.FormatUint(value, 10), nil
|
||||||
|
@ -54,14 +54,14 @@ func tomlValueStringRepresentation(v interface{}) (string, error) {
|
||||||
// Ensure a round float does contain a decimal point. Otherwise feeding
|
// Ensure a round float does contain a decimal point. Otherwise feeding
|
||||||
// the output back to the parser would convert to an integer.
|
// the output back to the parser would convert to an integer.
|
||||||
if math.Trunc(value) == value {
|
if math.Trunc(value) == value {
|
||||||
return strconv.FormatFloat(value, 'f', 1, 32), nil
|
return strings.ToLower(strconv.FormatFloat(value, 'f', 1, 32)), nil
|
||||||
}
|
}
|
||||||
return strconv.FormatFloat(value, 'f', -1, 32), nil
|
return strings.ToLower(strconv.FormatFloat(value, 'f', -1, 32)), nil
|
||||||
case string:
|
case string:
|
||||||
return "\"" + encodeTomlString(value) + "\"", nil
|
return "\"" + encodeTomlString(value) + "\"", nil
|
||||||
case []byte:
|
case []byte:
|
||||||
b, _ := v.([]byte)
|
b, _ := v.([]byte)
|
||||||
return tomlValueStringRepresentation(string(b))
|
return tomlValueStringRepresentation(string(b), indent, arraysOneElementPerLine)
|
||||||
case bool:
|
case bool:
|
||||||
if value {
|
if value {
|
||||||
return "true", nil
|
return "true", nil
|
||||||
|
@ -76,21 +76,40 @@ func tomlValueStringRepresentation(v interface{}) (string, error) {
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
|
|
||||||
if rv.Kind() == reflect.Slice {
|
if rv.Kind() == reflect.Slice {
|
||||||
values := []string{}
|
var values []string
|
||||||
for i := 0; i < rv.Len(); i++ {
|
for i := 0; i < rv.Len(); i++ {
|
||||||
item := rv.Index(i).Interface()
|
item := rv.Index(i).Interface()
|
||||||
itemRepr, err := tomlValueStringRepresentation(item)
|
itemRepr, err := tomlValueStringRepresentation(item, indent, arraysOneElementPerLine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
values = append(values, itemRepr)
|
values = append(values, itemRepr)
|
||||||
}
|
}
|
||||||
|
if arraysOneElementPerLine && len(values) > 1 {
|
||||||
|
stringBuffer := bytes.Buffer{}
|
||||||
|
valueIndent := indent + ` ` // TODO: move that to a shared encoder state
|
||||||
|
|
||||||
|
stringBuffer.WriteString("[\n")
|
||||||
|
|
||||||
|
for i, value := range values {
|
||||||
|
stringBuffer.WriteString(valueIndent)
|
||||||
|
stringBuffer.WriteString(value)
|
||||||
|
if i != len(values)-1 {
|
||||||
|
stringBuffer.WriteString(`,`)
|
||||||
|
}
|
||||||
|
stringBuffer.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
stringBuffer.WriteString(indent + "]")
|
||||||
|
|
||||||
|
return stringBuffer.String(), nil
|
||||||
|
}
|
||||||
return "[" + strings.Join(values, ",") + "]", nil
|
return "[" + strings.Join(values, ",") + "]", nil
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("unsupported value type %T: %v", v, v)
|
return "", fmt.Errorf("unsupported value type %T: %v", v, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) {
|
func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
|
||||||
simpleValuesKeys := make([]string, 0)
|
simpleValuesKeys := make([]string, 0)
|
||||||
complexValuesKeys := make([]string, 0)
|
complexValuesKeys := make([]string, 0)
|
||||||
|
|
||||||
|
@ -113,12 +132,29 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
||||||
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
|
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
|
||||||
}
|
}
|
||||||
|
|
||||||
repr, err := tomlValueStringRepresentation(v.value)
|
repr, err := tomlValueStringRepresentation(v.value, indent, arraysOneElementPerLine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
|
|
||||||
writtenBytesCount, err := writeStrings(w, indent, k, " = ", repr, "\n")
|
if v.comment != "" {
|
||||||
|
comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1)
|
||||||
|
start := "# "
|
||||||
|
if strings.HasPrefix(comment, "#") {
|
||||||
|
start = ""
|
||||||
|
}
|
||||||
|
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n")
|
||||||
|
bytesCount += int64(writtenBytesCountComment)
|
||||||
|
if errc != nil {
|
||||||
|
return bytesCount, errc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var commented string
|
||||||
|
if v.commented {
|
||||||
|
commented = "# "
|
||||||
|
}
|
||||||
|
writtenBytesCount, err := writeStrings(w, indent, commented, k, " = ", repr, "\n")
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
|
@ -132,28 +168,48 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
||||||
if keyspace != "" {
|
if keyspace != "" {
|
||||||
combinedKey = keyspace + "." + combinedKey
|
combinedKey = keyspace + "." + combinedKey
|
||||||
}
|
}
|
||||||
|
var commented string
|
||||||
|
if t.commented {
|
||||||
|
commented = "# "
|
||||||
|
}
|
||||||
|
|
||||||
switch node := v.(type) {
|
switch node := v.(type) {
|
||||||
// node has to be of those two types given how keys are sorted above
|
// node has to be of those two types given how keys are sorted above
|
||||||
case *Tree:
|
case *Tree:
|
||||||
writtenBytesCount, err := writeStrings(w, "\n", indent, "[", combinedKey, "]\n")
|
tv, ok := t.values[k].(*Tree)
|
||||||
|
if !ok {
|
||||||
|
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
|
||||||
|
}
|
||||||
|
if tv.comment != "" {
|
||||||
|
comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1)
|
||||||
|
start := "# "
|
||||||
|
if strings.HasPrefix(comment, "#") {
|
||||||
|
start = ""
|
||||||
|
}
|
||||||
|
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment)
|
||||||
|
bytesCount += int64(writtenBytesCountComment)
|
||||||
|
if errc != nil {
|
||||||
|
return bytesCount, errc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount)
|
bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
case []*Tree:
|
case []*Tree:
|
||||||
for _, subTree := range node {
|
for _, subTree := range node {
|
||||||
writtenBytesCount, err := writeStrings(w, "\n", indent, "[[", combinedKey, "]]\n")
|
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount)
|
bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
|
@ -179,7 +235,7 @@ func writeStrings(w io.Writer, s ...string) (int, error) {
|
||||||
// WriteTo encode the Tree as Toml and writes it to the writer w.
|
// WriteTo encode the Tree as Toml and writes it to the writer w.
|
||||||
// Returns the number of bytes written in case of success, or an error if anything happened.
|
// Returns the number of bytes written in case of success, or an error if anything happened.
|
||||||
func (t *Tree) WriteTo(w io.Writer) (int64, error) {
|
func (t *Tree) WriteTo(w io.Writer) (int64, error) {
|
||||||
return t.writeTo(w, "", "", 0)
|
return t.writeTo(w, "", "", 0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTomlString generates a human-readable representation of the current tree.
|
// ToTomlString generates a human-readable representation of the current tree.
|
||||||
|
|
1
vendor/github.com/satori/uuid/.travis.yml
generated
vendored
1
vendor/github.com/satori/uuid/.travis.yml
generated
vendored
|
@ -8,6 +8,7 @@ go:
|
||||||
- 1.6
|
- 1.6
|
||||||
- 1.7
|
- 1.7
|
||||||
- 1.8
|
- 1.8
|
||||||
|
- 1.9
|
||||||
- tip
|
- tip
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
|
|
2
vendor/github.com/satori/uuid/LICENSE
generated
vendored
2
vendor/github.com/satori/uuid/LICENSE
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
Copyright (C) 2013-2016 by Maxim Bublis <b@codemonkey.ru>
|
Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
2
vendor/github.com/satori/uuid/README.md
generated
vendored
2
vendor/github.com/satori/uuid/README.md
generated
vendored
|
@ -59,7 +59,7 @@ func main() {
|
||||||
|
|
||||||
## Copyright
|
## Copyright
|
||||||
|
|
||||||
Copyright (C) 2013-2016 by Maxim Bublis <b@codemonkey.ru>.
|
Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>.
|
||||||
|
|
||||||
UUID package released under MIT License.
|
UUID package released under MIT License.
|
||||||
See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.
|
See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.
|
||||||
|
|
206
vendor/github.com/satori/uuid/codec.go
generated
vendored
Normal file
206
vendor/github.com/satori/uuid/codec.go
generated
vendored
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromBytes returns UUID converted from raw byte slice input.
|
||||||
|
// It will return error if the slice isn't 16 bytes long.
|
||||||
|
func FromBytes(input []byte) (u UUID, err error) {
|
||||||
|
err = u.UnmarshalBinary(input)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBytesOrNil returns UUID converted from raw byte slice input.
|
||||||
|
// Same behavior as FromBytes, but returns a Nil UUID on error.
|
||||||
|
func FromBytesOrNil(input []byte) UUID {
|
||||||
|
uuid, err := FromBytes(input)
|
||||||
|
if err != nil {
|
||||||
|
return Nil
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromString returns UUID parsed from string input.
|
||||||
|
// Input is expected in a form accepted by UnmarshalText.
|
||||||
|
func FromString(input string) (u UUID, err error) {
|
||||||
|
err = u.UnmarshalText([]byte(input))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStringOrNil returns UUID parsed from string input.
|
||||||
|
// Same behavior as FromString, but returns a Nil UUID on error.
|
||||||
|
func FromStringOrNil(input string) UUID {
|
||||||
|
uuid, err := FromString(input)
|
||||||
|
if err != nil {
|
||||||
|
return Nil
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
// The encoding is the same as returned by String.
|
||||||
|
func (u UUID) MarshalText() (text []byte, err error) {
|
||||||
|
text = []byte(u.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
// Following formats are supported:
|
||||||
|
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
||||||
|
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
|
||||||
|
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
|
||||||
|
// "6ba7b8109dad11d180b400c04fd430c8"
|
||||||
|
// ABNF for supported UUID text representation follows:
|
||||||
|
// uuid := canonical | hashlike | braced | urn
|
||||||
|
// plain := canonical | hashlike
|
||||||
|
// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
|
||||||
|
// hashlike := 12hexoct
|
||||||
|
// braced := '{' plain '}'
|
||||||
|
// urn := URN ':' UUID-NID ':' plain
|
||||||
|
// URN := 'urn'
|
||||||
|
// UUID-NID := 'uuid'
|
||||||
|
// 12hexoct := 6hexoct 6hexoct
|
||||||
|
// 6hexoct := 4hexoct 2hexoct
|
||||||
|
// 4hexoct := 2hexoct 2hexoct
|
||||||
|
// 2hexoct := hexoct hexoct
|
||||||
|
// hexoct := hexdig hexdig
|
||||||
|
// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
|
||||||
|
// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
|
||||||
|
// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
|
||||||
|
func (u *UUID) UnmarshalText(text []byte) (err error) {
|
||||||
|
switch len(text) {
|
||||||
|
case 32:
|
||||||
|
return u.decodeHashLike(text)
|
||||||
|
case 36:
|
||||||
|
return u.decodeCanonical(text)
|
||||||
|
case 38:
|
||||||
|
return u.decodeBraced(text)
|
||||||
|
case 41:
|
||||||
|
fallthrough
|
||||||
|
case 45:
|
||||||
|
return u.decodeURN(text)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("uuid: incorrect UUID length: %s", text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeCanonical decodes UUID string in format
|
||||||
|
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
|
||||||
|
func (u *UUID) decodeCanonical(t []byte) (err error) {
|
||||||
|
if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
|
||||||
|
return fmt.Errorf("uuid: incorrect UUID format %s", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
src := t[:]
|
||||||
|
dst := u[:]
|
||||||
|
|
||||||
|
for i, byteGroup := range byteGroups {
|
||||||
|
if i > 0 {
|
||||||
|
src = src[1:] // skip dash
|
||||||
|
}
|
||||||
|
_, err = hex.Decode(dst[:byteGroup/2], src[:byteGroup])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
src = src[byteGroup:]
|
||||||
|
dst = dst[byteGroup/2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeHashLike decodes UUID string in format
|
||||||
|
// "6ba7b8109dad11d180b400c04fd430c8".
|
||||||
|
func (u *UUID) decodeHashLike(t []byte) (err error) {
|
||||||
|
src := t[:]
|
||||||
|
dst := u[:]
|
||||||
|
|
||||||
|
if _, err = hex.Decode(dst, src); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeBraced decodes UUID string in format
|
||||||
|
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" or in format
|
||||||
|
// "{6ba7b8109dad11d180b400c04fd430c8}".
|
||||||
|
func (u *UUID) decodeBraced(t []byte) (err error) {
|
||||||
|
l := len(t)
|
||||||
|
|
||||||
|
if t[0] != '{' || t[l-1] != '}' {
|
||||||
|
return fmt.Errorf("uuid: incorrect UUID format %s", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.decodePlain(t[1 : l-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeURN decodes UUID string in format
|
||||||
|
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in format
|
||||||
|
// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8".
|
||||||
|
func (u *UUID) decodeURN(t []byte) (err error) {
|
||||||
|
total := len(t)
|
||||||
|
|
||||||
|
urn_uuid_prefix := t[:9]
|
||||||
|
|
||||||
|
if !bytes.Equal(urn_uuid_prefix, urnPrefix) {
|
||||||
|
return fmt.Errorf("uuid: incorrect UUID format: %s", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.decodePlain(t[9:total])
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodePlain decodes UUID string in canonical format
|
||||||
|
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format
|
||||||
|
// "6ba7b8109dad11d180b400c04fd430c8".
|
||||||
|
func (u *UUID) decodePlain(t []byte) (err error) {
|
||||||
|
switch len(t) {
|
||||||
|
case 32:
|
||||||
|
return u.decodeHashLike(t)
|
||||||
|
case 36:
|
||||||
|
return u.decodeCanonical(t)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("uuid: incorrrect UUID length: %s", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
||||||
|
func (u UUID) MarshalBinary() (data []byte, err error) {
|
||||||
|
data = u.Bytes()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
||||||
|
// It will return error if the slice isn't 16 bytes long.
|
||||||
|
func (u *UUID) UnmarshalBinary(data []byte) (err error) {
|
||||||
|
if len(data) != Size {
|
||||||
|
err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(u[:], data)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
239
vendor/github.com/satori/uuid/generator.go
generated
vendored
Normal file
239
vendor/github.com/satori/uuid/generator.go
generated
vendored
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/binary"
|
||||||
|
"hash"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Difference in 100-nanosecond intervals between
|
||||||
|
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
|
||||||
|
const epochStart = 122192928000000000
|
||||||
|
|
||||||
|
var (
|
||||||
|
global = newDefaultGenerator()
|
||||||
|
|
||||||
|
epochFunc = unixTimeFunc
|
||||||
|
posixUID = uint32(os.Getuid())
|
||||||
|
posixGID = uint32(os.Getgid())
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewV1 returns UUID based on current timestamp and MAC address.
|
||||||
|
func NewV1() UUID {
|
||||||
|
return global.NewV1()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
||||||
|
func NewV2(domain byte) UUID {
|
||||||
|
return global.NewV2(domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
||||||
|
func NewV3(ns UUID, name string) UUID {
|
||||||
|
return global.NewV3(ns, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV4 returns random generated UUID.
|
||||||
|
func NewV4() UUID {
|
||||||
|
return global.NewV4()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
||||||
|
func NewV5(ns UUID, name string) UUID {
|
||||||
|
return global.NewV5(ns, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generator provides interface for generating UUIDs.
|
||||||
|
type Generator interface {
|
||||||
|
NewV1() UUID
|
||||||
|
NewV2(domain byte) UUID
|
||||||
|
NewV3(ns UUID, name string) UUID
|
||||||
|
NewV4() UUID
|
||||||
|
NewV5(ns UUID, name string) UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default generator implementation.
|
||||||
|
type generator struct {
|
||||||
|
storageOnce sync.Once
|
||||||
|
storageMutex sync.Mutex
|
||||||
|
|
||||||
|
lastTime uint64
|
||||||
|
clockSequence uint16
|
||||||
|
hardwareAddr [6]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDefaultGenerator() Generator {
|
||||||
|
return &generator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV1 returns UUID based on current timestamp and MAC address.
|
||||||
|
func (g *generator) NewV1() UUID {
|
||||||
|
u := UUID{}
|
||||||
|
|
||||||
|
timeNow, clockSeq, hardwareAddr := g.getStorage()
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
|
||||||
|
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
|
||||||
|
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
|
||||||
|
binary.BigEndian.PutUint16(u[8:], clockSeq)
|
||||||
|
|
||||||
|
copy(u[10:], hardwareAddr)
|
||||||
|
|
||||||
|
u.SetVersion(V1)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
||||||
|
func (g *generator) NewV2(domain byte) UUID {
|
||||||
|
u := UUID{}
|
||||||
|
|
||||||
|
timeNow, clockSeq, hardwareAddr := g.getStorage()
|
||||||
|
|
||||||
|
switch domain {
|
||||||
|
case DomainPerson:
|
||||||
|
binary.BigEndian.PutUint32(u[0:], posixUID)
|
||||||
|
case DomainGroup:
|
||||||
|
binary.BigEndian.PutUint32(u[0:], posixGID)
|
||||||
|
}
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
|
||||||
|
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
|
||||||
|
binary.BigEndian.PutUint16(u[8:], clockSeq)
|
||||||
|
u[9] = domain
|
||||||
|
|
||||||
|
copy(u[10:], hardwareAddr)
|
||||||
|
|
||||||
|
u.SetVersion(V2)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
||||||
|
func (g *generator) NewV3(ns UUID, name string) UUID {
|
||||||
|
u := newFromHash(md5.New(), ns, name)
|
||||||
|
u.SetVersion(V3)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV4 returns random generated UUID.
|
||||||
|
func (g *generator) NewV4() UUID {
|
||||||
|
u := UUID{}
|
||||||
|
g.safeRandom(u[:])
|
||||||
|
u.SetVersion(V4)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
||||||
|
func (g *generator) NewV5(ns UUID, name string) UUID {
|
||||||
|
u := newFromHash(sha1.New(), ns, name)
|
||||||
|
u.SetVersion(V5)
|
||||||
|
u.SetVariant(VariantRFC4122)
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) initStorage() {
|
||||||
|
g.initClockSequence()
|
||||||
|
g.initHardwareAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) initClockSequence() {
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
g.safeRandom(buf)
|
||||||
|
g.clockSequence = binary.BigEndian.Uint16(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) initHardwareAddr() {
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err == nil {
|
||||||
|
for _, iface := range interfaces {
|
||||||
|
if len(iface.HardwareAddr) >= 6 {
|
||||||
|
copy(g.hardwareAddr[:], iface.HardwareAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize hardwareAddr randomly in case
|
||||||
|
// of real network interfaces absence
|
||||||
|
g.safeRandom(g.hardwareAddr[:])
|
||||||
|
|
||||||
|
// Set multicast bit as recommended in RFC 4122
|
||||||
|
g.hardwareAddr[0] |= 0x01
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) safeRandom(dest []byte) {
|
||||||
|
if _, err := rand.Read(dest); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns UUID v1/v2 storage state.
|
||||||
|
// Returns epoch timestamp, clock sequence, and hardware address.
|
||||||
|
func (g *generator) getStorage() (uint64, uint16, []byte) {
|
||||||
|
g.storageOnce.Do(g.initStorage)
|
||||||
|
|
||||||
|
g.storageMutex.Lock()
|
||||||
|
defer g.storageMutex.Unlock()
|
||||||
|
|
||||||
|
timeNow := epochFunc()
|
||||||
|
// Clock changed backwards since last UUID generation.
|
||||||
|
// Should increase clock sequence.
|
||||||
|
if timeNow <= g.lastTime {
|
||||||
|
g.clockSequence++
|
||||||
|
}
|
||||||
|
g.lastTime = timeNow
|
||||||
|
|
||||||
|
return timeNow, g.clockSequence, g.hardwareAddr[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns difference in 100-nanosecond intervals between
|
||||||
|
// UUID epoch (October 15, 1582) and current time.
|
||||||
|
// This is default epoch calculation function.
|
||||||
|
func unixTimeFunc() uint64 {
|
||||||
|
return epochStart + uint64(time.Now().UnixNano()/100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns UUID based on hashing of namespace UUID and name.
|
||||||
|
func newFromHash(h hash.Hash, ns UUID, name string) UUID {
|
||||||
|
u := UUID{}
|
||||||
|
h.Write(ns[:])
|
||||||
|
h.Write([]byte(name))
|
||||||
|
copy(u[:], h.Sum(nil))
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
78
vendor/github.com/satori/uuid/sql.go
generated
vendored
Normal file
78
vendor/github.com/satori/uuid/sql.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Value implements the driver.Valuer interface.
|
||||||
|
func (u UUID) Value() (driver.Value, error) {
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the sql.Scanner interface.
|
||||||
|
// A 16-byte slice is handled by UnmarshalBinary, while
|
||||||
|
// a longer byte slice or a string is handled by UnmarshalText.
|
||||||
|
func (u *UUID) Scan(src interface{}) error {
|
||||||
|
switch src := src.(type) {
|
||||||
|
case []byte:
|
||||||
|
if len(src) == Size {
|
||||||
|
return u.UnmarshalBinary(src)
|
||||||
|
}
|
||||||
|
return u.UnmarshalText(src)
|
||||||
|
|
||||||
|
case string:
|
||||||
|
return u.UnmarshalText([]byte(src))
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("uuid: cannot convert %T to UUID", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NullUUID can be used with the standard sql package to represent a
|
||||||
|
// UUID value that can be NULL in the database
|
||||||
|
type NullUUID struct {
|
||||||
|
UUID UUID
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver.Valuer interface.
|
||||||
|
func (u NullUUID) Value() (driver.Value, error) {
|
||||||
|
if !u.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// Delegate to UUID Value function
|
||||||
|
return u.UUID.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the sql.Scanner interface.
|
||||||
|
func (u *NullUUID) Scan(src interface{}) error {
|
||||||
|
if src == nil {
|
||||||
|
u.UUID, u.Valid = Nil, false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delegate to UUID Scan function
|
||||||
|
u.Valid = true
|
||||||
|
return u.UUID.Scan(src)
|
||||||
|
}
|
436
vendor/github.com/satori/uuid/uuid.go
generated
vendored
436
vendor/github.com/satori/uuid/uuid.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
|
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
// a copy of this software and associated documentation files (the
|
||||||
|
@ -26,23 +26,29 @@ package uuid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/md5"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha1"
|
|
||||||
"database/sql/driver"
|
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
)
|
||||||
"hash"
|
|
||||||
"net"
|
// Size of a UUID in bytes.
|
||||||
"os"
|
const Size = 16
|
||||||
"sync"
|
|
||||||
"time"
|
// UUID representation compliant with specification
|
||||||
|
// described in RFC 4122.
|
||||||
|
type UUID [Size]byte
|
||||||
|
|
||||||
|
// UUID versions
|
||||||
|
const (
|
||||||
|
_ byte = iota
|
||||||
|
V1
|
||||||
|
V2
|
||||||
|
V3
|
||||||
|
V4
|
||||||
|
V5
|
||||||
)
|
)
|
||||||
|
|
||||||
// UUID layout variants.
|
// UUID layout variants.
|
||||||
const (
|
const (
|
||||||
VariantNCS = iota
|
VariantNCS byte = iota
|
||||||
VariantRFC4122
|
VariantRFC4122
|
||||||
VariantMicrosoft
|
VariantMicrosoft
|
||||||
VariantFuture
|
VariantFuture
|
||||||
|
@ -55,137 +61,49 @@ const (
|
||||||
DomainOrg
|
DomainOrg
|
||||||
)
|
)
|
||||||
|
|
||||||
// Difference in 100-nanosecond intervals between
|
|
||||||
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
|
|
||||||
const epochStart = 122192928000000000
|
|
||||||
|
|
||||||
// Used in string method conversion
|
|
||||||
const dash byte = '-'
|
|
||||||
|
|
||||||
// UUID v1/v2 storage.
|
|
||||||
var (
|
|
||||||
storageMutex sync.Mutex
|
|
||||||
storageOnce sync.Once
|
|
||||||
epochFunc = unixTimeFunc
|
|
||||||
clockSequence uint16
|
|
||||||
lastTime uint64
|
|
||||||
hardwareAddr [6]byte
|
|
||||||
posixUID = uint32(os.Getuid())
|
|
||||||
posixGID = uint32(os.Getgid())
|
|
||||||
)
|
|
||||||
|
|
||||||
// String parse helpers.
|
// String parse helpers.
|
||||||
var (
|
var (
|
||||||
urnPrefix = []byte("urn:uuid:")
|
urnPrefix = []byte("urn:uuid:")
|
||||||
byteGroups = []int{8, 4, 4, 4, 12}
|
byteGroups = []int{8, 4, 4, 4, 12}
|
||||||
)
|
)
|
||||||
|
|
||||||
func initClockSequence() {
|
// Nil is special form of UUID that is specified to have all
|
||||||
buf := make([]byte, 2)
|
|
||||||
safeRandom(buf)
|
|
||||||
clockSequence = binary.BigEndian.Uint16(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initHardwareAddr() {
|
|
||||||
interfaces, err := net.Interfaces()
|
|
||||||
if err == nil {
|
|
||||||
for _, iface := range interfaces {
|
|
||||||
if len(iface.HardwareAddr) >= 6 {
|
|
||||||
copy(hardwareAddr[:], iface.HardwareAddr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize hardwareAddr randomly in case
|
|
||||||
// of real network interfaces absence
|
|
||||||
safeRandom(hardwareAddr[:])
|
|
||||||
|
|
||||||
// Set multicast bit as recommended in RFC 4122
|
|
||||||
hardwareAddr[0] |= 0x01
|
|
||||||
}
|
|
||||||
|
|
||||||
func initStorage() {
|
|
||||||
initClockSequence()
|
|
||||||
initHardwareAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeRandom(dest []byte) {
|
|
||||||
if _, err := rand.Read(dest); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns difference in 100-nanosecond intervals between
|
|
||||||
// UUID epoch (October 15, 1582) and current time.
|
|
||||||
// This is default epoch calculation function.
|
|
||||||
func unixTimeFunc() uint64 {
|
|
||||||
return epochStart + uint64(time.Now().UnixNano()/100)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UUID representation compliant with specification
|
|
||||||
// described in RFC 4122.
|
|
||||||
type UUID [16]byte
|
|
||||||
|
|
||||||
// NullUUID can be used with the standard sql package to represent a
|
|
||||||
// UUID value that can be NULL in the database
|
|
||||||
type NullUUID struct {
|
|
||||||
UUID UUID
|
|
||||||
Valid bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// The nil UUID is special form of UUID that is specified to have all
|
|
||||||
// 128 bits set to zero.
|
// 128 bits set to zero.
|
||||||
var Nil = UUID{}
|
var Nil = UUID{}
|
||||||
|
|
||||||
// Predefined namespace UUIDs.
|
// Predefined namespace UUIDs.
|
||||||
var (
|
var (
|
||||||
NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
|
NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
|
NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
|
NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
)
|
)
|
||||||
|
|
||||||
// And returns result of binary AND of two UUIDs.
|
|
||||||
func And(u1 UUID, u2 UUID) UUID {
|
|
||||||
u := UUID{}
|
|
||||||
for i := 0; i < 16; i++ {
|
|
||||||
u[i] = u1[i] & u2[i]
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// Or returns result of binary OR of two UUIDs.
|
|
||||||
func Or(u1 UUID, u2 UUID) UUID {
|
|
||||||
u := UUID{}
|
|
||||||
for i := 0; i < 16; i++ {
|
|
||||||
u[i] = u1[i] | u2[i]
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal returns true if u1 and u2 equals, otherwise returns false.
|
// Equal returns true if u1 and u2 equals, otherwise returns false.
|
||||||
func Equal(u1 UUID, u2 UUID) bool {
|
func Equal(u1 UUID, u2 UUID) bool {
|
||||||
return bytes.Equal(u1[:], u2[:])
|
return bytes.Equal(u1[:], u2[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version returns algorithm version used to generate UUID.
|
// Version returns algorithm version used to generate UUID.
|
||||||
func (u UUID) Version() uint {
|
func (u UUID) Version() byte {
|
||||||
return uint(u[6] >> 4)
|
return u[6] >> 4
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variant returns UUID layout variant.
|
// Variant returns UUID layout variant.
|
||||||
func (u UUID) Variant() uint {
|
func (u UUID) Variant() byte {
|
||||||
switch {
|
switch {
|
||||||
case (u[8] & 0x80) == 0x00:
|
case (u[8] >> 7) == 0x00:
|
||||||
return VariantNCS
|
return VariantNCS
|
||||||
case (u[8]&0xc0)|0x80 == 0x80:
|
case (u[8] >> 6) == 0x02:
|
||||||
return VariantRFC4122
|
return VariantRFC4122
|
||||||
case (u[8]&0xe0)|0xc0 == 0xc0:
|
case (u[8] >> 5) == 0x06:
|
||||||
return VariantMicrosoft
|
return VariantMicrosoft
|
||||||
}
|
case (u[8] >> 5) == 0x07:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
return VariantFuture
|
return VariantFuture
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bytes returns bytes slice representation of UUID.
|
// Bytes returns bytes slice representation of UUID.
|
||||||
func (u UUID) Bytes() []byte {
|
func (u UUID) Bytes() []byte {
|
||||||
|
@ -198,13 +116,13 @@ func (u UUID) String() string {
|
||||||
buf := make([]byte, 36)
|
buf := make([]byte, 36)
|
||||||
|
|
||||||
hex.Encode(buf[0:8], u[0:4])
|
hex.Encode(buf[0:8], u[0:4])
|
||||||
buf[8] = dash
|
buf[8] = '-'
|
||||||
hex.Encode(buf[9:13], u[4:6])
|
hex.Encode(buf[9:13], u[4:6])
|
||||||
buf[13] = dash
|
buf[13] = '-'
|
||||||
hex.Encode(buf[14:18], u[6:8])
|
hex.Encode(buf[14:18], u[6:8])
|
||||||
buf[18] = dash
|
buf[18] = '-'
|
||||||
hex.Encode(buf[19:23], u[8:10])
|
hex.Encode(buf[19:23], u[8:10])
|
||||||
buf[23] = dash
|
buf[23] = '-'
|
||||||
hex.Encode(buf[24:], u[10:])
|
hex.Encode(buf[24:], u[10:])
|
||||||
|
|
||||||
return string(buf)
|
return string(buf)
|
||||||
|
@ -215,267 +133,29 @@ func (u *UUID) SetVersion(v byte) {
|
||||||
u[6] = (u[6] & 0x0f) | (v << 4)
|
u[6] = (u[6] & 0x0f) | (v << 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetVariant sets variant bits as described in RFC 4122.
|
// SetVariant sets variant bits.
|
||||||
func (u *UUID) SetVariant() {
|
func (u *UUID) SetVariant(v byte) {
|
||||||
u[8] = (u[8] & 0xbf) | 0x80
|
switch v {
|
||||||
|
case VariantNCS:
|
||||||
|
u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
|
||||||
|
case VariantRFC4122:
|
||||||
|
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
|
||||||
|
case VariantMicrosoft:
|
||||||
|
u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
|
||||||
|
case VariantFuture:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalText implements the encoding.TextMarshaler interface.
|
// Must is a helper that wraps a call to a function returning (UUID, error)
|
||||||
// The encoding is the same as returned by String.
|
// and panics if the error is non-nil. It is intended for use in variable
|
||||||
func (u UUID) MarshalText() (text []byte, err error) {
|
// initializations such as
|
||||||
text = []byte(u.String())
|
// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
|
||||||
return
|
func Must(u UUID, err error) UUID {
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
|
||||||
// Following formats are supported:
|
|
||||||
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
||||||
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
|
|
||||||
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
|
|
||||||
func (u *UUID) UnmarshalText(text []byte) (err error) {
|
|
||||||
if len(text) < 32 {
|
|
||||||
err = fmt.Errorf("uuid: UUID string too short: %s", text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t := text[:]
|
|
||||||
braced := false
|
|
||||||
|
|
||||||
if bytes.Equal(t[:9], urnPrefix) {
|
|
||||||
t = t[9:]
|
|
||||||
} else if t[0] == '{' {
|
|
||||||
braced = true
|
|
||||||
t = t[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
b := u[:]
|
|
||||||
|
|
||||||
for i, byteGroup := range byteGroups {
|
|
||||||
if i > 0 {
|
|
||||||
if t[0] != '-' {
|
|
||||||
err = fmt.Errorf("uuid: invalid string format")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t = t[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(t) < byteGroup {
|
|
||||||
err = fmt.Errorf("uuid: UUID string too short: %s", text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == 4 && len(t) > byteGroup &&
|
|
||||||
((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) {
|
|
||||||
err = fmt.Errorf("uuid: UUID string too long: %s", text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = hex.Decode(b[:byteGroup/2], t[:byteGroup])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t = t[byteGroup:]
|
|
||||||
b = b[byteGroup/2:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
|
||||||
func (u UUID) MarshalBinary() (data []byte, err error) {
|
|
||||||
data = u.Bytes()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
|
||||||
// It will return error if the slice isn't 16 bytes long.
|
|
||||||
func (u *UUID) UnmarshalBinary(data []byte) (err error) {
|
|
||||||
if len(data) != 16 {
|
|
||||||
err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
copy(u[:], data)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value implements the driver.Valuer interface.
|
|
||||||
func (u UUID) Value() (driver.Value, error) {
|
|
||||||
return u.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan implements the sql.Scanner interface.
|
|
||||||
// A 16-byte slice is handled by UnmarshalBinary, while
|
|
||||||
// a longer byte slice or a string is handled by UnmarshalText.
|
|
||||||
func (u *UUID) Scan(src interface{}) error {
|
|
||||||
switch src := src.(type) {
|
|
||||||
case []byte:
|
|
||||||
if len(src) == 16 {
|
|
||||||
return u.UnmarshalBinary(src)
|
|
||||||
}
|
|
||||||
return u.UnmarshalText(src)
|
|
||||||
|
|
||||||
case string:
|
|
||||||
return u.UnmarshalText([]byte(src))
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("uuid: cannot convert %T to UUID", src)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value implements the driver.Valuer interface.
|
|
||||||
func (u NullUUID) Value() (driver.Value, error) {
|
|
||||||
if !u.Valid {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
// Delegate to UUID Value function
|
|
||||||
return u.UUID.Value()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan implements the sql.Scanner interface.
|
|
||||||
func (u *NullUUID) Scan(src interface{}) error {
|
|
||||||
if src == nil {
|
|
||||||
u.UUID, u.Valid = Nil, false
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delegate to UUID Scan function
|
|
||||||
u.Valid = true
|
|
||||||
return u.UUID.Scan(src)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromBytes returns UUID converted from raw byte slice input.
|
|
||||||
// It will return error if the slice isn't 16 bytes long.
|
|
||||||
func FromBytes(input []byte) (u UUID, err error) {
|
|
||||||
err = u.UnmarshalBinary(input)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromBytesOrNil returns UUID converted from raw byte slice input.
|
|
||||||
// Same behavior as FromBytes, but returns a Nil UUID on error.
|
|
||||||
func FromBytesOrNil(input []byte) UUID {
|
|
||||||
uuid, err := FromBytes(input)
|
|
||||||
if err != nil {
|
|
||||||
return Nil
|
|
||||||
}
|
|
||||||
return uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromString returns UUID parsed from string input.
|
|
||||||
// Input is expected in a form accepted by UnmarshalText.
|
|
||||||
func FromString(input string) (u UUID, err error) {
|
|
||||||
err = u.UnmarshalText([]byte(input))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStringOrNil returns UUID parsed from string input.
|
|
||||||
// Same behavior as FromString, but returns a Nil UUID on error.
|
|
||||||
func FromStringOrNil(input string) UUID {
|
|
||||||
uuid, err := FromString(input)
|
|
||||||
if err != nil {
|
|
||||||
return Nil
|
|
||||||
}
|
|
||||||
return uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns UUID v1/v2 storage state.
|
|
||||||
// Returns epoch timestamp, clock sequence, and hardware address.
|
|
||||||
func getStorage() (uint64, uint16, []byte) {
|
|
||||||
storageOnce.Do(initStorage)
|
|
||||||
|
|
||||||
storageMutex.Lock()
|
|
||||||
defer storageMutex.Unlock()
|
|
||||||
|
|
||||||
timeNow := epochFunc()
|
|
||||||
// Clock changed backwards since last UUID generation.
|
|
||||||
// Should increase clock sequence.
|
|
||||||
if timeNow <= lastTime {
|
|
||||||
clockSequence++
|
|
||||||
}
|
|
||||||
lastTime = timeNow
|
|
||||||
|
|
||||||
return timeNow, clockSequence, hardwareAddr[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewV1 returns UUID based on current timestamp and MAC address.
|
|
||||||
func NewV1() UUID {
|
|
||||||
u := UUID{}
|
|
||||||
|
|
||||||
timeNow, clockSeq, hardwareAddr := getStorage()
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
|
|
||||||
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
|
|
||||||
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
|
|
||||||
binary.BigEndian.PutUint16(u[8:], clockSeq)
|
|
||||||
|
|
||||||
copy(u[10:], hardwareAddr)
|
|
||||||
|
|
||||||
u.SetVersion(1)
|
|
||||||
u.SetVariant()
|
|
||||||
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
|
||||||
func NewV2(domain byte) UUID {
|
|
||||||
u := UUID{}
|
|
||||||
|
|
||||||
timeNow, clockSeq, hardwareAddr := getStorage()
|
|
||||||
|
|
||||||
switch domain {
|
|
||||||
case DomainPerson:
|
|
||||||
binary.BigEndian.PutUint32(u[0:], posixUID)
|
|
||||||
case DomainGroup:
|
|
||||||
binary.BigEndian.PutUint32(u[0:], posixGID)
|
|
||||||
}
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
|
|
||||||
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
|
|
||||||
binary.BigEndian.PutUint16(u[8:], clockSeq)
|
|
||||||
u[9] = domain
|
|
||||||
|
|
||||||
copy(u[10:], hardwareAddr)
|
|
||||||
|
|
||||||
u.SetVersion(2)
|
|
||||||
u.SetVariant()
|
|
||||||
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
|
||||||
func NewV3(ns UUID, name string) UUID {
|
|
||||||
u := newFromHash(md5.New(), ns, name)
|
|
||||||
u.SetVersion(3)
|
|
||||||
u.SetVariant()
|
|
||||||
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewV4 returns random generated UUID.
|
|
||||||
func NewV4() UUID {
|
|
||||||
u := UUID{}
|
|
||||||
safeRandom(u[:])
|
|
||||||
u.SetVersion(4)
|
|
||||||
u.SetVariant()
|
|
||||||
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
|
||||||
func NewV5(ns UUID, name string) UUID {
|
|
||||||
u := newFromHash(sha1.New(), ns, name)
|
|
||||||
u.SetVersion(5)
|
|
||||||
u.SetVariant()
|
|
||||||
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns UUID based on hashing of namespace UUID and name.
|
|
||||||
func newFromHash(h hash.Hash, ns UUID, name string) UUID {
|
|
||||||
u := UUID{}
|
|
||||||
h.Write(ns[:])
|
|
||||||
h.Write([]byte(name))
|
|
||||||
copy(u[:], h.Sum(nil))
|
|
||||||
|
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
5
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
5
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
|
@ -8,5 +8,8 @@ env:
|
||||||
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
||||||
install:
|
install:
|
||||||
- go get github.com/stretchr/testify/assert
|
- go get github.com/stretchr/testify/assert
|
||||||
|
- go get gopkg.in/gemnasium/logrus-airbrake-hook.v2
|
||||||
|
- go get golang.org/x/sys/unix
|
||||||
|
- go get golang.org/x/sys/windows
|
||||||
script:
|
script:
|
||||||
- go test -race -v .
|
- go test -race -v ./...
|
||||||
|
|
23
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
23
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
|
@ -1,3 +1,26 @@
|
||||||
|
# 1.0.5
|
||||||
|
|
||||||
|
* Fix hooks race (#707)
|
||||||
|
* Fix panic deadlock (#695)
|
||||||
|
|
||||||
|
# 1.0.4
|
||||||
|
|
||||||
|
* Fix race when adding hooks (#612)
|
||||||
|
* Fix terminal check in AppEngine (#635)
|
||||||
|
|
||||||
|
# 1.0.3
|
||||||
|
|
||||||
|
* Replace example files with testable examples
|
||||||
|
|
||||||
|
# 1.0.2
|
||||||
|
|
||||||
|
* bug: quote non-string values in text formatter (#583)
|
||||||
|
* Make (*Logger) SetLevel a public method
|
||||||
|
|
||||||
|
# 1.0.1
|
||||||
|
|
||||||
|
* bug: fix escaping in text formatter (#575)
|
||||||
|
|
||||||
# 1.0.0
|
# 1.0.0
|
||||||
|
|
||||||
* Officially changed name to lower-case
|
* Officially changed name to lower-case
|
||||||
|
|
26
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
26
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
|
@ -1,7 +1,7 @@
|
||||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
|
||||||
|
|
||||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||||
the standard library logger. [Godoc][godoc].
|
the standard library logger.
|
||||||
|
|
||||||
**Seeing weird case-sensitive problems?** It's in the past been possible to
|
**Seeing weird case-sensitive problems?** It's in the past been possible to
|
||||||
import Logrus as both upper- and lower-case. Due to the Go package environment,
|
import Logrus as both upper- and lower-case. Due to the Go package environment,
|
||||||
|
@ -10,10 +10,10 @@ experienced problems with the upper-case variant, so the lower-case was decided.
|
||||||
Everything using `logrus` will need to use the lower-case:
|
Everything using `logrus` will need to use the lower-case:
|
||||||
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
|
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
|
||||||
|
|
||||||
**I am terribly sorry for this inconvenience.** Logrus strives hard for backwards
|
To fix Glide, see [these
|
||||||
compatibility, and the author failed to realize the cascading consequences of
|
|
||||||
such a name-change. To fix Glide, see [these
|
|
||||||
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
|
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
|
||||||
|
For an in-depth explanation of the casing issue, see [this
|
||||||
|
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
|
||||||
|
|
||||||
**Are you interested in assisting in maintaining Logrus?** Currently I have a
|
**Are you interested in assisting in maintaining Logrus?** Currently I have a
|
||||||
lot of obligations, and I am unable to provide Logrus with the maintainership it
|
lot of obligations, and I am unable to provide Logrus with the maintainership it
|
||||||
|
@ -220,7 +220,7 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
|
||||||
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
)
|
)
|
||||||
|
@ -247,6 +247,8 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
|
||||||
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||||
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
|
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
|
||||||
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
||||||
|
| [Application Insights](https://github.com/jjcollinge/logrus-appinsights) | Hook for logging to [Application Insights](https://azure.microsoft.com/en-us/services/application-insights/)
|
||||||
|
| [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage|
|
||||||
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||||
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||||
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
|
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
|
||||||
|
@ -260,19 +262,23 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
|
||||||
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||||
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
|
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
|
||||||
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||||
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
|
| [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka |
|
||||||
|
| [Kafka REST Proxy](https://github.com/Nordstrom/logrus-kafka-rest-proxy) | Hook for logging to [Kafka REST Proxy](https://docs.confluent.io/current/kafka-rest/docs) |
|
||||||
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||||
|
| [Logbeat](https://github.com/macandmia/logbeat) | Hook for logging to [Opbeat](https://opbeat.com/) |
|
||||||
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
||||||
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
||||||
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
|
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
|
||||||
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||||
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
||||||
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||||
|
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
|
||||||
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||||
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
|
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
|
||||||
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||||
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
||||||
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
|
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
|
||||||
|
| [Promrus](https://github.com/weaveworks/promrus) | Expose number of log messages as [Prometheus](https://prometheus.io/) metrics |
|
||||||
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
|
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
|
||||||
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||||
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
||||||
|
@ -282,8 +288,9 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
|
||||||
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||||
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
|
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
|
||||||
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
||||||
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||||
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
|
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
|
||||||
|
| [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) |
|
||||||
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
|
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
|
||||||
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
||||||
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
|
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
|
||||||
|
@ -371,6 +378,7 @@ The built-in logging formatters are:
|
||||||
|
|
||||||
Third party logging formatters:
|
Third party logging formatters:
|
||||||
|
|
||||||
|
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
|
||||||
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
||||||
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||||
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
@ -451,13 +459,13 @@ Logrus has a built in facility for asserting the presence of log messages. This
|
||||||
```go
|
```go
|
||||||
import(
|
import(
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/sirupsen/logrus/hooks/null"
|
"github.com/sirupsen/logrus/hooks/test"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSomething(t*testing.T){
|
func TestSomething(t*testing.T){
|
||||||
logger, hook := null.NewNullLogger()
|
logger, hook := test.NewNullLogger()
|
||||||
logger.Error("Helloerror")
|
logger.Error("Helloerror")
|
||||||
|
|
||||||
assert.Equal(t, 1, len(hook.Entries))
|
assert.Equal(t, 1, len(hook.Entries))
|
||||||
|
|
14
vendor/github.com/sirupsen/logrus/appveyor.yml
generated
vendored
Normal file
14
vendor/github.com/sirupsen/logrus/appveyor.yml
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
version: "{build}"
|
||||||
|
platform: x64
|
||||||
|
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
|
||||||
|
environment:
|
||||||
|
GOPATH: c:\gopath
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
install:
|
||||||
|
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
|
||||||
|
- go version
|
||||||
|
build_script:
|
||||||
|
- go get -t
|
||||||
|
- go test
|
49
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
49
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
|
@ -35,6 +35,7 @@ type Entry struct {
|
||||||
Time time.Time
|
Time time.Time
|
||||||
|
|
||||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
||||||
Level Level
|
Level Level
|
||||||
|
|
||||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
@ -93,29 +94,16 @@ func (entry Entry) log(level Level, msg string) {
|
||||||
entry.Level = level
|
entry.Level = level
|
||||||
entry.Message = msg
|
entry.Message = msg
|
||||||
|
|
||||||
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
entry.fireHooks()
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
}
|
|
||||||
buffer = bufferPool.Get().(*bytes.Buffer)
|
buffer = bufferPool.Get().(*bytes.Buffer)
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
defer bufferPool.Put(buffer)
|
defer bufferPool.Put(buffer)
|
||||||
entry.Buffer = buffer
|
entry.Buffer = buffer
|
||||||
serialized, err := entry.Logger.Formatter.Format(&entry)
|
|
||||||
|
entry.write()
|
||||||
|
|
||||||
entry.Buffer = nil
|
entry.Buffer = nil
|
||||||
if err != nil {
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
} else {
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
_, err = entry.Logger.Out.Write(serialized)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
|
||||||
}
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// To avoid Entry#log() returning a value that only would make sense for
|
// To avoid Entry#log() returning a value that only would make sense for
|
||||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||||
|
@ -125,6 +113,31 @@ func (entry Entry) log(level Level, msg string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is not declared with a pointer value because otherwise
|
||||||
|
// race conditions will occur when using multiple goroutines
|
||||||
|
func (entry Entry) fireHooks() {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
defer entry.Logger.mu.Unlock()
|
||||||
|
err := entry.Logger.Hooks.Fire(entry.Level, &entry)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) write() {
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
defer entry.Logger.mu.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||||
|
} else {
|
||||||
|
_, err = entry.Logger.Out.Write(serialized)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (entry *Entry) Debug(args ...interface{}) {
|
func (entry *Entry) Debug(args ...interface{}) {
|
||||||
if entry.Logger.level() >= DebugLevel {
|
if entry.Logger.level() >= DebugLevel {
|
||||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||||
|
|
2
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
|
@ -31,7 +31,7 @@ func SetFormatter(formatter Formatter) {
|
||||||
func SetLevel(level Level) {
|
func SetLevel(level Level) {
|
||||||
std.mu.Lock()
|
std.mu.Lock()
|
||||||
defer std.mu.Unlock()
|
defer std.mu.Unlock()
|
||||||
std.setLevel(level)
|
std.SetLevel(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLevel returns the standard logger level.
|
// GetLevel returns the standard logger level.
|
||||||
|
|
2
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
|
@ -2,7 +2,7 @@ package logrus
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const DefaultTimestampFormat = time.RFC3339
|
const defaultTimestampFormat = time.RFC3339
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
|
|
9
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
9
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
|
@ -6,8 +6,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type fieldKey string
|
type fieldKey string
|
||||||
|
|
||||||
|
// FieldMap allows customization of the key names for default fields.
|
||||||
type FieldMap map[fieldKey]string
|
type FieldMap map[fieldKey]string
|
||||||
|
|
||||||
|
// Default key names for the default fields
|
||||||
const (
|
const (
|
||||||
FieldKeyMsg = "msg"
|
FieldKeyMsg = "msg"
|
||||||
FieldKeyLevel = "level"
|
FieldKeyLevel = "level"
|
||||||
|
@ -22,6 +25,7 @@ func (f FieldMap) resolve(key fieldKey) string {
|
||||||
return string(key)
|
return string(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSONFormatter formats logs into parsable json
|
||||||
type JSONFormatter struct {
|
type JSONFormatter struct {
|
||||||
// TimestampFormat sets the format used for marshaling timestamps.
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||||
TimestampFormat string
|
TimestampFormat string
|
||||||
|
@ -29,7 +33,7 @@ type JSONFormatter struct {
|
||||||
// DisableTimestamp allows disabling automatic timestamps in output
|
// DisableTimestamp allows disabling automatic timestamps in output
|
||||||
DisableTimestamp bool
|
DisableTimestamp bool
|
||||||
|
|
||||||
// FieldMap allows users to customize the names of keys for various fields.
|
// FieldMap allows users to customize the names of keys for default fields.
|
||||||
// As an example:
|
// As an example:
|
||||||
// formatter := &JSONFormatter{
|
// formatter := &JSONFormatter{
|
||||||
// FieldMap: FieldMap{
|
// FieldMap: FieldMap{
|
||||||
|
@ -41,6 +45,7 @@ type JSONFormatter struct {
|
||||||
FieldMap FieldMap
|
FieldMap FieldMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format renders a single log entry
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
data := make(Fields, len(entry.Data)+3)
|
data := make(Fields, len(entry.Data)+3)
|
||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
|
@ -57,7 +62,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
timestampFormat := f.TimestampFormat
|
||||||
if timestampFormat == "" {
|
if timestampFormat == "" {
|
||||||
timestampFormat = DefaultTimestampFormat
|
timestampFormat = defaultTimestampFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
|
|
10
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
10
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
|
@ -25,7 +25,7 @@ type Logger struct {
|
||||||
Formatter Formatter
|
Formatter Formatter
|
||||||
// The logging level the logger should log at. This is typically (and defaults
|
// The logging level the logger should log at. This is typically (and defaults
|
||||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||||
// logged. `logrus.Debug` is useful in
|
// logged.
|
||||||
Level Level
|
Level Level
|
||||||
// Used to sync writing to the log. Locking is enabled by Default
|
// Used to sync writing to the log. Locking is enabled by Default
|
||||||
mu MutexWrap
|
mu MutexWrap
|
||||||
|
@ -312,6 +312,12 @@ func (logger *Logger) level() Level {
|
||||||
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) setLevel(level Level) {
|
func (logger *Logger) SetLevel(level Level) {
|
||||||
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) AddHook(hook Hook) {
|
||||||
|
logger.mu.Lock()
|
||||||
|
defer logger.mu.Unlock()
|
||||||
|
logger.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
|
10
vendor/github.com/sirupsen/logrus/terminal_appengine.go
generated
vendored
10
vendor/github.com/sirupsen/logrus/terminal_appengine.go
generated
vendored
|
@ -1,10 +0,0 @@
|
||||||
// +build appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
|
||||||
func IsTerminal(f io.Writer) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
8
vendor/github.com/sirupsen/logrus/terminal_bsd.go
generated
vendored
8
vendor/github.com/sirupsen/logrus/terminal_bsd.go
generated
vendored
|
@ -1,10 +1,10 @@
|
||||||
// +build darwin freebsd openbsd netbsd dragonfly
|
// +build darwin freebsd openbsd netbsd dragonfly
|
||||||
// +build !appengine
|
// +build !appengine,!gopherjs
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import "syscall"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TIOCGETA
|
const ioctlReadTermios = unix.TIOCGETA
|
||||||
|
|
||||||
type Termios syscall.Termios
|
type Termios unix.Termios
|
||||||
|
|
11
vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
Normal file
11
vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// +build appengine gopherjs
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
return true
|
||||||
|
}
|
19
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
Normal file
19
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// +build !appengine,!gopherjs
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
switch v := w.(type) {
|
||||||
|
case *os.File:
|
||||||
|
return terminal.IsTerminal(int(v.Fd()))
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
8
vendor/github.com/sirupsen/logrus/terminal_linux.go
generated
vendored
8
vendor/github.com/sirupsen/logrus/terminal_linux.go
generated
vendored
|
@ -3,12 +3,12 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !appengine
|
// +build !appengine,!gopherjs
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import "syscall"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TCGETS
|
const ioctlReadTermios = unix.TCGETS
|
||||||
|
|
||||||
type Termios syscall.Termios
|
type Termios unix.Termios
|
||||||
|
|
28
vendor/github.com/sirupsen/logrus/terminal_notwindows.go
generated
vendored
28
vendor/github.com/sirupsen/logrus/terminal_notwindows.go
generated
vendored
|
@ -1,28 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build linux darwin freebsd openbsd netbsd dragonfly
|
|
||||||
// +build !appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
|
||||||
func IsTerminal(f io.Writer) bool {
|
|
||||||
var termios Termios
|
|
||||||
switch v := f.(type) {
|
|
||||||
case *os.File:
|
|
||||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
|
||||||
return err == 0
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
21
vendor/github.com/sirupsen/logrus/terminal_solaris.go
generated
vendored
21
vendor/github.com/sirupsen/logrus/terminal_solaris.go
generated
vendored
|
@ -1,21 +0,0 @@
|
||||||
// +build solaris,!appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
||||||
func IsTerminal(f io.Writer) bool {
|
|
||||||
switch v := f.(type) {
|
|
||||||
case *os.File:
|
|
||||||
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
|
|
||||||
return err == nil
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
82
vendor/github.com/sirupsen/logrus/terminal_windows.go
generated
vendored
82
vendor/github.com/sirupsen/logrus/terminal_windows.go
generated
vendored
|
@ -1,82 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build windows,!appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
||||||
|
|
||||||
var (
|
|
||||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
||||||
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
enableProcessedOutput = 0x0001
|
|
||||||
enableWrapAtEolOutput = 0x0002
|
|
||||||
enableVirtualTerminalProcessing = 0x0004
|
|
||||||
)
|
|
||||||
|
|
||||||
func getVersion() (float64, error) {
|
|
||||||
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
|
|
||||||
cmd := exec.Command("cmd", "ver")
|
|
||||||
cmd.Stdout = stdout
|
|
||||||
cmd.Stderr = stderr
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The output should be like "Microsoft Windows [Version XX.X.XXXXXX]"
|
|
||||||
version := strings.Replace(stdout.String(), "\n", "", -1)
|
|
||||||
version = strings.Replace(version, "\r\n", "", -1)
|
|
||||||
|
|
||||||
x1 := strings.Index(version, "[Version")
|
|
||||||
|
|
||||||
if x1 == -1 || strings.Index(version, "]") == -1 {
|
|
||||||
return -1, errors.New("Can't determine Windows version")
|
|
||||||
}
|
|
||||||
|
|
||||||
return strconv.ParseFloat(version[x1+9:x1+13], 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
ver, err := getVersion()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Activate Virtual Processing for Windows CMD
|
|
||||||
// Info: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
|
||||||
if ver >= 10 {
|
|
||||||
handle := syscall.Handle(os.Stderr.Fd())
|
|
||||||
procSetConsoleMode.Call(uintptr(handle), enableProcessedOutput|enableWrapAtEolOutput|enableVirtualTerminalProcessing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
|
||||||
func IsTerminal(f io.Writer) bool {
|
|
||||||
switch v := f.(type) {
|
|
||||||
case *os.File:
|
|
||||||
var st uint32
|
|
||||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
|
|
||||||
return r != 0 && e == 0
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
45
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
45
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
|
@ -14,7 +14,7 @@ const (
|
||||||
red = 31
|
red = 31
|
||||||
green = 32
|
green = 32
|
||||||
yellow = 33
|
yellow = 33
|
||||||
blue = 34
|
blue = 36
|
||||||
gray = 37
|
gray = 37
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ func init() {
|
||||||
baseTimestamp = time.Now()
|
baseTimestamp = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TextFormatter formats logs into text
|
||||||
type TextFormatter struct {
|
type TextFormatter struct {
|
||||||
// Set to true to bypass checking for a TTY before outputting colors.
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||||
ForceColors bool
|
ForceColors bool
|
||||||
|
@ -52,10 +53,6 @@ type TextFormatter struct {
|
||||||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||||
QuoteEmptyFields bool
|
QuoteEmptyFields bool
|
||||||
|
|
||||||
// QuoteCharacter can be set to the override the default quoting character "
|
|
||||||
// with something else. For example: ', or `.
|
|
||||||
QuoteCharacter string
|
|
||||||
|
|
||||||
// Whether the logger's out is to a terminal
|
// Whether the logger's out is to a terminal
|
||||||
isTerminal bool
|
isTerminal bool
|
||||||
|
|
||||||
|
@ -63,14 +60,12 @@ type TextFormatter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) init(entry *Entry) {
|
func (f *TextFormatter) init(entry *Entry) {
|
||||||
if len(f.QuoteCharacter) == 0 {
|
|
||||||
f.QuoteCharacter = "\""
|
|
||||||
}
|
|
||||||
if entry.Logger != nil {
|
if entry.Logger != nil {
|
||||||
f.isTerminal = IsTerminal(entry.Logger.Out)
|
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format renders a single log entry
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
var b *bytes.Buffer
|
var b *bytes.Buffer
|
||||||
keys := make([]string, 0, len(entry.Data))
|
keys := make([]string, 0, len(entry.Data))
|
||||||
|
@ -95,7 +90,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
timestampFormat := f.TimestampFormat
|
||||||
if timestampFormat == "" {
|
if timestampFormat == "" {
|
||||||
timestampFormat = DefaultTimestampFormat
|
timestampFormat = defaultTimestampFormat
|
||||||
}
|
}
|
||||||
if isColored {
|
if isColored {
|
||||||
f.printColored(b, entry, keys, timestampFormat)
|
f.printColored(b, entry, keys, timestampFormat)
|
||||||
|
@ -153,7 +148,7 @@ func (f *TextFormatter) needsQuoting(text string) bool {
|
||||||
if !((ch >= 'a' && ch <= 'z') ||
|
if !((ch >= 'a' && ch <= 'z') ||
|
||||||
(ch >= 'A' && ch <= 'Z') ||
|
(ch >= 'A' && ch <= 'Z') ||
|
||||||
(ch >= '0' && ch <= '9') ||
|
(ch >= '0' && ch <= '9') ||
|
||||||
ch == '-' || ch == '.') {
|
ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,29 +156,23 @@ func (f *TextFormatter) needsQuoting(text string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||||
|
if b.Len() > 0 {
|
||||||
|
b.WriteByte(' ')
|
||||||
|
}
|
||||||
b.WriteString(key)
|
b.WriteString(key)
|
||||||
b.WriteByte('=')
|
b.WriteByte('=')
|
||||||
f.appendValue(b, value)
|
f.appendValue(b, value)
|
||||||
b.WriteByte(' ')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
|
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
|
||||||
switch value := value.(type) {
|
stringVal, ok := value.(string)
|
||||||
case string:
|
if !ok {
|
||||||
if !f.needsQuoting(value) {
|
stringVal = fmt.Sprint(value)
|
||||||
b.WriteString(value)
|
}
|
||||||
|
|
||||||
|
if !f.needsQuoting(stringVal) {
|
||||||
|
b.WriteString(stringVal)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
|
b.WriteString(fmt.Sprintf("%q", stringVal))
|
||||||
}
|
|
||||||
case error:
|
|
||||||
errmsg := value.Error()
|
|
||||||
if !f.needsQuoting(errmsg) {
|
|
||||||
b.WriteString(errmsg)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fmt.Fprint(b, value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
105
vendor/github.com/spf13/pflag/bytes.go
generated
vendored
Normal file
105
vendor/github.com/spf13/pflag/bytes.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
|
||||||
|
type bytesHexValue []byte
|
||||||
|
|
||||||
|
func (bytesHex bytesHexValue) String() string {
|
||||||
|
return fmt.Sprintf("%X", []byte(bytesHex))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bytesHex *bytesHexValue) Set(value string) error {
|
||||||
|
bin, err := hex.DecodeString(strings.TrimSpace(value))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*bytesHex = bin
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*bytesHexValue) Type() string {
|
||||||
|
return "bytesHex"
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue {
|
||||||
|
*p = val
|
||||||
|
return (*bytesHexValue)(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bytesHexConv(sval string) (interface{}, error) {
|
||||||
|
|
||||||
|
bin, err := hex.DecodeString(sval)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return bin, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytesHex return the []byte value of a flag with the given name
|
||||||
|
func (f *FlagSet) GetBytesHex(name string) ([]byte, error) {
|
||||||
|
val, err := f.getFlagType(name, "bytesHex", bytesHexConv)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return val.([]byte), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to an []byte variable in which to store the value of the flag.
|
||||||
|
func (f *FlagSet) BytesHexVar(p *[]byte, name string, value []byte, usage string) {
|
||||||
|
f.VarP(newBytesHexValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
|
||||||
|
f.VarP(newBytesHexValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to an []byte variable in which to store the value of the flag.
|
||||||
|
func BytesHexVar(p *[]byte, name string, value []byte, usage string) {
|
||||||
|
CommandLine.VarP(newBytesHexValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
|
||||||
|
CommandLine.VarP(newBytesHexValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesHex defines an []byte flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of an []byte variable that stores the value of the flag.
|
||||||
|
func (f *FlagSet) BytesHex(name string, value []byte, usage string) *[]byte {
|
||||||
|
p := new([]byte)
|
||||||
|
f.BytesHexVarP(p, name, "", value, usage)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
|
||||||
|
p := new([]byte)
|
||||||
|
f.BytesHexVarP(p, name, shorthand, value, usage)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesHex defines an []byte flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of an []byte variable that stores the value of the flag.
|
||||||
|
func BytesHex(name string, value []byte, usage string) *[]byte {
|
||||||
|
return CommandLine.BytesHexP(name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
|
||||||
|
return CommandLine.BytesHexP(name, shorthand, value, usage)
|
||||||
|
}
|
12
vendor/github.com/spf13/pflag/count.go
generated
vendored
12
vendor/github.com/spf13/pflag/count.go
generated
vendored
|
@ -11,13 +11,13 @@ func newCountValue(val int, p *int) *countValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *countValue) Set(s string) error {
|
func (i *countValue) Set(s string) error {
|
||||||
v, err := strconv.ParseInt(s, 0, 64)
|
// "+1" means that no specific value was passed, so increment
|
||||||
// -1 means that no specific value was passed, so increment
|
if s == "+1" {
|
||||||
if v == -1 {
|
|
||||||
*i = countValue(*i + 1)
|
*i = countValue(*i + 1)
|
||||||
} else {
|
return nil
|
||||||
*i = countValue(v)
|
|
||||||
}
|
}
|
||||||
|
v, err := strconv.ParseInt(s, 0, 0)
|
||||||
|
*i = countValue(v)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func (f *FlagSet) CountVar(p *int, name string, usage string) {
|
||||||
// CountVarP is like CountVar only take a shorthand for the flag name.
|
// CountVarP is like CountVar only take a shorthand for the flag name.
|
||||||
func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) {
|
func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) {
|
||||||
flag := f.VarPF(newCountValue(0, p), name, shorthand, usage)
|
flag := f.VarPF(newCountValue(0, p), name, shorthand, usage)
|
||||||
flag.NoOptDefVal = "-1"
|
flag.NoOptDefVal = "+1"
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set
|
// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set
|
||||||
|
|
128
vendor/github.com/spf13/pflag/duration_slice.go
generated
vendored
Normal file
128
vendor/github.com/spf13/pflag/duration_slice.go
generated
vendored
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -- durationSlice Value
|
||||||
|
type durationSliceValue struct {
|
||||||
|
value *[]time.Duration
|
||||||
|
changed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDurationSliceValue(val []time.Duration, p *[]time.Duration) *durationSliceValue {
|
||||||
|
dsv := new(durationSliceValue)
|
||||||
|
dsv.value = p
|
||||||
|
*dsv.value = val
|
||||||
|
return dsv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *durationSliceValue) Set(val string) error {
|
||||||
|
ss := strings.Split(val, ",")
|
||||||
|
out := make([]time.Duration, len(ss))
|
||||||
|
for i, d := range ss {
|
||||||
|
var err error
|
||||||
|
out[i], err = time.ParseDuration(d)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if !s.changed {
|
||||||
|
*s.value = out
|
||||||
|
} else {
|
||||||
|
*s.value = append(*s.value, out...)
|
||||||
|
}
|
||||||
|
s.changed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *durationSliceValue) Type() string {
|
||||||
|
return "durationSlice"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *durationSliceValue) String() string {
|
||||||
|
out := make([]string, len(*s.value))
|
||||||
|
for i, d := range *s.value {
|
||||||
|
out[i] = fmt.Sprintf("%s", d)
|
||||||
|
}
|
||||||
|
return "[" + strings.Join(out, ",") + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func durationSliceConv(val string) (interface{}, error) {
|
||||||
|
val = strings.Trim(val, "[]")
|
||||||
|
// Empty string would cause a slice with one (empty) entry
|
||||||
|
if len(val) == 0 {
|
||||||
|
return []time.Duration{}, nil
|
||||||
|
}
|
||||||
|
ss := strings.Split(val, ",")
|
||||||
|
out := make([]time.Duration, len(ss))
|
||||||
|
for i, d := range ss {
|
||||||
|
var err error
|
||||||
|
out[i], err = time.ParseDuration(d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDurationSlice returns the []time.Duration value of a flag with the given name
|
||||||
|
func (f *FlagSet) GetDurationSlice(name string) ([]time.Duration, error) {
|
||||||
|
val, err := f.getFlagType(name, "durationSlice", durationSliceConv)
|
||||||
|
if err != nil {
|
||||||
|
return []time.Duration{}, err
|
||||||
|
}
|
||||||
|
return val.([]time.Duration), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationSliceVar defines a durationSlice flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to a []time.Duration variable in which to store the value of the flag.
|
||||||
|
func (f *FlagSet) DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
|
||||||
|
f.VarP(newDurationSliceValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
|
||||||
|
f.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationSliceVar defines a duration[] flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to a duration[] variable in which to store the value of the flag.
|
||||||
|
func DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
|
||||||
|
CommandLine.VarP(newDurationSliceValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
|
||||||
|
CommandLine.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of a []time.Duration variable that stores the value of the flag.
|
||||||
|
func (f *FlagSet) DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
|
||||||
|
p := []time.Duration{}
|
||||||
|
f.DurationSliceVarP(&p, name, "", value, usage)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
|
||||||
|
p := []time.Duration{}
|
||||||
|
f.DurationSliceVarP(&p, name, shorthand, value, usage)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of a []time.Duration variable that stores the value of the flag.
|
||||||
|
func DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
|
||||||
|
return CommandLine.DurationSliceP(name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
|
||||||
|
return CommandLine.DurationSliceP(name, shorthand, value, usage)
|
||||||
|
}
|
131
vendor/github.com/spf13/pflag/flag.go
generated
vendored
131
vendor/github.com/spf13/pflag/flag.go
generated
vendored
|
@ -101,6 +101,7 @@ package pflag
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
goflag "flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -123,6 +124,12 @@ const (
|
||||||
PanicOnError
|
PanicOnError
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ParseErrorsWhitelist defines the parsing errors that can be ignored
|
||||||
|
type ParseErrorsWhitelist struct {
|
||||||
|
// UnknownFlags will ignore unknown flags errors and continue parsing rest of the flags
|
||||||
|
UnknownFlags bool
|
||||||
|
}
|
||||||
|
|
||||||
// NormalizedName is a flag name that has been normalized according to rules
|
// NormalizedName is a flag name that has been normalized according to rules
|
||||||
// for the FlagSet (e.g. making '-' and '_' equivalent).
|
// for the FlagSet (e.g. making '-' and '_' equivalent).
|
||||||
type NormalizedName string
|
type NormalizedName string
|
||||||
|
@ -138,6 +145,9 @@ type FlagSet struct {
|
||||||
// help/usage messages.
|
// help/usage messages.
|
||||||
SortFlags bool
|
SortFlags bool
|
||||||
|
|
||||||
|
// ParseErrorsWhitelist is used to configure a whitelist of errors
|
||||||
|
ParseErrorsWhitelist ParseErrorsWhitelist
|
||||||
|
|
||||||
name string
|
name string
|
||||||
parsed bool
|
parsed bool
|
||||||
actual map[NormalizedName]*Flag
|
actual map[NormalizedName]*Flag
|
||||||
|
@ -153,6 +163,8 @@ type FlagSet struct {
|
||||||
output io.Writer // nil means stderr; use out() accessor
|
output io.Writer // nil means stderr; use out() accessor
|
||||||
interspersed bool // allow interspersed option/non-option args
|
interspersed bool // allow interspersed option/non-option args
|
||||||
normalizeNameFunc func(f *FlagSet, name string) NormalizedName
|
normalizeNameFunc func(f *FlagSet, name string) NormalizedName
|
||||||
|
|
||||||
|
addedGoFlagSets []*goflag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Flag represents the state of a flag.
|
// A Flag represents the state of a flag.
|
||||||
|
@ -202,12 +214,18 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
|
||||||
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
|
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
|
||||||
f.normalizeNameFunc = n
|
f.normalizeNameFunc = n
|
||||||
f.sortedFormal = f.sortedFormal[:0]
|
f.sortedFormal = f.sortedFormal[:0]
|
||||||
for k, v := range f.orderedFormal {
|
for fname, flag := range f.formal {
|
||||||
delete(f.formal, NormalizedName(v.Name))
|
nname := f.normalizeFlagName(flag.Name)
|
||||||
nname := f.normalizeFlagName(v.Name)
|
if fname == nname {
|
||||||
v.Name = string(nname)
|
continue
|
||||||
f.formal[nname] = v
|
}
|
||||||
f.orderedFormal[k] = v
|
flag.Name = string(nname)
|
||||||
|
delete(f.formal, fname)
|
||||||
|
f.formal[nname] = flag
|
||||||
|
if _, set := f.actual[fname]; set {
|
||||||
|
delete(f.actual, fname)
|
||||||
|
f.actual[nname] = flag
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,16 +279,16 @@ func (f *FlagSet) VisitAll(fn func(*Flag)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasFlags returns a bool to indicate if the FlagSet has any flags definied.
|
// HasFlags returns a bool to indicate if the FlagSet has any flags defined.
|
||||||
func (f *FlagSet) HasFlags() bool {
|
func (f *FlagSet) HasFlags() bool {
|
||||||
return len(f.formal) > 0
|
return len(f.formal) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags
|
// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags
|
||||||
// definied that are not hidden or deprecated.
|
// that are not hidden.
|
||||||
func (f *FlagSet) HasAvailableFlags() bool {
|
func (f *FlagSet) HasAvailableFlags() bool {
|
||||||
for _, flag := range f.formal {
|
for _, flag := range f.formal {
|
||||||
if !flag.Hidden && len(flag.Deprecated) == 0 {
|
if !flag.Hidden {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,6 +398,7 @@ func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error {
|
||||||
return fmt.Errorf("deprecated message for flag %q must be set", name)
|
return fmt.Errorf("deprecated message for flag %q must be set", name)
|
||||||
}
|
}
|
||||||
flag.Deprecated = usageMessage
|
flag.Deprecated = usageMessage
|
||||||
|
flag.Hidden = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,6 +459,7 @@ func (f *FlagSet) Set(name, value string) error {
|
||||||
return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
|
return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !flag.Changed {
|
||||||
if f.actual == nil {
|
if f.actual == nil {
|
||||||
f.actual = make(map[NormalizedName]*Flag)
|
f.actual = make(map[NormalizedName]*Flag)
|
||||||
}
|
}
|
||||||
|
@ -447,6 +467,7 @@ func (f *FlagSet) Set(name, value string) error {
|
||||||
f.orderedActual = append(f.orderedActual, flag)
|
f.orderedActual = append(f.orderedActual, flag)
|
||||||
|
|
||||||
flag.Changed = true
|
flag.Changed = true
|
||||||
|
}
|
||||||
|
|
||||||
if flag.Deprecated != "" {
|
if flag.Deprecated != "" {
|
||||||
fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
|
fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
|
||||||
|
@ -556,6 +577,14 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
|
||||||
name = "int"
|
name = "int"
|
||||||
case "uint64":
|
case "uint64":
|
||||||
name = "uint"
|
name = "uint"
|
||||||
|
case "stringSlice":
|
||||||
|
name = "strings"
|
||||||
|
case "intSlice":
|
||||||
|
name = "ints"
|
||||||
|
case "uintSlice":
|
||||||
|
name = "uints"
|
||||||
|
case "boolSlice":
|
||||||
|
name = "bools"
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -570,11 +599,14 @@ func wrapN(i, slop int, s string) (string, string) {
|
||||||
return s, ""
|
return s, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
w := strings.LastIndexAny(s[:i], " \t")
|
w := strings.LastIndexAny(s[:i], " \t\n")
|
||||||
if w <= 0 {
|
if w <= 0 {
|
||||||
return s, ""
|
return s, ""
|
||||||
}
|
}
|
||||||
|
nlPos := strings.LastIndex(s[:i], "\n")
|
||||||
|
if nlPos > 0 && nlPos < w {
|
||||||
|
return s[:nlPos], s[nlPos+1:]
|
||||||
|
}
|
||||||
return s[:w], s[w+1:]
|
return s[:w], s[w+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +615,7 @@ func wrapN(i, slop int, s string) (string, string) {
|
||||||
// caller). Pass `w` == 0 to do no wrapping
|
// caller). Pass `w` == 0 to do no wrapping
|
||||||
func wrap(i, w int, s string) string {
|
func wrap(i, w int, s string) string {
|
||||||
if w == 0 {
|
if w == 0 {
|
||||||
return s
|
return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// space between indent i and end of line width w into which
|
// space between indent i and end of line width w into which
|
||||||
|
@ -601,7 +633,7 @@ func wrap(i, w int, s string) string {
|
||||||
}
|
}
|
||||||
// If still not enough space then don't even try to wrap.
|
// If still not enough space then don't even try to wrap.
|
||||||
if wrap < 24 {
|
if wrap < 24 {
|
||||||
return s
|
return strings.Replace(s, "\n", r, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to avoid short orphan words on the final line, by
|
// Try to avoid short orphan words on the final line, by
|
||||||
|
@ -613,14 +645,14 @@ func wrap(i, w int, s string) string {
|
||||||
// Handle first line, which is indented by the caller (or the
|
// Handle first line, which is indented by the caller (or the
|
||||||
// special case above)
|
// special case above)
|
||||||
l, s = wrapN(wrap, slop, s)
|
l, s = wrapN(wrap, slop, s)
|
||||||
r = r + l
|
r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||||
|
|
||||||
// Now wrap the rest
|
// Now wrap the rest
|
||||||
for s != "" {
|
for s != "" {
|
||||||
var t string
|
var t string
|
||||||
|
|
||||||
t, s = wrapN(wrap, slop, s)
|
t, s = wrapN(wrap, slop, s)
|
||||||
r = r + "\n" + strings.Repeat(" ", i) + t
|
r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
@ -637,7 +669,7 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
|
||||||
|
|
||||||
maxlen := 0
|
maxlen := 0
|
||||||
f.VisitAll(func(flag *Flag) {
|
f.VisitAll(func(flag *Flag) {
|
||||||
if flag.Deprecated != "" || flag.Hidden {
|
if flag.Hidden {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,6 +692,10 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
|
||||||
if flag.NoOptDefVal != "true" {
|
if flag.NoOptDefVal != "true" {
|
||||||
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||||
}
|
}
|
||||||
|
case "count":
|
||||||
|
if flag.NoOptDefVal != "+1" {
|
||||||
|
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||||
}
|
}
|
||||||
|
@ -680,6 +716,9 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
|
||||||
line += fmt.Sprintf(" (default %s)", flag.DefValue)
|
line += fmt.Sprintf(" (default %s)", flag.DefValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(flag.Deprecated) != 0 {
|
||||||
|
line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
|
||||||
|
}
|
||||||
|
|
||||||
lines = append(lines, line)
|
lines = append(lines, line)
|
||||||
})
|
})
|
||||||
|
@ -857,8 +896,10 @@ func VarP(value Value, name, shorthand, usage string) {
|
||||||
// returns the error.
|
// returns the error.
|
||||||
func (f *FlagSet) failf(format string, a ...interface{}) error {
|
func (f *FlagSet) failf(format string, a ...interface{}) error {
|
||||||
err := fmt.Errorf(format, a...)
|
err := fmt.Errorf(format, a...)
|
||||||
|
if f.errorHandling != ContinueOnError {
|
||||||
fmt.Fprintln(f.out(), err)
|
fmt.Fprintln(f.out(), err)
|
||||||
f.usage()
|
f.usage()
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,6 +915,25 @@ func (f *FlagSet) usage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--unknown (args will be empty)
|
||||||
|
//--unknown --next-flag ... (args will be --next-flag ...)
|
||||||
|
//--unknown arg ... (args will be arg ...)
|
||||||
|
func stripUnknownFlagValue(args []string) []string {
|
||||||
|
if len(args) == 0 {
|
||||||
|
//--unknown
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
first := args[0]
|
||||||
|
if first[0] == '-' {
|
||||||
|
//--unknown --next-flag ...
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
//--unknown arg ... (args will be arg ...)
|
||||||
|
return args[1:]
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {
|
func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {
|
||||||
a = args
|
a = args
|
||||||
name := s[2:]
|
name := s[2:]
|
||||||
|
@ -885,14 +945,25 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
|
||||||
split := strings.SplitN(name, "=", 2)
|
split := strings.SplitN(name, "=", 2)
|
||||||
name = split[0]
|
name = split[0]
|
||||||
flag, exists := f.formal[f.normalizeFlagName(name)]
|
flag, exists := f.formal[f.normalizeFlagName(name)]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
if name == "help" { // special case for nice help message.
|
switch {
|
||||||
|
case name == "help":
|
||||||
f.usage()
|
f.usage()
|
||||||
return a, ErrHelp
|
return a, ErrHelp
|
||||||
|
case f.ParseErrorsWhitelist.UnknownFlags:
|
||||||
|
// --unknown=unknownval arg ...
|
||||||
|
// we do not want to lose arg in this case
|
||||||
|
if len(split) >= 2 {
|
||||||
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return stripUnknownFlagValue(a), nil
|
||||||
|
default:
|
||||||
err = f.failf("unknown flag: --%s", name)
|
err = f.failf("unknown flag: --%s", name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var value string
|
var value string
|
||||||
if len(split) == 2 {
|
if len(split) == 2 {
|
||||||
|
@ -912,6 +983,9 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fn(flag, value)
|
err = fn(flag, value)
|
||||||
|
if err != nil {
|
||||||
|
f.failf(err.Error())
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -926,14 +1000,26 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse
|
||||||
|
|
||||||
flag, exists := f.shorthands[c]
|
flag, exists := f.shorthands[c]
|
||||||
if !exists {
|
if !exists {
|
||||||
if c == 'h' { // special case for nice help message.
|
switch {
|
||||||
|
case c == 'h':
|
||||||
f.usage()
|
f.usage()
|
||||||
err = ErrHelp
|
err = ErrHelp
|
||||||
return
|
return
|
||||||
|
case f.ParseErrorsWhitelist.UnknownFlags:
|
||||||
|
// '-f=arg arg ...'
|
||||||
|
// we do not want to lose arg in this case
|
||||||
|
if len(shorthands) > 2 && shorthands[1] == '=' {
|
||||||
|
outShorts = ""
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outArgs = stripUnknownFlagValue(outArgs)
|
||||||
|
return
|
||||||
|
default:
|
||||||
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
|
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var value string
|
var value string
|
||||||
if len(shorthands) > 2 && shorthands[1] == '=' {
|
if len(shorthands) > 2 && shorthands[1] == '=' {
|
||||||
|
@ -962,6 +1048,9 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fn(flag, value)
|
err = fn(flag, value)
|
||||||
|
if err != nil {
|
||||||
|
f.failf(err.Error())
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1016,6 +1105,11 @@ func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) {
|
||||||
// are defined and before flags are accessed by the program.
|
// are defined and before flags are accessed by the program.
|
||||||
// The return value will be ErrHelp if -help was set but not defined.
|
// The return value will be ErrHelp if -help was set but not defined.
|
||||||
func (f *FlagSet) Parse(arguments []string) error {
|
func (f *FlagSet) Parse(arguments []string) error {
|
||||||
|
if f.addedGoFlagSets != nil {
|
||||||
|
for _, goFlagSet := range f.addedGoFlagSets {
|
||||||
|
goFlagSet.Parse(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
f.parsed = true
|
f.parsed = true
|
||||||
|
|
||||||
if len(arguments) < 0 {
|
if len(arguments) < 0 {
|
||||||
|
@ -1034,6 +1128,7 @@ func (f *FlagSet) Parse(arguments []string) error {
|
||||||
case ContinueOnError:
|
case ContinueOnError:
|
||||||
return err
|
return err
|
||||||
case ExitOnError:
|
case ExitOnError:
|
||||||
|
fmt.Println(err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
case PanicOnError:
|
case PanicOnError:
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
4
vendor/github.com/spf13/pflag/golangflag.go
generated
vendored
4
vendor/github.com/spf13/pflag/golangflag.go
generated
vendored
|
@ -98,4 +98,8 @@ func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) {
|
||||||
newSet.VisitAll(func(goflag *goflag.Flag) {
|
newSet.VisitAll(func(goflag *goflag.Flag) {
|
||||||
f.AddGoFlag(goflag)
|
f.AddGoFlag(goflag)
|
||||||
})
|
})
|
||||||
|
if f.addedGoFlagSets == nil {
|
||||||
|
f.addedGoFlagSets = make([]*goflag.FlagSet, 0)
|
||||||
|
}
|
||||||
|
f.addedGoFlagSets = append(f.addedGoFlagSets, newSet)
|
||||||
}
|
}
|
||||||
|
|
88
vendor/github.com/spf13/pflag/int16.go
generated
vendored
Normal file
88
vendor/github.com/spf13/pflag/int16.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// -- int16 Value
|
||||||
|
type int16Value int16
|
||||||
|
|
||||||
|
func newInt16Value(val int16, p *int16) *int16Value {
|
||||||
|
*p = val
|
||||||
|
return (*int16Value)(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *int16Value) Set(s string) error {
|
||||||
|
v, err := strconv.ParseInt(s, 0, 16)
|
||||||
|
*i = int16Value(v)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *int16Value) Type() string {
|
||||||
|
return "int16"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *int16Value) String() string { return strconv.FormatInt(int64(*i), 10) }
|
||||||
|
|
||||||
|
func int16Conv(sval string) (interface{}, error) {
|
||||||
|
v, err := strconv.ParseInt(sval, 0, 16)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int16(v), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt16 returns the int16 value of a flag with the given name
|
||||||
|
func (f *FlagSet) GetInt16(name string) (int16, error) {
|
||||||
|
val, err := f.getFlagType(name, "int16", int16Conv)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return val.(int16), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Var defines an int16 flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to an int16 variable in which to store the value of the flag.
|
||||||
|
func (f *FlagSet) Int16Var(p *int16, name string, value int16, usage string) {
|
||||||
|
f.VarP(newInt16Value(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) Int16VarP(p *int16, name, shorthand string, value int16, usage string) {
|
||||||
|
f.VarP(newInt16Value(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Var defines an int16 flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to an int16 variable in which to store the value of the flag.
|
||||||
|
func Int16Var(p *int16, name string, value int16, usage string) {
|
||||||
|
CommandLine.VarP(newInt16Value(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func Int16VarP(p *int16, name, shorthand string, value int16, usage string) {
|
||||||
|
CommandLine.VarP(newInt16Value(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16 defines an int16 flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of an int16 variable that stores the value of the flag.
|
||||||
|
func (f *FlagSet) Int16(name string, value int16, usage string) *int16 {
|
||||||
|
p := new(int16)
|
||||||
|
f.Int16VarP(p, name, "", value, usage)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) Int16P(name, shorthand string, value int16, usage string) *int16 {
|
||||||
|
p := new(int16)
|
||||||
|
f.Int16VarP(p, name, shorthand, value, usage)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16 defines an int16 flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of an int16 variable that stores the value of the flag.
|
||||||
|
func Int16(name string, value int16, usage string) *int16 {
|
||||||
|
return CommandLine.Int16P(name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func Int16P(name, shorthand string, value int16, usage string) *int16 {
|
||||||
|
return CommandLine.Int16P(name, shorthand, value, usage)
|
||||||
|
}
|
8
vendor/github.com/spf13/pflag/string_array.go
generated
vendored
8
vendor/github.com/spf13/pflag/string_array.go
generated
vendored
|
@ -52,7 +52,7 @@ func (f *FlagSet) GetStringArray(name string) ([]string, error) {
|
||||||
|
|
||||||
// StringArrayVar defines a string flag with specified name, default value, and usage string.
|
// StringArrayVar defines a string flag with specified name, default value, and usage string.
|
||||||
// The argument p points to a []string variable in which to store the values of the multiple flags.
|
// The argument p points to a []string variable in which to store the values of the multiple flags.
|
||||||
// The value of each argument will not try to be separated by comma
|
// The value of each argument will not try to be separated by comma. Use a StringSlice for that.
|
||||||
func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) {
|
func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) {
|
||||||
f.VarP(newStringArrayValue(value, p), name, "", usage)
|
f.VarP(newStringArrayValue(value, p), name, "", usage)
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []s
|
||||||
|
|
||||||
// StringArrayVar defines a string flag with specified name, default value, and usage string.
|
// StringArrayVar defines a string flag with specified name, default value, and usage string.
|
||||||
// The argument p points to a []string variable in which to store the value of the flag.
|
// The argument p points to a []string variable in which to store the value of the flag.
|
||||||
// The value of each argument will not try to be separated by comma
|
// The value of each argument will not try to be separated by comma. Use a StringSlice for that.
|
||||||
func StringArrayVar(p *[]string, name string, value []string, usage string) {
|
func StringArrayVar(p *[]string, name string, value []string, usage string) {
|
||||||
CommandLine.VarP(newStringArrayValue(value, p), name, "", usage)
|
CommandLine.VarP(newStringArrayValue(value, p), name, "", usage)
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage
|
||||||
|
|
||||||
// StringArray defines a string flag with specified name, default value, and usage string.
|
// StringArray defines a string flag with specified name, default value, and usage string.
|
||||||
// The return value is the address of a []string variable that stores the value of the flag.
|
// The return value is the address of a []string variable that stores the value of the flag.
|
||||||
// The value of each argument will not try to be separated by comma
|
// The value of each argument will not try to be separated by comma. Use a StringSlice for that.
|
||||||
func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string {
|
func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string {
|
||||||
p := []string{}
|
p := []string{}
|
||||||
f.StringArrayVarP(&p, name, "", value, usage)
|
f.StringArrayVarP(&p, name, "", value, usage)
|
||||||
|
@ -92,7 +92,7 @@ func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage str
|
||||||
|
|
||||||
// StringArray defines a string flag with specified name, default value, and usage string.
|
// StringArray defines a string flag with specified name, default value, and usage string.
|
||||||
// The return value is the address of a []string variable that stores the value of the flag.
|
// The return value is the address of a []string variable that stores the value of the flag.
|
||||||
// The value of each argument will not try to be separated by comma
|
// The value of each argument will not try to be separated by comma. Use a StringSlice for that.
|
||||||
func StringArray(name string, value []string, usage string) *[]string {
|
func StringArray(name string, value []string, usage string) *[]string {
|
||||||
return CommandLine.StringArrayP(name, "", value, usage)
|
return CommandLine.StringArrayP(name, "", value, usage)
|
||||||
}
|
}
|
||||||
|
|
20
vendor/github.com/spf13/pflag/string_slice.go
generated
vendored
20
vendor/github.com/spf13/pflag/string_slice.go
generated
vendored
|
@ -82,6 +82,11 @@ func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
|
||||||
|
|
||||||
// StringSliceVar defines a string flag with specified name, default value, and usage string.
|
// StringSliceVar defines a string flag with specified name, default value, and usage string.
|
||||||
// The argument p points to a []string variable in which to store the value of the flag.
|
// The argument p points to a []string variable in which to store the value of the flag.
|
||||||
|
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
|
||||||
|
// For example:
|
||||||
|
// --ss="v1,v2" -ss="v3"
|
||||||
|
// will result in
|
||||||
|
// []string{"v1", "v2", "v3"}
|
||||||
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
|
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
|
||||||
f.VarP(newStringSliceValue(value, p), name, "", usage)
|
f.VarP(newStringSliceValue(value, p), name, "", usage)
|
||||||
}
|
}
|
||||||
|
@ -93,6 +98,11 @@ func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []s
|
||||||
|
|
||||||
// StringSliceVar defines a string flag with specified name, default value, and usage string.
|
// StringSliceVar defines a string flag with specified name, default value, and usage string.
|
||||||
// The argument p points to a []string variable in which to store the value of the flag.
|
// The argument p points to a []string variable in which to store the value of the flag.
|
||||||
|
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
|
||||||
|
// For example:
|
||||||
|
// --ss="v1,v2" -ss="v3"
|
||||||
|
// will result in
|
||||||
|
// []string{"v1", "v2", "v3"}
|
||||||
func StringSliceVar(p *[]string, name string, value []string, usage string) {
|
func StringSliceVar(p *[]string, name string, value []string, usage string) {
|
||||||
CommandLine.VarP(newStringSliceValue(value, p), name, "", usage)
|
CommandLine.VarP(newStringSliceValue(value, p), name, "", usage)
|
||||||
}
|
}
|
||||||
|
@ -104,6 +114,11 @@ func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage
|
||||||
|
|
||||||
// StringSlice defines a string flag with specified name, default value, and usage string.
|
// StringSlice defines a string flag with specified name, default value, and usage string.
|
||||||
// The return value is the address of a []string variable that stores the value of the flag.
|
// The return value is the address of a []string variable that stores the value of the flag.
|
||||||
|
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
|
||||||
|
// For example:
|
||||||
|
// --ss="v1,v2" -ss="v3"
|
||||||
|
// will result in
|
||||||
|
// []string{"v1", "v2", "v3"}
|
||||||
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
|
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
|
||||||
p := []string{}
|
p := []string{}
|
||||||
f.StringSliceVarP(&p, name, "", value, usage)
|
f.StringSliceVarP(&p, name, "", value, usage)
|
||||||
|
@ -119,6 +134,11 @@ func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage str
|
||||||
|
|
||||||
// StringSlice defines a string flag with specified name, default value, and usage string.
|
// StringSlice defines a string flag with specified name, default value, and usage string.
|
||||||
// The return value is the address of a []string variable that stores the value of the flag.
|
// The return value is the address of a []string variable that stores the value of the flag.
|
||||||
|
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
|
||||||
|
// For example:
|
||||||
|
// --ss="v1,v2" -ss="v3"
|
||||||
|
// will result in
|
||||||
|
// []string{"v1", "v2", "v3"}
|
||||||
func StringSlice(name string, value []string, usage string) *[]string {
|
func StringSlice(name string, value []string, usage string) *[]string {
|
||||||
return CommandLine.StringSliceP(name, "", value, usage)
|
return CommandLine.StringSliceP(name, "", value, usage)
|
||||||
}
|
}
|
||||||
|
|
6
vendor/github.com/xuyu/goredis/redis.go
generated
vendored
6
vendor/github.com/xuyu/goredis/redis.go
generated
vendored
|
@ -331,7 +331,6 @@ func (r *Redis) ExecuteCommand(args ...interface{}) (*Reply, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() { r.pool.Put(c) }()
|
|
||||||
if err := c.SendCommand(args...); err != nil {
|
if err := c.SendCommand(args...); err != nil {
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -356,7 +355,10 @@ func (r *Redis) ExecuteCommand(args ...interface{}) (*Reply, error) {
|
||||||
if err = c.SendCommand(args...); err != nil {
|
if err = c.SendCommand(args...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return c.RecvReply()
|
rp, err = c.RecvReply()
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
r.pool.Put(c)
|
||||||
}
|
}
|
||||||
return rp, err
|
return rp, err
|
||||||
}
|
}
|
||||||
|
|
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/crypto/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at https://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/crypto/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at https://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/crypto/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/crypto/PATENTS
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
951
vendor/golang.org/x/crypto/ssh/terminal/terminal.go
generated
vendored
Normal file
951
vendor/golang.org/x/crypto/ssh/terminal/terminal.go
generated
vendored
Normal file
|
@ -0,0 +1,951 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package terminal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EscapeCodes contains escape sequences that can be written to the terminal in
|
||||||
|
// order to achieve different styles of text.
|
||||||
|
type EscapeCodes struct {
|
||||||
|
// Foreground colors
|
||||||
|
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
|
||||||
|
|
||||||
|
// Reset all attributes
|
||||||
|
Reset []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var vt100EscapeCodes = EscapeCodes{
|
||||||
|
Black: []byte{keyEscape, '[', '3', '0', 'm'},
|
||||||
|
Red: []byte{keyEscape, '[', '3', '1', 'm'},
|
||||||
|
Green: []byte{keyEscape, '[', '3', '2', 'm'},
|
||||||
|
Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
|
||||||
|
Blue: []byte{keyEscape, '[', '3', '4', 'm'},
|
||||||
|
Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
|
||||||
|
Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
|
||||||
|
White: []byte{keyEscape, '[', '3', '7', 'm'},
|
||||||
|
|
||||||
|
Reset: []byte{keyEscape, '[', '0', 'm'},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminal contains the state for running a VT100 terminal that is capable of
|
||||||
|
// reading lines of input.
|
||||||
|
type Terminal struct {
|
||||||
|
// AutoCompleteCallback, if non-null, is called for each keypress with
|
||||||
|
// the full input line and the current position of the cursor (in
|
||||||
|
// bytes, as an index into |line|). If it returns ok=false, the key
|
||||||
|
// press is processed normally. Otherwise it returns a replacement line
|
||||||
|
// and the new cursor position.
|
||||||
|
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
|
||||||
|
|
||||||
|
// Escape contains a pointer to the escape codes for this terminal.
|
||||||
|
// It's always a valid pointer, although the escape codes themselves
|
||||||
|
// may be empty if the terminal doesn't support them.
|
||||||
|
Escape *EscapeCodes
|
||||||
|
|
||||||
|
// lock protects the terminal and the state in this object from
|
||||||
|
// concurrent processing of a key press and a Write() call.
|
||||||
|
lock sync.Mutex
|
||||||
|
|
||||||
|
c io.ReadWriter
|
||||||
|
prompt []rune
|
||||||
|
|
||||||
|
// line is the current line being entered.
|
||||||
|
line []rune
|
||||||
|
// pos is the logical position of the cursor in line
|
||||||
|
pos int
|
||||||
|
// echo is true if local echo is enabled
|
||||||
|
echo bool
|
||||||
|
// pasteActive is true iff there is a bracketed paste operation in
|
||||||
|
// progress.
|
||||||
|
pasteActive bool
|
||||||
|
|
||||||
|
// cursorX contains the current X value of the cursor where the left
|
||||||
|
// edge is 0. cursorY contains the row number where the first row of
|
||||||
|
// the current line is 0.
|
||||||
|
cursorX, cursorY int
|
||||||
|
// maxLine is the greatest value of cursorY so far.
|
||||||
|
maxLine int
|
||||||
|
|
||||||
|
termWidth, termHeight int
|
||||||
|
|
||||||
|
// outBuf contains the terminal data to be sent.
|
||||||
|
outBuf []byte
|
||||||
|
// remainder contains the remainder of any partial key sequences after
|
||||||
|
// a read. It aliases into inBuf.
|
||||||
|
remainder []byte
|
||||||
|
inBuf [256]byte
|
||||||
|
|
||||||
|
// history contains previously entered commands so that they can be
|
||||||
|
// accessed with the up and down keys.
|
||||||
|
history stRingBuffer
|
||||||
|
// historyIndex stores the currently accessed history entry, where zero
|
||||||
|
// means the immediately previous entry.
|
||||||
|
historyIndex int
|
||||||
|
// When navigating up and down the history it's possible to return to
|
||||||
|
// the incomplete, initial line. That value is stored in
|
||||||
|
// historyPending.
|
||||||
|
historyPending string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
|
||||||
|
// a local terminal, that terminal must first have been put into raw mode.
|
||||||
|
// prompt is a string that is written at the start of each input line (i.e.
|
||||||
|
// "> ").
|
||||||
|
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
|
||||||
|
return &Terminal{
|
||||||
|
Escape: &vt100EscapeCodes,
|
||||||
|
c: c,
|
||||||
|
prompt: []rune(prompt),
|
||||||
|
termWidth: 80,
|
||||||
|
termHeight: 24,
|
||||||
|
echo: true,
|
||||||
|
historyIndex: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
keyCtrlD = 4
|
||||||
|
keyCtrlU = 21
|
||||||
|
keyEnter = '\r'
|
||||||
|
keyEscape = 27
|
||||||
|
keyBackspace = 127
|
||||||
|
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
|
||||||
|
keyUp
|
||||||
|
keyDown
|
||||||
|
keyLeft
|
||||||
|
keyRight
|
||||||
|
keyAltLeft
|
||||||
|
keyAltRight
|
||||||
|
keyHome
|
||||||
|
keyEnd
|
||||||
|
keyDeleteWord
|
||||||
|
keyDeleteLine
|
||||||
|
keyClearScreen
|
||||||
|
keyPasteStart
|
||||||
|
keyPasteEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
crlf = []byte{'\r', '\n'}
|
||||||
|
pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
|
||||||
|
pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
|
||||||
|
)
|
||||||
|
|
||||||
|
// bytesToKey tries to parse a key sequence from b. If successful, it returns
|
||||||
|
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
|
||||||
|
func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return utf8.RuneError, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pasteActive {
|
||||||
|
switch b[0] {
|
||||||
|
case 1: // ^A
|
||||||
|
return keyHome, b[1:]
|
||||||
|
case 5: // ^E
|
||||||
|
return keyEnd, b[1:]
|
||||||
|
case 8: // ^H
|
||||||
|
return keyBackspace, b[1:]
|
||||||
|
case 11: // ^K
|
||||||
|
return keyDeleteLine, b[1:]
|
||||||
|
case 12: // ^L
|
||||||
|
return keyClearScreen, b[1:]
|
||||||
|
case 23: // ^W
|
||||||
|
return keyDeleteWord, b[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[0] != keyEscape {
|
||||||
|
if !utf8.FullRune(b) {
|
||||||
|
return utf8.RuneError, b
|
||||||
|
}
|
||||||
|
r, l := utf8.DecodeRune(b)
|
||||||
|
return r, b[l:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
|
||||||
|
switch b[2] {
|
||||||
|
case 'A':
|
||||||
|
return keyUp, b[3:]
|
||||||
|
case 'B':
|
||||||
|
return keyDown, b[3:]
|
||||||
|
case 'C':
|
||||||
|
return keyRight, b[3:]
|
||||||
|
case 'D':
|
||||||
|
return keyLeft, b[3:]
|
||||||
|
case 'H':
|
||||||
|
return keyHome, b[3:]
|
||||||
|
case 'F':
|
||||||
|
return keyEnd, b[3:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
|
||||||
|
switch b[5] {
|
||||||
|
case 'C':
|
||||||
|
return keyAltRight, b[6:]
|
||||||
|
case 'D':
|
||||||
|
return keyAltLeft, b[6:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
|
||||||
|
return keyPasteStart, b[6:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
|
||||||
|
return keyPasteEnd, b[6:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here then we have a key that we don't recognise, or a
|
||||||
|
// partial sequence. It's not clear how one should find the end of a
|
||||||
|
// sequence without knowing them all, but it seems that [a-zA-Z~] only
|
||||||
|
// appears at the end of a sequence.
|
||||||
|
for i, c := range b[0:] {
|
||||||
|
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
|
||||||
|
return keyUnknown, b[i+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return utf8.RuneError, b
|
||||||
|
}
|
||||||
|
|
||||||
|
// queue appends data to the end of t.outBuf
|
||||||
|
func (t *Terminal) queue(data []rune) {
|
||||||
|
t.outBuf = append(t.outBuf, []byte(string(data))...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
|
||||||
|
var space = []rune{' '}
|
||||||
|
|
||||||
|
func isPrintable(key rune) bool {
|
||||||
|
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
|
||||||
|
return key >= 32 && !isInSurrogateArea
|
||||||
|
}
|
||||||
|
|
||||||
|
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
|
||||||
|
// given, logical position in the text.
|
||||||
|
func (t *Terminal) moveCursorToPos(pos int) {
|
||||||
|
if !t.echo {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
x := visualLength(t.prompt) + pos
|
||||||
|
y := x / t.termWidth
|
||||||
|
x = x % t.termWidth
|
||||||
|
|
||||||
|
up := 0
|
||||||
|
if y < t.cursorY {
|
||||||
|
up = t.cursorY - y
|
||||||
|
}
|
||||||
|
|
||||||
|
down := 0
|
||||||
|
if y > t.cursorY {
|
||||||
|
down = y - t.cursorY
|
||||||
|
}
|
||||||
|
|
||||||
|
left := 0
|
||||||
|
if x < t.cursorX {
|
||||||
|
left = t.cursorX - x
|
||||||
|
}
|
||||||
|
|
||||||
|
right := 0
|
||||||
|
if x > t.cursorX {
|
||||||
|
right = x - t.cursorX
|
||||||
|
}
|
||||||
|
|
||||||
|
t.cursorX = x
|
||||||
|
t.cursorY = y
|
||||||
|
t.move(up, down, left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) move(up, down, left, right int) {
|
||||||
|
movement := make([]rune, 3*(up+down+left+right))
|
||||||
|
m := movement
|
||||||
|
for i := 0; i < up; i++ {
|
||||||
|
m[0] = keyEscape
|
||||||
|
m[1] = '['
|
||||||
|
m[2] = 'A'
|
||||||
|
m = m[3:]
|
||||||
|
}
|
||||||
|
for i := 0; i < down; i++ {
|
||||||
|
m[0] = keyEscape
|
||||||
|
m[1] = '['
|
||||||
|
m[2] = 'B'
|
||||||
|
m = m[3:]
|
||||||
|
}
|
||||||
|
for i := 0; i < left; i++ {
|
||||||
|
m[0] = keyEscape
|
||||||
|
m[1] = '['
|
||||||
|
m[2] = 'D'
|
||||||
|
m = m[3:]
|
||||||
|
}
|
||||||
|
for i := 0; i < right; i++ {
|
||||||
|
m[0] = keyEscape
|
||||||
|
m[1] = '['
|
||||||
|
m[2] = 'C'
|
||||||
|
m = m[3:]
|
||||||
|
}
|
||||||
|
|
||||||
|
t.queue(movement)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) clearLineToRight() {
|
||||||
|
op := []rune{keyEscape, '[', 'K'}
|
||||||
|
t.queue(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxLineLength = 4096
|
||||||
|
|
||||||
|
func (t *Terminal) setLine(newLine []rune, newPos int) {
|
||||||
|
if t.echo {
|
||||||
|
t.moveCursorToPos(0)
|
||||||
|
t.writeLine(newLine)
|
||||||
|
for i := len(newLine); i < len(t.line); i++ {
|
||||||
|
t.writeLine(space)
|
||||||
|
}
|
||||||
|
t.moveCursorToPos(newPos)
|
||||||
|
}
|
||||||
|
t.line = newLine
|
||||||
|
t.pos = newPos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) advanceCursor(places int) {
|
||||||
|
t.cursorX += places
|
||||||
|
t.cursorY += t.cursorX / t.termWidth
|
||||||
|
if t.cursorY > t.maxLine {
|
||||||
|
t.maxLine = t.cursorY
|
||||||
|
}
|
||||||
|
t.cursorX = t.cursorX % t.termWidth
|
||||||
|
|
||||||
|
if places > 0 && t.cursorX == 0 {
|
||||||
|
// Normally terminals will advance the current position
|
||||||
|
// when writing a character. But that doesn't happen
|
||||||
|
// for the last character in a line. However, when
|
||||||
|
// writing a character (except a new line) that causes
|
||||||
|
// a line wrap, the position will be advanced two
|
||||||
|
// places.
|
||||||
|
//
|
||||||
|
// So, if we are stopping at the end of a line, we
|
||||||
|
// need to write a newline so that our cursor can be
|
||||||
|
// advanced to the next line.
|
||||||
|
t.outBuf = append(t.outBuf, '\r', '\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) eraseNPreviousChars(n int) {
|
||||||
|
if n == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.pos < n {
|
||||||
|
n = t.pos
|
||||||
|
}
|
||||||
|
t.pos -= n
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
|
||||||
|
copy(t.line[t.pos:], t.line[n+t.pos:])
|
||||||
|
t.line = t.line[:len(t.line)-n]
|
||||||
|
if t.echo {
|
||||||
|
t.writeLine(t.line[t.pos:])
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
t.queue(space)
|
||||||
|
}
|
||||||
|
t.advanceCursor(n)
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// countToLeftWord returns then number of characters from the cursor to the
|
||||||
|
// start of the previous word.
|
||||||
|
func (t *Terminal) countToLeftWord() int {
|
||||||
|
if t.pos == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := t.pos - 1
|
||||||
|
for pos > 0 {
|
||||||
|
if t.line[pos] != ' ' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pos--
|
||||||
|
}
|
||||||
|
for pos > 0 {
|
||||||
|
if t.line[pos] == ' ' {
|
||||||
|
pos++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pos--
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.pos - pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// countToRightWord returns then number of characters from the cursor to the
|
||||||
|
// start of the next word.
|
||||||
|
func (t *Terminal) countToRightWord() int {
|
||||||
|
pos := t.pos
|
||||||
|
for pos < len(t.line) {
|
||||||
|
if t.line[pos] == ' ' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
for pos < len(t.line) {
|
||||||
|
if t.line[pos] != ' ' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
return pos - t.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// visualLength returns the number of visible glyphs in s.
|
||||||
|
func visualLength(runes []rune) int {
|
||||||
|
inEscapeSeq := false
|
||||||
|
length := 0
|
||||||
|
|
||||||
|
for _, r := range runes {
|
||||||
|
switch {
|
||||||
|
case inEscapeSeq:
|
||||||
|
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
|
||||||
|
inEscapeSeq = false
|
||||||
|
}
|
||||||
|
case r == '\x1b':
|
||||||
|
inEscapeSeq = true
|
||||||
|
default:
|
||||||
|
length++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return length
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleKey processes the given key and, optionally, returns a line of text
|
||||||
|
// that the user has entered.
|
||||||
|
func (t *Terminal) handleKey(key rune) (line string, ok bool) {
|
||||||
|
if t.pasteActive && key != keyEnter {
|
||||||
|
t.addKeyToLine(key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch key {
|
||||||
|
case keyBackspace:
|
||||||
|
if t.pos == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.eraseNPreviousChars(1)
|
||||||
|
case keyAltLeft:
|
||||||
|
// move left by a word.
|
||||||
|
t.pos -= t.countToLeftWord()
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
case keyAltRight:
|
||||||
|
// move right by a word.
|
||||||
|
t.pos += t.countToRightWord()
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
case keyLeft:
|
||||||
|
if t.pos == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.pos--
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
case keyRight:
|
||||||
|
if t.pos == len(t.line) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.pos++
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
case keyHome:
|
||||||
|
if t.pos == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.pos = 0
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
case keyEnd:
|
||||||
|
if t.pos == len(t.line) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.pos = len(t.line)
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
case keyUp:
|
||||||
|
entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
|
||||||
|
if !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
if t.historyIndex == -1 {
|
||||||
|
t.historyPending = string(t.line)
|
||||||
|
}
|
||||||
|
t.historyIndex++
|
||||||
|
runes := []rune(entry)
|
||||||
|
t.setLine(runes, len(runes))
|
||||||
|
case keyDown:
|
||||||
|
switch t.historyIndex {
|
||||||
|
case -1:
|
||||||
|
return
|
||||||
|
case 0:
|
||||||
|
runes := []rune(t.historyPending)
|
||||||
|
t.setLine(runes, len(runes))
|
||||||
|
t.historyIndex--
|
||||||
|
default:
|
||||||
|
entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
|
||||||
|
if ok {
|
||||||
|
t.historyIndex--
|
||||||
|
runes := []rune(entry)
|
||||||
|
t.setLine(runes, len(runes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case keyEnter:
|
||||||
|
t.moveCursorToPos(len(t.line))
|
||||||
|
t.queue([]rune("\r\n"))
|
||||||
|
line = string(t.line)
|
||||||
|
ok = true
|
||||||
|
t.line = t.line[:0]
|
||||||
|
t.pos = 0
|
||||||
|
t.cursorX = 0
|
||||||
|
t.cursorY = 0
|
||||||
|
t.maxLine = 0
|
||||||
|
case keyDeleteWord:
|
||||||
|
// Delete zero or more spaces and then one or more characters.
|
||||||
|
t.eraseNPreviousChars(t.countToLeftWord())
|
||||||
|
case keyDeleteLine:
|
||||||
|
// Delete everything from the current cursor position to the
|
||||||
|
// end of line.
|
||||||
|
for i := t.pos; i < len(t.line); i++ {
|
||||||
|
t.queue(space)
|
||||||
|
t.advanceCursor(1)
|
||||||
|
}
|
||||||
|
t.line = t.line[:t.pos]
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
case keyCtrlD:
|
||||||
|
// Erase the character under the current position.
|
||||||
|
// The EOF case when the line is empty is handled in
|
||||||
|
// readLine().
|
||||||
|
if t.pos < len(t.line) {
|
||||||
|
t.pos++
|
||||||
|
t.eraseNPreviousChars(1)
|
||||||
|
}
|
||||||
|
case keyCtrlU:
|
||||||
|
t.eraseNPreviousChars(t.pos)
|
||||||
|
case keyClearScreen:
|
||||||
|
// Erases the screen and moves the cursor to the home position.
|
||||||
|
t.queue([]rune("\x1b[2J\x1b[H"))
|
||||||
|
t.queue(t.prompt)
|
||||||
|
t.cursorX, t.cursorY = 0, 0
|
||||||
|
t.advanceCursor(visualLength(t.prompt))
|
||||||
|
t.setLine(t.line, t.pos)
|
||||||
|
default:
|
||||||
|
if t.AutoCompleteCallback != nil {
|
||||||
|
prefix := string(t.line[:t.pos])
|
||||||
|
suffix := string(t.line[t.pos:])
|
||||||
|
|
||||||
|
t.lock.Unlock()
|
||||||
|
newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
|
||||||
|
t.lock.Lock()
|
||||||
|
|
||||||
|
if completeOk {
|
||||||
|
t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !isPrintable(key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(t.line) == maxLineLength {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.addKeyToLine(key)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// addKeyToLine inserts the given key at the current position in the current
|
||||||
|
// line.
|
||||||
|
func (t *Terminal) addKeyToLine(key rune) {
|
||||||
|
if len(t.line) == cap(t.line) {
|
||||||
|
newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
|
||||||
|
copy(newLine, t.line)
|
||||||
|
t.line = newLine
|
||||||
|
}
|
||||||
|
t.line = t.line[:len(t.line)+1]
|
||||||
|
copy(t.line[t.pos+1:], t.line[t.pos:])
|
||||||
|
t.line[t.pos] = key
|
||||||
|
if t.echo {
|
||||||
|
t.writeLine(t.line[t.pos:])
|
||||||
|
}
|
||||||
|
t.pos++
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) writeLine(line []rune) {
|
||||||
|
for len(line) != 0 {
|
||||||
|
remainingOnLine := t.termWidth - t.cursorX
|
||||||
|
todo := len(line)
|
||||||
|
if todo > remainingOnLine {
|
||||||
|
todo = remainingOnLine
|
||||||
|
}
|
||||||
|
t.queue(line[:todo])
|
||||||
|
t.advanceCursor(visualLength(line[:todo]))
|
||||||
|
line = line[todo:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
|
||||||
|
func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
|
||||||
|
for len(buf) > 0 {
|
||||||
|
i := bytes.IndexByte(buf, '\n')
|
||||||
|
todo := len(buf)
|
||||||
|
if i >= 0 {
|
||||||
|
todo = i
|
||||||
|
}
|
||||||
|
|
||||||
|
var nn int
|
||||||
|
nn, err = w.Write(buf[:todo])
|
||||||
|
n += nn
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
buf = buf[todo:]
|
||||||
|
|
||||||
|
if i >= 0 {
|
||||||
|
if _, err = w.Write(crlf); err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
buf = buf[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) Write(buf []byte) (n int, err error) {
|
||||||
|
t.lock.Lock()
|
||||||
|
defer t.lock.Unlock()
|
||||||
|
|
||||||
|
if t.cursorX == 0 && t.cursorY == 0 {
|
||||||
|
// This is the easy case: there's nothing on the screen that we
|
||||||
|
// have to move out of the way.
|
||||||
|
return writeWithCRLF(t.c, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a prompt and possibly user input on the screen. We
|
||||||
|
// have to clear it first.
|
||||||
|
t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
|
||||||
|
t.cursorX = 0
|
||||||
|
t.clearLineToRight()
|
||||||
|
|
||||||
|
for t.cursorY > 0 {
|
||||||
|
t.move(1 /* up */, 0, 0, 0)
|
||||||
|
t.cursorY--
|
||||||
|
t.clearLineToRight()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = t.c.Write(t.outBuf); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.outBuf = t.outBuf[:0]
|
||||||
|
|
||||||
|
if n, err = writeWithCRLF(t.c, buf); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.writeLine(t.prompt)
|
||||||
|
if t.echo {
|
||||||
|
t.writeLine(t.line)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
|
||||||
|
if _, err = t.c.Write(t.outBuf); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.outBuf = t.outBuf[:0]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadPassword temporarily changes the prompt and reads a password, without
|
||||||
|
// echo, from the terminal.
|
||||||
|
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
|
||||||
|
t.lock.Lock()
|
||||||
|
defer t.lock.Unlock()
|
||||||
|
|
||||||
|
oldPrompt := t.prompt
|
||||||
|
t.prompt = []rune(prompt)
|
||||||
|
t.echo = false
|
||||||
|
|
||||||
|
line, err = t.readLine()
|
||||||
|
|
||||||
|
t.prompt = oldPrompt
|
||||||
|
t.echo = true
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadLine returns a line of input from the terminal.
|
||||||
|
func (t *Terminal) ReadLine() (line string, err error) {
|
||||||
|
t.lock.Lock()
|
||||||
|
defer t.lock.Unlock()
|
||||||
|
|
||||||
|
return t.readLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) readLine() (line string, err error) {
|
||||||
|
// t.lock must be held at this point
|
||||||
|
|
||||||
|
if t.cursorX == 0 && t.cursorY == 0 {
|
||||||
|
t.writeLine(t.prompt)
|
||||||
|
t.c.Write(t.outBuf)
|
||||||
|
t.outBuf = t.outBuf[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
lineIsPasted := t.pasteActive
|
||||||
|
|
||||||
|
for {
|
||||||
|
rest := t.remainder
|
||||||
|
lineOk := false
|
||||||
|
for !lineOk {
|
||||||
|
var key rune
|
||||||
|
key, rest = bytesToKey(rest, t.pasteActive)
|
||||||
|
if key == utf8.RuneError {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !t.pasteActive {
|
||||||
|
if key == keyCtrlD {
|
||||||
|
if len(t.line) == 0 {
|
||||||
|
return "", io.EOF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if key == keyPasteStart {
|
||||||
|
t.pasteActive = true
|
||||||
|
if len(t.line) == 0 {
|
||||||
|
lineIsPasted = true
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if key == keyPasteEnd {
|
||||||
|
t.pasteActive = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !t.pasteActive {
|
||||||
|
lineIsPasted = false
|
||||||
|
}
|
||||||
|
line, lineOk = t.handleKey(key)
|
||||||
|
}
|
||||||
|
if len(rest) > 0 {
|
||||||
|
n := copy(t.inBuf[:], rest)
|
||||||
|
t.remainder = t.inBuf[:n]
|
||||||
|
} else {
|
||||||
|
t.remainder = nil
|
||||||
|
}
|
||||||
|
t.c.Write(t.outBuf)
|
||||||
|
t.outBuf = t.outBuf[:0]
|
||||||
|
if lineOk {
|
||||||
|
if t.echo {
|
||||||
|
t.historyIndex = -1
|
||||||
|
t.history.Add(line)
|
||||||
|
}
|
||||||
|
if lineIsPasted {
|
||||||
|
err = ErrPasteIndicator
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.remainder is a slice at the beginning of t.inBuf
|
||||||
|
// containing a partial key sequence
|
||||||
|
readBuf := t.inBuf[len(t.remainder):]
|
||||||
|
var n int
|
||||||
|
|
||||||
|
t.lock.Unlock()
|
||||||
|
n, err = t.c.Read(readBuf)
|
||||||
|
t.lock.Lock()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.remainder = t.inBuf[:n+len(t.remainder)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPrompt sets the prompt to be used when reading subsequent lines.
|
||||||
|
func (t *Terminal) SetPrompt(prompt string) {
|
||||||
|
t.lock.Lock()
|
||||||
|
defer t.lock.Unlock()
|
||||||
|
|
||||||
|
t.prompt = []rune(prompt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
|
||||||
|
// Move cursor to column zero at the start of the line.
|
||||||
|
t.move(t.cursorY, 0, t.cursorX, 0)
|
||||||
|
t.cursorX, t.cursorY = 0, 0
|
||||||
|
t.clearLineToRight()
|
||||||
|
for t.cursorY < numPrevLines {
|
||||||
|
// Move down a line
|
||||||
|
t.move(0, 1, 0, 0)
|
||||||
|
t.cursorY++
|
||||||
|
t.clearLineToRight()
|
||||||
|
}
|
||||||
|
// Move back to beginning.
|
||||||
|
t.move(t.cursorY, 0, 0, 0)
|
||||||
|
t.cursorX, t.cursorY = 0, 0
|
||||||
|
|
||||||
|
t.queue(t.prompt)
|
||||||
|
t.advanceCursor(visualLength(t.prompt))
|
||||||
|
t.writeLine(t.line)
|
||||||
|
t.moveCursorToPos(t.pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) SetSize(width, height int) error {
|
||||||
|
t.lock.Lock()
|
||||||
|
defer t.lock.Unlock()
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
width = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
oldWidth := t.termWidth
|
||||||
|
t.termWidth, t.termHeight = width, height
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case width == oldWidth:
|
||||||
|
// If the width didn't change then nothing else needs to be
|
||||||
|
// done.
|
||||||
|
return nil
|
||||||
|
case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
|
||||||
|
// If there is nothing on current line and no prompt printed,
|
||||||
|
// just do nothing
|
||||||
|
return nil
|
||||||
|
case width < oldWidth:
|
||||||
|
// Some terminals (e.g. xterm) will truncate lines that were
|
||||||
|
// too long when shinking. Others, (e.g. gnome-terminal) will
|
||||||
|
// attempt to wrap them. For the former, repainting t.maxLine
|
||||||
|
// works great, but that behaviour goes badly wrong in the case
|
||||||
|
// of the latter because they have doubled every full line.
|
||||||
|
|
||||||
|
// We assume that we are working on a terminal that wraps lines
|
||||||
|
// and adjust the cursor position based on every previous line
|
||||||
|
// wrapping and turning into two. This causes the prompt on
|
||||||
|
// xterms to move upwards, which isn't great, but it avoids a
|
||||||
|
// huge mess with gnome-terminal.
|
||||||
|
if t.cursorX >= t.termWidth {
|
||||||
|
t.cursorX = t.termWidth - 1
|
||||||
|
}
|
||||||
|
t.cursorY *= 2
|
||||||
|
t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
|
||||||
|
case width > oldWidth:
|
||||||
|
// If the terminal expands then our position calculations will
|
||||||
|
// be wrong in the future because we think the cursor is
|
||||||
|
// |t.pos| chars into the string, but there will be a gap at
|
||||||
|
// the end of any wrapped line.
|
||||||
|
//
|
||||||
|
// But the position will actually be correct until we move, so
|
||||||
|
// we can move back to the beginning and repaint everything.
|
||||||
|
t.clearAndRepaintLinePlusNPrevious(t.maxLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := t.c.Write(t.outBuf)
|
||||||
|
t.outBuf = t.outBuf[:0]
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type pasteIndicatorError struct{}
|
||||||
|
|
||||||
|
func (pasteIndicatorError) Error() string {
|
||||||
|
return "terminal: ErrPasteIndicator not correctly handled"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrPasteIndicator may be returned from ReadLine as the error, in addition
|
||||||
|
// to valid line data. It indicates that bracketed paste mode is enabled and
|
||||||
|
// that the returned line consists only of pasted data. Programs may wish to
|
||||||
|
// interpret pasted data more literally than typed data.
|
||||||
|
var ErrPasteIndicator = pasteIndicatorError{}
|
||||||
|
|
||||||
|
// SetBracketedPasteMode requests that the terminal bracket paste operations
|
||||||
|
// with markers. Not all terminals support this but, if it is supported, then
|
||||||
|
// enabling this mode will stop any autocomplete callback from running due to
|
||||||
|
// pastes. Additionally, any lines that are completely pasted will be returned
|
||||||
|
// from ReadLine with the error set to ErrPasteIndicator.
|
||||||
|
func (t *Terminal) SetBracketedPasteMode(on bool) {
|
||||||
|
if on {
|
||||||
|
io.WriteString(t.c, "\x1b[?2004h")
|
||||||
|
} else {
|
||||||
|
io.WriteString(t.c, "\x1b[?2004l")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stRingBuffer is a ring buffer of strings.
|
||||||
|
type stRingBuffer struct {
|
||||||
|
// entries contains max elements.
|
||||||
|
entries []string
|
||||||
|
max int
|
||||||
|
// head contains the index of the element most recently added to the ring.
|
||||||
|
head int
|
||||||
|
// size contains the number of elements in the ring.
|
||||||
|
size int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stRingBuffer) Add(a string) {
|
||||||
|
if s.entries == nil {
|
||||||
|
const defaultNumEntries = 100
|
||||||
|
s.entries = make([]string, defaultNumEntries)
|
||||||
|
s.max = defaultNumEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
s.head = (s.head + 1) % s.max
|
||||||
|
s.entries[s.head] = a
|
||||||
|
if s.size < s.max {
|
||||||
|
s.size++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NthPreviousEntry returns the value passed to the nth previous call to Add.
|
||||||
|
// If n is zero then the immediately prior value is returned, if one, then the
|
||||||
|
// next most recent, and so on. If such an element doesn't exist then ok is
|
||||||
|
// false.
|
||||||
|
func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
|
||||||
|
if n >= s.size {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
index := s.head - n
|
||||||
|
if index < 0 {
|
||||||
|
index += s.max
|
||||||
|
}
|
||||||
|
return s.entries[index], true
|
||||||
|
}
|
||||||
|
|
||||||
|
// readPasswordLine reads from reader until it finds \n or io.EOF.
|
||||||
|
// The slice returned does not include the \n.
|
||||||
|
// readPasswordLine also ignores any \r it finds.
|
||||||
|
func readPasswordLine(reader io.Reader) ([]byte, error) {
|
||||||
|
var buf [1]byte
|
||||||
|
var ret []byte
|
||||||
|
|
||||||
|
for {
|
||||||
|
n, err := reader.Read(buf[:])
|
||||||
|
if n > 0 {
|
||||||
|
switch buf[0] {
|
||||||
|
case '\n':
|
||||||
|
return ret, nil
|
||||||
|
case '\r':
|
||||||
|
// remove \r from passwords on Windows
|
||||||
|
default:
|
||||||
|
ret = append(ret, buf[0])
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF && len(ret) > 0 {
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
vendor/golang.org/x/crypto/ssh/terminal/util.go
generated
vendored
Normal file
114
vendor/golang.org/x/crypto/ssh/terminal/util.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
// 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 darwin dragonfly freebsd linux,!appengine netbsd openbsd
|
||||||
|
|
||||||
|
// Package terminal provides support functions for dealing with terminals, as
|
||||||
|
// commonly found on UNIX systems.
|
||||||
|
//
|
||||||
|
// Putting a terminal into raw mode is the most common requirement:
|
||||||
|
//
|
||||||
|
// oldState, err := terminal.MakeRaw(0)
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
// defer terminal.Restore(0, oldState)
|
||||||
|
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// State contains the state of a terminal.
|
||||||
|
type State struct {
|
||||||
|
termios unix.Termios
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||||
|
// restored.
|
||||||
|
func MakeRaw(fd int) (*State, error) {
|
||||||
|
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
oldState := State{termios: *termios}
|
||||||
|
|
||||||
|
// This attempts to replicate the behaviour documented for cfmakeraw in
|
||||||
|
// the termios(3) manpage.
|
||||||
|
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
||||||
|
termios.Oflag &^= unix.OPOST
|
||||||
|
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
||||||
|
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
||||||
|
termios.Cflag |= unix.CS8
|
||||||
|
termios.Cc[unix.VMIN] = 1
|
||||||
|
termios.Cc[unix.VTIME] = 0
|
||||||
|
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &oldState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetState returns the current state of a terminal which may be useful to
|
||||||
|
// restore the terminal after a signal.
|
||||||
|
func GetState(fd int) (*State, error) {
|
||||||
|
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &State{termios: *termios}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||||
|
// previous state.
|
||||||
|
func Restore(fd int, state *State) error {
|
||||||
|
return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSize returns the dimensions of the given terminal.
|
||||||
|
func GetSize(fd int) (width, height int, err error) {
|
||||||
|
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
|
||||||
|
if err != nil {
|
||||||
|
return -1, -1, err
|
||||||
|
}
|
||||||
|
return int(ws.Col), int(ws.Row), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// passwordReader is an io.Reader that reads from a specific file descriptor.
|
||||||
|
type passwordReader int
|
||||||
|
|
||||||
|
func (r passwordReader) Read(buf []byte) (int, error) {
|
||||||
|
return unix.Read(int(r), buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||||
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||||
|
// returned does not include the \n.
|
||||||
|
func ReadPassword(fd int) ([]byte, error) {
|
||||||
|
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newState := *termios
|
||||||
|
newState.Lflag &^= unix.ECHO
|
||||||
|
newState.Lflag |= unix.ICANON | unix.ISIG
|
||||||
|
newState.Iflag |= unix.ICRNL
|
||||||
|
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
|
||||||
|
|
||||||
|
return readPasswordLine(passwordReader(fd))
|
||||||
|
}
|
12
vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go
generated
vendored
Normal file
12
vendor/golang.org/x/crypto/ssh/terminal/util_bsd.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 dragonfly freebsd netbsd openbsd
|
||||||
|
|
||||||
|
package terminal
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
const ioctlReadTermios = unix.TIOCGETA
|
||||||
|
const ioctlWriteTermios = unix.TIOCSETA
|
|
@ -2,10 +2,9 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build dragonfly freebsd netbsd openbsd
|
package terminal
|
||||||
|
|
||||||
package unix
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
const ImplementsGetwd = false
|
const ioctlReadTermios = unix.TCGETS
|
||||||
|
const ioctlWriteTermios = unix.TCSETS
|
||||||
func Getwd() (string, error) { return "", ENOTSUP }
|
|
58
vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
generated
vendored
Normal file
58
vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package terminal provides support functions for dealing with terminals, as
|
||||||
|
// commonly found on UNIX systems.
|
||||||
|
//
|
||||||
|
// Putting a terminal into raw mode is the most common requirement:
|
||||||
|
//
|
||||||
|
// oldState, err := terminal.MakeRaw(0)
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
// defer terminal.Restore(0, oldState)
|
||||||
|
package terminal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type State struct{}
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal(fd int) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||||
|
// restored.
|
||||||
|
func MakeRaw(fd int) (*State, error) {
|
||||||
|
return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetState returns the current state of a terminal which may be useful to
|
||||||
|
// restore the terminal after a signal.
|
||||||
|
func GetState(fd int) (*State, error) {
|
||||||
|
return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||||
|
// previous state.
|
||||||
|
func Restore(fd int, state *State) error {
|
||||||
|
return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSize returns the dimensions of the given terminal.
|
||||||
|
func GetSize(fd int) (width, height int, err error) {
|
||||||
|
return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||||
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||||
|
// returned does not include the \n.
|
||||||
|
func ReadPassword(fd int) ([]byte, error) {
|
||||||
|
return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
124
vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
generated
vendored
Normal file
124
vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// 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 solaris
|
||||||
|
|
||||||
|
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"io"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// State contains the state of a terminal.
|
||||||
|
type State struct {
|
||||||
|
termios unix.Termios
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||||
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||||
|
// returned does not include the \n.
|
||||||
|
func ReadPassword(fd int) ([]byte, error) {
|
||||||
|
// see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
|
||||||
|
val, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
oldState := *val
|
||||||
|
|
||||||
|
newState := oldState
|
||||||
|
newState.Lflag &^= syscall.ECHO
|
||||||
|
newState.Lflag |= syscall.ICANON | syscall.ISIG
|
||||||
|
newState.Iflag |= syscall.ICRNL
|
||||||
|
err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState)
|
||||||
|
|
||||||
|
var buf [16]byte
|
||||||
|
var ret []byte
|
||||||
|
for {
|
||||||
|
n, err := syscall.Read(fd, buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
if len(ret) == 0 {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if buf[n-1] == '\n' {
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
ret = append(ret, buf[:n]...)
|
||||||
|
if n < len(buf) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRaw puts the terminal connected to the given file descriptor into raw
|
||||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||||
|
// restored.
|
||||||
|
// see http://cr.illumos.org/~webrev/andy_js/1060/
|
||||||
|
func MakeRaw(fd int) (*State, error) {
|
||||||
|
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
oldState := State{termios: *termios}
|
||||||
|
|
||||||
|
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
||||||
|
termios.Oflag &^= unix.OPOST
|
||||||
|
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
||||||
|
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
||||||
|
termios.Cflag |= unix.CS8
|
||||||
|
termios.Cc[unix.VMIN] = 1
|
||||||
|
termios.Cc[unix.VTIME] = 0
|
||||||
|
|
||||||
|
if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &oldState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||||
|
// previous state.
|
||||||
|
func Restore(fd int, oldState *State) error {
|
||||||
|
return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetState returns the current state of a terminal which may be useful to
|
||||||
|
// restore the terminal after a signal.
|
||||||
|
func GetState(fd int) (*State, error) {
|
||||||
|
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &State{termios: *termios}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSize returns the dimensions of the given terminal.
|
||||||
|
func GetSize(fd int) (width, height int, err error) {
|
||||||
|
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return int(ws.Col), int(ws.Row), nil
|
||||||
|
}
|
103
vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
generated
vendored
Normal file
103
vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
// 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 terminal provides support functions for dealing with terminals, as
|
||||||
|
// commonly found on UNIX systems.
|
||||||
|
//
|
||||||
|
// Putting a terminal into raw mode is the most common requirement:
|
||||||
|
//
|
||||||
|
// oldState, err := terminal.MakeRaw(0)
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
// defer terminal.Restore(0, oldState)
|
||||||
|
package terminal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
type State struct {
|
||||||
|
mode uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal(fd int) bool {
|
||||||
|
var st uint32
|
||||||
|
err := windows.GetConsoleMode(windows.Handle(fd), &st)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||||
|
// restored.
|
||||||
|
func MakeRaw(fd int) (*State, error) {
|
||||||
|
var st uint32
|
||||||
|
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT)
|
||||||
|
if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &State{st}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetState returns the current state of a terminal which may be useful to
|
||||||
|
// restore the terminal after a signal.
|
||||||
|
func GetState(fd int) (*State, error) {
|
||||||
|
var st uint32
|
||||||
|
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &State{st}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||||
|
// previous state.
|
||||||
|
func Restore(fd int, state *State) error {
|
||||||
|
return windows.SetConsoleMode(windows.Handle(fd), state.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSize returns the dimensions of the given terminal.
|
||||||
|
func GetSize(fd int) (width, height int, err error) {
|
||||||
|
var info windows.ConsoleScreenBufferInfo
|
||||||
|
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return int(info.Size.X), int(info.Size.Y), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||||
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||||
|
// returned does not include the \n.
|
||||||
|
func ReadPassword(fd int) ([]byte, error) {
|
||||||
|
var st uint32
|
||||||
|
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
old := st
|
||||||
|
|
||||||
|
st &^= (windows.ENABLE_ECHO_INPUT)
|
||||||
|
st |= (windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT)
|
||||||
|
if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer windows.SetConsoleMode(windows.Handle(fd), old)
|
||||||
|
|
||||||
|
var h windows.Handle
|
||||||
|
p, _ := windows.GetCurrentProcess()
|
||||||
|
if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f := os.NewFile(uintptr(h), "stdin")
|
||||||
|
defer f.Close()
|
||||||
|
return readPasswordLine(f)
|
||||||
|
}
|
1
vendor/golang.org/x/sys/unix/.gitignore
generated
vendored
1
vendor/golang.org/x/sys/unix/.gitignore
generated
vendored
|
@ -1 +1,2 @@
|
||||||
_obj/
|
_obj/
|
||||||
|
unix.test
|
||||||
|
|
124
vendor/golang.org/x/sys/unix/affinity_linux.go
generated
vendored
Normal file
124
vendor/golang.org/x/sys/unix/affinity_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// CPU affinity functions
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
|
||||||
|
|
||||||
|
// CPUSet represents a CPU affinity mask.
|
||||||
|
type CPUSet [cpuSetSize]cpuMask
|
||||||
|
|
||||||
|
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
|
||||||
|
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
|
||||||
|
if e != 0 {
|
||||||
|
return errnoErr(e)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
|
||||||
|
// If pid is 0 the calling thread is used.
|
||||||
|
func SchedGetaffinity(pid int, set *CPUSet) error {
|
||||||
|
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
|
||||||
|
// If pid is 0 the calling thread is used.
|
||||||
|
func SchedSetaffinity(pid int, set *CPUSet) error {
|
||||||
|
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero clears the set s, so that it contains no CPUs.
|
||||||
|
func (s *CPUSet) Zero() {
|
||||||
|
for i := range s {
|
||||||
|
s[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cpuBitsIndex(cpu int) int {
|
||||||
|
return cpu / _NCPUBITS
|
||||||
|
}
|
||||||
|
|
||||||
|
func cpuBitsMask(cpu int) cpuMask {
|
||||||
|
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set adds cpu to the set s.
|
||||||
|
func (s *CPUSet) Set(cpu int) {
|
||||||
|
i := cpuBitsIndex(cpu)
|
||||||
|
if i < len(s) {
|
||||||
|
s[i] |= cpuBitsMask(cpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear removes cpu from the set s.
|
||||||
|
func (s *CPUSet) Clear(cpu int) {
|
||||||
|
i := cpuBitsIndex(cpu)
|
||||||
|
if i < len(s) {
|
||||||
|
s[i] &^= cpuBitsMask(cpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSet reports whether cpu is in the set s.
|
||||||
|
func (s *CPUSet) IsSet(cpu int) bool {
|
||||||
|
i := cpuBitsIndex(cpu)
|
||||||
|
if i < len(s) {
|
||||||
|
return s[i]&cpuBitsMask(cpu) != 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the number of CPUs in the set s.
|
||||||
|
func (s *CPUSet) Count() int {
|
||||||
|
c := 0
|
||||||
|
for _, b := range s {
|
||||||
|
c += onesCount64(uint64(b))
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
|
||||||
|
// Once this package can require Go 1.9, we can delete this
|
||||||
|
// and update the caller to use bits.OnesCount64.
|
||||||
|
func onesCount64(x uint64) int {
|
||||||
|
const m0 = 0x5555555555555555 // 01010101 ...
|
||||||
|
const m1 = 0x3333333333333333 // 00110011 ...
|
||||||
|
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
|
||||||
|
const m3 = 0x00ff00ff00ff00ff // etc.
|
||||||
|
const m4 = 0x0000ffff0000ffff
|
||||||
|
|
||||||
|
// Implementation: Parallel summing of adjacent bits.
|
||||||
|
// See "Hacker's Delight", Chap. 5: Counting Bits.
|
||||||
|
// The following pattern shows the general approach:
|
||||||
|
//
|
||||||
|
// x = x>>1&(m0&m) + x&(m0&m)
|
||||||
|
// x = x>>2&(m1&m) + x&(m1&m)
|
||||||
|
// x = x>>4&(m2&m) + x&(m2&m)
|
||||||
|
// x = x>>8&(m3&m) + x&(m3&m)
|
||||||
|
// x = x>>16&(m4&m) + x&(m4&m)
|
||||||
|
// x = x>>32&(m5&m) + x&(m5&m)
|
||||||
|
// return int(x)
|
||||||
|
//
|
||||||
|
// Masking (& operations) can be left away when there's no
|
||||||
|
// danger that a field's sum will carry over into the next
|
||||||
|
// field: Since the result cannot be > 64, 8 bits is enough
|
||||||
|
// and we can ignore the masks for the shifts by 8 and up.
|
||||||
|
// Per "Hacker's Delight", the first line can be simplified
|
||||||
|
// more, but it saves at best one instruction, so we leave
|
||||||
|
// it alone for clarity.
|
||||||
|
const m = 1<<64 - 1
|
||||||
|
x = x>>1&(m0&m) + x&(m0&m)
|
||||||
|
x = x>>2&(m1&m) + x&(m1&m)
|
||||||
|
x = (x>>4 + x) & (m2 & m)
|
||||||
|
x += x >> 8
|
||||||
|
x += x >> 16
|
||||||
|
x += x >> 32
|
||||||
|
return int(x) & (1<<7 - 1)
|
||||||
|
}
|
30
vendor/golang.org/x/sys/unix/asm_linux_386.s
generated
vendored
30
vendor/golang.org/x/sys/unix/asm_linux_386.s
generated
vendored
|
@ -10,6 +10,10 @@
|
||||||
// System calls for 386, Linux
|
// System calls for 386, Linux
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
|
||||||
|
// instead of the glibc-specific "CALL 0x10(GS)".
|
||||||
|
#define INVOKE_SYSCALL INT $0x80
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
// Just jump to package syscall's implementation for all these functions.
|
||||||
// The runtime may know about them.
|
// The runtime may know about them.
|
||||||
|
|
||||||
|
@ -19,12 +23,38 @@ TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||||
JMP syscall·Syscall6(SB)
|
JMP syscall·Syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
||||||
|
CALL runtime·entersyscall(SB)
|
||||||
|
MOVL trap+0(FP), AX // syscall entry
|
||||||
|
MOVL a1+4(FP), BX
|
||||||
|
MOVL a2+8(FP), CX
|
||||||
|
MOVL a3+12(FP), DX
|
||||||
|
MOVL $0, SI
|
||||||
|
MOVL $0, DI
|
||||||
|
INVOKE_SYSCALL
|
||||||
|
MOVL AX, r1+16(FP)
|
||||||
|
MOVL DX, r2+20(FP)
|
||||||
|
CALL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||||
JMP syscall·RawSyscall(SB)
|
JMP syscall·RawSyscall(SB)
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||||
JMP syscall·RawSyscall6(SB)
|
JMP syscall·RawSyscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
||||||
|
MOVL trap+0(FP), AX // syscall entry
|
||||||
|
MOVL a1+4(FP), BX
|
||||||
|
MOVL a2+8(FP), CX
|
||||||
|
MOVL a3+12(FP), DX
|
||||||
|
MOVL $0, SI
|
||||||
|
MOVL $0, DI
|
||||||
|
INVOKE_SYSCALL
|
||||||
|
MOVL AX, r1+16(FP)
|
||||||
|
MOVL DX, r2+20(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·socketcall(SB),NOSPLIT,$0-36
|
TEXT ·socketcall(SB),NOSPLIT,$0-36
|
||||||
JMP syscall·socketcall(SB)
|
JMP syscall·socketcall(SB)
|
||||||
|
|
||||||
|
|
28
vendor/golang.org/x/sys/unix/asm_linux_amd64.s
generated
vendored
28
vendor/golang.org/x/sys/unix/asm_linux_amd64.s
generated
vendored
|
@ -19,11 +19,39 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||||
JMP syscall·Syscall6(SB)
|
JMP syscall·Syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
CALL runtime·entersyscall(SB)
|
||||||
|
MOVQ a1+8(FP), DI
|
||||||
|
MOVQ a2+16(FP), SI
|
||||||
|
MOVQ a3+24(FP), DX
|
||||||
|
MOVQ $0, R10
|
||||||
|
MOVQ $0, R8
|
||||||
|
MOVQ $0, R9
|
||||||
|
MOVQ trap+0(FP), AX // syscall entry
|
||||||
|
SYSCALL
|
||||||
|
MOVQ AX, r1+32(FP)
|
||||||
|
MOVQ DX, r2+40(FP)
|
||||||
|
CALL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||||
JMP syscall·RawSyscall(SB)
|
JMP syscall·RawSyscall(SB)
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||||
JMP syscall·RawSyscall6(SB)
|
JMP syscall·RawSyscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
MOVQ a1+8(FP), DI
|
||||||
|
MOVQ a2+16(FP), SI
|
||||||
|
MOVQ a3+24(FP), DX
|
||||||
|
MOVQ $0, R10
|
||||||
|
MOVQ $0, R8
|
||||||
|
MOVQ $0, R9
|
||||||
|
MOVQ trap+0(FP), AX // syscall entry
|
||||||
|
SYSCALL
|
||||||
|
MOVQ AX, r1+32(FP)
|
||||||
|
MOVQ DX, r2+40(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
|
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
|
||||||
JMP syscall·gettimeofday(SB)
|
JMP syscall·gettimeofday(SB)
|
||||||
|
|
29
vendor/golang.org/x/sys/unix/asm_linux_arm.s
generated
vendored
29
vendor/golang.org/x/sys/unix/asm_linux_arm.s
generated
vendored
|
@ -19,11 +19,38 @@ TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||||
B syscall·Syscall6(SB)
|
B syscall·Syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
||||||
|
BL runtime·entersyscall(SB)
|
||||||
|
MOVW trap+0(FP), R7
|
||||||
|
MOVW a1+4(FP), R0
|
||||||
|
MOVW a2+8(FP), R1
|
||||||
|
MOVW a3+12(FP), R2
|
||||||
|
MOVW $0, R3
|
||||||
|
MOVW $0, R4
|
||||||
|
MOVW $0, R5
|
||||||
|
SWI $0
|
||||||
|
MOVW R0, r1+16(FP)
|
||||||
|
MOVW $0, R0
|
||||||
|
MOVW R0, r2+20(FP)
|
||||||
|
BL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||||
B syscall·RawSyscall(SB)
|
B syscall·RawSyscall(SB)
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||||
B syscall·RawSyscall6(SB)
|
B syscall·RawSyscall6(SB)
|
||||||
|
|
||||||
TEXT ·seek(SB),NOSPLIT,$0-32
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
||||||
|
MOVW trap+0(FP), R7 // syscall entry
|
||||||
|
MOVW a1+4(FP), R0
|
||||||
|
MOVW a2+8(FP), R1
|
||||||
|
MOVW a3+12(FP), R2
|
||||||
|
SWI $0
|
||||||
|
MOVW R0, r1+16(FP)
|
||||||
|
MOVW $0, R0
|
||||||
|
MOVW R0, r2+20(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·seek(SB),NOSPLIT,$0-28
|
||||||
B syscall·seek(SB)
|
B syscall·seek(SB)
|
||||||
|
|
28
vendor/golang.org/x/sys/unix/asm_linux_arm64.s
generated
vendored
28
vendor/golang.org/x/sys/unix/asm_linux_arm64.s
generated
vendored
|
@ -17,8 +17,36 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||||
B syscall·Syscall6(SB)
|
B syscall·Syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
BL runtime·entersyscall(SB)
|
||||||
|
MOVD a1+8(FP), R0
|
||||||
|
MOVD a2+16(FP), R1
|
||||||
|
MOVD a3+24(FP), R2
|
||||||
|
MOVD $0, R3
|
||||||
|
MOVD $0, R4
|
||||||
|
MOVD $0, R5
|
||||||
|
MOVD trap+0(FP), R8 // syscall entry
|
||||||
|
SVC
|
||||||
|
MOVD R0, r1+32(FP) // r1
|
||||||
|
MOVD R1, r2+40(FP) // r2
|
||||||
|
BL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||||
B syscall·RawSyscall(SB)
|
B syscall·RawSyscall(SB)
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||||
B syscall·RawSyscall6(SB)
|
B syscall·RawSyscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
MOVD a1+8(FP), R0
|
||||||
|
MOVD a2+16(FP), R1
|
||||||
|
MOVD a3+24(FP), R2
|
||||||
|
MOVD $0, R3
|
||||||
|
MOVD $0, R4
|
||||||
|
MOVD $0, R5
|
||||||
|
MOVD trap+0(FP), R8 // syscall entry
|
||||||
|
SVC
|
||||||
|
MOVD R0, r1+32(FP)
|
||||||
|
MOVD R1, r2+40(FP)
|
||||||
|
RET
|
||||||
|
|
28
vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
generated
vendored
28
vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
generated
vendored
|
@ -21,8 +21,36 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||||
JMP syscall·Syscall6(SB)
|
JMP syscall·Syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
JAL runtime·entersyscall(SB)
|
||||||
|
MOVV a1+8(FP), R4
|
||||||
|
MOVV a2+16(FP), R5
|
||||||
|
MOVV a3+24(FP), R6
|
||||||
|
MOVV R0, R7
|
||||||
|
MOVV R0, R8
|
||||||
|
MOVV R0, R9
|
||||||
|
MOVV trap+0(FP), R2 // syscall entry
|
||||||
|
SYSCALL
|
||||||
|
MOVV R2, r1+32(FP)
|
||||||
|
MOVV R3, r2+40(FP)
|
||||||
|
JAL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||||
JMP syscall·RawSyscall(SB)
|
JMP syscall·RawSyscall(SB)
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||||
JMP syscall·RawSyscall6(SB)
|
JMP syscall·RawSyscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
MOVV a1+8(FP), R4
|
||||||
|
MOVV a2+16(FP), R5
|
||||||
|
MOVV a3+24(FP), R6
|
||||||
|
MOVV R0, R7
|
||||||
|
MOVV R0, R8
|
||||||
|
MOVV R0, R9
|
||||||
|
MOVV trap+0(FP), R2 // syscall entry
|
||||||
|
SYSCALL
|
||||||
|
MOVV R2, r1+32(FP)
|
||||||
|
MOVV R3, r2+40(FP)
|
||||||
|
RET
|
||||||
|
|
23
vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
generated
vendored
23
vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
generated
vendored
|
@ -24,8 +24,31 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||||
JMP syscall·Syscall9(SB)
|
JMP syscall·Syscall9(SB)
|
||||||
|
|
||||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
||||||
|
JAL runtime·entersyscall(SB)
|
||||||
|
MOVW a1+4(FP), R4
|
||||||
|
MOVW a2+8(FP), R5
|
||||||
|
MOVW a3+12(FP), R6
|
||||||
|
MOVW R0, R7
|
||||||
|
MOVW trap+0(FP), R2 // syscall entry
|
||||||
|
SYSCALL
|
||||||
|
MOVW R2, r1+16(FP) // r1
|
||||||
|
MOVW R3, r2+20(FP) // r2
|
||||||
|
JAL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||||
JMP syscall·RawSyscall(SB)
|
JMP syscall·RawSyscall(SB)
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||||
JMP syscall·RawSyscall6(SB)
|
JMP syscall·RawSyscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
||||||
|
MOVW a1+4(FP), R4
|
||||||
|
MOVW a2+8(FP), R5
|
||||||
|
MOVW a3+12(FP), R6
|
||||||
|
MOVW trap+0(FP), R2 // syscall entry
|
||||||
|
SYSCALL
|
||||||
|
MOVW R2, r1+16(FP)
|
||||||
|
MOVW R3, r2+20(FP)
|
||||||
|
RET
|
||||||
|
|
28
vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
generated
vendored
28
vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
generated
vendored
|
@ -21,8 +21,36 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||||
BR syscall·Syscall6(SB)
|
BR syscall·Syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
BL runtime·entersyscall(SB)
|
||||||
|
MOVD a1+8(FP), R3
|
||||||
|
MOVD a2+16(FP), R4
|
||||||
|
MOVD a3+24(FP), R5
|
||||||
|
MOVD R0, R6
|
||||||
|
MOVD R0, R7
|
||||||
|
MOVD R0, R8
|
||||||
|
MOVD trap+0(FP), R9 // syscall entry
|
||||||
|
SYSCALL R9
|
||||||
|
MOVD R3, r1+32(FP)
|
||||||
|
MOVD R4, r2+40(FP)
|
||||||
|
BL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||||
BR syscall·RawSyscall(SB)
|
BR syscall·RawSyscall(SB)
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||||
BR syscall·RawSyscall6(SB)
|
BR syscall·RawSyscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
MOVD a1+8(FP), R3
|
||||||
|
MOVD a2+16(FP), R4
|
||||||
|
MOVD a3+24(FP), R5
|
||||||
|
MOVD R0, R6
|
||||||
|
MOVD R0, R7
|
||||||
|
MOVD R0, R8
|
||||||
|
MOVD trap+0(FP), R9 // syscall entry
|
||||||
|
SYSCALL R9
|
||||||
|
MOVD R3, r1+32(FP)
|
||||||
|
MOVD R4, r2+40(FP)
|
||||||
|
RET
|
||||||
|
|
28
vendor/golang.org/x/sys/unix/asm_linux_s390x.s
generated
vendored
28
vendor/golang.org/x/sys/unix/asm_linux_s390x.s
generated
vendored
|
@ -21,8 +21,36 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||||
BR syscall·Syscall6(SB)
|
BR syscall·Syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
BL runtime·entersyscall(SB)
|
||||||
|
MOVD a1+8(FP), R2
|
||||||
|
MOVD a2+16(FP), R3
|
||||||
|
MOVD a3+24(FP), R4
|
||||||
|
MOVD $0, R5
|
||||||
|
MOVD $0, R6
|
||||||
|
MOVD $0, R7
|
||||||
|
MOVD trap+0(FP), R1 // syscall entry
|
||||||
|
SYSCALL
|
||||||
|
MOVD R2, r1+32(FP)
|
||||||
|
MOVD R3, r2+40(FP)
|
||||||
|
BL runtime·exitsyscall(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||||
BR syscall·RawSyscall(SB)
|
BR syscall·RawSyscall(SB)
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||||
BR syscall·RawSyscall6(SB)
|
BR syscall·RawSyscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||||
|
MOVD a1+8(FP), R2
|
||||||
|
MOVD a2+16(FP), R3
|
||||||
|
MOVD a3+24(FP), R4
|
||||||
|
MOVD $0, R5
|
||||||
|
MOVD $0, R6
|
||||||
|
MOVD $0, R7
|
||||||
|
MOVD trap+0(FP), R1 // syscall entry
|
||||||
|
SYSCALL
|
||||||
|
MOVD R2, r1+32(FP)
|
||||||
|
MOVD R3, r2+40(FP)
|
||||||
|
RET
|
||||||
|
|
29
vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
generated
vendored
Normal file
29
vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2017 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 !gccgo
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// System call support for ARM, OpenBSD
|
||||||
|
//
|
||||||
|
|
||||||
|
// Just jump to package syscall's implementation for all these functions.
|
||||||
|
// The runtime may know about them.
|
||||||
|
|
||||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||||
|
B syscall·Syscall(SB)
|
||||||
|
|
||||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||||
|
B syscall·Syscall6(SB)
|
||||||
|
|
||||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||||
|
B syscall·Syscall9(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||||
|
B syscall·RawSyscall(SB)
|
||||||
|
|
||||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||||
|
B syscall·RawSyscall6(SB)
|
195
vendor/golang.org/x/sys/unix/cap_freebsd.go
generated
vendored
Normal file
195
vendor/golang.org/x/sys/unix/cap_freebsd.go
generated
vendored
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
// Copyright 2017 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
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
|
||||||
|
|
||||||
|
const (
|
||||||
|
// This is the version of CapRights this package understands. See C implementation for parallels.
|
||||||
|
capRightsGoVersion = CAP_RIGHTS_VERSION_00
|
||||||
|
capArSizeMin = CAP_RIGHTS_VERSION_00 + 2
|
||||||
|
capArSizeMax = capRightsGoVersion + 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bit2idx = []int{
|
||||||
|
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func capidxbit(right uint64) int {
|
||||||
|
return int((right >> 57) & 0x1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rightToIndex(right uint64) (int, error) {
|
||||||
|
idx := capidxbit(right)
|
||||||
|
if idx < 0 || idx >= len(bit2idx) {
|
||||||
|
return -2, fmt.Errorf("index for right 0x%x out of range", right)
|
||||||
|
}
|
||||||
|
return bit2idx[idx], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func caprver(right uint64) int {
|
||||||
|
return int(right >> 62)
|
||||||
|
}
|
||||||
|
|
||||||
|
func capver(rights *CapRights) int {
|
||||||
|
return caprver(rights.Rights[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func caparsize(rights *CapRights) int {
|
||||||
|
return capver(rights) + 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapRightsSet sets the permissions in setrights in rights.
|
||||||
|
func CapRightsSet(rights *CapRights, setrights []uint64) error {
|
||||||
|
// This is essentially a copy of cap_rights_vset()
|
||||||
|
if capver(rights) != CAP_RIGHTS_VERSION_00 {
|
||||||
|
return fmt.Errorf("bad rights version %d", capver(rights))
|
||||||
|
}
|
||||||
|
|
||||||
|
n := caparsize(rights)
|
||||||
|
if n < capArSizeMin || n > capArSizeMax {
|
||||||
|
return errors.New("bad rights size")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, right := range setrights {
|
||||||
|
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||||
|
return errors.New("bad right version")
|
||||||
|
}
|
||||||
|
i, err := rightToIndex(right)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if i >= n {
|
||||||
|
return errors.New("index overflow")
|
||||||
|
}
|
||||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||||
|
return errors.New("index mismatch")
|
||||||
|
}
|
||||||
|
rights.Rights[i] |= right
|
||||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||||
|
return errors.New("index mismatch (after assign)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapRightsClear clears the permissions in clearrights from rights.
|
||||||
|
func CapRightsClear(rights *CapRights, clearrights []uint64) error {
|
||||||
|
// This is essentially a copy of cap_rights_vclear()
|
||||||
|
if capver(rights) != CAP_RIGHTS_VERSION_00 {
|
||||||
|
return fmt.Errorf("bad rights version %d", capver(rights))
|
||||||
|
}
|
||||||
|
|
||||||
|
n := caparsize(rights)
|
||||||
|
if n < capArSizeMin || n > capArSizeMax {
|
||||||
|
return errors.New("bad rights size")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, right := range clearrights {
|
||||||
|
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||||
|
return errors.New("bad right version")
|
||||||
|
}
|
||||||
|
i, err := rightToIndex(right)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if i >= n {
|
||||||
|
return errors.New("index overflow")
|
||||||
|
}
|
||||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||||
|
return errors.New("index mismatch")
|
||||||
|
}
|
||||||
|
rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
|
||||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||||
|
return errors.New("index mismatch (after assign)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
|
||||||
|
func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
|
||||||
|
// This is essentially a copy of cap_rights_is_vset()
|
||||||
|
if capver(rights) != CAP_RIGHTS_VERSION_00 {
|
||||||
|
return false, fmt.Errorf("bad rights version %d", capver(rights))
|
||||||
|
}
|
||||||
|
|
||||||
|
n := caparsize(rights)
|
||||||
|
if n < capArSizeMin || n > capArSizeMax {
|
||||||
|
return false, errors.New("bad rights size")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, right := range setrights {
|
||||||
|
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||||
|
return false, errors.New("bad right version")
|
||||||
|
}
|
||||||
|
i, err := rightToIndex(right)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if i >= n {
|
||||||
|
return false, errors.New("index overflow")
|
||||||
|
}
|
||||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||||
|
return false, errors.New("index mismatch")
|
||||||
|
}
|
||||||
|
if (rights.Rights[i] & right) != right {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func capright(idx uint64, bit uint64) uint64 {
|
||||||
|
return ((1 << (57 + idx)) | bit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
|
||||||
|
// See man cap_rights_init(3) and rights(4).
|
||||||
|
func CapRightsInit(rights []uint64) (*CapRights, error) {
|
||||||
|
var r CapRights
|
||||||
|
r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
|
||||||
|
r.Rights[1] = capright(1, 0)
|
||||||
|
|
||||||
|
err := CapRightsSet(&r, rights)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
|
||||||
|
// The capability rights on fd can never be increased by CapRightsLimit.
|
||||||
|
// See man cap_rights_limit(2) and rights(4).
|
||||||
|
func CapRightsLimit(fd uintptr, rights *CapRights) error {
|
||||||
|
return capRightsLimit(int(fd), rights)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
|
||||||
|
// See man cap_rights_get(3) and rights(4).
|
||||||
|
func CapRightsGet(fd uintptr) (*CapRights, error) {
|
||||||
|
r, err := CapRightsInit(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = capRightsGet(capRightsGoVersion, int(fd), r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
24
vendor/golang.org/x/sys/unix/dev_darwin.go
generated
vendored
Normal file
24
vendor/golang.org/x/sys/unix/dev_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// Functions to access/create device major and minor numbers matching the
|
||||||
|
// encoding used in Darwin's sys/types.h header.
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
// Major returns the major component of a Darwin device number.
|
||||||
|
func Major(dev uint64) uint32 {
|
||||||
|
return uint32((dev >> 24) & 0xff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minor returns the minor component of a Darwin device number.
|
||||||
|
func Minor(dev uint64) uint32 {
|
||||||
|
return uint32(dev & 0xffffff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdev returns a Darwin device number generated from the given major and minor
|
||||||
|
// components.
|
||||||
|
func Mkdev(major, minor uint32) uint64 {
|
||||||
|
return (uint64(major) << 24) | uint64(minor)
|
||||||
|
}
|
30
vendor/golang.org/x/sys/unix/dev_dragonfly.go
generated
vendored
Normal file
30
vendor/golang.org/x/sys/unix/dev_dragonfly.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// Functions to access/create device major and minor numbers matching the
|
||||||
|
// encoding used in Dragonfly's sys/types.h header.
|
||||||
|
//
|
||||||
|
// The information below is extracted and adapted from sys/types.h:
|
||||||
|
//
|
||||||
|
// Minor gives a cookie instead of an index since in order to avoid changing the
|
||||||
|
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
|
||||||
|
// devices that don't use them.
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
// Major returns the major component of a DragonFlyBSD device number.
|
||||||
|
func Major(dev uint64) uint32 {
|
||||||
|
return uint32((dev >> 8) & 0xff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minor returns the minor component of a DragonFlyBSD device number.
|
||||||
|
func Minor(dev uint64) uint32 {
|
||||||
|
return uint32(dev & 0xffff00ff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdev returns a DragonFlyBSD device number generated from the given major and
|
||||||
|
// minor components.
|
||||||
|
func Mkdev(major, minor uint32) uint64 {
|
||||||
|
return (uint64(major) << 8) | uint64(minor)
|
||||||
|
}
|
30
vendor/golang.org/x/sys/unix/dev_freebsd.go
generated
vendored
Normal file
30
vendor/golang.org/x/sys/unix/dev_freebsd.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// Functions to access/create device major and minor numbers matching the
|
||||||
|
// encoding used in FreeBSD's sys/types.h header.
|
||||||
|
//
|
||||||
|
// The information below is extracted and adapted from sys/types.h:
|
||||||
|
//
|
||||||
|
// Minor gives a cookie instead of an index since in order to avoid changing the
|
||||||
|
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
|
||||||
|
// devices that don't use them.
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
// Major returns the major component of a FreeBSD device number.
|
||||||
|
func Major(dev uint64) uint32 {
|
||||||
|
return uint32((dev >> 8) & 0xff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minor returns the minor component of a FreeBSD device number.
|
||||||
|
func Minor(dev uint64) uint32 {
|
||||||
|
return uint32(dev & 0xffff00ff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdev returns a FreeBSD device number generated from the given major and
|
||||||
|
// minor components.
|
||||||
|
func Mkdev(major, minor uint32) uint64 {
|
||||||
|
return (uint64(major) << 8) | uint64(minor)
|
||||||
|
}
|
42
vendor/golang.org/x/sys/unix/dev_linux.go
generated
vendored
Normal file
42
vendor/golang.org/x/sys/unix/dev_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// Functions to access/create device major and minor numbers matching the
|
||||||
|
// encoding used by the Linux kernel and glibc.
|
||||||
|
//
|
||||||
|
// The information below is extracted and adapted from bits/sysmacros.h in the
|
||||||
|
// glibc sources:
|
||||||
|
//
|
||||||
|
// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
|
||||||
|
// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
|
||||||
|
// number and m is a hex digit of the minor number. This is backward compatible
|
||||||
|
// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
|
||||||
|
// backward compatible with the Linux kernel, which for some architectures uses
|
||||||
|
// 32-bit dev_t, encoded as mmmM MMmm.
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
// Major returns the major component of a Linux device number.
|
||||||
|
func Major(dev uint64) uint32 {
|
||||||
|
major := uint32((dev & 0x00000000000fff00) >> 8)
|
||||||
|
major |= uint32((dev & 0xfffff00000000000) >> 32)
|
||||||
|
return major
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minor returns the minor component of a Linux device number.
|
||||||
|
func Minor(dev uint64) uint32 {
|
||||||
|
minor := uint32((dev & 0x00000000000000ff) >> 0)
|
||||||
|
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
|
||||||
|
return minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdev returns a Linux device number generated from the given major and minor
|
||||||
|
// components.
|
||||||
|
func Mkdev(major, minor uint32) uint64 {
|
||||||
|
dev := (uint64(major) & 0x00000fff) << 8
|
||||||
|
dev |= (uint64(major) & 0xfffff000) << 32
|
||||||
|
dev |= (uint64(minor) & 0x000000ff) << 0
|
||||||
|
dev |= (uint64(minor) & 0xffffff00) << 12
|
||||||
|
return dev
|
||||||
|
}
|
29
vendor/golang.org/x/sys/unix/dev_netbsd.go
generated
vendored
Normal file
29
vendor/golang.org/x/sys/unix/dev_netbsd.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// Functions to access/create device major and minor numbers matching the
|
||||||
|
// encoding used in NetBSD's sys/types.h header.
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
// Major returns the major component of a NetBSD device number.
|
||||||
|
func Major(dev uint64) uint32 {
|
||||||
|
return uint32((dev & 0x000fff00) >> 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minor returns the minor component of a NetBSD device number.
|
||||||
|
func Minor(dev uint64) uint32 {
|
||||||
|
minor := uint32((dev & 0x000000ff) >> 0)
|
||||||
|
minor |= uint32((dev & 0xfff00000) >> 12)
|
||||||
|
return minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdev returns a NetBSD device number generated from the given major and minor
|
||||||
|
// components.
|
||||||
|
func Mkdev(major, minor uint32) uint64 {
|
||||||
|
dev := (uint64(major) << 8) & 0x000fff00
|
||||||
|
dev |= (uint64(minor) << 12) & 0xfff00000
|
||||||
|
dev |= (uint64(minor) << 0) & 0x000000ff
|
||||||
|
return dev
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue