mirror of
https://github.com/genuinetools/reg.git
synced 2024-06-28 10:24:17 -04:00
cleanup
Signed-off-by: Jess Frazelle <acidburn@google.com>
This commit is contained in:
parent
38fed8500a
commit
ef361e5ef0
64
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/alt_exit.go
generated
vendored
64
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/alt_exit.go
generated
vendored
|
@ -1,64 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
// The following code was sourced and modified from the
|
|
||||||
// https://bitbucket.org/tebeka/atexit package governed by the following license:
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
// this software and associated documentation files (the "Software"), to deal in
|
|
||||||
// the Software without restriction, including without limitation the rights to
|
|
||||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
// subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
var handlers = []func(){}
|
|
||||||
|
|
||||||
func runHandler(handler func()) {
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
handler()
|
|
||||||
}
|
|
||||||
|
|
||||||
func runHandlers() {
|
|
||||||
for _, handler := range handlers {
|
|
||||||
runHandler(handler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
|
|
||||||
func Exit(code int) {
|
|
||||||
runHandlers()
|
|
||||||
os.Exit(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
|
|
||||||
// all handlers. The handlers will also be invoked when any Fatal log entry is
|
|
||||||
// made.
|
|
||||||
//
|
|
||||||
// This method is useful when a caller wishes to use logrus to log a fatal
|
|
||||||
// message but also needs to gracefully shutdown. An example usecase could be
|
|
||||||
// closing database connections, or sending a alert that the application is
|
|
||||||
// closing.
|
|
||||||
func RegisterExitHandler(handler func()) {
|
|
||||||
handlers = append(handlers, handler)
|
|
||||||
}
|
|
26
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
26
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
|
||||||
|
|
||||||
|
|
||||||
The simplest way to use Logrus is simply the package-level exported logger:
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
"number": 1,
|
|
||||||
"size": 10,
|
|
||||||
}).Info("A walrus appears")
|
|
||||||
}
|
|
||||||
|
|
||||||
Output:
|
|
||||||
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
|
||||||
|
|
||||||
For a full guide visit https://github.com/Sirupsen/logrus
|
|
||||||
*/
|
|
||||||
package logrus
|
|
275
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
275
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
|
@ -1,275 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var bufferPool *sync.Pool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
bufferPool = &sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return new(bytes.Buffer)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defines the key when adding errors using WithError.
|
|
||||||
var ErrorKey = "error"
|
|
||||||
|
|
||||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
|
||||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
|
||||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
|
||||||
// passed around as much as you wish to avoid field duplication.
|
|
||||||
type Entry struct {
|
|
||||||
Logger *Logger
|
|
||||||
|
|
||||||
// Contains all the fields set by the user.
|
|
||||||
Data Fields
|
|
||||||
|
|
||||||
// Time at which the log entry was created
|
|
||||||
Time time.Time
|
|
||||||
|
|
||||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
|
||||||
Level Level
|
|
||||||
|
|
||||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
|
||||||
Message string
|
|
||||||
|
|
||||||
// When formatter is called in entry.log(), an Buffer may be set to entry
|
|
||||||
Buffer *bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEntry(logger *Logger) *Entry {
|
|
||||||
return &Entry{
|
|
||||||
Logger: logger,
|
|
||||||
// Default is three fields, give a little extra room
|
|
||||||
Data: make(Fields, 5),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the string representation from the reader and ultimately the
|
|
||||||
// formatter.
|
|
||||||
func (entry *Entry) String() (string, error) {
|
|
||||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
str := string(serialized)
|
|
||||||
return str, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
|
||||||
func (entry *Entry) WithError(err error) *Entry {
|
|
||||||
return entry.WithField(ErrorKey, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a single field to the Entry.
|
|
||||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
|
||||||
return entry.WithFields(Fields{key: value})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a map of fields to the Entry.
|
|
||||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
|
||||||
data := make(Fields, len(entry.Data)+len(fields))
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
for k, v := range fields {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
return &Entry{Logger: entry.Logger, Data: data}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is not declared with a pointer value because otherwise
|
|
||||||
// race conditions will occur when using multiple goroutines
|
|
||||||
func (entry Entry) log(level Level, msg string) {
|
|
||||||
var buffer *bytes.Buffer
|
|
||||||
entry.Time = time.Now()
|
|
||||||
entry.Level = level
|
|
||||||
entry.Message = msg
|
|
||||||
|
|
||||||
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
}
|
|
||||||
buffer = bufferPool.Get().(*bytes.Buffer)
|
|
||||||
buffer.Reset()
|
|
||||||
defer bufferPool.Put(buffer)
|
|
||||||
entry.Buffer = buffer
|
|
||||||
serialized, err := entry.Logger.Formatter.Format(&entry)
|
|
||||||
entry.Buffer = nil
|
|
||||||
if err != nil {
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
} else {
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
_, err = entry.Logger.Out.Write(serialized)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
|
||||||
}
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// To avoid Entry#log() returning a value that only would make sense for
|
|
||||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
|
||||||
// directly here.
|
|
||||||
if level <= PanicLevel {
|
|
||||||
panic(&entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Debug(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= DebugLevel {
|
|
||||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Print(args ...interface{}) {
|
|
||||||
entry.Info(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Info(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= InfoLevel {
|
|
||||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warn(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= WarnLevel {
|
|
||||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warning(args ...interface{}) {
|
|
||||||
entry.Warn(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Error(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= ErrorLevel {
|
|
||||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatal(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= FatalLevel {
|
|
||||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panic(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= PanicLevel {
|
|
||||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
panic(fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry Printf family functions
|
|
||||||
|
|
||||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= DebugLevel {
|
|
||||||
entry.Debug(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= InfoLevel {
|
|
||||||
entry.Info(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
|
||||||
entry.Infof(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= WarnLevel {
|
|
||||||
entry.Warn(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
|
||||||
entry.Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= ErrorLevel {
|
|
||||||
entry.Error(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= FatalLevel {
|
|
||||||
entry.Fatal(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= PanicLevel {
|
|
||||||
entry.Panic(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry Println family functions
|
|
||||||
|
|
||||||
func (entry *Entry) Debugln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= DebugLevel {
|
|
||||||
entry.Debug(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Infoln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= InfoLevel {
|
|
||||||
entry.Info(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Println(args ...interface{}) {
|
|
||||||
entry.Infoln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warnln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= WarnLevel {
|
|
||||||
entry.Warn(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warningln(args ...interface{}) {
|
|
||||||
entry.Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Errorln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= ErrorLevel {
|
|
||||||
entry.Error(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= FatalLevel {
|
|
||||||
entry.Fatal(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panicln(args ...interface{}) {
|
|
||||||
if entry.Logger.Level >= PanicLevel {
|
|
||||||
entry.Panic(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
|
||||||
// fmt.Sprintln where spaces are always added between operands, regardless of
|
|
||||||
// their type. Instead of vendoring the Sprintln implementation to spare a
|
|
||||||
// string allocation, we do the simplest thing.
|
|
||||||
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
|
||||||
msg := fmt.Sprintln(args...)
|
|
||||||
return msg[:len(msg)-1]
|
|
||||||
}
|
|
193
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
193
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
|
@ -1,193 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// std is the name of the standard logger in stdlib `log`
|
|
||||||
std = New()
|
|
||||||
)
|
|
||||||
|
|
||||||
func StandardLogger() *Logger {
|
|
||||||
return std
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOutput sets the standard logger output.
|
|
||||||
func SetOutput(out io.Writer) {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Out = out
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFormatter sets the standard logger formatter.
|
|
||||||
func SetFormatter(formatter Formatter) {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Formatter = formatter
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLevel sets the standard logger level.
|
|
||||||
func SetLevel(level Level) {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Level = level
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLevel returns the standard logger level.
|
|
||||||
func GetLevel() Level {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
return std.Level
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHook adds a hook to the standard logger hooks.
|
|
||||||
func AddHook(hook Hook) {
|
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Hooks.Add(hook)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
|
||||||
func WithError(err error) *Entry {
|
|
||||||
return std.WithField(ErrorKey, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithField creates an entry from the standard logger and adds a field to
|
|
||||||
// it. If you want multiple fields, use `WithFields`.
|
|
||||||
//
|
|
||||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
|
||||||
// or Panic on the Entry it returns.
|
|
||||||
func WithField(key string, value interface{}) *Entry {
|
|
||||||
return std.WithField(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithFields creates an entry from the standard logger and adds multiple
|
|
||||||
// fields to it. This is simply a helper for `WithField`, invoking it
|
|
||||||
// once for each field.
|
|
||||||
//
|
|
||||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
|
||||||
// or Panic on the Entry it returns.
|
|
||||||
func WithFields(fields Fields) *Entry {
|
|
||||||
return std.WithFields(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug logs a message at level Debug on the standard logger.
|
|
||||||
func Debug(args ...interface{}) {
|
|
||||||
std.Debug(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print logs a message at level Info on the standard logger.
|
|
||||||
func Print(args ...interface{}) {
|
|
||||||
std.Print(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info logs a message at level Info on the standard logger.
|
|
||||||
func Info(args ...interface{}) {
|
|
||||||
std.Info(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn logs a message at level Warn on the standard logger.
|
|
||||||
func Warn(args ...interface{}) {
|
|
||||||
std.Warn(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warning logs a message at level Warn on the standard logger.
|
|
||||||
func Warning(args ...interface{}) {
|
|
||||||
std.Warning(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error logs a message at level Error on the standard logger.
|
|
||||||
func Error(args ...interface{}) {
|
|
||||||
std.Error(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panic logs a message at level Panic on the standard logger.
|
|
||||||
func Panic(args ...interface{}) {
|
|
||||||
std.Panic(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatal logs a message at level Fatal on the standard logger.
|
|
||||||
func Fatal(args ...interface{}) {
|
|
||||||
std.Fatal(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debugf logs a message at level Debug on the standard logger.
|
|
||||||
func Debugf(format string, args ...interface{}) {
|
|
||||||
std.Debugf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Printf logs a message at level Info on the standard logger.
|
|
||||||
func Printf(format string, args ...interface{}) {
|
|
||||||
std.Printf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infof logs a message at level Info on the standard logger.
|
|
||||||
func Infof(format string, args ...interface{}) {
|
|
||||||
std.Infof(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warnf logs a message at level Warn on the standard logger.
|
|
||||||
func Warnf(format string, args ...interface{}) {
|
|
||||||
std.Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningf logs a message at level Warn on the standard logger.
|
|
||||||
func Warningf(format string, args ...interface{}) {
|
|
||||||
std.Warningf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf logs a message at level Error on the standard logger.
|
|
||||||
func Errorf(format string, args ...interface{}) {
|
|
||||||
std.Errorf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panicf logs a message at level Panic on the standard logger.
|
|
||||||
func Panicf(format string, args ...interface{}) {
|
|
||||||
std.Panicf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalf logs a message at level Fatal on the standard logger.
|
|
||||||
func Fatalf(format string, args ...interface{}) {
|
|
||||||
std.Fatalf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debugln logs a message at level Debug on the standard logger.
|
|
||||||
func Debugln(args ...interface{}) {
|
|
||||||
std.Debugln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Println logs a message at level Info on the standard logger.
|
|
||||||
func Println(args ...interface{}) {
|
|
||||||
std.Println(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infoln logs a message at level Info on the standard logger.
|
|
||||||
func Infoln(args ...interface{}) {
|
|
||||||
std.Infoln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warnln logs a message at level Warn on the standard logger.
|
|
||||||
func Warnln(args ...interface{}) {
|
|
||||||
std.Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningln logs a message at level Warn on the standard logger.
|
|
||||||
func Warningln(args ...interface{}) {
|
|
||||||
std.Warningln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorln logs a message at level Error on the standard logger.
|
|
||||||
func Errorln(args ...interface{}) {
|
|
||||||
std.Errorln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panicln logs a message at level Panic on the standard logger.
|
|
||||||
func Panicln(args ...interface{}) {
|
|
||||||
std.Panicln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalln logs a message at level Fatal on the standard logger.
|
|
||||||
func Fatalln(args ...interface{}) {
|
|
||||||
std.Fatalln(args...)
|
|
||||||
}
|
|
45
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
45
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
|
@ -1,45 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
const DefaultTimestampFormat = time.RFC3339
|
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
|
||||||
//
|
|
||||||
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
|
||||||
// * `entry.Data["time"]`. The timestamp.
|
|
||||||
// * `entry.Data["level"]. The level the entry was logged at.
|
|
||||||
//
|
|
||||||
// Any additional fields added with `WithField` or `WithFields` are also in
|
|
||||||
// `entry.Data`. Format is expected to return an array of bytes which are then
|
|
||||||
// logged to `logger.Out`.
|
|
||||||
type Formatter interface {
|
|
||||||
Format(*Entry) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
|
||||||
// dumping it. If this code wasn't there doing:
|
|
||||||
//
|
|
||||||
// logrus.WithField("level", 1).Info("hello")
|
|
||||||
//
|
|
||||||
// Would just silently drop the user provided level. Instead with this code
|
|
||||||
// it'll logged as:
|
|
||||||
//
|
|
||||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
|
||||||
//
|
|
||||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
|
||||||
// avoid code duplication between the two default formatters.
|
|
||||||
func prefixFieldClashes(data Fields) {
|
|
||||||
if t, ok := data["time"]; ok {
|
|
||||||
data["fields.time"] = t
|
|
||||||
}
|
|
||||||
|
|
||||||
if m, ok := data["msg"]; ok {
|
|
||||||
data["fields.msg"] = m
|
|
||||||
}
|
|
||||||
|
|
||||||
if l, ok := data["level"]; ok {
|
|
||||||
data["fields.level"] = l
|
|
||||||
}
|
|
||||||
}
|
|
34
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
34
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
|
@ -1,34 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
// A hook to be fired when logging on the logging levels returned from
|
|
||||||
// `Levels()` on your implementation of the interface. Note that this is not
|
|
||||||
// fired in a goroutine or a channel with workers, you should handle such
|
|
||||||
// functionality yourself if your call is non-blocking and you don't wish for
|
|
||||||
// the logging calls for levels returned from `Levels()` to block.
|
|
||||||
type Hook interface {
|
|
||||||
Levels() []Level
|
|
||||||
Fire(*Entry) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal type for storing the hooks on a logger instance.
|
|
||||||
type LevelHooks map[Level][]Hook
|
|
||||||
|
|
||||||
// Add a hook to an instance of logger. This is called with
|
|
||||||
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
|
||||||
func (hooks LevelHooks) Add(hook Hook) {
|
|
||||||
for _, level := range hook.Levels() {
|
|
||||||
hooks[level] = append(hooks[level], hook)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
|
||||||
// appropriate hooks for a log entry.
|
|
||||||
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
|
||||||
for _, hook := range hooks[level] {
|
|
||||||
if err := hook.Fire(entry); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JSONFormatter struct {
|
|
||||||
// TimestampFormat sets the format used for marshaling timestamps.
|
|
||||||
TimestampFormat string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
data := make(Fields, len(entry.Data)+3)
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case error:
|
|
||||||
// Otherwise errors are ignored by `encoding/json`
|
|
||||||
// https://github.com/Sirupsen/logrus/issues/137
|
|
||||||
data[k] = v.Error()
|
|
||||||
default:
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prefixFieldClashes(data)
|
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
|
||||||
if timestampFormat == "" {
|
|
||||||
timestampFormat = DefaultTimestampFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
data["time"] = entry.Time.Format(timestampFormat)
|
|
||||||
data["msg"] = entry.Message
|
|
||||||
data["level"] = entry.Level.String()
|
|
||||||
|
|
||||||
serialized, err := json.Marshal(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
|
||||||
}
|
|
||||||
return append(serialized, '\n'), nil
|
|
||||||
}
|
|
308
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
308
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
|
@ -1,308 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Logger struct {
|
|
||||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
|
||||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
|
||||||
// something more adventorous, such as logging to Kafka.
|
|
||||||
Out io.Writer
|
|
||||||
// Hooks for the logger instance. These allow firing events based on logging
|
|
||||||
// levels and log entries. For example, to send errors to an error tracking
|
|
||||||
// service, log to StatsD or dump the core on fatal errors.
|
|
||||||
Hooks LevelHooks
|
|
||||||
// All log entries pass through the formatter before logged to Out. The
|
|
||||||
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
|
||||||
// TextFormatter is the default. In development (when a TTY is attached) it
|
|
||||||
// logs with colors, but to a file it wouldn't. You can easily implement your
|
|
||||||
// own that implements the `Formatter` interface, see the `README` or included
|
|
||||||
// formatters for examples.
|
|
||||||
Formatter Formatter
|
|
||||||
// The logging level the logger should log at. This is typically (and defaults
|
|
||||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
|
||||||
// logged. `logrus.Debug` is useful in
|
|
||||||
Level Level
|
|
||||||
// Used to sync writing to the log. Locking is enabled by Default
|
|
||||||
mu MutexWrap
|
|
||||||
// Reusable empty entry
|
|
||||||
entryPool sync.Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
type MutexWrap struct {
|
|
||||||
lock sync.Mutex
|
|
||||||
disabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mw *MutexWrap) Lock() {
|
|
||||||
if !mw.disabled {
|
|
||||||
mw.lock.Lock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mw *MutexWrap) Unlock() {
|
|
||||||
if !mw.disabled {
|
|
||||||
mw.lock.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mw *MutexWrap) Disable() {
|
|
||||||
mw.disabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
|
||||||
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
|
||||||
// instantiate your own:
|
|
||||||
//
|
|
||||||
// var log = &Logger{
|
|
||||||
// Out: os.Stderr,
|
|
||||||
// Formatter: new(JSONFormatter),
|
|
||||||
// Hooks: make(LevelHooks),
|
|
||||||
// Level: logrus.DebugLevel,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// It's recommended to make this a global instance called `log`.
|
|
||||||
func New() *Logger {
|
|
||||||
return &Logger{
|
|
||||||
Out: os.Stderr,
|
|
||||||
Formatter: new(TextFormatter),
|
|
||||||
Hooks: make(LevelHooks),
|
|
||||||
Level: InfoLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) newEntry() *Entry {
|
|
||||||
entry, ok := logger.entryPool.Get().(*Entry)
|
|
||||||
if ok {
|
|
||||||
return entry
|
|
||||||
}
|
|
||||||
return NewEntry(logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) releaseEntry(entry *Entry) {
|
|
||||||
logger.entryPool.Put(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds a field to the log entry, note that it doesn't log until you call
|
|
||||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
|
||||||
// If you want multiple fields, use `WithFields`.
|
|
||||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
defer logger.releaseEntry(entry)
|
|
||||||
return entry.WithField(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
|
||||||
// each `Field`.
|
|
||||||
func (logger *Logger) WithFields(fields Fields) *Entry {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
defer logger.releaseEntry(entry)
|
|
||||||
return entry.WithFields(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an error as single field to the log entry. All it does is call
|
|
||||||
// `WithError` for the given `error`.
|
|
||||||
func (logger *Logger) WithError(err error) *Entry {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
defer logger.releaseEntry(entry)
|
|
||||||
return entry.WithError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
|
||||||
if logger.Level >= DebugLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Debugf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
|
||||||
if logger.Level >= InfoLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Infof(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Printf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
|
||||||
if logger.Level >= WarnLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warnf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
|
||||||
if logger.Level >= WarnLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warnf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
|
||||||
if logger.Level >= ErrorLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Errorf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
|
||||||
if logger.Level >= FatalLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Fatalf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
|
||||||
if logger.Level >= PanicLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Panicf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debug(args ...interface{}) {
|
|
||||||
if logger.Level >= DebugLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Debug(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Info(args ...interface{}) {
|
|
||||||
if logger.Level >= InfoLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Info(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Info(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warn(args ...interface{}) {
|
|
||||||
if logger.Level >= WarnLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warn(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warning(args ...interface{}) {
|
|
||||||
if logger.Level >= WarnLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warn(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Error(args ...interface{}) {
|
|
||||||
if logger.Level >= ErrorLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Error(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatal(args ...interface{}) {
|
|
||||||
if logger.Level >= FatalLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Fatal(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panic(args ...interface{}) {
|
|
||||||
if logger.Level >= PanicLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Panic(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debugln(args ...interface{}) {
|
|
||||||
if logger.Level >= DebugLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Debugln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Infoln(args ...interface{}) {
|
|
||||||
if logger.Level >= InfoLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Infoln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Println(args ...interface{}) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Println(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warnln(args ...interface{}) {
|
|
||||||
if logger.Level >= WarnLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warnln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
|
||||||
if logger.Level >= WarnLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warnln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
|
||||||
if logger.Level >= ErrorLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Errorln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
|
||||||
if logger.Level >= FatalLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Fatalln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panicln(args ...interface{}) {
|
|
||||||
if logger.Level >= PanicLevel {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Panicln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//When file is opened with appending mode, it's safe to
|
|
||||||
//write concurrently to a file (within 4k message on Linux).
|
|
||||||
//In these cases user can choose to disable the lock.
|
|
||||||
func (logger *Logger) SetNoLock() {
|
|
||||||
logger.mu.Disable()
|
|
||||||
}
|
|
143
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
143
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
|
@ -1,143 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fields type, used to pass to `WithFields`.
|
|
||||||
type Fields map[string]interface{}
|
|
||||||
|
|
||||||
// Level type
|
|
||||||
type Level uint8
|
|
||||||
|
|
||||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
|
||||||
func (level Level) String() string {
|
|
||||||
switch level {
|
|
||||||
case DebugLevel:
|
|
||||||
return "debug"
|
|
||||||
case InfoLevel:
|
|
||||||
return "info"
|
|
||||||
case WarnLevel:
|
|
||||||
return "warning"
|
|
||||||
case ErrorLevel:
|
|
||||||
return "error"
|
|
||||||
case FatalLevel:
|
|
||||||
return "fatal"
|
|
||||||
case PanicLevel:
|
|
||||||
return "panic"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
|
||||||
func ParseLevel(lvl string) (Level, error) {
|
|
||||||
switch strings.ToLower(lvl) {
|
|
||||||
case "panic":
|
|
||||||
return PanicLevel, nil
|
|
||||||
case "fatal":
|
|
||||||
return FatalLevel, nil
|
|
||||||
case "error":
|
|
||||||
return ErrorLevel, nil
|
|
||||||
case "warn", "warning":
|
|
||||||
return WarnLevel, nil
|
|
||||||
case "info":
|
|
||||||
return InfoLevel, nil
|
|
||||||
case "debug":
|
|
||||||
return DebugLevel, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var l Level
|
|
||||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A constant exposing all logging levels
|
|
||||||
var AllLevels = []Level{
|
|
||||||
PanicLevel,
|
|
||||||
FatalLevel,
|
|
||||||
ErrorLevel,
|
|
||||||
WarnLevel,
|
|
||||||
InfoLevel,
|
|
||||||
DebugLevel,
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are the different logging levels. You can set the logging level to log
|
|
||||||
// on your instance of logger, obtained with `logrus.New()`.
|
|
||||||
const (
|
|
||||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
|
||||||
// message passed to Debug, Info, ...
|
|
||||||
PanicLevel Level = iota
|
|
||||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
|
||||||
// logging level is set to Panic.
|
|
||||||
FatalLevel
|
|
||||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
|
||||||
// Commonly used for hooks to send errors to an error tracking service.
|
|
||||||
ErrorLevel
|
|
||||||
// WarnLevel level. Non-critical entries that deserve eyes.
|
|
||||||
WarnLevel
|
|
||||||
// InfoLevel level. General operational entries about what's going on inside the
|
|
||||||
// application.
|
|
||||||
InfoLevel
|
|
||||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
|
||||||
DebugLevel
|
|
||||||
)
|
|
||||||
|
|
||||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
|
||||||
var (
|
|
||||||
_ StdLogger = &log.Logger{}
|
|
||||||
_ StdLogger = &Entry{}
|
|
||||||
_ StdLogger = &Logger{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// StdLogger is what your logrus-enabled library should take, that way
|
|
||||||
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
|
||||||
// interface, this is the closest we get, unfortunately.
|
|
||||||
type StdLogger interface {
|
|
||||||
Print(...interface{})
|
|
||||||
Printf(string, ...interface{})
|
|
||||||
Println(...interface{})
|
|
||||||
|
|
||||||
Fatal(...interface{})
|
|
||||||
Fatalf(string, ...interface{})
|
|
||||||
Fatalln(...interface{})
|
|
||||||
|
|
||||||
Panic(...interface{})
|
|
||||||
Panicf(string, ...interface{})
|
|
||||||
Panicln(...interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// The FieldLogger interface generalizes the Entry and Logger types
|
|
||||||
type FieldLogger interface {
|
|
||||||
WithField(key string, value interface{}) *Entry
|
|
||||||
WithFields(fields Fields) *Entry
|
|
||||||
WithError(err error) *Entry
|
|
||||||
|
|
||||||
Debugf(format string, args ...interface{})
|
|
||||||
Infof(format string, args ...interface{})
|
|
||||||
Printf(format string, args ...interface{})
|
|
||||||
Warnf(format string, args ...interface{})
|
|
||||||
Warningf(format string, args ...interface{})
|
|
||||||
Errorf(format string, args ...interface{})
|
|
||||||
Fatalf(format string, args ...interface{})
|
|
||||||
Panicf(format string, args ...interface{})
|
|
||||||
|
|
||||||
Debug(args ...interface{})
|
|
||||||
Info(args ...interface{})
|
|
||||||
Print(args ...interface{})
|
|
||||||
Warn(args ...interface{})
|
|
||||||
Warning(args ...interface{})
|
|
||||||
Error(args ...interface{})
|
|
||||||
Fatal(args ...interface{})
|
|
||||||
Panic(args ...interface{})
|
|
||||||
|
|
||||||
Debugln(args ...interface{})
|
|
||||||
Infoln(args ...interface{})
|
|
||||||
Println(args ...interface{})
|
|
||||||
Warnln(args ...interface{})
|
|
||||||
Warningln(args ...interface{})
|
|
||||||
Errorln(args ...interface{})
|
|
||||||
Fatalln(args ...interface{})
|
|
||||||
Panicln(args ...interface{})
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
// +build appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
|
||||||
func IsTerminal() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
10
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
10
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
|
@ -1,10 +0,0 @@
|
||||||
// +build darwin freebsd openbsd netbsd dragonfly
|
|
||||||
// +build !appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TIOCGETA
|
|
||||||
|
|
||||||
type Termios syscall.Termios
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
const ioctlReadTermios = syscall.TCGETS
|
|
||||||
|
|
||||||
type Termios syscall.Termios
|
|
|
@ -1,22 +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 (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
|
||||||
func IsTerminal() bool {
|
|
||||||
fd := syscall.Stderr
|
|
||||||
var termios Termios
|
|
||||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
|
||||||
return err == 0
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
// +build solaris,!appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
||||||
func IsTerminal() bool {
|
|
||||||
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
|
@ -1,27 +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 (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
||||||
|
|
||||||
var (
|
|
||||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
|
||||||
func IsTerminal() bool {
|
|
||||||
fd := syscall.Stderr
|
|
||||||
var st uint32
|
|
||||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
|
||||||
return r != 0 && e == 0
|
|
||||||
}
|
|
168
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
168
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
|
@ -1,168 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
nocolor = 0
|
|
||||||
red = 31
|
|
||||||
green = 32
|
|
||||||
yellow = 33
|
|
||||||
blue = 34
|
|
||||||
gray = 37
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
baseTimestamp time.Time
|
|
||||||
isTerminal bool
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
baseTimestamp = time.Now()
|
|
||||||
isTerminal = IsTerminal()
|
|
||||||
}
|
|
||||||
|
|
||||||
func miniTS() int {
|
|
||||||
return int(time.Since(baseTimestamp) / time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
type TextFormatter struct {
|
|
||||||
// Set to true to bypass checking for a TTY before outputting colors.
|
|
||||||
ForceColors bool
|
|
||||||
|
|
||||||
// Force disabling colors.
|
|
||||||
DisableColors bool
|
|
||||||
|
|
||||||
// Disable timestamp logging. useful when output is redirected to logging
|
|
||||||
// system that already adds timestamps.
|
|
||||||
DisableTimestamp bool
|
|
||||||
|
|
||||||
// Enable logging the full timestamp when a TTY is attached instead of just
|
|
||||||
// the time passed since beginning of execution.
|
|
||||||
FullTimestamp bool
|
|
||||||
|
|
||||||
// TimestampFormat to use for display when a full timestamp is printed
|
|
||||||
TimestampFormat string
|
|
||||||
|
|
||||||
// The fields are sorted by default for a consistent output. For applications
|
|
||||||
// that log extremely frequently and don't use the JSON formatter this may not
|
|
||||||
// be desired.
|
|
||||||
DisableSorting bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
var b *bytes.Buffer
|
|
||||||
var keys []string = make([]string, 0, len(entry.Data))
|
|
||||||
for k := range entry.Data {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !f.DisableSorting {
|
|
||||||
sort.Strings(keys)
|
|
||||||
}
|
|
||||||
if entry.Buffer != nil {
|
|
||||||
b = entry.Buffer
|
|
||||||
} else {
|
|
||||||
b = &bytes.Buffer{}
|
|
||||||
}
|
|
||||||
|
|
||||||
prefixFieldClashes(entry.Data)
|
|
||||||
|
|
||||||
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
|
|
||||||
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
|
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
|
||||||
if timestampFormat == "" {
|
|
||||||
timestampFormat = DefaultTimestampFormat
|
|
||||||
}
|
|
||||||
if isColored {
|
|
||||||
f.printColored(b, entry, keys, timestampFormat)
|
|
||||||
} else {
|
|
||||||
if !f.DisableTimestamp {
|
|
||||||
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
|
||||||
}
|
|
||||||
f.appendKeyValue(b, "level", entry.Level.String())
|
|
||||||
if entry.Message != "" {
|
|
||||||
f.appendKeyValue(b, "msg", entry.Message)
|
|
||||||
}
|
|
||||||
for _, key := range keys {
|
|
||||||
f.appendKeyValue(b, key, entry.Data[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.WriteByte('\n')
|
|
||||||
return b.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
|
||||||
var levelColor int
|
|
||||||
switch entry.Level {
|
|
||||||
case DebugLevel:
|
|
||||||
levelColor = gray
|
|
||||||
case WarnLevel:
|
|
||||||
levelColor = yellow
|
|
||||||
case ErrorLevel, FatalLevel, PanicLevel:
|
|
||||||
levelColor = red
|
|
||||||
default:
|
|
||||||
levelColor = blue
|
|
||||||
}
|
|
||||||
|
|
||||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
|
||||||
|
|
||||||
if !f.FullTimestamp {
|
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
|
||||||
}
|
|
||||||
for _, k := range keys {
|
|
||||||
v := entry.Data[k]
|
|
||||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
|
|
||||||
f.appendValue(b, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func needsQuoting(text string) bool {
|
|
||||||
for _, ch := range text {
|
|
||||||
if !((ch >= 'a' && ch <= 'z') ||
|
|
||||||
(ch >= 'A' && ch <= 'Z') ||
|
|
||||||
(ch >= '0' && ch <= '9') ||
|
|
||||||
ch == '-' || ch == '.') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
|
||||||
|
|
||||||
b.WriteString(key)
|
|
||||||
b.WriteByte('=')
|
|
||||||
f.appendValue(b, value)
|
|
||||||
b.WriteByte(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
|
|
||||||
switch value := value.(type) {
|
|
||||||
case string:
|
|
||||||
if !needsQuoting(value) {
|
|
||||||
b.WriteString(value)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(b, "%q", value)
|
|
||||||
}
|
|
||||||
case error:
|
|
||||||
errmsg := value.Error()
|
|
||||||
if !needsQuoting(errmsg) {
|
|
||||||
b.WriteString(errmsg)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(b, "%q", errmsg)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fmt.Fprint(b, value)
|
|
||||||
}
|
|
||||||
}
|
|
53
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
53
vendor/github.com/docker/distribution/vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
|
@ -1,53 +0,0 @@
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"io"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (logger *Logger) Writer() *io.PipeWriter {
|
|
||||||
return logger.WriterLevel(InfoLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
|
|
||||||
reader, writer := io.Pipe()
|
|
||||||
|
|
||||||
var printFunc func(args ...interface{})
|
|
||||||
switch level {
|
|
||||||
case DebugLevel:
|
|
||||||
printFunc = logger.Debug
|
|
||||||
case InfoLevel:
|
|
||||||
printFunc = logger.Info
|
|
||||||
case WarnLevel:
|
|
||||||
printFunc = logger.Warn
|
|
||||||
case ErrorLevel:
|
|
||||||
printFunc = logger.Error
|
|
||||||
case FatalLevel:
|
|
||||||
printFunc = logger.Fatal
|
|
||||||
case PanicLevel:
|
|
||||||
printFunc = logger.Panic
|
|
||||||
default:
|
|
||||||
printFunc = logger.Print
|
|
||||||
}
|
|
||||||
|
|
||||||
go logger.writerScanner(reader, printFunc)
|
|
||||||
runtime.SetFinalizer(writer, writerFinalizer)
|
|
||||||
|
|
||||||
return writer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
|
|
||||||
scanner := bufio.NewScanner(reader)
|
|
||||||
for scanner.Scan() {
|
|
||||||
printFunc(scanner.Text())
|
|
||||||
}
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
logger.Errorf("Error while reading from Writer: %s", err)
|
|
||||||
}
|
|
||||||
reader.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func writerFinalizer(writer *io.PipeWriter) {
|
|
||||||
writer.Close()
|
|
||||||
}
|
|
143
vendor/github.com/docker/distribution/vendor/github.com/gorilla/context/context.go
generated
vendored
143
vendor/github.com/docker/distribution/vendor/github.com/gorilla/context/context.go
generated
vendored
|
@ -1,143 +0,0 @@
|
||||||
// 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 context
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
mutex sync.RWMutex
|
|
||||||
data = make(map[*http.Request]map[interface{}]interface{})
|
|
||||||
datat = make(map[*http.Request]int64)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set stores a value for a given key in a given request.
|
|
||||||
func Set(r *http.Request, key, val interface{}) {
|
|
||||||
mutex.Lock()
|
|
||||||
if data[r] == nil {
|
|
||||||
data[r] = make(map[interface{}]interface{})
|
|
||||||
datat[r] = time.Now().Unix()
|
|
||||||
}
|
|
||||||
data[r][key] = val
|
|
||||||
mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns a value stored for a given key in a given request.
|
|
||||||
func Get(r *http.Request, key interface{}) interface{} {
|
|
||||||
mutex.RLock()
|
|
||||||
if ctx := data[r]; ctx != nil {
|
|
||||||
value := ctx[key]
|
|
||||||
mutex.RUnlock()
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
mutex.RUnlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOk returns stored value and presence state like multi-value return of map access.
|
|
||||||
func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
|
|
||||||
mutex.RLock()
|
|
||||||
if _, ok := data[r]; ok {
|
|
||||||
value, ok := data[r][key]
|
|
||||||
mutex.RUnlock()
|
|
||||||
return value, ok
|
|
||||||
}
|
|
||||||
mutex.RUnlock()
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.
|
|
||||||
func GetAll(r *http.Request) map[interface{}]interface{} {
|
|
||||||
mutex.RLock()
|
|
||||||
if context, ok := data[r]; ok {
|
|
||||||
result := make(map[interface{}]interface{}, len(context))
|
|
||||||
for k, v := range context {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
mutex.RUnlock()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
mutex.RUnlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if
|
|
||||||
// the request was registered.
|
|
||||||
func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
|
|
||||||
mutex.RLock()
|
|
||||||
context, ok := data[r]
|
|
||||||
result := make(map[interface{}]interface{}, len(context))
|
|
||||||
for k, v := range context {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
mutex.RUnlock()
|
|
||||||
return result, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete removes a value stored for a given key in a given request.
|
|
||||||
func Delete(r *http.Request, key interface{}) {
|
|
||||||
mutex.Lock()
|
|
||||||
if data[r] != nil {
|
|
||||||
delete(data[r], key)
|
|
||||||
}
|
|
||||||
mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear removes all values stored for a given request.
|
|
||||||
//
|
|
||||||
// This is usually called by a handler wrapper to clean up request
|
|
||||||
// variables at the end of a request lifetime. See ClearHandler().
|
|
||||||
func Clear(r *http.Request) {
|
|
||||||
mutex.Lock()
|
|
||||||
clear(r)
|
|
||||||
mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear is Clear without the lock.
|
|
||||||
func clear(r *http.Request) {
|
|
||||||
delete(data, r)
|
|
||||||
delete(datat, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge removes request data stored for longer than maxAge, in seconds.
|
|
||||||
// It returns the amount of requests removed.
|
|
||||||
//
|
|
||||||
// If maxAge <= 0, all request data is removed.
|
|
||||||
//
|
|
||||||
// This is only used for sanity check: in case context cleaning was not
|
|
||||||
// properly set some request data can be kept forever, consuming an increasing
|
|
||||||
// amount of memory. In case this is detected, Purge() must be called
|
|
||||||
// periodically until the problem is fixed.
|
|
||||||
func Purge(maxAge int) int {
|
|
||||||
mutex.Lock()
|
|
||||||
count := 0
|
|
||||||
if maxAge <= 0 {
|
|
||||||
count = len(data)
|
|
||||||
data = make(map[*http.Request]map[interface{}]interface{})
|
|
||||||
datat = make(map[*http.Request]int64)
|
|
||||||
} else {
|
|
||||||
min := time.Now().Unix() - int64(maxAge)
|
|
||||||
for r := range data {
|
|
||||||
if datat[r] < min {
|
|
||||||
clear(r)
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex.Unlock()
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearHandler wraps an http.Handler and clears request values at the end
|
|
||||||
// of a request lifetime.
|
|
||||||
func ClearHandler(h http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
defer Clear(r)
|
|
||||||
h.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
82
vendor/github.com/docker/distribution/vendor/github.com/gorilla/context/doc.go
generated
vendored
82
vendor/github.com/docker/distribution/vendor/github.com/gorilla/context/doc.go
generated
vendored
|
@ -1,82 +0,0 @@
|
||||||
// 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 context stores values shared during a request lifetime.
|
|
||||||
|
|
||||||
For example, a router can set variables extracted from the URL and later
|
|
||||||
application handlers can access those values, or it can be used to store
|
|
||||||
sessions values to be saved at the end of a request. There are several
|
|
||||||
others common uses.
|
|
||||||
|
|
||||||
The idea was posted by Brad Fitzpatrick to the go-nuts mailing list:
|
|
||||||
|
|
||||||
http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53
|
|
||||||
|
|
||||||
Here's the basic usage: first define the keys that you will need. The key
|
|
||||||
type is interface{} so a key can be of any type that supports equality.
|
|
||||||
Here we define a key using a custom int type to avoid name collisions:
|
|
||||||
|
|
||||||
package foo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gorilla/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type key int
|
|
||||||
|
|
||||||
const MyKey key = 0
|
|
||||||
|
|
||||||
Then set a variable. Variables are bound to an http.Request object, so you
|
|
||||||
need a request instance to set a value:
|
|
||||||
|
|
||||||
context.Set(r, MyKey, "bar")
|
|
||||||
|
|
||||||
The application can later access the variable using the same key you provided:
|
|
||||||
|
|
||||||
func MyHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// val is "bar".
|
|
||||||
val := context.Get(r, foo.MyKey)
|
|
||||||
|
|
||||||
// returns ("bar", true)
|
|
||||||
val, ok := context.GetOk(r, foo.MyKey)
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
And that's all about the basic usage. We discuss some other ideas below.
|
|
||||||
|
|
||||||
Any type can be stored in the context. To enforce a given type, make the key
|
|
||||||
private and wrap Get() and Set() to accept and return values of a specific
|
|
||||||
type:
|
|
||||||
|
|
||||||
type key int
|
|
||||||
|
|
||||||
const mykey key = 0
|
|
||||||
|
|
||||||
// GetMyKey returns a value for this package from the request values.
|
|
||||||
func GetMyKey(r *http.Request) SomeType {
|
|
||||||
if rv := context.Get(r, mykey); rv != nil {
|
|
||||||
return rv.(SomeType)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMyKey sets a value for this package in the request values.
|
|
||||||
func SetMyKey(r *http.Request, val SomeType) {
|
|
||||||
context.Set(r, mykey, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
Variables must be cleared at the end of a request, to remove all values
|
|
||||||
that were stored. This can be done in an http.Handler, after a request was
|
|
||||||
served. Just call Clear() passing the request:
|
|
||||||
|
|
||||||
context.Clear(r)
|
|
||||||
|
|
||||||
...or use ClearHandler(), which conveniently wraps an http.Handler to clear
|
|
||||||
variables at the end of a request lifetime.
|
|
||||||
|
|
||||||
The Routers from the packages gorilla/mux and gorilla/pat call Clear()
|
|
||||||
so if you are using either of them you don't need to clear the context manually.
|
|
||||||
*/
|
|
||||||
package context
|
|
|
@ -1,144 +0,0 @@
|
||||||
package digest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Algorithm identifies and implementation of a digester by an identifier.
|
|
||||||
// Note the that this defines both the hash algorithm used and the string
|
|
||||||
// encoding.
|
|
||||||
type Algorithm string
|
|
||||||
|
|
||||||
// supported digest types
|
|
||||||
const (
|
|
||||||
SHA256 Algorithm = "sha256" // sha256 with hex encoding
|
|
||||||
SHA384 Algorithm = "sha384" // sha384 with hex encoding
|
|
||||||
SHA512 Algorithm = "sha512" // sha512 with hex encoding
|
|
||||||
|
|
||||||
// Canonical is the primary digest algorithm used with the distribution
|
|
||||||
// project. Other digests may be used but this one is the primary storage
|
|
||||||
// digest.
|
|
||||||
Canonical = SHA256
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// TODO(stevvooe): Follow the pattern of the standard crypto package for
|
|
||||||
// registration of digests. Effectively, we are a registerable set and
|
|
||||||
// common symbol access.
|
|
||||||
|
|
||||||
// algorithms maps values to hash.Hash implementations. Other algorithms
|
|
||||||
// may be available but they cannot be calculated by the digest package.
|
|
||||||
algorithms = map[Algorithm]crypto.Hash{
|
|
||||||
SHA256: crypto.SHA256,
|
|
||||||
SHA384: crypto.SHA384,
|
|
||||||
SHA512: crypto.SHA512,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Available returns true if the digest type is available for use. If this
|
|
||||||
// returns false, Digester and Hash will return nil.
|
|
||||||
func (a Algorithm) Available() bool {
|
|
||||||
h, ok := algorithms[a]
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// check availability of the hash, as well
|
|
||||||
return h.Available()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Algorithm) String() string {
|
|
||||||
return string(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns number of bytes returned by the hash.
|
|
||||||
func (a Algorithm) Size() int {
|
|
||||||
h, ok := algorithms[a]
|
|
||||||
if !ok {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return h.Size()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set implemented to allow use of Algorithm as a command line flag.
|
|
||||||
func (a *Algorithm) Set(value string) error {
|
|
||||||
if value == "" {
|
|
||||||
*a = Canonical
|
|
||||||
} else {
|
|
||||||
// just do a type conversion, support is queried with Available.
|
|
||||||
*a = Algorithm(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !a.Available() {
|
|
||||||
return ErrDigestUnsupported
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Digester returns a new digester for the specified algorithm. If the algorithm
|
|
||||||
// does not have a digester implementation, nil will be returned. This can be
|
|
||||||
// checked by calling Available before calling Digester.
|
|
||||||
func (a Algorithm) Digester() Digester {
|
|
||||||
return &digester{
|
|
||||||
alg: a,
|
|
||||||
hash: a.Hash(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns a new hash as used by the algorithm. If not available, the
|
|
||||||
// method will panic. Check Algorithm.Available() before calling.
|
|
||||||
func (a Algorithm) Hash() hash.Hash {
|
|
||||||
if !a.Available() {
|
|
||||||
// Empty algorithm string is invalid
|
|
||||||
if a == "" {
|
|
||||||
panic(fmt.Sprintf("empty digest algorithm, validate before calling Algorithm.Hash()"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(stevvooe): A missing hash is usually a programming error that
|
|
||||||
// must be resolved at compile time. We don't import in the digest
|
|
||||||
// package to allow users to choose their hash implementation (such as
|
|
||||||
// when using stevvooe/resumable or a hardware accelerated package).
|
|
||||||
//
|
|
||||||
// Applications that may want to resolve the hash at runtime should
|
|
||||||
// call Algorithm.Available before call Algorithm.Hash().
|
|
||||||
panic(fmt.Sprintf("%v not available (make sure it is imported)", a))
|
|
||||||
}
|
|
||||||
|
|
||||||
return algorithms[a].New()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromReader returns the digest of the reader using the algorithm.
|
|
||||||
func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
|
|
||||||
digester := a.Digester()
|
|
||||||
|
|
||||||
if _, err := io.Copy(digester.Hash(), rd); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return digester.Digest(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromBytes digests the input and returns a Digest.
|
|
||||||
func (a Algorithm) FromBytes(p []byte) Digest {
|
|
||||||
digester := a.Digester()
|
|
||||||
|
|
||||||
if _, err := digester.Hash().Write(p); err != nil {
|
|
||||||
// Writes to a Hash should never fail. None of the existing
|
|
||||||
// hash implementations in the stdlib or hashes vendored
|
|
||||||
// here can return errors from Write. Having a panic in this
|
|
||||||
// condition instead of having FromBytes return an error value
|
|
||||||
// avoids unnecessary error handling paths in all callers.
|
|
||||||
panic("write to hash function returned error: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return digester.Digest()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromString digests the string input and returns a Digest.
|
|
||||||
func (a Algorithm) FromString(s string) Digest {
|
|
||||||
return a.FromBytes([]byte(s))
|
|
||||||
}
|
|
140
vendor/github.com/docker/distribution/vendor/github.com/opencontainers/go-digest/digest.go
generated
vendored
140
vendor/github.com/docker/distribution/vendor/github.com/opencontainers/go-digest/digest.go
generated
vendored
|
@ -1,140 +0,0 @@
|
||||||
package digest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Digest allows simple protection of hex formatted digest strings, prefixed
|
|
||||||
// by their algorithm. Strings of type Digest have some guarantee of being in
|
|
||||||
// the correct format and it provides quick access to the components of a
|
|
||||||
// digest string.
|
|
||||||
//
|
|
||||||
// The following is an example of the contents of Digest types:
|
|
||||||
//
|
|
||||||
// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
|
|
||||||
//
|
|
||||||
// This allows to abstract the digest behind this type and work only in those
|
|
||||||
// terms.
|
|
||||||
type Digest string
|
|
||||||
|
|
||||||
// NewDigest returns a Digest from alg and a hash.Hash object.
|
|
||||||
func NewDigest(alg Algorithm, h hash.Hash) Digest {
|
|
||||||
return NewDigestFromBytes(alg, h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDigestFromBytes returns a new digest from the byte contents of p.
|
|
||||||
// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...)
|
|
||||||
// functions. This is also useful for rebuilding digests from binary
|
|
||||||
// serializations.
|
|
||||||
func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
|
|
||||||
return Digest(fmt.Sprintf("%s:%x", alg, p))
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDigestFromHex returns a Digest from alg and a the hex encoded digest.
|
|
||||||
func NewDigestFromHex(alg, hex string) Digest {
|
|
||||||
return Digest(fmt.Sprintf("%s:%s", alg, hex))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DigestRegexp matches valid digest types.
|
|
||||||
var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`)
|
|
||||||
|
|
||||||
// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match.
|
|
||||||
var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrDigestInvalidFormat returned when digest format invalid.
|
|
||||||
ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")
|
|
||||||
|
|
||||||
// ErrDigestInvalidLength returned when digest has invalid length.
|
|
||||||
ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")
|
|
||||||
|
|
||||||
// ErrDigestUnsupported returned when the digest algorithm is unsupported.
|
|
||||||
ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Parse parses s and returns the validated digest object. An error will
|
|
||||||
// be returned if the format is invalid.
|
|
||||||
func Parse(s string) (Digest, error) {
|
|
||||||
d := Digest(s)
|
|
||||||
return d, d.Validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromReader consumes the content of rd until io.EOF, returning canonical digest.
|
|
||||||
func FromReader(rd io.Reader) (Digest, error) {
|
|
||||||
return Canonical.FromReader(rd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromBytes digests the input and returns a Digest.
|
|
||||||
func FromBytes(p []byte) Digest {
|
|
||||||
return Canonical.FromBytes(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromString digests the input and returns a Digest.
|
|
||||||
func FromString(s string) Digest {
|
|
||||||
return Canonical.FromString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate checks that the contents of d is a valid digest, returning an
|
|
||||||
// error if not.
|
|
||||||
func (d Digest) Validate() error {
|
|
||||||
s := string(d)
|
|
||||||
|
|
||||||
i := strings.Index(s, ":")
|
|
||||||
|
|
||||||
// validate i then run through regexp
|
|
||||||
if i < 0 || i+1 == len(s) || !DigestRegexpAnchored.MatchString(s) {
|
|
||||||
return ErrDigestInvalidFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
algorithm := Algorithm(s[:i])
|
|
||||||
if !algorithm.Available() {
|
|
||||||
return ErrDigestUnsupported
|
|
||||||
}
|
|
||||||
|
|
||||||
// Digests much always be hex-encoded, ensuring that their hex portion will
|
|
||||||
// always be size*2
|
|
||||||
if algorithm.Size()*2 != len(s[i+1:]) {
|
|
||||||
return ErrDigestInvalidLength
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Algorithm returns the algorithm portion of the digest. This will panic if
|
|
||||||
// the underlying digest is not in a valid format.
|
|
||||||
func (d Digest) Algorithm() Algorithm {
|
|
||||||
return Algorithm(d[:d.sepIndex()])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verifier returns a writer object that can be used to verify a stream of
|
|
||||||
// content against the digest. If the digest is invalid, the method will panic.
|
|
||||||
func (d Digest) Verifier() Verifier {
|
|
||||||
return hashVerifier{
|
|
||||||
hash: d.Algorithm().Hash(),
|
|
||||||
digest: d,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hex returns the hex digest portion of the digest. This will panic if the
|
|
||||||
// underlying digest is not in a valid format.
|
|
||||||
func (d Digest) Hex() string {
|
|
||||||
return string(d[d.sepIndex()+1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Digest) String() string {
|
|
||||||
return string(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Digest) sepIndex() int {
|
|
||||||
i := strings.Index(string(d), ":")
|
|
||||||
|
|
||||||
if i < 0 {
|
|
||||||
panic(fmt.Sprintf("no ':' separator in digest %q", d))
|
|
||||||
}
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package digest
|
|
||||||
|
|
||||||
import "hash"
|
|
||||||
|
|
||||||
// Digester calculates the digest of written data. Writes should go directly
|
|
||||||
// to the return value of Hash, while calling Digest will return the current
|
|
||||||
// value of the digest.
|
|
||||||
type Digester interface {
|
|
||||||
Hash() hash.Hash // provides direct access to underlying hash instance.
|
|
||||||
Digest() Digest
|
|
||||||
}
|
|
||||||
|
|
||||||
// digester provides a simple digester definition that embeds a hasher.
|
|
||||||
type digester struct {
|
|
||||||
alg Algorithm
|
|
||||||
hash hash.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *digester) Hash() hash.Hash {
|
|
||||||
return d.hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *digester) Digest() Digest {
|
|
||||||
return NewDigest(d.alg, d.hash)
|
|
||||||
}
|
|
42
vendor/github.com/docker/distribution/vendor/github.com/opencontainers/go-digest/doc.go
generated
vendored
42
vendor/github.com/docker/distribution/vendor/github.com/opencontainers/go-digest/doc.go
generated
vendored
|
@ -1,42 +0,0 @@
|
||||||
// Package digest provides a generalized type to opaquely represent message
|
|
||||||
// digests and their operations within the registry. The Digest type is
|
|
||||||
// designed to serve as a flexible identifier in a content-addressable system.
|
|
||||||
// More importantly, it provides tools and wrappers to work with
|
|
||||||
// hash.Hash-based digests with little effort.
|
|
||||||
//
|
|
||||||
// Basics
|
|
||||||
//
|
|
||||||
// The format of a digest is simply a string with two parts, dubbed the
|
|
||||||
// "algorithm" and the "digest", separated by a colon:
|
|
||||||
//
|
|
||||||
// <algorithm>:<digest>
|
|
||||||
//
|
|
||||||
// An example of a sha256 digest representation follows:
|
|
||||||
//
|
|
||||||
// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
|
|
||||||
//
|
|
||||||
// In this case, the string "sha256" is the algorithm and the hex bytes are
|
|
||||||
// the "digest".
|
|
||||||
//
|
|
||||||
// Because the Digest type is simply a string, once a valid Digest is
|
|
||||||
// obtained, comparisons are cheap, quick and simple to express with the
|
|
||||||
// standard equality operator.
|
|
||||||
//
|
|
||||||
// Verification
|
|
||||||
//
|
|
||||||
// The main benefit of using the Digest type is simple verification against a
|
|
||||||
// given digest. The Verifier interface, modeled after the stdlib hash.Hash
|
|
||||||
// interface, provides a common write sink for digest verification. After
|
|
||||||
// writing is complete, calling the Verifier.Verified method will indicate
|
|
||||||
// whether or not the stream of bytes matches the target digest.
|
|
||||||
//
|
|
||||||
// Missing Features
|
|
||||||
//
|
|
||||||
// In addition to the above, we intend to add the following features to this
|
|
||||||
// package:
|
|
||||||
//
|
|
||||||
// 1. A Digester type that supports write sink digest calculation.
|
|
||||||
//
|
|
||||||
// 2. Suspend and resume of ongoing digest calculations to support efficient digest verification in the registry.
|
|
||||||
//
|
|
||||||
package digest
|
|
|
@ -1,31 +0,0 @@
|
||||||
package digest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Verifier presents a general verification interface to be used with message
|
|
||||||
// digests and other byte stream verifications. Users instantiate a Verifier
|
|
||||||
// from one of the various methods, write the data under test to it then check
|
|
||||||
// the result with the Verified method.
|
|
||||||
type Verifier interface {
|
|
||||||
io.Writer
|
|
||||||
|
|
||||||
// Verified will return true if the content written to Verifier matches
|
|
||||||
// the digest.
|
|
||||||
Verified() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type hashVerifier struct {
|
|
||||||
digest Digest
|
|
||||||
hash hash.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hv hashVerifier) Write(p []byte) (n int, err error) {
|
|
||||||
return hv.hash.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hv hashVerifier) Verified() bool {
|
|
||||||
return hv.digest == NewDigest(hv.digest.Algorithm(), hv.hash)
|
|
||||||
}
|
|
|
@ -176,7 +176,7 @@
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
Copyright 2013-2017 Docker, Inc.
|
Copyright 2015 Docker, Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
|
@ -176,7 +176,7 @@
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
Copyright 2013-2017 Docker, Inc.
|
Copyright 2015 Docker, Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
https://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
@ -176,13 +176,13 @@
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
Copyright 2013-2017 Docker, Inc.
|
Copyright 2014 Docker, Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
https://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
@ -152,7 +152,7 @@ func NewIdentityAuthTLSClientConfig(dockerUrl string, trustUnknownHosts bool, ro
|
||||||
}
|
}
|
||||||
|
|
||||||
// joseBase64UrlEncode encodes the given data using the standard base64 url
|
// joseBase64UrlEncode encodes the given data using the standard base64 url
|
||||||
// encoding format but with all trailing '=' characters ommitted in accordance
|
// encoding format but with all trailing '=' characters omitted in accordance
|
||||||
// with the jose specification.
|
// with the jose specification.
|
||||||
// http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2
|
// http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2
|
||||||
func joseBase64UrlEncode(b []byte) string {
|
func joseBase64UrlEncode(b []byte) string {
|
||||||
|
@ -164,6 +164,8 @@ func joseBase64UrlEncode(b []byte) string {
|
||||||
// accordance with the jose specification.
|
// accordance with the jose specification.
|
||||||
// http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2
|
// http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2
|
||||||
func joseBase64UrlDecode(s string) ([]byte, error) {
|
func joseBase64UrlDecode(s string) ([]byte, error) {
|
||||||
|
s = strings.Replace(s, "\n", "", -1)
|
||||||
|
s = strings.Replace(s, " ", "", -1)
|
||||||
switch len(s) % 4 {
|
switch len(s) % 4 {
|
||||||
case 0:
|
case 0:
|
||||||
case 2:
|
case 2:
|
27
vendor/github.com/gorilla/mux/LICENSE
generated
vendored
Normal file
27
vendor/github.com/gorilla/mux/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2012 Rodrigo Moraes. 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.
|
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
|
||||||
|
}
|
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -60,8 +69,8 @@ Routes can also be restricted to a domain or subdomain. Just define a host
|
||||||
pattern to be matched. They can also have variables:
|
pattern to be matched. They can also have variables:
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
// Only matches if domain is "www.domain.com".
|
// Only matches if domain is "www.example.com".
|
||||||
r.Host("www.domain.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")
|
||||||
|
|
||||||
|
@ -89,12 +98,12 @@ There are several other matchers that can be added. To match path prefixes:
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
r.HandleFunc("/products", ProductsHandler).
|
r.HandleFunc("/products", ProductsHandler).
|
||||||
Host("www.domain.com").
|
Host("www.example.com").
|
||||||
Methods("GET").
|
Methods("GET").
|
||||||
Schemes("http")
|
Schemes("http")
|
||||||
|
|
||||||
|
@ -103,11 +112,11 @@ a way to group several routes that share the same requirements.
|
||||||
We call it "subrouting".
|
We call it "subrouting".
|
||||||
|
|
||||||
For example, let's say we have several URLs that should only match when the
|
For example, let's say we have several URLs that should only match when the
|
||||||
host is "www.domain.com". Create a route for that host and get a "subrouter"
|
host is "www.example.com". Create a route for that host and get a "subrouter"
|
||||||
from it:
|
from it:
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
s := r.Host("www.domain.com").Subrouter()
|
s := r.Host("www.example.com").Subrouter()
|
||||||
|
|
||||||
Then register routes in the subrouter:
|
Then register routes in the subrouter:
|
||||||
|
|
||||||
|
@ -116,7 +125,7 @@ Then register routes in the subrouter:
|
||||||
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.domain.com", because the subrouter is tested first. This is not
|
"www.example.com", because the subrouter is tested first. This is not
|
||||||
only convenient, but also optimizes request matching. You can create
|
only convenient, but also optimizes request matching. You can create
|
||||||
subrouters combining any attribute matchers accepted by a route.
|
subrouters combining any attribute matchers accepted by a route.
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -164,14 +198,21 @@ This also works for host variables:
|
||||||
|
|
||||||
// url.String() will be "http://news.domain.com/articles/technology/42"
|
// url.String() will be "http://news.domain.com/articles/technology/42"
|
||||||
url, err := r.Get("article").URL("subdomain", "news",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42")
|
||||||
|
|
||||||
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
|
||||||
generated URL will always match a registered route -- the only exception is
|
generated URL will always match a registered route -- the only exception is
|
||||||
for explicitly defined "build-only" routes which never match.
|
for explicitly defined "build-only" routes which never match.
|
||||||
|
|
||||||
|
Regex support also exists for matching Headers within a route. For example, we could do:
|
||||||
|
|
||||||
|
r.HeadersRegexp("Content-Type", "application/(text|json)")
|
||||||
|
|
||||||
|
...and the route will match both requests with a Content-Type of `application/json` as well as
|
||||||
|
`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,
|
use the methods URLHost() or URLPath() instead. For the previous route,
|
||||||
we would do:
|
we would do:
|
||||||
|
@ -193,7 +234,7 @@ as well:
|
||||||
|
|
||||||
// "http://news.domain.com/articles/technology/42"
|
// "http://news.domain.com/articles/technology/42"
|
||||||
url, err := r.Get("article").URL("subdomain", "news",
|
url, err := r.Get("article").URL("subdomain", "news",
|
||||||
"category", "technology",
|
"category", "technology",
|
||||||
"id", "42")
|
"id", "42")
|
||||||
*/
|
*/
|
||||||
package mux
|
package mux
|
|
@ -5,11 +5,12 @@
|
||||||
package mux
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
"github.com/gorilla/context"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRouter returns a new router instance.
|
// NewRouter returns a new router instance.
|
||||||
|
@ -46,8 +47,14 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match matches registered routes against the request.
|
// Match matches registered routes against the request.
|
||||||
|
@ -57,6 +64,12 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Closest match for a router (includes sub-routers)
|
||||||
|
if r.NotFoundHandler != nil {
|
||||||
|
match.Handler = r.NotFoundHandler
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,35 +78,38 @@ 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) {
|
||||||
// Clean path to canonical form and redirect.
|
if !r.skipClean {
|
||||||
if p := cleanPath(req.URL.Path); p != req.URL.Path {
|
path := req.URL.Path
|
||||||
|
if r.useEncodedPath {
|
||||||
|
path = getPath(req)
|
||||||
|
}
|
||||||
|
// Clean path to canonical form and redirect.
|
||||||
|
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
|
||||||
url.Path = p
|
url.Path = p
|
||||||
p = url.String()
|
p = url.String()
|
||||||
|
|
||||||
w.Header().Set("Location", p)
|
w.Header().Set("Location", p)
|
||||||
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 {
|
if handler == nil {
|
||||||
handler = r.NotFoundHandler
|
handler = http.NotFoundHandler()
|
||||||
if handler == nil {
|
|
||||||
handler = http.NotFoundHandler()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !r.KeepContext {
|
if !r.KeepContext {
|
||||||
defer context.Clear(req)
|
defer contextClear(req)
|
||||||
}
|
}
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
}
|
}
|
||||||
|
@ -128,6 +144,34 @@ 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".
|
||||||
|
// This behavior has the drawback of needing to match routes against
|
||||||
|
// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix)
|
||||||
|
// to r.URL.Path will not affect routing when this flag is on and thus may
|
||||||
|
// induce unintended behavior.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -152,13 +196,20 @@ func (r *Router) getRegexpGroup() *routeRegexpGroup {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Router) buildVars(m map[string]string) map[string]string {
|
||||||
|
if r.parent != nil {
|
||||||
|
m = r.parent.buildVars(m)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Route factories
|
// Route factories
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
@ -224,6 +275,61 @@ func (r *Router) Schemes(schemes ...string) *Route {
|
||||||
return r.NewRoute().Schemes(schemes...)
|
return r.NewRoute().Schemes(schemes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildVarsFunc registers a new route with a custom function for modifying
|
||||||
|
// route variables before building a URL.
|
||||||
|
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
|
||||||
|
return r.NewRoute().BuildVarsFunc(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk walks the router and all its sub-routers, calling walkFn for each route
|
||||||
|
// in the tree. The routes are walked in the order they were added. Sub-routers
|
||||||
|
// are explored depth-first.
|
||||||
|
func (r *Router) Walk(walkFn WalkFunc) error {
|
||||||
|
return r.walk(walkFn, []*Route{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkipRouter is used as a return value from WalkFuncs to indicate that the
|
||||||
|
// router that walk is about to descend down to should be skipped.
|
||||||
|
var SkipRouter = errors.New("skip this router")
|
||||||
|
|
||||||
|
// WalkFunc is the type of the function called for each route visited by Walk.
|
||||||
|
// At every invocation, it is given the current route, and the current router,
|
||||||
|
// and a list of ancestor routes that lead to the current route.
|
||||||
|
type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
|
||||||
|
|
||||||
|
func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
|
||||||
|
for _, t := range r.routes {
|
||||||
|
if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err := walkFn(t, r, ancestors)
|
||||||
|
if err == SkipRouter {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, sr := range t.matchers {
|
||||||
|
if h, ok := sr.(*Router); ok {
|
||||||
|
err := h.walk(walkFn, ancestors)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if h, ok := t.handler.(*Router); ok {
|
||||||
|
ancestors = append(ancestors, t)
|
||||||
|
err := h.walk(walkFn, ancestors)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ancestors = ancestors[:len(ancestors)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Context
|
// Context
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -244,32 +350,58 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentRoute returns the matched route for the current request, if any.
|
// CurrentRoute returns the matched route for the current request, if any.
|
||||||
|
// This only works when called inside the handler of the matched route
|
||||||
|
// because the matched route is stored in the request context which is cleared
|
||||||
|
// after the handler returns, unless the KeepContext option is set on the
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// getPath returns the escaped path if possible; doing what URL.EscapedPath()
|
||||||
|
// which was added in go1.5 does
|
||||||
|
func getPath(req *http.Request) string {
|
||||||
|
if req.RequestURI != "" {
|
||||||
|
// Extract the path from RequestURI (which is escaped unlike URL.Path)
|
||||||
|
// as detailed here as detailed in https://golang.org/pkg/net/url/#URL
|
||||||
|
// for < 1.5 server side workaround
|
||||||
|
// http://localhost/path/here?v=1 -> /path/here
|
||||||
|
path := req.RequestURI
|
||||||
|
path = strings.TrimPrefix(path, req.URL.Scheme+`://`)
|
||||||
|
path = strings.TrimPrefix(path, req.URL.Host)
|
||||||
|
if i := strings.LastIndex(path, "?"); i > -1 {
|
||||||
|
path = path[:i]
|
||||||
|
}
|
||||||
|
if i := strings.LastIndex(path, "#"); i > -1 {
|
||||||
|
path = path[:i]
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return req.URL.Path
|
||||||
|
}
|
||||||
|
|
||||||
// cleanPath returns the canonical path for p, eliminating . and .. elements.
|
// cleanPath returns the canonical path for p, eliminating . and .. elements.
|
||||||
// Borrowed from the net/http package.
|
// Borrowed from the net/http package.
|
||||||
func cleanPath(p string) string {
|
func cleanPath(p string) string {
|
||||||
|
@ -285,6 +417,7 @@ func cleanPath(p string) string {
|
||||||
if p[len(p)-1] == '/' && np != "/" {
|
if p[len(p)-1] == '/' && np != "/" {
|
||||||
np += "/"
|
np += "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
return np
|
return np
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,13 +433,24 @@ func uniqueVars(s1, s2 []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mapFromPairs converts variadic string parameters to a string map.
|
// checkPairs returns the count of strings passed in, and an error if
|
||||||
func mapFromPairs(pairs ...string) (map[string]string, error) {
|
// the count is not an even number.
|
||||||
|
func checkPairs(pairs ...string) (int, error) {
|
||||||
length := len(pairs)
|
length := len(pairs)
|
||||||
if length%2 != 0 {
|
if length%2 != 0 {
|
||||||
return nil, fmt.Errorf(
|
return length, fmt.Errorf(
|
||||||
"mux: number of parameters must be multiple of 2, got %v", pairs)
|
"mux: number of parameters must be multiple of 2, got %v", pairs)
|
||||||
}
|
}
|
||||||
|
return length, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// mapFromPairsToString converts variadic string parameters to a
|
||||||
|
// string to string map.
|
||||||
|
func mapFromPairsToString(pairs ...string) (map[string]string, error) {
|
||||||
|
length, err := checkPairs(pairs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
m := make(map[string]string, length/2)
|
m := make(map[string]string, length/2)
|
||||||
for i := 0; i < length; i += 2 {
|
for i := 0; i < length; i += 2 {
|
||||||
m[pairs[i]] = pairs[i+1]
|
m[pairs[i]] = pairs[i+1]
|
||||||
|
@ -314,6 +458,24 @@ func mapFromPairs(pairs ...string) (map[string]string, error) {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mapFromPairsToRegex converts variadic string paramers to a
|
||||||
|
// string to regex map.
|
||||||
|
func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
|
||||||
|
length, err := checkPairs(pairs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m := make(map[string]*regexp.Regexp, length/2)
|
||||||
|
for i := 0; i < length; i += 2 {
|
||||||
|
regex, err := regexp.Compile(pairs[i+1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m[pairs[i]] = regex
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
// matchInArray returns true if the given string value is in the array.
|
// matchInArray returns true if the given string value is in the array.
|
||||||
func matchInArray(arr []string, value string) bool {
|
func matchInArray(arr []string, value string) bool {
|
||||||
for _, v := range arr {
|
for _, v := range arr {
|
||||||
|
@ -324,9 +486,8 @@ func matchInArray(arr []string, value string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchMap returns true if the given key/value pairs exist in a given map.
|
// matchMapWithString returns true if the given key/value pairs exist in a given map.
|
||||||
func matchMap(toCheck map[string]string, toMatch map[string][]string,
|
func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
|
||||||
canonicalKey bool) bool {
|
|
||||||
for k, v := range toCheck {
|
for k, v := range toCheck {
|
||||||
// Check if key exists.
|
// Check if key exists.
|
||||||
if canonicalKey {
|
if canonicalKey {
|
||||||
|
@ -351,3 +512,31 @@ func matchMap(toCheck map[string]string, toMatch map[string][]string,
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
|
||||||
|
// the given regex
|
||||||
|
func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
|
||||||
|
for k, v := range toCheck {
|
||||||
|
// Check if key exists.
|
||||||
|
if canonicalKey {
|
||||||
|
k = http.CanonicalHeaderKey(k)
|
||||||
|
}
|
||||||
|
if values := toMatch[k]; values == nil {
|
||||||
|
return false
|
||||||
|
} else if v != nil {
|
||||||
|
// If value was defined as an empty string we only check that the
|
||||||
|
// key exists. Otherwise we also check for equality.
|
||||||
|
valueExists := false
|
||||||
|
for _, value := range values {
|
||||||
|
if v.MatchString(value) {
|
||||||
|
valueExists = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !valueExists {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,7 +24,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, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*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,8 +35,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
// Now let's parse it.
|
// Now let's parse it.
|
||||||
defaultPattern := "[^/]+"
|
defaultPattern := "[^/]+"
|
||||||
if matchQuery {
|
if matchQuery {
|
||||||
defaultPattern = "[^?&]+"
|
defaultPattern = "[^?&]*"
|
||||||
matchPrefix = true
|
|
||||||
} else if matchHost {
|
} else if matchHost {
|
||||||
defaultPattern = "[^.]+"
|
defaultPattern = "[^.]+"
|
||||||
matchPrefix = false
|
matchPrefix = false
|
||||||
|
@ -53,9 +53,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
varsN := make([]string, len(idxs)/2)
|
varsN := make([]string, len(idxs)/2)
|
||||||
varsR := make([]*regexp.Regexp, len(idxs)/2)
|
varsR := make([]*regexp.Regexp, len(idxs)/2)
|
||||||
pattern := bytes.NewBufferString("")
|
pattern := bytes.NewBufferString("")
|
||||||
if !matchQuery {
|
pattern.WriteByte('^')
|
||||||
pattern.WriteByte('^')
|
|
||||||
}
|
|
||||||
reverse := bytes.NewBufferString("")
|
reverse := bytes.NewBufferString("")
|
||||||
var end int
|
var end int
|
||||||
var err error
|
var err error
|
||||||
|
@ -75,9 +73,11 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
tpl[idxs[i]:end])
|
tpl[idxs[i]:end])
|
||||||
}
|
}
|
||||||
// Build the regexp pattern.
|
// Build the regexp pattern.
|
||||||
fmt.Fprintf(pattern, "%s(%s)", regexp.QuoteMeta(raw), patt)
|
fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), 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[i/2] = name
|
varsN[i/2] = name
|
||||||
varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
|
varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
|
||||||
|
@ -91,6 +91,12 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash
|
||||||
if strictSlash {
|
if strictSlash {
|
||||||
pattern.WriteString("[/]?")
|
pattern.WriteString("[/]?")
|
||||||
}
|
}
|
||||||
|
if matchQuery {
|
||||||
|
// Add the default pattern if the query value is empty
|
||||||
|
if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
|
||||||
|
pattern.WriteString(defaultPattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
if !matchPrefix {
|
if !matchPrefix {
|
||||||
pattern.WriteByte('$')
|
pattern.WriteByte('$')
|
||||||
}
|
}
|
||||||
|
@ -103,16 +109,24 @@ 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,
|
matchHost: matchHost,
|
||||||
matchQuery: matchQuery,
|
matchQuery: matchQuery,
|
||||||
strictSlash: strictSlash,
|
strictSlash: strictSlash,
|
||||||
regexp: reg,
|
useEncodedPath: useEncodedPath,
|
||||||
reverse: reverse.String(),
|
regexp: reg,
|
||||||
varsN: varsN,
|
reverse: reverse.String(),
|
||||||
varsR: varsR,
|
varsN: varsN,
|
||||||
|
varsR: varsR,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +141,9 @@ type routeRegexp struct {
|
||||||
matchQuery bool
|
matchQuery bool
|
||||||
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
|
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
|
||||||
strictSlash bool
|
strictSlash bool
|
||||||
|
// Determines whether to use encoded path from getPath function or unencoded
|
||||||
|
// req.URL.Path for path matching
|
||||||
|
useEncodedPath bool
|
||||||
// Expanded regexp.
|
// Expanded regexp.
|
||||||
regexp *regexp.Regexp
|
regexp *regexp.Regexp
|
||||||
// Reverse template.
|
// Reverse template.
|
||||||
|
@ -141,20 +158,20 @@ type routeRegexp struct {
|
||||||
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.matchHost {
|
||||||
if r.matchQuery {
|
if r.matchQuery {
|
||||||
return r.regexp.MatchString(req.URL.RawQuery)
|
return r.matchQueryString(req)
|
||||||
} else {
|
|
||||||
return r.regexp.MatchString(req.URL.Path)
|
|
||||||
}
|
}
|
||||||
|
path := req.URL.Path
|
||||||
|
if r.useEncodedPath {
|
||||||
|
path = getPath(req)
|
||||||
|
}
|
||||||
|
return r.regexp.MatchString(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.regexp.MatchString(getHost(req))
|
return r.regexp.MatchString(getHost(req))
|
||||||
}
|
}
|
||||||
|
|
||||||
// url builds a URL part using the given values.
|
// url builds a URL part using the given values.
|
||||||
func (r *routeRegexp) url(pairs ...string) (string, error) {
|
func (r *routeRegexp) url(values map[string]string) (string, error) {
|
||||||
values, err := mapFromPairs(pairs...)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
urlValues := make([]interface{}, len(r.varsN))
|
urlValues := make([]interface{}, len(r.varsN))
|
||||||
for k, v := range r.varsN {
|
for k, v := range r.varsN {
|
||||||
value, ok := values[v]
|
value, ok := values[v]
|
||||||
|
@ -179,11 +196,31 @@ func (r *routeRegexp) url(pairs ...string) (string, error) {
|
||||||
return rv, nil
|
return rv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getURLQuery returns a single query parameter from a request URL.
|
||||||
|
// For a URL with foo=bar&baz=ding, we return only the relevant key
|
||||||
|
// value pair for the routeRegexp.
|
||||||
|
func (r *routeRegexp) getURLQuery(req *http.Request) string {
|
||||||
|
if !r.matchQuery {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
templateKey := strings.SplitN(r.template, "=", 2)[0]
|
||||||
|
for key, vals := range req.URL.Query() {
|
||||||
|
if key == templateKey && len(vals) > 0 {
|
||||||
|
return key + "=" + vals[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *routeRegexp) matchQueryString(req *http.Request) bool {
|
||||||
|
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 '{':
|
||||||
|
@ -204,6 +241,11 @@ func braceIndices(s string) ([]int, error) {
|
||||||
return idxs, nil
|
return idxs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// varGroupName builds a capturing group name for the indexed variable.
|
||||||
|
func varGroupName(idx int) string {
|
||||||
|
return "v" + strconv.Itoa(idx)
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// routeRegexpGroup
|
// routeRegexpGroup
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -219,23 +261,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)
|
||||||
for k, v := range v.host.varsN {
|
if len(matches) > 0 {
|
||||||
m.Vars[v] = hostVars[k+1]
|
extractVars(host, matches, v.host.varsN, m.Vars)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
path := req.URL.Path
|
||||||
|
if r.useEncodedPath {
|
||||||
|
path = getPath(req)
|
||||||
|
}
|
||||||
// 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 {
|
||||||
for k, v := range v.path.varsN {
|
extractVars(path, matches, v.path.varsN, m.Vars)
|
||||||
m.Vars[v] = pathVars[k+1]
|
|
||||||
}
|
|
||||||
// Check if we should redirect.
|
// Check if we should redirect.
|
||||||
if v.path.strictSlash {
|
if v.path.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())
|
||||||
|
@ -250,13 +293,11 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Store query string variables.
|
// Store query string variables.
|
||||||
rawQuery := req.URL.RawQuery
|
|
||||||
for _, q := range v.queries {
|
for _, q := range v.queries {
|
||||||
queryVars := q.regexp.FindStringSubmatch(rawQuery)
|
queryURL := q.getURLQuery(req)
|
||||||
if queryVars != nil {
|
matches := q.regexp.FindStringSubmatchIndex(queryURL)
|
||||||
for k, v := range q.varsN {
|
if len(matches) > 0 {
|
||||||
m.Vars[v] = queryVars[k+1]
|
extractVars(queryURL, matches, q.varsN, m.Vars)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,3 +315,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]]
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,12 +26,23 @@ 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
|
||||||
// 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.
|
||||||
name string
|
name string
|
||||||
// Error resulted from building a route.
|
// Error resulted from building a route.
|
||||||
err error
|
err error
|
||||||
|
|
||||||
|
buildVarsFunc BuildVarsFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Route) SkipClean() bool {
|
||||||
|
return r.skipClean
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match matches the route against the request.
|
// Match matches the route against the request.
|
||||||
|
@ -141,14 +153,14 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
|
||||||
}
|
}
|
||||||
r.regexp = r.getRegexpGroup()
|
r.regexp = r.getRegexpGroup()
|
||||||
if !matchHost && !matchQuery {
|
if !matchHost && !matchQuery {
|
||||||
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, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -186,7 +198,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
|
||||||
type headerMatcher map[string]string
|
type headerMatcher map[string]string
|
||||||
|
|
||||||
func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
||||||
return matchMap(m, r.Header, true)
|
return matchMapWithString(m, r.Header, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headers adds a matcher for request header values.
|
// Headers adds a matcher for request header values.
|
||||||
|
@ -197,22 +209,46 @@ func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
||||||
// "X-Requested-With", "XMLHttpRequest")
|
// "X-Requested-With", "XMLHttpRequest")
|
||||||
//
|
//
|
||||||
// The above route will only match if both request header values match.
|
// The above route will only match if both request header values match.
|
||||||
//
|
// If the value is an empty string, it will match any value if the key is set.
|
||||||
// It the value is an empty string, it will match any value if the key is set.
|
|
||||||
func (r *Route) Headers(pairs ...string) *Route {
|
func (r *Route) Headers(pairs ...string) *Route {
|
||||||
if r.err == nil {
|
if r.err == nil {
|
||||||
var headers map[string]string
|
var headers map[string]string
|
||||||
headers, r.err = mapFromPairs(pairs...)
|
headers, r.err = mapFromPairsToString(pairs...)
|
||||||
return r.addMatcher(headerMatcher(headers))
|
return r.addMatcher(headerMatcher(headers))
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// headerRegexMatcher matches the request against the route given a regex for the header
|
||||||
|
type headerRegexMatcher map[string]*regexp.Regexp
|
||||||
|
|
||||||
|
func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
||||||
|
return matchMapWithRegex(m, r.Header, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
|
||||||
|
// support. For example:
|
||||||
|
//
|
||||||
|
// r := mux.NewRouter()
|
||||||
|
// r.HeadersRegexp("Content-Type", "application/(text|json)",
|
||||||
|
// "X-Requested-With", "XMLHttpRequest")
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
func (r *Route) HeadersRegexp(pairs ...string) *Route {
|
||||||
|
if r.err == nil {
|
||||||
|
var headers map[string]*regexp.Regexp
|
||||||
|
headers, r.err = mapFromPairsToRegex(pairs...)
|
||||||
|
return r.addMatcher(headerRegexMatcher(headers))
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// Host -----------------------------------------------------------------------
|
// Host -----------------------------------------------------------------------
|
||||||
|
|
||||||
// Host adds a matcher for the URL host.
|
// Host adds a matcher for the URL host.
|
||||||
// It accepts a template with zero or more URL variables enclosed by {}.
|
// It accepts a template with zero or more URL variables enclosed by {}.
|
||||||
// Variables can define an optional regexp pattern to me matched:
|
// Variables can define an optional regexp pattern to be matched:
|
||||||
//
|
//
|
||||||
// - {name} matches anything until the next dot.
|
// - {name} matches anything until the next dot.
|
||||||
//
|
//
|
||||||
|
@ -221,7 +257,7 @@ func (r *Route) Headers(pairs ...string) *Route {
|
||||||
// For example:
|
// For example:
|
||||||
//
|
//
|
||||||
// r := mux.NewRouter()
|
// r := mux.NewRouter()
|
||||||
// r.Host("www.domain.com")
|
// r.Host("www.example.com")
|
||||||
// r.Host("{subdomain}.domain.com")
|
// r.Host("{subdomain}.domain.com")
|
||||||
// r.Host("{subdomain:[a-z]+}.domain.com")
|
// r.Host("{subdomain:[a-z]+}.domain.com")
|
||||||
//
|
//
|
||||||
|
@ -237,6 +273,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)
|
||||||
}
|
}
|
||||||
|
@ -270,7 +307,7 @@ func (r *Route) Methods(methods ...string) *Route {
|
||||||
// Path adds a matcher for the URL path.
|
// Path adds a matcher for the URL path.
|
||||||
// It accepts a template with zero or more URL variables enclosed by {}. The
|
// It accepts a template with zero or more URL variables enclosed by {}. The
|
||||||
// template must start with a "/".
|
// template must start with a "/".
|
||||||
// Variables can define an optional regexp pattern to me matched:
|
// Variables can define an optional regexp pattern to be matched:
|
||||||
//
|
//
|
||||||
// - {name} matches anything until the next slash.
|
// - {name} matches anything until the next slash.
|
||||||
//
|
//
|
||||||
|
@ -321,7 +358,7 @@ func (r *Route) PathPrefix(tpl string) *Route {
|
||||||
//
|
//
|
||||||
// It the value is an empty string, it will match any value if the key is set.
|
// It the value is an empty string, it will match any value if the key is set.
|
||||||
//
|
//
|
||||||
// Variables can define an optional regexp pattern to me matched:
|
// Variables can define an optional regexp pattern to be matched:
|
||||||
//
|
//
|
||||||
// - {name} matches anything until the next slash.
|
// - {name} matches anything until the next slash.
|
||||||
//
|
//
|
||||||
|
@ -334,7 +371,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, true, true); r.err != nil {
|
if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,6 +397,19 @@ func (r *Route) Schemes(schemes ...string) *Route {
|
||||||
return r.addMatcher(schemeMatcher(schemes))
|
return r.addMatcher(schemeMatcher(schemes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildVarsFunc --------------------------------------------------------------
|
||||||
|
|
||||||
|
// BuildVarsFunc is the function signature used by custom build variable
|
||||||
|
// functions (which can modify route variables before a route's URL is built).
|
||||||
|
type BuildVarsFunc func(map[string]string) map[string]string
|
||||||
|
|
||||||
|
// BuildVarsFunc adds a custom function to be used to modify build variables
|
||||||
|
// before a route's URL is built.
|
||||||
|
func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
|
||||||
|
r.buildVarsFunc = f
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// Subrouter ------------------------------------------------------------------
|
// Subrouter ------------------------------------------------------------------
|
||||||
|
|
||||||
// Subrouter creates a subrouter for the route.
|
// Subrouter creates a subrouter for the route.
|
||||||
|
@ -367,7 +417,7 @@ func (r *Route) Schemes(schemes ...string) *Route {
|
||||||
// It will test the inner routes only if the parent route matched. For example:
|
// It will test the inner routes only if the parent route matched. For example:
|
||||||
//
|
//
|
||||||
// r := mux.NewRouter()
|
// r := mux.NewRouter()
|
||||||
// s := r.Host("www.domain.com").Subrouter()
|
// s := r.Host("www.example.com").Subrouter()
|
||||||
// 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)
|
||||||
|
@ -422,17 +472,20 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
|
||||||
if r.regexp == nil {
|
if r.regexp == nil {
|
||||||
return nil, errors.New("mux: route doesn't have a host or path")
|
return nil, errors.New("mux: route doesn't have a host or path")
|
||||||
}
|
}
|
||||||
|
values, err := r.prepareVars(pairs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var scheme, host, path string
|
var scheme, host, path string
|
||||||
var err error
|
|
||||||
if r.regexp.host != nil {
|
if r.regexp.host != nil {
|
||||||
// Set a default scheme.
|
// Set a default scheme.
|
||||||
scheme = "http"
|
scheme = "http"
|
||||||
if host, err = r.regexp.host.url(pairs...); err != nil {
|
if host, err = r.regexp.host.url(values); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if r.regexp.path != nil {
|
if r.regexp.path != nil {
|
||||||
if path, err = r.regexp.path.url(pairs...); err != nil {
|
if path, err = r.regexp.path.url(values); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,7 +506,11 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
|
||||||
if r.regexp == nil || r.regexp.host == nil {
|
if r.regexp == nil || r.regexp.host == nil {
|
||||||
return nil, errors.New("mux: route doesn't have a host")
|
return nil, errors.New("mux: route doesn't have a host")
|
||||||
}
|
}
|
||||||
host, err := r.regexp.host.url(pairs...)
|
values, err := r.prepareVars(pairs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
host, err := r.regexp.host.url(values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -473,7 +530,11 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
||||||
if r.regexp == nil || r.regexp.path == nil {
|
if r.regexp == nil || r.regexp.path == nil {
|
||||||
return nil, errors.New("mux: route doesn't have a path")
|
return nil, errors.New("mux: route doesn't have a path")
|
||||||
}
|
}
|
||||||
path, err := r.regexp.path.url(pairs...)
|
values, err := r.prepareVars(pairs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
path, err := r.regexp.path.url(values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -482,6 +543,56 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// BuildVarsFunc, it is invoked.
|
||||||
|
func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
|
||||||
|
m, err := mapFromPairsToString(pairs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r.buildVars(m), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Route) buildVars(m map[string]string) map[string]string {
|
||||||
|
if r.parent != nil {
|
||||||
|
m = r.parent.buildVars(m)
|
||||||
|
}
|
||||||
|
if r.buildVarsFunc != nil {
|
||||||
|
m = r.buildVarsFunc(m)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// parentRoute
|
// parentRoute
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -490,6 +601,7 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
|
||||||
type parentRoute interface {
|
type parentRoute interface {
|
||||||
getNamedRoutes() map[string]*Route
|
getNamedRoutes() map[string]*Route
|
||||||
getRegexpGroup() *routeRegexpGroup
|
getRegexpGroup() *routeRegexpGroup
|
||||||
|
buildVars(map[string]string) map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// getNamedRoutes returns the map where named routes are registered.
|
// getNamedRoutes returns the map where named routes are registered.
|
191
vendor/github.com/opencontainers/runc/libcontainer/user/LICENSE
generated
vendored
Normal file
191
vendor/github.com/opencontainers/runc/libcontainer/user/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor 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, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Copyright 2014 Docker, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -199,18 +199,16 @@ type ExecUser struct {
|
||||||
// files cannot be opened for any reason, the error is ignored and a nil
|
// files cannot be opened for any reason, the error is ignored and a nil
|
||||||
// io.Reader is passed instead.
|
// io.Reader is passed instead.
|
||||||
func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) {
|
func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) {
|
||||||
passwd, err := os.Open(passwdPath)
|
var passwd, group io.Reader
|
||||||
if err != nil {
|
|
||||||
passwd = nil
|
if passwdFile, err := os.Open(passwdPath); err == nil {
|
||||||
} else {
|
passwd = passwdFile
|
||||||
defer passwd.Close()
|
defer passwdFile.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
group, err := os.Open(groupPath)
|
if groupFile, err := os.Open(groupPath); err == nil {
|
||||||
if err != nil {
|
group = groupFile
|
||||||
group = nil
|
defer groupFile.Close()
|
||||||
} else {
|
|
||||||
defer group.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetExecUser(userSpec, defaults, passwd, group)
|
return GetExecUser(userSpec, defaults, passwd, group)
|
||||||
|
@ -343,7 +341,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) (
|
||||||
if len(groups) > 0 {
|
if len(groups) > 0 {
|
||||||
// First match wins, even if there's more than one matching entry.
|
// First match wins, even if there's more than one matching entry.
|
||||||
user.Gid = groups[0].Gid
|
user.Gid = groups[0].Gid
|
||||||
} else if groupArg != "" {
|
} else {
|
||||||
// If we can't find a group with the given name, the only other valid
|
// If we can't find a group with the given name, the only other valid
|
||||||
// option is if it's a numeric group name with no associated entry in group.
|
// option is if it's a numeric group name with no associated entry in group.
|
||||||
|
|
||||||
|
@ -433,9 +431,11 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err
|
||||||
// that opens the groupPath given and gives it as an argument to
|
// that opens the groupPath given and gives it as an argument to
|
||||||
// GetAdditionalGroups.
|
// GetAdditionalGroups.
|
||||||
func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) {
|
func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) {
|
||||||
group, err := os.Open(groupPath)
|
var group io.Reader
|
||||||
if err == nil {
|
|
||||||
defer group.Close()
|
if groupFile, err := os.Open(groupPath); err == nil {
|
||||||
|
group = groupFile
|
||||||
|
defer groupFile.Close()
|
||||||
}
|
}
|
||||||
return GetAdditionalGroups(additionalGroups, group)
|
return GetAdditionalGroups(additionalGroups, group)
|
||||||
}
|
}
|
27
vendor/golang.org/x/net/context/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/net/context/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.
|
156
vendor/golang.org/x/net/context/context.go
generated
vendored
Normal file
156
vendor/golang.org/x/net/context/context.go
generated
vendored
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
// Copyright 2014 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 context defines the Context type, which carries deadlines,
|
||||||
|
// cancelation signals, and other request-scoped values across API boundaries
|
||||||
|
// and between processes.
|
||||||
|
//
|
||||||
|
// Incoming requests to a server should create a Context, and outgoing calls to
|
||||||
|
// servers should accept a Context. The chain of function calls between must
|
||||||
|
// propagate the Context, optionally replacing it with a modified copy created
|
||||||
|
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
||||||
|
//
|
||||||
|
// Programs that use Contexts should follow these rules to keep interfaces
|
||||||
|
// consistent across packages and enable static analysis tools to check context
|
||||||
|
// propagation:
|
||||||
|
//
|
||||||
|
// Do not store Contexts inside a struct type; instead, pass a Context
|
||||||
|
// explicitly to each function that needs it. The Context should be the first
|
||||||
|
// parameter, typically named ctx:
|
||||||
|
//
|
||||||
|
// func DoSomething(ctx context.Context, arg Arg) error {
|
||||||
|
// // ... use ctx ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||||
|
// if you are unsure about which Context to use.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
//
|
||||||
|
// The same Context may be passed to functions running in different goroutines;
|
||||||
|
// Contexts are safe for simultaneous use by multiple goroutines.
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/context for example code for a server that uses
|
||||||
|
// Contexts.
|
||||||
|
package context // import "golang.org/x/net/context"
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// A Context carries a deadline, a cancelation signal, and other values across
|
||||||
|
// API boundaries.
|
||||||
|
//
|
||||||
|
// Context's methods may be called by multiple goroutines simultaneously.
|
||||||
|
type Context interface {
|
||||||
|
// Deadline returns the time when work done on behalf of this context
|
||||||
|
// should be canceled. Deadline returns ok==false when no deadline is
|
||||||
|
// set. Successive calls to Deadline return the same results.
|
||||||
|
Deadline() (deadline time.Time, ok bool)
|
||||||
|
|
||||||
|
// Done returns a channel that's closed when work done on behalf of this
|
||||||
|
// context should be canceled. Done may return nil if this context can
|
||||||
|
// never be canceled. Successive calls to Done return the same value.
|
||||||
|
//
|
||||||
|
// WithCancel arranges for Done to be closed when cancel is called;
|
||||||
|
// WithDeadline arranges for Done to be closed when the deadline
|
||||||
|
// expires; WithTimeout arranges for Done to be closed when the timeout
|
||||||
|
// elapses.
|
||||||
|
//
|
||||||
|
// Done is provided for use in select statements:
|
||||||
|
//
|
||||||
|
// // Stream generates values with DoSomething and sends them to out
|
||||||
|
// // until DoSomething returns an error or ctx.Done is closed.
|
||||||
|
// func Stream(ctx context.Context, out chan<- Value) error {
|
||||||
|
// for {
|
||||||
|
// v, err := DoSomething(ctx)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// select {
|
||||||
|
// case <-ctx.Done():
|
||||||
|
// return ctx.Err()
|
||||||
|
// case out <- v:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/pipelines for more examples of how to use
|
||||||
|
// a Done channel for cancelation.
|
||||||
|
Done() <-chan struct{}
|
||||||
|
|
||||||
|
// Err returns a non-nil error value after Done is closed. Err returns
|
||||||
|
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||||
|
// context's deadline passed. No other values for Err are defined.
|
||||||
|
// After Done is closed, successive calls to Err return the same value.
|
||||||
|
Err() error
|
||||||
|
|
||||||
|
// Value returns the value associated with this context for key, or nil
|
||||||
|
// if no value is associated with key. Successive calls to Value with
|
||||||
|
// the same key returns the same result.
|
||||||
|
//
|
||||||
|
// Use context values only for request-scoped data that transits
|
||||||
|
// processes and API boundaries, not for passing optional parameters to
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
|
// A key identifies a specific value in a Context. Functions that wish
|
||||||
|
// to store values in Context typically allocate a key in a global
|
||||||
|
// variable then use that key as the argument to context.WithValue and
|
||||||
|
// Context.Value. A key can be any type that supports equality;
|
||||||
|
// packages should define keys as an unexported type to avoid
|
||||||
|
// collisions.
|
||||||
|
//
|
||||||
|
// Packages that define a Context key should provide type-safe accessors
|
||||||
|
// for the values stores using that key:
|
||||||
|
//
|
||||||
|
// // Package user defines a User type that's stored in Contexts.
|
||||||
|
// package user
|
||||||
|
//
|
||||||
|
// import "golang.org/x/net/context"
|
||||||
|
//
|
||||||
|
// // User is the type of value stored in the Contexts.
|
||||||
|
// type User struct {...}
|
||||||
|
//
|
||||||
|
// // key is an unexported type for keys defined in this package.
|
||||||
|
// // This prevents collisions with keys defined in other packages.
|
||||||
|
// type key int
|
||||||
|
//
|
||||||
|
// // userKey is the key for user.User values in Contexts. It is
|
||||||
|
// // unexported; clients use user.NewContext and user.FromContext
|
||||||
|
// // instead of using this key directly.
|
||||||
|
// var userKey key = 0
|
||||||
|
//
|
||||||
|
// // NewContext returns a new Context that carries value u.
|
||||||
|
// func NewContext(ctx context.Context, u *User) context.Context {
|
||||||
|
// return context.WithValue(ctx, userKey, u)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // FromContext returns the User value stored in ctx, if any.
|
||||||
|
// func FromContext(ctx context.Context) (*User, bool) {
|
||||||
|
// u, ok := ctx.Value(userKey).(*User)
|
||||||
|
// return u, ok
|
||||||
|
// }
|
||||||
|
Value(key interface{}) interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background returns a non-nil, empty Context. It is never canceled, has no
|
||||||
|
// values, and has no deadline. It is typically used by the main function,
|
||||||
|
// initialization, and tests, and as the top-level Context for incoming
|
||||||
|
// requests.
|
||||||
|
func Background() Context {
|
||||||
|
return background
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||||
|
// it's unclear which Context to use or it is not yet available (because the
|
||||||
|
// surrounding function has not yet been extended to accept a Context
|
||||||
|
// parameter). TODO is recognized by static analysis tools that determine
|
||||||
|
// whether Contexts are propagated correctly in a program.
|
||||||
|
func TODO() Context {
|
||||||
|
return todo
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CancelFunc tells an operation to abandon its work.
|
||||||
|
// A CancelFunc does not wait for the work to stop.
|
||||||
|
// After the first call, subsequent calls to a CancelFunc do nothing.
|
||||||
|
type CancelFunc func()
|
72
vendor/golang.org/x/net/context/go17.go
generated
vendored
Normal file
72
vendor/golang.org/x/net/context/go17.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context" // standard library's context, as of Go 1.7
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
todo = context.TODO()
|
||||||
|
background = context.Background()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Canceled is the error returned by Context.Err when the context is canceled.
|
||||||
|
var Canceled = context.Canceled
|
||||||
|
|
||||||
|
// DeadlineExceeded is the error returned by Context.Err when the context's
|
||||||
|
// deadline passes.
|
||||||
|
var DeadlineExceeded = context.DeadlineExceeded
|
||||||
|
|
||||||
|
// WithCancel returns a copy of parent with a new Done channel. The returned
|
||||||
|
// context's Done channel is closed when the returned cancel function is called
|
||||||
|
// or when the parent context's Done channel is closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||||
|
ctx, f := context.WithCancel(parent)
|
||||||
|
return ctx, CancelFunc(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
|
// closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
|
ctx, f := context.WithDeadline(parent, deadline)
|
||||||
|
return ctx, CancelFunc(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete:
|
||||||
|
//
|
||||||
|
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
|
||||||
|
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||||
|
// defer cancel() // releases resources if slowOperation completes before timeout elapses
|
||||||
|
// return slowOperation(ctx)
|
||||||
|
// }
|
||||||
|
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
|
||||||
|
return WithDeadline(parent, time.Now().Add(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValue returns a copy of parent in which the value associated with key is
|
||||||
|
// val.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||||
|
return context.WithValue(parent, key, val)
|
||||||
|
}
|
|
@ -2,39 +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.
|
||||||
|
|
||||||
// Package context defines the Context type, which carries deadlines,
|
// +build !go1.7
|
||||||
// cancelation signals, and other request-scoped values across API boundaries
|
|
||||||
// and between processes.
|
package context
|
||||||
//
|
|
||||||
// Incoming requests to a server should create a Context, and outgoing calls to
|
|
||||||
// servers should accept a Context. The chain of function calls between must
|
|
||||||
// propagate the Context, optionally replacing it with a modified copy created
|
|
||||||
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
|
||||||
//
|
|
||||||
// Programs that use Contexts should follow these rules to keep interfaces
|
|
||||||
// consistent across packages and enable static analysis tools to check context
|
|
||||||
// propagation:
|
|
||||||
//
|
|
||||||
// Do not store Contexts inside a struct type; instead, pass a Context
|
|
||||||
// explicitly to each function that needs it. The Context should be the first
|
|
||||||
// parameter, typically named ctx:
|
|
||||||
//
|
|
||||||
// func DoSomething(ctx context.Context, arg Arg) error {
|
|
||||||
// // ... use ctx ...
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
|
||||||
// if you are unsure about which Context to use.
|
|
||||||
//
|
|
||||||
// Use context Values only for request-scoped data that transits processes and
|
|
||||||
// APIs, not for passing optional parameters to functions.
|
|
||||||
//
|
|
||||||
// The same Context may be passed to functions running in different goroutines;
|
|
||||||
// Contexts are safe for simultaneous use by multiple goroutines.
|
|
||||||
//
|
|
||||||
// See http://blog.golang.org/context for example code for a server that uses
|
|
||||||
// Contexts.
|
|
||||||
package context // import "golang.org/x/net/context"
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -43,109 +13,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Context carries a deadline, a cancelation signal, and other values across
|
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||||
// API boundaries.
|
|
||||||
//
|
|
||||||
// Context's methods may be called by multiple goroutines simultaneously.
|
|
||||||
type Context interface {
|
|
||||||
// Deadline returns the time when work done on behalf of this context
|
|
||||||
// should be canceled. Deadline returns ok==false when no deadline is
|
|
||||||
// set. Successive calls to Deadline return the same results.
|
|
||||||
Deadline() (deadline time.Time, ok bool)
|
|
||||||
|
|
||||||
// Done returns a channel that's closed when work done on behalf of this
|
|
||||||
// context should be canceled. Done may return nil if this context can
|
|
||||||
// never be canceled. Successive calls to Done return the same value.
|
|
||||||
//
|
|
||||||
// WithCancel arranges for Done to be closed when cancel is called;
|
|
||||||
// WithDeadline arranges for Done to be closed when the deadline
|
|
||||||
// expires; WithTimeout arranges for Done to be closed when the timeout
|
|
||||||
// elapses.
|
|
||||||
//
|
|
||||||
// Done is provided for use in select statements:
|
|
||||||
//
|
|
||||||
// // Stream generates values with DoSomething and sends them to out
|
|
||||||
// // until DoSomething returns an error or ctx.Done is closed.
|
|
||||||
// func Stream(ctx context.Context, out <-chan Value) error {
|
|
||||||
// for {
|
|
||||||
// v, err := DoSomething(ctx)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// select {
|
|
||||||
// case <-ctx.Done():
|
|
||||||
// return ctx.Err()
|
|
||||||
// case out <- v:
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// See http://blog.golang.org/pipelines for more examples of how to use
|
|
||||||
// a Done channel for cancelation.
|
|
||||||
Done() <-chan struct{}
|
|
||||||
|
|
||||||
// Err returns a non-nil error value after Done is closed. Err returns
|
|
||||||
// Canceled if the context was canceled or DeadlineExceeded if the
|
|
||||||
// context's deadline passed. No other values for Err are defined.
|
|
||||||
// After Done is closed, successive calls to Err return the same value.
|
|
||||||
Err() error
|
|
||||||
|
|
||||||
// Value returns the value associated with this context for key, or nil
|
|
||||||
// if no value is associated with key. Successive calls to Value with
|
|
||||||
// the same key returns the same result.
|
|
||||||
//
|
|
||||||
// Use context values only for request-scoped data that transits
|
|
||||||
// processes and API boundaries, not for passing optional parameters to
|
|
||||||
// functions.
|
|
||||||
//
|
|
||||||
// A key identifies a specific value in a Context. Functions that wish
|
|
||||||
// to store values in Context typically allocate a key in a global
|
|
||||||
// variable then use that key as the argument to context.WithValue and
|
|
||||||
// Context.Value. A key can be any type that supports equality;
|
|
||||||
// packages should define keys as an unexported type to avoid
|
|
||||||
// collisions.
|
|
||||||
//
|
|
||||||
// Packages that define a Context key should provide type-safe accessors
|
|
||||||
// for the values stores using that key:
|
|
||||||
//
|
|
||||||
// // Package user defines a User type that's stored in Contexts.
|
|
||||||
// package user
|
|
||||||
//
|
|
||||||
// import "golang.org/x/net/context"
|
|
||||||
//
|
|
||||||
// // User is the type of value stored in the Contexts.
|
|
||||||
// type User struct {...}
|
|
||||||
//
|
|
||||||
// // key is an unexported type for keys defined in this package.
|
|
||||||
// // This prevents collisions with keys defined in other packages.
|
|
||||||
// type key int
|
|
||||||
//
|
|
||||||
// // userKey is the key for user.User values in Contexts. It is
|
|
||||||
// // unexported; clients use user.NewContext and user.FromContext
|
|
||||||
// // instead of using this key directly.
|
|
||||||
// var userKey key = 0
|
|
||||||
//
|
|
||||||
// // NewContext returns a new Context that carries value u.
|
|
||||||
// func NewContext(ctx context.Context, u *User) context.Context {
|
|
||||||
// return context.WithValue(ctx, userKey, u)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // FromContext returns the User value stored in ctx, if any.
|
|
||||||
// func FromContext(ctx context.Context) (*User, bool) {
|
|
||||||
// u, ok := ctx.Value(userKey).(*User)
|
|
||||||
// return u, ok
|
|
||||||
// }
|
|
||||||
Value(key interface{}) interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canceled is the error returned by Context.Err when the context is canceled.
|
|
||||||
var Canceled = errors.New("context canceled")
|
|
||||||
|
|
||||||
// DeadlineExceeded is the error returned by Context.Err when the context's
|
|
||||||
// deadline passes.
|
|
||||||
var DeadlineExceeded = errors.New("context deadline exceeded")
|
|
||||||
|
|
||||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
|
||||||
// struct{}, since vars of this type must have distinct addresses.
|
// struct{}, since vars of this type must have distinct addresses.
|
||||||
type emptyCtx int
|
type emptyCtx int
|
||||||
|
|
||||||
|
@ -180,27 +48,12 @@ var (
|
||||||
todo = new(emptyCtx)
|
todo = new(emptyCtx)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Background returns a non-nil, empty Context. It is never canceled, has no
|
// Canceled is the error returned by Context.Err when the context is canceled.
|
||||||
// values, and has no deadline. It is typically used by the main function,
|
var Canceled = errors.New("context canceled")
|
||||||
// initialization, and tests, and as the top-level Context for incoming
|
|
||||||
// requests.
|
|
||||||
func Background() Context {
|
|
||||||
return background
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
// DeadlineExceeded is the error returned by Context.Err when the context's
|
||||||
// it's unclear which Context to use or it is not yet available (because the
|
// deadline passes.
|
||||||
// surrounding function has not yet been extended to accept a Context
|
var DeadlineExceeded = errors.New("context deadline exceeded")
|
||||||
// parameter). TODO is recognized by static analysis tools that determine
|
|
||||||
// whether Contexts are propagated correctly in a program.
|
|
||||||
func TODO() Context {
|
|
||||||
return todo
|
|
||||||
}
|
|
||||||
|
|
||||||
// A CancelFunc tells an operation to abandon its work.
|
|
||||||
// A CancelFunc does not wait for the work to stop.
|
|
||||||
// After the first call, subsequent calls to a CancelFunc do nothing.
|
|
||||||
type CancelFunc func()
|
|
||||||
|
|
||||||
// WithCancel returns a copy of parent with a new Done channel. The returned
|
// WithCancel returns a copy of parent with a new Done channel. The returned
|
||||||
// context's Done channel is closed when the returned cancel function is called
|
// context's Done channel is closed when the returned cancel function is called
|
||||||
|
@ -251,7 +104,7 @@ func propagateCancel(parent Context, child canceler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parentCancelCtx follows a chain of parent references until it finds a
|
// parentCancelCtx follows a chain of parent references until it finds a
|
||||||
// *cancelCtx. This function understands how each of the concrete types in this
|
// *cancelCtx. This function understands how each of the concrete types in this
|
||||||
// package represents its parent.
|
// package represents its parent.
|
||||||
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||||
for {
|
for {
|
||||||
|
@ -281,14 +134,14 @@ func removeChild(parent Context, child canceler) {
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// A canceler is a context type that can be canceled directly. The
|
// A canceler is a context type that can be canceled directly. The
|
||||||
// implementations are *cancelCtx and *timerCtx.
|
// implementations are *cancelCtx and *timerCtx.
|
||||||
type canceler interface {
|
type canceler interface {
|
||||||
cancel(removeFromParent bool, err error)
|
cancel(removeFromParent bool, err error)
|
||||||
Done() <-chan struct{}
|
Done() <-chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||||
// that implement canceler.
|
// that implement canceler.
|
||||||
type cancelCtx struct {
|
type cancelCtx struct {
|
||||||
Context
|
Context
|
||||||
|
@ -340,8 +193,8 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
// context's Done channel is closed when the deadline expires, when the returned
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
// cancel function is called, or when the parent context's Done channel is
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
// closed, whichever happens first.
|
// closed, whichever happens first.
|
||||||
|
@ -373,8 +226,8 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
return c, func() { c.cancel(true, Canceled) }
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||||
// implement Done and Err. It implements cancel by stopping its timer then
|
// implement Done and Err. It implements cancel by stopping its timer then
|
||||||
// delegating to cancelCtx.cancel.
|
// delegating to cancelCtx.cancel.
|
||||||
type timerCtx struct {
|
type timerCtx struct {
|
||||||
*cancelCtx
|
*cancelCtx
|
||||||
|
@ -428,7 +281,7 @@ func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||||
return &valueCtx{parent, key, val}
|
return &valueCtx{parent, key, val}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A valueCtx carries a key-value pair. It implements Value for that key and
|
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||||
// delegates all other calls to the embedded Context.
|
// delegates all other calls to the embedded Context.
|
||||||
type valueCtx struct {
|
type valueCtx struct {
|
||||||
Context
|
Context
|
59
vendor/manifest
vendored
59
vendor/manifest
vendored
|
@ -394,6 +394,31 @@
|
||||||
"path": "vendor/golang.org/x/time/rate",
|
"path": "vendor/golang.org/x/time/rate",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/docker/go-connections/nat",
|
||||||
|
"repository": "https://github.com/docker/go-connections",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "a2afab9802043837035592f1c24827fb70766de9",
|
||||||
|
"branch": "master",
|
||||||
|
"path": "/nat",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/docker/go-units",
|
||||||
|
"repository": "https://github.com/docker/go-units",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "0dadbb0345b35ec7ef35e228dabb8de89a65bf52",
|
||||||
|
"branch": "master",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/docker/libtrust",
|
||||||
|
"repository": "https://github.com/docker/libtrust",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "aabc10ec26b754e797f9028f4589c5b7bd90dc20",
|
||||||
|
"branch": "master",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"importpath": "github.com/dustin/go-humanize",
|
"importpath": "github.com/dustin/go-humanize",
|
||||||
"repository": "https://github.com/dustin/go-humanize",
|
"repository": "https://github.com/dustin/go-humanize",
|
||||||
|
@ -402,6 +427,22 @@
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/gorilla/context",
|
||||||
|
"repository": "https://github.com/gorilla/context",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "08b5f424b9271eedf6f9f0ce86cb9396ed337a42",
|
||||||
|
"branch": "master",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/gorilla/mux",
|
||||||
|
"repository": "https://github.com/gorilla/mux",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "599cba5e7b6137d46ddf58fb1765f5d928e69604",
|
||||||
|
"branch": "master",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"importpath": "github.com/opencontainers/go-digest",
|
"importpath": "github.com/opencontainers/go-digest",
|
||||||
"repository": "https://github.com/opencontainers/go-digest",
|
"repository": "https://github.com/opencontainers/go-digest",
|
||||||
|
@ -410,6 +451,15 @@
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"importpath": "github.com/opencontainers/runc/libcontainer/user",
|
||||||
|
"repository": "https://github.com/opencontainers/runc",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "291bf601105c97dc1aa631fdfb7fca63c947319b",
|
||||||
|
"branch": "master",
|
||||||
|
"path": "/libcontainer/user",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"importpath": "github.com/peterhellberg/link",
|
"importpath": "github.com/peterhellberg/link",
|
||||||
"repository": "https://github.com/peterhellberg/link",
|
"repository": "https://github.com/peterhellberg/link",
|
||||||
|
@ -426,6 +476,15 @@
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"importpath": "golang.org/x/net/context",
|
||||||
|
"repository": "https://go.googlesource.com/net",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "d379faa25cbdc04d653984913a2ceb43b0bc46d7",
|
||||||
|
"branch": "master",
|
||||||
|
"path": "/context",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"importpath": "golang.org/x/sys/unix",
|
"importpath": "golang.org/x/sys/unix",
|
||||||
"repository": "https://go.googlesource.com/sys",
|
"repository": "https://go.googlesource.com/sys",
|
||||||
|
|
Loading…
Reference in a new issue