Update vendoring + fix issue with timestamps being added to log

As per the vendoring here:
e9544ca894
for some odd issue, text_formatter.go in the logrus package was updated
to an older file.

This commit updates the vendoring as well as specifies a specific
version for logrus to be used.

Closes + fixes
https://github.com/kubernetes-incubator/kompose/issues/532
This commit is contained in:
Charlie Drage 2017-03-31 09:18:03 -04:00
parent eead1cb8f7
commit ecea95a2a0
197 changed files with 35663 additions and 5912 deletions

41
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: a1dbf2b8c2789bec3a0e75cb5a24273d1b8ec9b38a1ef1b351eda824cdd56ae7
updated: 2017-03-17T01:50:53.646322363+05:30
hash: fb9ae173966398b98197a943500bc00f948ce48590c4866721105a10ef8e7c35
updated: 2017-03-31T09:12:51.358332263-04:00
imports:
- name: cloud.google.com/go
version: 3b1ae45394a234c385be014e9a488f2bb6eef821
@ -210,11 +210,11 @@ imports:
- name: github.com/evanphx/json-patch
version: 465937c80b3c07a7c7ad20cc934898646a91c1de
- name: github.com/fatih/structs
version: dc3312cb1a4513a366c4c9e622ad55c32df12ed3
version: a720dfa8df582c51dee1b36feabb906bde1588bd
- name: github.com/flynn/go-shlex
version: 3f9db97f856818214da2e1057f8ad84803971cff
- name: github.com/fsnotify/fsnotify
version: 629574ca2a5df945712d3079857300b5e4da0236
version: 4da3e2cfbabc9f751898f250b49f2439785783a1
- name: github.com/fsouza/go-dockerclient
version: bf97c77db7c945cbcdbf09d56c6f87a66f54537b
subpackages:
@ -332,7 +332,7 @@ imports:
- runtime/internal
- utilities
- name: github.com/hashicorp/hcl
version: 7cb7455c285ca3bf3362aa4ba6a06a6d6f5c3ba0
version: 630949a3c5fa3c613328e1b8256052cbc2327c9b
subpackages:
- hcl/ast
- hcl/parser
@ -351,13 +351,13 @@ imports:
- name: github.com/juju/ratelimit
version: 77ed1c8a01217656d2080ad51981f6e99adaa177
- name: github.com/magiconair/properties
version: c265cfa48dda6474e208715ca93e987829f572f8
version: 51463bfca2576e06c62a8504b5c0f06d61312647
- name: github.com/matttproud/golang_protobuf_extensions
version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
subpackages:
- pbutil
- name: github.com/mitchellh/mapstructure
version: f3009df150dadf309fdee4a54ed65c124afad715
version: 53818660ed4955e899c0bcafa97299a388bd7c8e
- name: github.com/openshift/origin
version: b4e0954faa4a0d11d9c1a536b76ad4a8c0206b7c
subpackages:
@ -403,11 +403,11 @@ imports:
- name: github.com/pborman/uuid
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- name: github.com/pelletier/go-buffruneio
version: df1e16fde7fc330a0ca68167c23bf7ed6ac31d6d
version: c37440a7cf42ac63b919c752ca73a85067e05992
- name: github.com/pelletier/go-toml
version: 64ff1ea4d585bc1fca65e6331eb8239f2ff31845
version: e32a2e04744250647a72bf17da1b09befc03b6b1
- name: github.com/pkg/errors
version: 248dadf4e9068a0b3e79f02ed0a610d935de5302
version: ff09b135c25aae272398c51a07235b90a75aa4f0
- name: github.com/prometheus/client_golang
version: e51041b3fa41cece0dca035740ba6411905be473
subpackages:
@ -425,21 +425,21 @@ imports:
- name: github.com/prometheus/procfs
version: 454a56f35412459b5e684fd5ec0f9211b94f002a
- name: github.com/Sirupsen/logrus
version: aaf92c95712104318fc35409745f1533aa5ff327
version: ba1b36c82c5e05c4f912a88eab0dcd91a171688f
- name: github.com/spf13/afero
version: 06b7e5f50606ecd49148a01a6008942d9b669217
version: 9be650865eab0c12963d8753212f4f9c66cdcf12
subpackages:
- mem
- name: github.com/spf13/cast
version: 24b6558033ffe202bf42f0f3b870dcc798dd2ba8
version: ce135a4ebeee6cfe9a26c93ee0d37825f26113c7
- name: github.com/spf13/cobra
version: 7c674d9e72017ed25f6d2b5e497a1368086b6a6f
version: 7be4beda01ec05d0b93d80b3facd2b6f44080d94
- name: github.com/spf13/jwalterweatherman
version: 33c24e77fb80341fe7130ee7c594256ff08ccc46
version: fa7ca7e836cf3a8bb4ebf799f472c12d7e903d66
- name: github.com/spf13/pflag
version: 5ccb023bc27df288a957c5e994cd44fd19619465
version: d16db1e50e33dff1b6cdf37596cef36742128670
- name: github.com/spf13/viper
version: 651d9d916abc3c3d6a91a12549495caba5edffd2
version: 84f94806c67f59dd7ae87bc5351f7a9c94a4558d
- name: github.com/ugorji/go
version: f4485b318aadd133842532f841dc205a8e339d74
subpackages:
@ -449,7 +449,7 @@ imports:
- name: github.com/xeipuuv/gojsonreference
version: e02fc20de94c78484cd5ffb007f8af96be030a45
- name: github.com/xeipuuv/gojsonschema
version: ff0417f4272e480246b4507459b3f6ae721a87ac
version: 702b404897d4364af44dc8dcabc9815947942325
- name: golang.org/x/net
version: e90d6d0afc4c315a0d87a568ae68577cc15149a0
subpackages:
@ -473,10 +473,9 @@ imports:
- jws
- jwt
- name: golang.org/x/sys
version: 833a04a10549a95dc34458c195cbad61bbb6cb4d
version: 9a7256cb28ed514b4e1e5f68959914c4c28a92e0
subpackages:
- unix
- windows
- name: golang.org/x/text
version: ceefd2213ed29504fff30155163c8f59827734f3
subpackages:
@ -516,7 +515,7 @@ imports:
- name: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/yaml.v2
version: a83829b6f1293c91addabc89d0571c246397bbf4
version: a3f3340b5840cee44f372bddb5880fcbc419b46a
- name: k8s.io/client-go
version: d72c0e162789e1bbb33c33cfa26858a1375efe01
subpackages:

View File

@ -5,6 +5,8 @@ licence: Apache-2.0
import:
- package: github.com/Sirupsen/logrus
version: v0.11.5
- package: github.com/fatih/structs
- package: github.com/ghodss/yaml
- package: github.com/spf13/cobra

64
vendor/github.com/Sirupsen/logrus/alt_exit.go generated vendored Normal file
View File

@ -0,0 +1,64 @@
package logrus
// The following code was sourced and modified from the
// https://bitbucket.org/tebeka/atexit package governed by the following license:
//
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import (
"fmt"
"os"
)
var handlers = []func(){}
func runHandler(handler func()) {
defer func() {
if err := recover(); err != nil {
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
}
}()
handler()
}
func runHandlers() {
for _, handler := range handlers {
runHandler(handler)
}
}
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
func Exit(code int) {
runHandlers()
os.Exit(code)
}
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
// all handlers. The handlers will also be invoked when any Fatal log entry is
// made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
// closing database connections, or sending a alert that the application is
// closing.
func RegisterExitHandler(handler func()) {
handlers = append(handlers, handler)
}

26
vendor/github.com/Sirupsen/logrus/doc.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
/*
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
The simplest way to use Logrus is simply the package-level exported logger:
package main
import (
log "github.com/Sirupsen/logrus"
)
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
"number": 1,
"size": 10,
}).Info("A walrus appears")
}
Output:
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
For a full guide visit https://github.com/Sirupsen/logrus
*/
package logrus

View File

@ -3,11 +3,24 @@ package logrus
import (
"bytes"
"fmt"
"io"
"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
@ -26,6 +39,9 @@ type Entry struct {
// 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 {
@ -36,21 +52,20 @@ func NewEntry(logger *Logger) *Entry {
}
}
// Returns a reader for the entry, which is a proxy to the formatter.
func (entry *Entry) Reader() (*bytes.Buffer, error) {
serialized, err := entry.Logger.Formatter.Format(entry)
return bytes.NewBuffer(serialized), err
}
// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
reader, err := entry.Reader()
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
return "", err
}
str := string(serialized)
return str, nil
}
return reader.String(), err
// 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.
@ -60,7 +75,7 @@ func (entry *Entry) WithField(key string, value interface{}) *Entry {
// Add a map of fields to the Entry.
func (entry *Entry) WithFields(fields Fields) *Entry {
data := Fields{}
data := make(Fields, len(entry.Data)+len(fields))
for k, v := range entry.Data {
data[k] = v
}
@ -70,37 +85,43 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
return &Entry{Logger: entry.Logger, Data: data}
}
func (entry *Entry) log(level Level, msg string) {
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) 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 {
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()
}
reader, err := entry.Reader()
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()
defer entry.Logger.mu.Unlock()
_, err = io.Copy(entry.Logger.Out, reader)
_, 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)
panic(&entry)
}
}
@ -140,7 +161,7 @@ func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.Level >= FatalLevel {
entry.log(FatalLevel, fmt.Sprint(args...))
}
os.Exit(1)
Exit(1)
}
func (entry *Entry) Panic(args ...interface{}) {
@ -188,6 +209,7 @@ 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{}) {
@ -234,6 +256,7 @@ func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.Level >= FatalLevel {
entry.Fatal(entry.sprintlnn(args...))
}
Exit(1)
}
func (entry *Entry) Panicln(args ...interface{}) {

View File

@ -48,6 +48,11 @@ func AddHook(hook Hook) {
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`.
//

View File

@ -31,18 +31,15 @@ type Formatter interface {
// 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) {
_, ok := data["time"]
if ok {
data["fields.time"] = data["time"]
if t, ok := data["time"]; ok {
data["fields.time"] = t
}
_, ok = data["msg"]
if ok {
data["fields.msg"] = data["msg"]
if m, ok := data["msg"]; ok {
data["fields.msg"] = m
}
_, ok = data["level"]
if ok {
data["fields.level"] = data["level"]
if l, ok := data["level"]; ok {
data["fields.level"] = l
}
}

View File

@ -11,11 +11,11 @@ type Hook interface {
}
// Internal type for storing the hooks on a logger instance.
type levelHooks map[Level][]Hook
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) {
func (hooks LevelHooks) Add(hook Hook) {
for _, level := range hook.Levels() {
hooks[level] = append(hooks[level], hook)
}
@ -23,7 +23,7 @@ func (hooks levelHooks) Add(hook 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 {
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
for _, hook := range hooks[level] {
if err := hook.Fire(entry); err != nil {
return err

View File

@ -5,9 +5,40 @@ import (
"fmt"
)
type fieldKey string
type FieldMap map[fieldKey]string
const (
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
)
func (f FieldMap) resolve(key fieldKey) string {
if k, ok := f[key]; ok {
return k
}
return string(key)
}
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// FieldMap allows users to customize the names of keys for various fields.
// As an example:
// formatter := &JSONFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyLevel: "@message",
// },
// }
FieldMap FieldMap
}
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
@ -24,13 +55,16 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
}
prefixFieldClashes(data)
if f.TimestampFormat == "" {
f.TimestampFormat = DefaultTimestampFormat
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat
}
data["time"] = entry.Time.Format(f.TimestampFormat)
data["msg"] = entry.Message
data["level"] = entry.Level.String()
if !f.DisableTimestamp {
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
}
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
serialized, err := json.Marshal(data)
if err != nil {

View File

@ -8,13 +8,13 @@ import (
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.Stdout`. You can also set this to
// 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
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
@ -26,8 +26,31 @@ type Logger struct {
// 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.
mu sync.Mutex
// 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`,
@ -37,7 +60,7 @@ type Logger struct {
// var log = &Logger{
// Out: os.Stderr,
// Formatter: new(JSONFormatter),
// Hooks: make(levelHooks),
// Hooks: make(LevelHooks),
// Level: logrus.DebugLevel,
// }
//
@ -46,158 +69,240 @@ func New() *Logger {
return &Logger{
Out: os.Stderr,
Formatter: new(TextFormatter),
Hooks: make(levelHooks),
Hooks: make(LevelHooks),
Level: InfoLevel,
}
}
// Adds a field to the log entry, note that you it doesn't log until you call
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.
// Ff you want multiple fields, use `WithFields`.
// If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry {
return NewEntry(logger).WithField(key, value)
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 {
return NewEntry(logger).WithFields(fields)
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 {
NewEntry(logger).Debugf(format, args...)
entry := logger.newEntry()
entry.Debugf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Infof(format, args...)
entry := logger.newEntry()
entry.Infof(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Printf(format string, args ...interface{}) {
NewEntry(logger).Printf(format, args...)
entry := logger.newEntry()
entry.Printf(format, args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnf(format, args...)
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnf(format, args...)
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Errorf(format, args...)
entry := logger.newEntry()
entry.Errorf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatalf(format, args...)
entry := logger.newEntry()
entry.Fatalf(format, args...)
logger.releaseEntry(entry)
}
Exit(1)
}
func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panicf(format, args...)
entry := logger.newEntry()
entry.Panicf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Debug(args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debug(args...)
entry := logger.newEntry()
entry.Debug(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Info(args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Info(args...)
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Print(args ...interface{}) {
NewEntry(logger).Info(args...)
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warn(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warn(args...)
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warning(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warn(args...)
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Error(args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Error(args...)
entry := logger.newEntry()
entry.Error(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatal(args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatal(args...)
entry := logger.newEntry()
entry.Fatal(args...)
logger.releaseEntry(entry)
}
Exit(1)
}
func (logger *Logger) Panic(args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panic(args...)
entry := logger.newEntry()
entry.Panic(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Debugln(args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debugln(args...)
entry := logger.newEntry()
entry.Debugln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infoln(args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Infoln(args...)
entry := logger.newEntry()
entry.Infoln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Println(args ...interface{}) {
NewEntry(logger).Println(args...)
entry := logger.newEntry()
entry.Println(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warnln(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnln(args...)
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warningln(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnln(args...)
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Errorln(args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Errorln(args...)
entry := logger.newEntry()
entry.Errorln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatalln(args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatalln(args...)
entry := logger.newEntry()
entry.Fatalln(args...)
logger.releaseEntry(entry)
}
Exit(1)
}
func (logger *Logger) Panicln(args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panicln(args...)
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()
}

View File

@ -3,6 +3,7 @@ package logrus
import (
"fmt"
"log"
"strings"
)
// Fields type, used to pass to `WithFields`.
@ -33,7 +34,7 @@ func (level Level) String() string {
// ParseLevel takes a string level and returns the Logrus log level constant.
func ParseLevel(lvl string) (Level, error) {
switch lvl {
switch strings.ToLower(lvl) {
case "panic":
return PanicLevel, nil
case "fatal":
@ -52,6 +53,16 @@ func ParseLevel(lvl string) (Level, error) {
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 (
@ -74,7 +85,11 @@ const (
)
// Won't compile if StdLogger can't be realized by a log.Logger
var _ StdLogger = &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
@ -92,3 +107,37 @@ type StdLogger 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{})
}

View File

@ -0,0 +1,10 @@
// +build appengine
package logrus
import "io"
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
return true
}

View File

@ -1,3 +1,6 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus
import "syscall"

View File

@ -1,12 +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.
package logrus
import "syscall"
const ioctlReadTermios = syscall.TIOCGETA
type Termios syscall.Termios

View File

@ -1,20 +0,0 @@
/*
Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
*/
package logrus
import (
"syscall"
)
const ioctlReadTermios = syscall.TIOCGETA
type Termios struct {
Iflag uint32
Oflag uint32
Cflag uint32
Lflag uint32
Cc [20]uint8
Ispeed uint32
Ospeed uint32
}

View File

@ -3,6 +3,8 @@
// 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"

View File

@ -3,19 +3,26 @@
// 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
// +build linux darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal() bool {
fd := syscall.Stdout
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
var termios Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
switch v := f.(type) {
case *os.File:
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
default:
return false
}
}

21
vendor/github.com/Sirupsen/logrus/terminal_solaris.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
// +build solaris,!appengine
package logrus
import (
"io"
"os"
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
return err == nil
default:
return false
}
}

View File

@ -3,11 +3,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// +build windows,!appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
@ -18,10 +20,14 @@ var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal() bool {
fd := syscall.Stdout
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
default:
return false
}
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
"sort"
"strings"
"sync"
"time"
)
@ -19,16 +20,10 @@ const (
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 {
@ -53,10 +48,32 @@ type TextFormatter struct {
// that log extremely frequently and don't use the JSON formatter this may not
// be desired.
DisableSorting bool
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal
isTerminal bool
sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out)
}
}
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var keys []string = make([]string, 0, len(entry.Data))
var b *bytes.Buffer
keys := make([]string, 0, len(entry.Data))
for k := range entry.Data {
keys = append(keys, k)
}
@ -64,24 +81,32 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
if !f.DisableSorting {
sort.Strings(keys)
}
b := &bytes.Buffer{}
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
prefixFieldClashes(entry.Data)
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
f.Do(func() { f.init(entry) })
if f.TimestampFormat == "" {
f.TimestampFormat = DefaultTimestampFormat
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat
}
if isColored {
f.printColored(b, entry, keys)
f.printColored(b, entry, keys, timestampFormat)
} else {
if !f.DisableTimestamp {
f.appendKeyValue(b, "time", entry.Time.Format(f.TimestampFormat))
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])
}
@ -91,7 +116,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
return b.Bytes(), nil
}
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string) {
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
var levelColor int
switch entry.Level {
case DebugLevel:
@ -106,44 +131,59 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
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)
if f.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
} else if !f.FullTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
} else {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(f.TimestampFormat), entry.Message)
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
}
for _, k := range keys {
v := entry.Data[k]
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
f.appendValue(b, v)
}
}
func needsQuoting(text string) bool {
func (f *TextFormatter) needsQuoting(text string) bool {
if f.QuoteEmptyFields && len(text) == 0 {
return true
}
for _, ch := range text {
if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
ch == '-' || ch == '.') {
return false
}
}
return true
}
}
return false
}
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
switch value.(type) {
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.(string)) {
fmt.Fprintf(b, "%v=%s ", key, value)
if !f.needsQuoting(value) {
b.WriteString(value)
} else {
fmt.Fprintf(b, "%v=%q ", key, value)
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
}
case error:
if needsQuoting(value.(error).Error()) {
fmt.Fprintf(b, "%v=%s ", key, value)
errmsg := value.Error()
if !f.needsQuoting(errmsg) {
b.WriteString(errmsg)
} else {
fmt.Fprintf(b, "%v=%q ", key, value)
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
}
default:
fmt.Fprintf(b, "%v=%v ", key, value)
fmt.Fprint(b, value)
}
}

View File

@ -7,21 +7,52 @@ import (
)
func (logger *Logger) Writer() *io.PipeWriter {
return logger.WriterLevel(InfoLevel)
}
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
return NewEntry(logger).WriterLevel(level)
}
func (entry *Entry) Writer() *io.PipeWriter {
return entry.WriterLevel(InfoLevel)
}
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
reader, writer := io.Pipe()
go logger.writerScanner(reader)
var printFunc func(args ...interface{})
switch level {
case DebugLevel:
printFunc = entry.Debug
case InfoLevel:
printFunc = entry.Info
case WarnLevel:
printFunc = entry.Warn
case ErrorLevel:
printFunc = entry.Error
case FatalLevel:
printFunc = entry.Fatal
case PanicLevel:
printFunc = entry.Panic
default:
printFunc = entry.Print
}
go entry.writerScanner(reader, printFunc)
runtime.SetFinalizer(writer, writerFinalizer)
return writer
}
func (logger *Logger) writerScanner(reader *io.PipeReader) {
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
logger.Print(scanner.Text())
printFunc(scanner.Text())
}
if err := scanner.Err(); err != nil {
logger.Errorf("Error while reading from Writer: %s", err)
entry.Errorf("Error while reading from Writer: %s", err)
}
reader.Close()
}

View File

@ -530,15 +530,22 @@ func (s *Struct) nested(val reflect.Value) interface{} {
finalVal = m
}
case reflect.Map:
v := val.Type().Elem()
if v.Kind() == reflect.Ptr {
v = v.Elem()
// get the element type of the map
mapElem := val.Type()
switch val.Type().Kind() {
case reflect.Ptr, reflect.Array, reflect.Map,
reflect.Slice, reflect.Chan:
mapElem = val.Type().Elem()
if mapElem.Kind() == reflect.Ptr {
mapElem = mapElem.Elem()
}
}
// only iterate over struct types, ie: map[string]StructType,
// map[string][]StructType,
if v.Kind() == reflect.Struct ||
(v.Kind() == reflect.Slice && v.Elem().Kind() == reflect.Struct) {
if mapElem.Kind() == reflect.Struct ||
(mapElem.Kind() == reflect.Slice &&
mapElem.Elem().Kind() == reflect.Struct) {
m := make(map[string]interface{}, val.Len())
for _, k := range val.MapKeys() {
m[k.String()] = s.nested(val.MapIndex(k))

View File

@ -9,6 +9,7 @@ package fsnotify
import (
"bytes"
"errors"
"fmt"
)
@ -60,3 +61,6 @@ func (op Op) String() string {
func (e Event) String() string {
return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
}
// Common errors that can be reported by a watcher
var ErrEventOverflow = errors.New("fsnotify queue overflow")

View File

@ -24,7 +24,6 @@ type Watcher struct {
Events chan Event
Errors chan error
mu sync.Mutex // Map access
cv *sync.Cond // sync removing on rm_watch with IN_IGNORE
fd int
poller *fdPoller
watches map[string]*watch // Map of inotify watches (key: path)
@ -56,7 +55,6 @@ func NewWatcher() (*Watcher, error) {
done: make(chan struct{}),
doneResp: make(chan struct{}),
}
w.cv = sync.NewCond(&w.mu)
go w.readEvents()
return w, nil
@ -103,21 +101,23 @@ func (w *Watcher) Add(name string) error {
var flags uint32 = agnosticEvents
w.mu.Lock()
watchEntry, found := w.watches[name]
w.mu.Unlock()
if found {
watchEntry.flags |= flags
flags |= unix.IN_MASK_ADD
defer w.mu.Unlock()
watchEntry := w.watches[name]
if watchEntry != nil {
flags |= watchEntry.flags | unix.IN_MASK_ADD
}
wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
if wd == -1 {
return errno
}
w.mu.Lock()
if watchEntry == nil {
w.watches[name] = &watch{wd: uint32(wd), flags: flags}
w.paths[wd] = name
w.mu.Unlock()
} else {
watchEntry.wd = uint32(wd)
watchEntry.flags = flags
}
return nil
}
@ -135,6 +135,13 @@ func (w *Watcher) Remove(name string) error {
if !ok {
return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
}
// We successfully removed the watch if InotifyRmWatch doesn't return an
// error, we need to clean up our internal state to ensure it matches
// inotify's kernel state.
delete(w.paths, int(watch.wd))
delete(w.watches, name)
// inotify_rm_watch will return EINVAL if the file has been deleted;
// the inotify will already have been removed.
// watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
@ -152,13 +159,6 @@ func (w *Watcher) Remove(name string) error {
return errno
}
// wait until ignoreLinux() deleting maps
exists := true
for exists {
w.cv.Wait()
_, exists = w.watches[name]
}
return nil
}
@ -245,13 +245,31 @@ func (w *Watcher) readEvents() {
mask := uint32(raw.Mask)
nameLen := uint32(raw.Len)
if mask&unix.IN_Q_OVERFLOW != 0 {
select {
case w.Errors <- ErrEventOverflow:
case <-w.done:
return
}
}
// If the event happened to the watched directory or the watched file, the kernel
// doesn't append the filename to the event, but we would like to always fill the
// the "Name" field with a valid filename. We retrieve the path of the watch from
// the "paths" map.
w.mu.Lock()
name := w.paths[int(raw.Wd)]
name, ok := w.paths[int(raw.Wd)]
// IN_DELETE_SELF occurs when the file/directory being watched is removed.
// This is a sign to clean up the maps, otherwise we are no longer in sync
// with the inotify kernel state which has already deleted the watch
// automatically.
if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
delete(w.paths, int(raw.Wd))
delete(w.watches, name)
}
w.mu.Unlock()
if nameLen > 0 {
// Point "bytes" at the first byte of the filename
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
@ -262,7 +280,7 @@ func (w *Watcher) readEvents() {
event := newEvent(name, mask)
// Send the events that are not ignored on the events channel
if !event.ignoreLinux(w, raw.Wd, mask) {
if !event.ignoreLinux(mask) {
select {
case w.Events <- event:
case <-w.done:
@ -279,15 +297,9 @@ func (w *Watcher) readEvents() {
// Certain types of events can be "ignored" and not sent over the Events
// channel. Such as events marked ignore by the kernel, or MODIFY events
// against files that do not exist.
func (e *Event) ignoreLinux(w *Watcher, wd int32, mask uint32) bool {
func (e *Event) ignoreLinux(mask uint32) bool {
// Ignore anything the inotify API says to ignore
if mask&unix.IN_IGNORED == unix.IN_IGNORED {
w.mu.Lock()
defer w.mu.Unlock()
name := w.paths[int(wd)]
delete(w.paths, int(wd))
delete(w.watches, name)
w.cv.Broadcast()
return true
}

View File

@ -91,7 +91,7 @@ func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error
return d.decodeBool(name, node, result)
case reflect.Float64:
return d.decodeFloat(name, node, result)
case reflect.Int:
case reflect.Int, reflect.Int32, reflect.Int64:
return d.decodeInt(name, node, result)
case reflect.Interface:
// When we see an interface, we make our own thing
@ -164,7 +164,11 @@ func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) er
return err
}
if result.Kind() == reflect.Interface {
result.Set(reflect.ValueOf(int(v)))
} else {
result.SetInt(v)
}
return nil
case token.STRING:
v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0)
@ -172,7 +176,11 @@ func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) er
return err
}
if result.Kind() == reflect.Interface {
result.Set(reflect.ValueOf(int(v)))
} else {
result.SetInt(v)
}
return nil
}
}

View File

@ -256,7 +256,10 @@ func (p *Parser) objectKey() ([]*ast.ObjectKey, error) {
keyCount++
keys = append(keys, &ast.ObjectKey{Token: p.tok})
case token.ILLEGAL:
fmt.Println("illegal")
return keys, &PosError{
Pos: p.tok.Pos,
Err: fmt.Errorf("illegal character"),
}
default:
return keys, &PosError{
Pos: p.tok.Pos,
@ -343,7 +346,7 @@ func (p *Parser) listType() (*ast.ListType, error) {
}
}
switch tok.Type {
case token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC:
case token.BOOL, token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC:
node, err := p.literalType()
if err != nil {
return nil, err
@ -385,12 +388,16 @@ func (p *Parser) listType() (*ast.ListType, error) {
}
l.Add(node)
needComma = true
case token.BOOL:
// TODO(arslan) should we support? not supported by HCL yet
case token.LBRACK:
// TODO(arslan) should we support nested lists? Even though it's
// written in README of HCL, it's not a part of the grammar
// (not defined in parse.y)
node, err := p.listType()
if err != nil {
return nil, &PosError{
Pos: tok.Pos,
Err: fmt.Errorf(
"error while trying to parse list within list: %s", err),
}
}
l.Add(node)
case token.RBRACK:
// finished
l.Rbrack = p.tok.Pos

View File

@ -480,7 +480,7 @@ func (s *Scanner) scanString() {
// read character after quote
ch := s.next()
if ch < 0 || ch == eof {
if (ch == '\n' && braces == 0) || ch < 0 || ch == eof {
s.err("literal not terminated")
return
}

View File

@ -27,6 +27,9 @@ func Unquote(s string) (t string, err error) {
if quote != '"' {
return "", ErrSyntax
}
if !contains(s, '$') && !contains(s, '{') && contains(s, '\n') {
return "", ErrSyntax
}
// Is it trivial? Avoid allocation.
if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') {
@ -84,6 +87,10 @@ func Unquote(s string) (t string, err error) {
}
}
if s[0] == '\n' {
return "", ErrSyntax
}
c, multibyte, ss, err := unquoteChar(s, quote)
if err != nil {
return "", err

View File

@ -1,4 +1,4 @@
// Copyright 2016 Frank Schroeder. All rights reserved.
// Copyright 2017 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@ -158,16 +158,16 @@ func dec(p *Properties, key string, def *string, opts map[string]string, v refle
// keydef returns the property key and the default value based on the
// name of the struct field and the options in the tag.
keydef := func(f reflect.StructField) (string, *string, map[string]string) {
key, opts := parseTag(f.Tag.Get("properties"))
_key, _opts := parseTag(f.Tag.Get("properties"))
var def *string
if d, ok := opts["default"]; ok {
def = &d
var _def *string
if d, ok := _opts["default"]; ok {
_def = &d
}
if key != "" {
return key, def, opts
if _key != "" {
return _key, _def, _opts
}
return f.Name, def, opts
return f.Name, _def, _opts
}
switch {
@ -190,7 +190,7 @@ func dec(p *Properties, key string, def *string, opts map[string]string, v refle
fv := v.Field(i)
fk, def, opts := keydef(t.Field(i))
if !fv.CanSet() {
return fmt.Errorf("cannot set ", t.Field(i).Name)
return fmt.Errorf("cannot set %s", t.Field(i).Name)
}
if fk == "-" {
continue
@ -223,7 +223,7 @@ func dec(p *Properties, key string, def *string, opts map[string]string, v refle
case isMap(t):
valT := t.Elem()
m := reflect.MakeMap(t)
for postfix, _ := range p.FilterStripPrefix(key + ".").m {
for postfix := range p.FilterStripPrefix(key + ".").m {
pp := strings.SplitN(postfix, ".", 2)
mk, mv := pp[0], reflect.New(valT)
if err := dec(p, key+"."+mk, nil, nil, mv); err != nil {
@ -274,7 +274,6 @@ func isArray(t reflect.Type) bool { return t.Kind() == reflect.Array || t.Kin
func isBool(t reflect.Type) bool { return t.Kind() == reflect.Bool }
func isDuration(t reflect.Type) bool { return t == reflect.TypeOf(time.Second) }
func isMap(t reflect.Type) bool { return t.Kind() == reflect.Map }
func isNumeric(t reflect.Type) bool { return isInt(t) || isUint(t) || isFloat(t) }
func isPtr(t reflect.Type) bool { return t.Kind() == reflect.Ptr }
func isString(t reflect.Type) bool { return t.Kind() == reflect.String }
func isStruct(t reflect.Type) bool { return t.Kind() == reflect.Struct }

View File

@ -1,4 +1,4 @@
// Copyright 2016 Frank Schroeder. All rights reserved.
// Copyright 2017 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2016 Frank Schroeder. All rights reserved.
// Copyright 2017 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2016 Frank Schroeder. All rights reserved.
// Copyright 2017 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
@ -72,7 +72,7 @@ type lexer struct {
// next returns the next rune in the input.
func (l *lexer) next() rune {
if int(l.pos) >= len(l.input) {
if l.pos >= len(l.input) {
l.width = 0
return eof
}
@ -96,8 +96,8 @@ func (l *lexer) backup() {
// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
item := item{t, l.start, string(l.runes)}
l.items <- item
i := item{t, l.start, string(l.runes)}
l.items <- i
l.start = l.pos
l.runes = l.runes[:0]
}
@ -114,7 +114,7 @@ func (l *lexer) appendRune(r rune) {
// accept consumes the next rune if it's from the valid set.
func (l *lexer) accept(valid string) bool {
if strings.IndexRune(valid, l.next()) >= 0 {
if strings.ContainsRune(valid, l.next()) {
return true
}
l.backup()
@ -123,7 +123,7 @@ func (l *lexer) accept(valid string) bool {
// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
for strings.IndexRune(valid, l.next()) >= 0 {
for strings.ContainsRune(valid, l.next()) {
}
l.backup()
}
@ -156,9 +156,9 @@ func (l *lexer) errorf(format string, args ...interface{}) stateFn {
// nextItem returns the next item from the input.
func (l *lexer) nextItem() item {
item := <-l.items
l.lastPos = item.pos
return item
i := <-l.items
l.lastPos = i.pos
return i
}
// lex creates a new scanner for the input string.
@ -279,8 +279,7 @@ func lexValue(l *lexer) stateFn {
for {
switch r := l.next(); {
case isEscape(r):
r := l.peek()
if isEOL(r) {
if isEOL(l.peek()) {
l.next()
l.acceptRun(whitespace)
} else {

View File

@ -1,11 +1,10 @@
// Copyright 2016 Frank Schroeder. All rights reserved.
// Copyright 2017 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package properties
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
@ -34,16 +33,25 @@ func LoadString(s string) (*Properties, error) {
return loadBuf([]byte(s), UTF8)
}
// LoadMap creates a new Properties struct from a string map.
func LoadMap(m map[string]string) *Properties {
p := NewProperties()
for k, v := range m {
p.Set(k, v)
}
return p
}
// LoadFile reads a file into a Properties struct.
func LoadFile(filename string, enc Encoding) (*Properties, error) {
return loadFiles([]string{filename}, enc, false)
return loadAll([]string{filename}, enc, false)
}
// LoadFiles reads multiple files in the given order into
// a Properties struct. If 'ignoreMissing' is true then
// non-existent files will not be reported as error.
func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
return loadFiles(filenames, enc, ignoreMissing)
return loadAll(filenames, enc, ignoreMissing)
}
// LoadURL reads the content of the URL into a Properties struct.
@ -55,7 +63,7 @@ func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Propertie
// encoding is set to UTF-8. A missing content type header is
// interpreted as 'text/plain; charset=utf-8'.
func LoadURL(url string) (*Properties, error) {
return loadURLs([]string{url}, false)
return loadAll([]string{url}, UTF8, false)
}
// LoadURLs reads the content of multiple URLs in the given order into a
@ -63,7 +71,15 @@ func LoadURL(url string) (*Properties, error) {
// not be reported as error. See LoadURL for the Content-Type header
// and the encoding.
func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) {
return loadURLs(urls, ignoreMissing)
return loadAll(urls, UTF8, ignoreMissing)
}
// LoadAll reads the content of multiple URLs or files in the given order into a
// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will
// not be reported as error. Encoding sets the encoding for files. For the URLs please see
// LoadURL for the Content-Type header and the encoding.
func LoadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
return loadAll(names, enc, ignoreMissing)
}
// MustLoadString reads an UTF8 string into a Properties struct and
@ -91,13 +107,21 @@ func MustLoadURL(url string) *Properties {
return must(LoadURL(url))
}
// MustLoadFiles reads the content of multiple URLs in the given order into a
// MustLoadURLs reads the content of multiple URLs in the given order into a
// Properties struct and panics on error. If 'ignoreMissing' is true then a 404
// status code will not be reported as error.
func MustLoadURLs(urls []string, ignoreMissing bool) *Properties {
return must(LoadURLs(urls, ignoreMissing))
}
// MustLoadAll reads the content of multiple URLs or files in the given order into a
// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will
// not be reported as error. Encoding sets the encoding for files. For the URLs please see
// LoadURL for the Content-Type header and the encoding. It panics on error.
func MustLoadAll(names []string, enc Encoding, ignoreMissing bool) *Properties {
return must(LoadAll(names, enc, ignoreMissing))
}
func loadBuf(buf []byte, enc Encoding) (*Properties, error) {
p, err := parse(convert(buf, enc))
if err != nil {
@ -106,49 +130,62 @@ func loadBuf(buf []byte, enc Encoding) (*Properties, error) {
return p, p.check()
}
func loadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
var buf bytes.Buffer
for _, filename := range filenames {
f, err := expandFilename(filename)
func loadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
result := NewProperties()
for _, name := range names {
n, err := expandName(name)
if err != nil {
return nil, err
}
var p *Properties
if strings.HasPrefix(n, "http://") || strings.HasPrefix(n, "https://") {
p, err = loadURL(n, ignoreMissing)
} else {
p, err = loadFile(n, enc, ignoreMissing)
}
if err != nil {
return nil, err
}
result.Merge(p)
data, err := ioutil.ReadFile(f)
}
return result, result.check()
}
func loadFile(filename string, enc Encoding, ignoreMissing bool) (*Properties, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
if ignoreMissing && os.IsNotExist(err) {
LogPrintf("properties: %s not found. skipping", filename)
continue
return NewProperties(), nil
}
return nil, err
}
// concatenate the buffers and add a new line in case
// the previous file didn't end with a new line
buf.Write(data)
buf.WriteRune('\n')
p, err := parse(convert(data, enc))
if err != nil {
return nil, err
}
return loadBuf(buf.Bytes(), enc)
return p, nil
}
func loadURLs(urls []string, ignoreMissing bool) (*Properties, error) {
var buf bytes.Buffer
for _, u := range urls {
resp, err := http.Get(u)
func loadURL(url string, ignoreMissing bool) (*Properties, error) {
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("properties: error fetching %q. %s", u, err)
return nil, fmt.Errorf("properties: error fetching %q. %s", url, err)
}
if resp.StatusCode == 404 && ignoreMissing {
LogPrintf("properties: %s returned %d. skipping", u, resp.StatusCode)
continue
LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode)
return NewProperties(), nil
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("properties: %s returned %d", u, resp.StatusCode)
return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode)
}
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, fmt.Errorf("properties: %s error reading response. %s", u, err)
return nil, fmt.Errorf("properties: %s error reading response. %s", url, err)
}
if err = resp.Body.Close(); err != nil {
return nil, fmt.Errorf("properties: %s error reading response. %s", url, err)
}
ct := resp.Header.Get("Content-Type")
@ -162,10 +199,11 @@ func loadURLs(urls []string, ignoreMissing bool) (*Properties, error) {
return nil, fmt.Errorf("properties: invalid content type %s", ct)
}
buf.WriteString(convert(body, enc))
buf.WriteRune('\n')
p, err := parse(convert(body, enc))
if err != nil {
return nil, err
}
return loadBuf(buf.Bytes(), UTF8)
return p, nil
}
func must(p *Properties, err error) *Properties {
@ -175,12 +213,12 @@ func must(p *Properties, err error) *Properties {
return p
}
// expandFilename expands ${ENV_VAR} expressions in a filename.
// expandName expands ${ENV_VAR} expressions in a name.
// If the environment variable does not exist then it will be replaced
// with an empty string. Malformed expressions like "${ENV_VAR" will
// be reported as error.
func expandFilename(filename string) (string, error) {
return expand(filename, make(map[string]bool), "${", "}", make(map[string]string))
func expandName(name string) (string, error) {
return expand(name, make(map[string]bool), "${", "}", make(map[string]string))
}
// Interprets a byte buffer either as an ISO-8859-1 or UTF-8 encoded string.

View File

@ -1,4 +1,4 @@
// Copyright 2016 Frank Schroeder. All rights reserved.
// Copyright 2017 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2016 Frank Schroeder. All rights reserved.
// Copyright 2017 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@ -28,8 +28,10 @@ type ErrorHandlerFunc func(error)
// functions. The default is LogFatalHandler.
var ErrorHandler ErrorHandlerFunc = LogFatalHandler
// LogHandlerFunc defines the function prototype for logging errors.
type LogHandlerFunc func(fmt string, args ...interface{})
// LogPrintf defines a log handler which uses log.Printf.
var LogPrintf LogHandlerFunc = log.Printf
// LogFatalHandler handles the error by logging a fatal error and exiting.
@ -444,6 +446,8 @@ func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties {
pp := NewProperties()
for _, k := range p.k {
if re.MatchString(k) {
// TODO(fs): we are ignoring the error which flags a circular reference.
// TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
pp.Set(k, p.m[k])
}
}
@ -456,6 +460,8 @@ func (p *Properties) FilterPrefix(prefix string) *Properties {
pp := NewProperties()
for _, k := range p.k {
if strings.HasPrefix(k, prefix) {
// TODO(fs): we are ignoring the error which flags a circular reference.
// TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
pp.Set(k, p.m[k])
}
}
@ -469,6 +475,9 @@ func (p *Properties) FilterStripPrefix(prefix string) *Properties {
n := len(prefix)
for _, k := range p.k {
if len(k) > len(prefix) && strings.HasPrefix(k, prefix) {
// TODO(fs): we are ignoring the error which flags a circular reference.
// TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference
// TODO(fs): this function should probably return an error but the signature is fixed
pp.Set(k[n:], p.m[k])
}
}
@ -483,9 +492,7 @@ func (p *Properties) Len() int {
// Keys returns all keys in the same order as in the input.
func (p *Properties) Keys() []string {
keys := make([]string, len(p.k))
for i, k := range p.k {
keys[i] = k
}
copy(keys, p.k)
return keys
}
@ -535,6 +542,13 @@ func (p *Properties) Set(key, value string) (prev string, ok bool, err error) {
return prev, ok, nil
}
// SetValue sets property key to the default string value
// as defined by fmt.Sprintf("%v").
func (p *Properties) SetValue(key string, value interface{}) error {
_, _, err := p.Set(key, fmt.Sprintf("%v", value))
return err
}
// MustSet sets the property key to the corresponding value.
// If a value for key existed before then ok is true and prev
// contains the previous value. An empty key is silently ignored.
@ -615,6 +629,30 @@ func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n i
return
}
// Map returns a copy of the properties as a map.
func (p *Properties) Map() map[string]string {
m := make(map[string]string)
for k, v := range p.m {
m[k] = v
}
return m
}
// FilterFunc returns a copy of the properties which includes the values which passed all filters.
func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties {
pp := NewProperties()
outer:
for k, v := range p.m {
for _, f := range filters {
if !f(k, v) {
continue outer
}
pp.Set(k, v)
}
}
return pp
}
// ----------------------------------------------------------------------------
// Delete removes the key and its comments.
@ -624,12 +662,32 @@ func (p *Properties) Delete(key string) {
newKeys := []string{}
for _, k := range p.k {
if k != key {
newKeys = append(newKeys, key)
newKeys = append(newKeys, k)
}
}
p.k = newKeys
}
// Merge merges properties, comments and keys from other *Properties into p
func (p *Properties) Merge(other *Properties) {
for k, v := range other.m {
p.m[k] = v
}
for k, v := range other.c {
p.c[k] = v
}
outer:
for _, otherKey := range other.k {
for _, key := range p.k {
if otherKey == key {
continue outer
}
}
p.k = append(p.k, otherKey)
}
}
// ----------------------------------------------------------------------------
// check expands all values and returns an error if a circular reference or

View File

@ -1,4 +1,4 @@
// Copyright 2016 Frank Schroeder. All rights reserved.
// Copyright 2017 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,5 +1,5 @@
// The mapstructure package exposes functionality to convert an
// abitrary map[string]interface{} into a native Go structure.
// arbitrary map[string]interface{} into a native Go structure.
//
// The Go structure can be arbitrarily complex, containing slices,
// other structs, etc. and the decoder will properly decode nested
@ -69,6 +69,9 @@ type DecoderConfig struct {
// - empty array = empty map and vice versa
// - negative numbers to overflowed uint values (base 10)
// - slice of maps to a merged map
// - single values are converted to slices if required. Each
// element is weakly decoded. For example: "4" can become []int{4}
// if the target type is an int slice.
//
WeaklyTypedInput bool
@ -202,7 +205,7 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error
d.config.DecodeHook,
dataVal.Type(), val.Type(), data)
if err != nil {
return err
return fmt.Errorf("error decoding '%s': %s", name, err)
}
}
@ -229,6 +232,8 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error
err = d.decodePtr(name, data, val)
case reflect.Slice:
err = d.decodeSlice(name, data, val)
case reflect.Func:
err = d.decodeFunc(name, data, val)
default:
// If we reached this point then we weren't able to decode it
return fmt.Errorf("%s: unsupported type: %s", name, dataKind)
@ -546,7 +551,12 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) er
// into that. Then set the value of the pointer to this type.
valType := val.Type()
valElemType := valType.Elem()
realVal := reflect.New(valElemType)
realVal := val
if realVal.IsNil() || d.config.ZeroFields {
realVal = reflect.New(valElemType)
}
if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
return err
}
@ -555,6 +565,19 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) er
return nil
}
func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error {
// Create an element of the concrete (non pointer) type and decode
// into that. Then set the value of the pointer to this type.
dataVal := reflect.Indirect(reflect.ValueOf(data))
if val.Type() != dataVal.Type() {
return fmt.Errorf(
"'%s' expected type '%s', got unconvertible type '%s'",
name, val.Type(), dataVal.Type())
}
val.Set(dataVal)
return nil
}
func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error {
dataVal := reflect.Indirect(reflect.ValueOf(data))
dataValKind := dataVal.Kind()
@ -562,26 +585,44 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
valElemType := valType.Elem()
sliceType := reflect.SliceOf(valElemType)
valSlice := val
if valSlice.IsNil() || d.config.ZeroFields {
// Check input type
if dataValKind != reflect.Array && dataValKind != reflect.Slice {
// Accept empty map instead of array/slice in weakly typed mode
if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 {
if d.config.WeaklyTypedInput {
switch {
// Empty maps turn into empty slices
case dataValKind == reflect.Map:
if dataVal.Len() == 0 {
val.Set(reflect.MakeSlice(sliceType, 0, 0))
return nil
} else {
return fmt.Errorf(
"'%s': source data must be an array or slice, got %s", name, dataValKind)
}
// All other types we try to convert to the slice type
// and "lift" it into it. i.e. a string becomes a string slice.
default:
// Just re-try this function with data as a slice.
return d.decodeSlice(name, []interface{}{data}, val)
}
}
return fmt.Errorf(
"'%s': source data must be an array or slice, got %s", name, dataValKind)
}
// Make a new slice to hold our result, same size as the original data.
valSlice := reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
}
// Accumulate any errors
errors := make([]string, 0)
for i := 0; i < dataVal.Len(); i++ {
currentData := dataVal.Index(i).Interface()
for valSlice.Len() <= i {
valSlice = reflect.Append(valSlice, reflect.Zero(valElemType))
}
currentField := valSlice.Index(i)
fieldName := fmt.Sprintf("%s[%d]", name, i)

View File

@ -31,8 +31,13 @@ func NewReader(rd io.Reader) *Reader {
}
}
type runeWithSize struct {
r rune
size int
}
func (rd *Reader) feedBuffer() error {
r, _, err := rd.input.ReadRune()
r, size, err := rd.input.ReadRune()
if err != nil {
if err != io.EOF {
@ -41,7 +46,9 @@ func (rd *Reader) feedBuffer() error {
r = EOF
}
rd.buffer.PushBack(r)
newRuneWithSize := runeWithSize{r, size}
rd.buffer.PushBack(newRuneWithSize)
if rd.current == nil {
rd.current = rd.buffer.Back()
}
@ -49,17 +56,17 @@ func (rd *Reader) feedBuffer() error {
}
// ReadRune reads the next rune from buffer, or from the underlying reader if needed.
func (rd *Reader) ReadRune() (rune, error) {
func (rd *Reader) ReadRune() (rune, int, error) {
if rd.current == rd.buffer.Back() || rd.current == nil {
err := rd.feedBuffer()
if err != nil {
return EOF, err
return EOF, 0, err
}
}
r := rd.current.Value
runeWithSize := rd.current.Value.(runeWithSize)
rd.current = rd.current.Next()
return r.(rune), nil
return runeWithSize.r, runeWithSize.size, nil
}
// UnreadRune pushes back the previously read rune in the buffer, extending it if needed.
@ -84,9 +91,9 @@ func (rd *Reader) Forget() {
}
}
// Peek returns at most the next n runes, reading from the uderlying source if
// PeekRune returns at most the next n runes, reading from the uderlying source if
// needed. Does not move the current index. It includes EOF if reached.
func (rd *Reader) Peek(n int) []rune {
func (rd *Reader) PeekRunes(n int) []rune {
res := make([]rune, 0, n)
cursor := rd.current
for i := 0; i < n; i++ {
@ -98,7 +105,7 @@ func (rd *Reader) Peek(n int) []rune {
cursor = rd.buffer.Back()
}
if cursor != nil {
r := cursor.Value.(rune)
r := cursor.Value.(runeWithSize).r
res = append(res, r)
if r == EOF {
return res

21
vendor/github.com/pelletier/go-toml/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton
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.

View File

@ -22,8 +22,8 @@
// After parsing TOML data with Load() or LoadFile(), use the Has() and Get()
// methods on the returned TomlTree, to find your way through the document data.
//
// if tree.Has('foo') {
// fmt.Prinln("foo is: %v", tree.Get('foo'))
// if tree.Has("foo") {
// fmt.Println("foo is:", tree.Get("foo"))
// }
//
// Working with Paths
@ -44,10 +44,10 @@
// it avoids having to parse the passed key for '.' delimiters.
//
// // looks for a key named 'baz', within struct 'bar', within struct 'foo'
// tree.HasPath(string{}{"foo","bar","baz"})
// tree.HasPath([]string{"foo","bar","baz"})
//
// // returns the key at this path, if it is there
// tree.GetPath(string{}{"foo","bar","baz"})
// tree.GetPath([]string{"foo","bar","baz"})
//
// Note that this is distinct from the heavyweight query syntax supported by
// TomlTree.Query() and the Query() struct (see below).

View File

@ -4,6 +4,7 @@ package toml
import (
"bytes"
"errors"
"fmt"
"unicode"
)
@ -12,6 +13,7 @@ func parseKey(key string) ([]string, error) {
groups := []string{}
var buffer bytes.Buffer
inQuotes := false
wasInQuotes := false
escapeNext := false
ignoreSpace := true
expectDot := false
@ -33,16 +35,27 @@ func parseKey(key string) ([]string, error) {
escapeNext = true
continue
case '"':
if inQuotes {
groups = append(groups, buffer.String())
buffer.Reset()
wasInQuotes = true
}
inQuotes = !inQuotes
expectDot = false
case '.':
if inQuotes {
buffer.WriteRune(char)
} else {
if !wasInQuotes {
if buffer.Len() == 0 {
return nil, errors.New("empty table key")
}
groups = append(groups, buffer.String())
buffer.Reset()
}
ignoreSpace = true
expectDot = false
wasInQuotes = false
}
case ' ':
if inQuotes {
@ -55,23 +68,23 @@ func parseKey(key string) ([]string, error) {
return nil, fmt.Errorf("invalid bare character: %c", char)
}
if !inQuotes && expectDot {
return nil, fmt.Errorf("what?")
return nil, errors.New("what?")
}
buffer.WriteRune(char)
expectDot = false
}
}
if inQuotes {
return nil, fmt.Errorf("mismatched quotes")
return nil, errors.New("mismatched quotes")
}
if escapeNext {
return nil, fmt.Errorf("unfinished escape sequence")
return nil, errors.New("unfinished escape sequence")
}
if buffer.Len() > 0 {
groups = append(groups, buffer.String())
}
if len(groups) == 0 {
return nil, fmt.Errorf("empty key")
return nil, errors.New("empty key")
}
return groups, nil
}

View File

@ -1,6 +1,6 @@
// TOML lexer.
//
// Written using the principles developped by Rob Pike in
// Written using the principles developed by Rob Pike in
// http://www.youtube.com/watch?v=HxaD_trXwRE
package toml
@ -36,7 +36,7 @@ type tomlLexer struct {
// Basic read operations on input
func (l *tomlLexer) read() rune {
r, err := l.input.ReadRune()
r, _, err := l.input.ReadRune()
if err != nil {
panic(err)
}
@ -89,7 +89,7 @@ func (l *tomlLexer) emit(t tokenType) {
}
func (l *tomlLexer) peek() rune {
r, err := l.input.ReadRune()
r, _, err := l.input.ReadRune()
if err != nil {
panic(err)
}
@ -99,7 +99,7 @@ func (l *tomlLexer) peek() rune {
func (l *tomlLexer) follow(next string) bool {
for _, expectedRune := range next {
r, err := l.input.ReadRune()
r, _, err := l.input.ReadRune()
defer l.input.UnreadRune()
if err != nil {
panic(err)
@ -129,9 +129,9 @@ func (l *tomlLexer) lexVoid() tomlLexStateFn {
next := l.peek()
switch next {
case '[':
return l.lexKeyGroup
return l.lexTableKey
case '#':
return l.lexComment
return l.lexComment(l.lexVoid)
case '=':
return l.lexEqual
case '\r':
@ -182,7 +182,7 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
case '}':
return l.lexRightCurlyBrace
case '#':
return l.lexComment
return l.lexComment(l.lexRvalue)
case '"':
return l.lexString
case '\'':
@ -219,7 +219,7 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
break
}
possibleDate := string(l.input.Peek(35))
possibleDate := string(l.input.PeekRunes(35))
dateMatch := dateRegexp.FindString(possibleDate)
if dateMatch != "" {
l.fastForward(len(dateMatch))
@ -309,7 +309,8 @@ func (l *tomlLexer) lexKey() tomlLexStateFn {
return l.lexVoid
}
func (l *tomlLexer) lexComment() tomlLexStateFn {
func (l *tomlLexer) lexComment(previousState tomlLexStateFn) tomlLexStateFn {
return func() tomlLexStateFn {
for next := l.peek(); next != '\n' && next != eof; next = l.peek() {
if next == '\r' && l.follow("\r\n") {
break
@ -317,7 +318,8 @@ func (l *tomlLexer) lexComment() tomlLexStateFn {
l.next()
}
l.ignore()
return l.lexVoid
return previousState
}
}
func (l *tomlLexer) lexLeftBracket() tomlLexStateFn {
@ -516,21 +518,21 @@ func (l *tomlLexer) lexString() tomlLexStateFn {
return l.lexRvalue
}
func (l *tomlLexer) lexKeyGroup() tomlLexStateFn {
func (l *tomlLexer) lexTableKey() tomlLexStateFn {
l.next()
if l.peek() == '[' {
// token '[[' signifies an array of anonymous key groups
// token '[[' signifies an array of tables
l.next()
l.emit(tokenDoubleLeftBracket)
return l.lexInsideKeyGroupArray
return l.lexInsideTableArrayKey
}
// vanilla key group
// vanilla table key
l.emit(tokenLeftBracket)
return l.lexInsideKeyGroup
return l.lexInsideTableKey
}
func (l *tomlLexer) lexInsideKeyGroupArray() tomlLexStateFn {
func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
for r := l.peek(); r != eof; r = l.peek() {
switch r {
case ']':
@ -545,15 +547,15 @@ func (l *tomlLexer) lexInsideKeyGroupArray() tomlLexStateFn {
l.emit(tokenDoubleRightBracket)
return l.lexVoid
case '[':
return l.errorf("group name cannot contain ']'")
return l.errorf("table array key cannot contain ']'")
default:
l.next()
}
}
return l.errorf("unclosed key group array")
return l.errorf("unclosed table array key")
}
func (l *tomlLexer) lexInsideKeyGroup() tomlLexStateFn {
func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn {
for r := l.peek(); r != eof; r = l.peek() {
switch r {
case ']':
@ -564,12 +566,12 @@ func (l *tomlLexer) lexInsideKeyGroup() tomlLexStateFn {
l.emit(tokenRightBracket)
return l.lexVoid
case '[':
return l.errorf("group name cannot contain ']'")
return l.errorf("table key cannot contain ']'")
default:
l.next()
}
}
return l.errorf("unclosed key group")
return l.errorf("unclosed table key")
}
func (l *tomlLexer) lexRightBracket() tomlLexStateFn {

459
vendor/github.com/pelletier/go-toml/marshal.go generated vendored Normal file
View File

@ -0,0 +1,459 @@
package toml
import (
"errors"
"fmt"
"reflect"
"strings"
"time"
)
/*
TomlTree structural types and corresponding marshal types
-------------------------------------------------------------------------------
*TomlTree (*)struct, (*)map[string]interface{}
[]*TomlTree (*)[](*)struct, (*)[](*)map[string]interface{}
[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
interface{} (*)primitive
TomlTree primitive types and corresponding marshal types
-----------------------------------------------------------
uint64 uint, uint8-uint64, pointers to same
int64 int, int8-uint64, pointers to same
float64 float32, float64, pointers to same
string string, pointers to same
bool bool, pointers to same
time.Time time.Time{}, pointers to same
*/
type tomlOpts struct {
name string
include bool
omitempty bool
}
var timeType = reflect.TypeOf(time.Time{})
// Check if the given marshall type maps to a TomlTree primitive
func isPrimitive(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Ptr:
return isPrimitive(mtype.Elem())
case reflect.Bool:
return true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
case reflect.Struct:
return mtype == timeType
default:
return false
}
}
// Check if the given marshall type maps to a TomlTree slice
func isTreeSlice(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Slice:
return !isOtherSlice(mtype)
default:
return false
}
}
// Check if the given marshall type maps to a non-TomlTree slice
func isOtherSlice(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Ptr:
return isOtherSlice(mtype.Elem())
case reflect.Slice:
return isPrimitive(mtype.Elem()) || isOtherSlice(mtype.Elem())
default:
return false
}
}
// Check if the given marshall type maps to a TomlTree
func isTree(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Map:
return true
case reflect.Struct:
return !isPrimitive(mtype)
default:
return false
}
}
/*
Marshal returns the TOML encoding of v. Behavior is similar to the Go json
encoder, except that there is no concept of a Marshaler interface or MarshalTOML
function for sub-structs, and currently only definite types can be marshaled
(i.e. no `interface{}`).
Note that pointers are automatically assigned the "omitempty" option, as TOML
explicity does not handle null values (saying instead the label should be
dropped).
*/
func Marshal(v interface{}) ([]byte, error) {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Struct {
return []byte{}, errors.New("Only a struct can be marshaled to TOML")
}
sval := reflect.ValueOf(v)
t, err := valueToTree(mtype, sval)
if err != nil {
return []byte{}, err
}
s, err := t.ToTomlString()
return []byte(s), err
}
// Convert given marshal struct or map value to toml tree
func valueToTree(mtype reflect.Type, mval reflect.Value) (*TomlTree, error) {
if mtype.Kind() == reflect.Ptr {
return valueToTree(mtype.Elem(), mval.Elem())
}
tval := newTomlTree()
switch mtype.Kind() {
case reflect.Struct:
for i := 0; i < mtype.NumField(); i++ {
mtypef, mvalf := mtype.Field(i), mval.Field(i)
opts := tomlOptions(mtypef)
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
val, err := valueToToml(mtypef.Type, mvalf)
if err != nil {
return nil, err
}
tval.Set(opts.name, val)
}
}
case reflect.Map:
for _, key := range mval.MapKeys() {
mvalf := mval.MapIndex(key)
val, err := valueToToml(mtype.Elem(), mvalf)
if err != nil {
return nil, err
}
tval.Set(key.String(), val)
}
}
return tval, nil
}
// Convert given marshal slice to slice of Toml trees
func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*TomlTree, error) {
tval := make([]*TomlTree, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
val, err := valueToTree(mtype.Elem(), mval.Index(i))
if err != nil {
return nil, err
}
tval[i] = val
}
return tval, nil
}
// Convert given marshal slice to slice of toml values
func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
tval := make([]interface{}, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
val, err := valueToToml(mtype.Elem(), mval.Index(i))
if err != nil {
return nil, err
}
tval[i] = val
}
return tval, nil
}
// Convert given marshal value to toml value
func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
if mtype.Kind() == reflect.Ptr {
return valueToToml(mtype.Elem(), mval.Elem())
}
switch {
case isTree(mtype):
return valueToTree(mtype, mval)
case isTreeSlice(mtype):
return valueToTreeSlice(mtype, mval)
case isOtherSlice(mtype):
return valueToOtherSlice(mtype, mval)
default:
switch mtype.Kind() {
case reflect.Bool:
return mval.Bool(), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return mval.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return mval.Uint(), nil
case reflect.Float32, reflect.Float64:
return mval.Float(), nil
case reflect.String:
return mval.String(), nil
case reflect.Struct:
return mval.Interface().(time.Time), nil
default:
return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind())
}
}
}
/*
Unmarshal parses the TOML-encoded data and stores the result in the value
pointed to by v. Behavior is similar to the Go json encoder, except that there
is no concept of an Unmarshaler interface or UnmarshalTOML function for
sub-structs, and currently only definite types can be unmarshaled to (i.e. no
`interface{}`).
*/
func Unmarshal(data []byte, v interface{}) error {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
return errors.New("Only a pointer to struct can be unmarshaled from TOML")
}
t, err := Load(string(data))
if err != nil {
return err
}
sval, err := valueFromTree(mtype.Elem(), t)
if err != nil {
return err
}
reflect.ValueOf(v).Elem().Set(sval)
return nil
}
// Convert toml tree to marshal struct or map, using marshal type
func valueFromTree(mtype reflect.Type, tval *TomlTree) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
return unwrapPointer(mtype, tval)
}
var mval reflect.Value
switch mtype.Kind() {
case reflect.Struct:
mval = reflect.New(mtype).Elem()
for i := 0; i < mtype.NumField(); i++ {
mtypef := mtype.Field(i)
opts := tomlOptions(mtypef)
if opts.include {
key := opts.name
exists := tval.Has(key)
if exists {
val := tval.Get(key)
mvalf, err := valueFromToml(mtypef.Type, val)
if err != nil {
return mval, formatError(err, tval.GetPosition(key))
}
mval.Field(i).Set(mvalf)
}
}
}
case reflect.Map:
mval = reflect.MakeMap(mtype)
for _, key := range tval.Keys() {
val := tval.Get(key)
mvalf, err := valueFromToml(mtype.Elem(), val)
if err != nil {
return mval, formatError(err, tval.GetPosition(key))
}
mval.SetMapIndex(reflect.ValueOf(key), mvalf)
}
}
return mval, nil
}
// Convert toml value to marshal struct/map slice, using marshal type
func valueFromTreeSlice(mtype reflect.Type, tval []*TomlTree) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
val, err := valueFromTree(mtype.Elem(), tval[i])
if err != nil {
return mval, err
}
mval.Index(i).Set(val)
}
return mval, nil
}
// Convert toml value to marshal primitive slice, using marshal type
func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
val, err := valueFromToml(mtype.Elem(), tval[i])
if err != nil {
return mval, err
}
mval.Index(i).Set(val)
}
return mval, nil
}
// Convert toml value to marshal value, using marshal type
func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
return unwrapPointer(mtype, tval)
}
switch {
case isTree(mtype):
return valueFromTree(mtype, tval.(*TomlTree))
case isTreeSlice(mtype):
return valueFromTreeSlice(mtype, tval.([]*TomlTree))
case isOtherSlice(mtype):
return valueFromOtherSlice(mtype, tval.([]interface{}))
default:
switch mtype.Kind() {
case reflect.Bool:
val, ok := tval.(bool)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to bool", tval, tval)
}
return reflect.ValueOf(val), nil
case reflect.Int:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(int(val)), nil
case reflect.Int8:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(int8(val)), nil
case reflect.Int16:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(int16(val)), nil
case reflect.Int32:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(int32(val)), nil
case reflect.Int64:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(val), nil
case reflect.Uint:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint(val)), nil
case reflect.Uint8:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint8(val)), nil
case reflect.Uint16:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint16(val)), nil
case reflect.Uint32:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint32(val)), nil
case reflect.Uint64:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint64(val)), nil
case reflect.Float32:
val, ok := tval.(float64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
}
return reflect.ValueOf(float32(val)), nil
case reflect.Float64:
val, ok := tval.(float64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
}
return reflect.ValueOf(val), nil
case reflect.String:
val, ok := tval.(string)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to string", tval, tval)
}
return reflect.ValueOf(val), nil
case reflect.Struct:
val, ok := tval.(time.Time)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to time", tval, tval)
}
return reflect.ValueOf(val), nil
default:
return reflect.ValueOf(nil), fmt.Errorf("Unmarshal can't handle %v(%v)", mtype, mtype.Kind())
}
}
}
func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
val, err := valueFromToml(mtype.Elem(), tval)
if err != nil {
return reflect.ValueOf(nil), err
}
mval := reflect.New(mtype.Elem())
mval.Elem().Set(val)
return mval, nil
}
func tomlOptions(vf reflect.StructField) tomlOpts {
tag := vf.Tag.Get("toml")
parse := strings.Split(tag, ",")
result := tomlOpts{vf.Name, true, false}
if parse[0] != "" {
if parse[0] == "-" && len(parse) == 1 {
result.include = false
} else {
result.name = strings.Trim(parse[0], " ")
}
}
if vf.PkgPath != "" {
result.include = false
}
if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" {
result.omitempty = true
}
if vf.Type.Kind() == reflect.Ptr {
result.omitempty = true
}
return result
}
func isZero(val reflect.Value) bool {
switch val.Type().Kind() {
case reflect.Map:
fallthrough
case reflect.Array:
fallthrough
case reflect.Slice:
return val.Len() == 0
default:
return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface())
}
}
func formatError(err error, pos Position) error {
if err.Error()[0] == '(' { // Error already contains position information
return err
}
return fmt.Errorf("%s: %s", pos, err)
}

View File

@ -3,6 +3,7 @@
package toml
import (
"errors"
"fmt"
"reflect"
"regexp"
@ -15,8 +16,8 @@ type tomlParser struct {
flow chan token
tree *TomlTree
tokensBuffer []token
currentGroup []string
seenGroupKeys []string
currentTable []string
seenTableKeys []string
}
type tomlParserStateFn func() tomlParserStateFn
@ -95,13 +96,13 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
startToken := p.getToken() // discard the [[
key := p.getToken()
if key.typ != tokenKeyGroupArray {
p.raiseError(key, "unexpected token %s, was expecting a key group array", key)
p.raiseError(key, "unexpected token %s, was expecting a table array key", key)
}
// get or create group array element at the indicated part in the path
// get or create table array element at the indicated part in the path
keys, err := parseKey(key.val)
if err != nil {
p.raiseError(key, "invalid group array key: %s", err)
p.raiseError(key, "invalid table array key: %s", err)
}
p.tree.createSubTree(keys[:len(keys)-1], startToken.Position) // create parent entries
destTree := p.tree.GetPath(keys)
@ -111,32 +112,32 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
} else if target, ok := destTree.([]*TomlTree); ok && target != nil {
array = destTree.([]*TomlTree)
} else {
p.raiseError(key, "key %s is already assigned and not of type group array", key)
p.raiseError(key, "key %s is already assigned and not of type table array", key)
}
p.currentGroup = keys
p.currentTable = keys
// add a new tree to the end of the group array
// add a new tree to the end of the table array
newTree := newTomlTree()
newTree.position = startToken.Position
array = append(array, newTree)
p.tree.SetPath(p.currentGroup, array)
p.tree.SetPath(p.currentTable, array)
// remove all keys that were children of this group array
// remove all keys that were children of this table array
prefix := key.val + "."
found := false
for ii := 0; ii < len(p.seenGroupKeys); {
groupKey := p.seenGroupKeys[ii]
if strings.HasPrefix(groupKey, prefix) {
p.seenGroupKeys = append(p.seenGroupKeys[:ii], p.seenGroupKeys[ii+1:]...)
for ii := 0; ii < len(p.seenTableKeys); {
tableKey := p.seenTableKeys[ii]
if strings.HasPrefix(tableKey, prefix) {
p.seenTableKeys = append(p.seenTableKeys[:ii], p.seenTableKeys[ii+1:]...)
} else {
found = (groupKey == key.val)
found = (tableKey == key.val)
ii++
}
}
// keep this key name from use by other kinds of assignments
if !found {
p.seenGroupKeys = append(p.seenGroupKeys, key.val)
p.seenTableKeys = append(p.seenTableKeys, key.val)
}
// move to next parser state
@ -148,24 +149,24 @@ func (p *tomlParser) parseGroup() tomlParserStateFn {
startToken := p.getToken() // discard the [
key := p.getToken()
if key.typ != tokenKeyGroup {
p.raiseError(key, "unexpected token %s, was expecting a key group", key)
p.raiseError(key, "unexpected token %s, was expecting a table key", key)
}
for _, item := range p.seenGroupKeys {
for _, item := range p.seenTableKeys {
if item == key.val {
p.raiseError(key, "duplicated tables")
}
}
p.seenGroupKeys = append(p.seenGroupKeys, key.val)
p.seenTableKeys = append(p.seenTableKeys, key.val)
keys, err := parseKey(key.val)
if err != nil {
p.raiseError(key, "invalid group array key: %s", err)
p.raiseError(key, "invalid table array key: %s", err)
}
if err := p.tree.createSubTree(keys, startToken.Position); err != nil {
p.raiseError(key, "%s", err)
}
p.assume(tokenRightBracket)
p.currentGroup = keys
p.currentTable = keys
return p.parseStart
}
@ -174,26 +175,26 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
p.assume(tokenEqual)
value := p.parseRvalue()
var groupKey []string
if len(p.currentGroup) > 0 {
groupKey = p.currentGroup
var tableKey []string
if len(p.currentTable) > 0 {
tableKey = p.currentTable
} else {
groupKey = []string{}
tableKey = []string{}
}
// find the group to assign, looking out for arrays of groups
// find the table to assign, looking out for arrays of tables
var targetNode *TomlTree
switch node := p.tree.GetPath(groupKey).(type) {
switch node := p.tree.GetPath(tableKey).(type) {
case []*TomlTree:
targetNode = node[len(node)-1]
case *TomlTree:
targetNode = node
default:
p.raiseError(key, "Unknown group type for path: %s",
strings.Join(groupKey, "."))
p.raiseError(key, "Unknown table type for path: %s",
strings.Join(tableKey, "."))
}
// assign value to the found group
// assign value to the found table
keyVals, err := parseKey(key.val)
if err != nil {
p.raiseError(key, "%s", err)
@ -203,7 +204,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
}
keyVal := keyVals[0]
localKey := []string{keyVal}
finalKey := append(groupKey, keyVal)
finalKey := append(tableKey, keyVal)
if targetNode.GetPath(localKey) != nil {
p.raiseError(key, "The following key was defined twice: %s",
strings.Join(finalKey, "."))
@ -211,7 +212,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
var toInsert interface{}
switch value.(type) {
case *TomlTree:
case *TomlTree, []*TomlTree:
toInsert = value
default:
toInsert = &tomlValue{value, key.Position}
@ -224,7 +225,7 @@ var numberUnderscoreInvalidRegexp *regexp.Regexp
func cleanupNumberToken(value string) (string, error) {
if numberUnderscoreInvalidRegexp.MatchString(value) {
return "", fmt.Errorf("invalid use of _ in number")
return "", errors.New("invalid use of _ in number")
}
cleanedVal := strings.Replace(value, "_", "", -1)
return cleanedVal, nil
@ -380,8 +381,8 @@ func parseToml(flow chan token) *TomlTree {
flow: flow,
tree: result,
tokensBuffer: make([]token, 0),
currentGroup: make([]string, 0),
seenGroupKeys: make([]string, 0),
currentTable: make([]string, 0),
seenTableKeys: make([]string, 0),
}
parser.run()
return result

View File

@ -18,12 +18,12 @@ type Position struct {
// String representation of the position.
// Displays 1-indexed line and column numbers.
func (p *Position) String() string {
func (p Position) String() string {
return fmt.Sprintf("(%d, %d)", p.Line, p.Col)
}
// Invalid returns whether or not the position is valid (i.e. with negative or
// null values)
func (p *Position) Invalid() bool {
func (p Position) Invalid() bool {
return p.Line <= 0 || p.Col <= 0
}

View File

@ -30,7 +30,7 @@ func (r *QueryResult) appendResult(node interface{}, pos Position) {
// Values is a set of values within a QueryResult. The order of values is not
// guaranteed to be in document order, and may be different each time a query is
// executed.
func (r *QueryResult) Values() []interface{} {
func (r QueryResult) Values() []interface{} {
values := make([]interface{}, len(r.items))
for i, v := range r.items {
o, ok := v.(*tomlValue)
@ -45,7 +45,7 @@ func (r *QueryResult) Values() []interface{} {
// Positions is a set of positions for values within a QueryResult. Each index
// in Positions() corresponds to the entry in Value() of the same index.
func (r *QueryResult) Positions() []Position {
func (r QueryResult) Positions() []Position {
return r.positions
}

View File

@ -272,6 +272,23 @@ func (l *queryLexer) lexString() queryLexStateFn {
return l.errorf("invalid unicode escape: \\u" + code)
}
growingString += string(rune(intcode))
} else if l.follow("\\U") {
l.pos += 2
code := ""
for i := 0; i < 8; i++ {
c := l.peek()
l.pos++
if !isHexDigit(c) {
return l.errorf("unfinished unicode escape")
}
code = code + string(c)
}
l.pos--
intcode, err := strconv.ParseInt(code, 16, 32)
if err != nil {
return l.errorf("invalid unicode escape: \\u" + code)
}
growingString += string(rune(intcode))
} else if l.follow("\\") {
l.pos++
return l.errorf("invalid escape sequence: \\" + string(l.peek()))

View File

@ -135,5 +135,6 @@ func isDigit(r rune) bool {
func isHexDigit(r rune) bool {
return isDigit(r) ||
r == 'A' || r == 'B' || r == 'C' || r == 'D' || r == 'E' || r == 'F'
(r >= 'a' && r <= 'f') ||
(r >= 'A' && r <= 'F')
}

View File

@ -10,13 +10,13 @@ import (
)
type tomlValue struct {
value interface{}
value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
position Position
}
// TomlTree is the result of the parsing of a TOML file.
type TomlTree struct {
values map[string]interface{}
values map[string]interface{} // string -> *tomlValue, *TomlTree, []*TomlTree
position Position
}
@ -28,10 +28,12 @@ func newTomlTree() *TomlTree {
}
// TreeFromMap initializes a new TomlTree object using the given map.
func TreeFromMap(m map[string]interface{}) *TomlTree {
return &TomlTree{
values: m,
func TreeFromMap(m map[string]interface{}) (*TomlTree, error) {
result, err := toTree(m)
if err != nil {
return nil, err
}
return result.(*TomlTree), nil
}
// Has returns a boolean indicating if the given key exists.
@ -222,9 +224,6 @@ func (t *TomlTree) SetPath(keys []string, value interface{}) {
func (t *TomlTree) createSubTree(keys []string, pos Position) error {
subtree := t
for _, intermediateKey := range keys {
if intermediateKey == "" {
return fmt.Errorf("empty intermediate table")
}
nextTree, exists := subtree.values[intermediateKey]
if !exists {
tree := newTomlTree()

View File

@ -1,144 +0,0 @@
// Tools to convert a TomlTree to different representations
package toml
import (
"fmt"
"strconv"
"strings"
"time"
)
// encodes a string to a TOML-compliant string value
func encodeTomlString(value string) string {
result := ""
for _, rr := range value {
intRr := uint16(rr)
switch rr {
case '\b':
result += "\\b"
case '\t':
result += "\\t"
case '\n':
result += "\\n"
case '\f':
result += "\\f"
case '\r':
result += "\\r"
case '"':
result += "\\\""
case '\\':
result += "\\\\"
default:
if intRr < 0x001F {
result += fmt.Sprintf("\\u%0.4X", intRr)
} else {
result += string(rr)
}
}
}
return result
}
// Value print support function for ToString()
// Outputs the TOML compliant string representation of a value
func toTomlValue(item interface{}, indent int) string {
tab := strings.Repeat(" ", indent)
switch value := item.(type) {
case int64:
return tab + strconv.FormatInt(value, 10)
case float64:
return tab + strconv.FormatFloat(value, 'f', -1, 64)
case string:
return tab + "\"" + encodeTomlString(value) + "\""
case bool:
if value {
return "true"
}
return "false"
case time.Time:
return tab + value.Format(time.RFC3339)
case []interface{}:
result := tab + "[\n"
for _, item := range value {
result += toTomlValue(item, indent+2) + ",\n"
}
return result + tab + "]"
default:
panic(fmt.Sprintf("unsupported value type: %v", value))
}
}
// Recursive support function for ToString()
// Outputs a tree, using the provided keyspace to prefix group names
func (t *TomlTree) toToml(indent, keyspace string) string {
result := ""
for k, v := range t.values {
// figure out the keyspace
combinedKey := k
if keyspace != "" {
combinedKey = keyspace + "." + combinedKey
}
// output based on type
switch node := v.(type) {
case []*TomlTree:
for _, item := range node {
if len(item.Keys()) > 0 {
result += fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey)
}
result += item.toToml(indent+" ", combinedKey)
}
case *TomlTree:
if len(node.Keys()) > 0 {
result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
}
result += node.toToml(indent+" ", combinedKey)
case map[string]interface{}:
sub := TreeFromMap(node)
if len(sub.Keys()) > 0 {
result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
}
result += sub.toToml(indent+" ", combinedKey)
case *tomlValue:
result += fmt.Sprintf("%s%s = %s\n", indent, k, toTomlValue(node.value, 0))
default:
result += fmt.Sprintf("%s%s = %s\n", indent, k, toTomlValue(v, 0))
}
}
return result
}
// ToString is an alias for String
func (t *TomlTree) ToString() string {
return t.String()
}
// ToString generates a human-readable representation of the current tree.
// Output spans multiple lines, and is suitable for ingest by a TOML parser
func (t *TomlTree) String() string {
return t.toToml("", "")
}
// ToMap recursively generates a representation of the current tree using map[string]interface{}.
func (t *TomlTree) ToMap() map[string]interface{} {
result := map[string]interface{}{}
for k, v := range t.values {
switch node := v.(type) {
case []*TomlTree:
result[k] = make([]interface{}, 0)
for _, item := range node {
result[k] = item.ToMap()
}
case *TomlTree:
result[k] = node.ToMap()
case map[string]interface{}:
sub := TreeFromMap(node)
result[k] = sub.ToMap()
case *tomlValue:
result[k] = node.value
}
}
return result
}

135
vendor/github.com/pelletier/go-toml/tomltree_create.go generated vendored Normal file
View File

@ -0,0 +1,135 @@
package toml
import (
"fmt"
"reflect"
"time"
)
// supported values:
// string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32
var kindToTypeMapping = map[reflect.Kind]reflect.Type{
reflect.Bool: reflect.TypeOf(true),
reflect.String: reflect.TypeOf(""),
reflect.Float32: reflect.TypeOf(float64(1)),
reflect.Float64: reflect.TypeOf(float64(1)),
reflect.Int: reflect.TypeOf(int64(1)),
reflect.Int8: reflect.TypeOf(int64(1)),
reflect.Int16: reflect.TypeOf(int64(1)),
reflect.Int32: reflect.TypeOf(int64(1)),
reflect.Int64: reflect.TypeOf(int64(1)),
reflect.Uint: reflect.TypeOf(uint64(1)),
reflect.Uint8: reflect.TypeOf(uint64(1)),
reflect.Uint16: reflect.TypeOf(uint64(1)),
reflect.Uint32: reflect.TypeOf(uint64(1)),
reflect.Uint64: reflect.TypeOf(uint64(1)),
}
func simpleValueCoercion(object interface{}) (interface{}, error) {
switch original := object.(type) {
case string, bool, int64, uint64, float64, time.Time:
return original, nil
case int:
return int64(original), nil
case int8:
return int64(original), nil
case int16:
return int64(original), nil
case int32:
return int64(original), nil
case uint:
return uint64(original), nil
case uint8:
return uint64(original), nil
case uint16:
return uint64(original), nil
case uint32:
return uint64(original), nil
case float32:
return float64(original), nil
case fmt.Stringer:
return original.String(), nil
default:
return nil, fmt.Errorf("cannot convert type %T to TomlTree", object)
}
}
func sliceToTree(object interface{}) (interface{}, error) {
// arrays are a bit tricky, since they can represent either a
// collection of simple values, which is represented by one
// *tomlValue, or an array of tables, which is represented by an
// array of *TomlTree.
// holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice
value := reflect.ValueOf(object)
insideType := value.Type().Elem()
length := value.Len()
if length > 0 {
insideType = reflect.ValueOf(value.Index(0).Interface()).Type()
}
if insideType.Kind() == reflect.Map {
// this is considered as an array of tables
tablesArray := make([]*TomlTree, 0, length)
for i := 0; i < length; i++ {
table := value.Index(i)
tree, err := toTree(table.Interface())
if err != nil {
return nil, err
}
tablesArray = append(tablesArray, tree.(*TomlTree))
}
return tablesArray, nil
}
sliceType := kindToTypeMapping[insideType.Kind()]
if sliceType == nil {
sliceType = insideType
}
arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length)
for i := 0; i < length; i++ {
val := value.Index(i).Interface()
simpleValue, err := simpleValueCoercion(val)
if err != nil {
return nil, err
}
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
}
return &tomlValue{arrayValue.Interface(), Position{}}, nil
}
func toTree(object interface{}) (interface{}, error) {
value := reflect.ValueOf(object)
if value.Kind() == reflect.Map {
values := map[string]interface{}{}
keys := value.MapKeys()
for _, key := range keys {
if key.Kind() != reflect.String {
if _, ok := key.Interface().(string); !ok {
return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind())
}
}
v := value.MapIndex(key)
newValue, err := toTree(v.Interface())
if err != nil {
return nil, err
}
values[key.String()] = newValue
}
return &TomlTree{values, Position{}}, nil
}
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
return sliceToTree(object)
}
simpleValue, err := simpleValueCoercion(object)
if err != nil {
return nil, err
}
return &tomlValue{simpleValue, Position{}}, nil
}

214
vendor/github.com/pelletier/go-toml/tomltree_write.go generated vendored Normal file
View File

@ -0,0 +1,214 @@
package toml
import (
"bytes"
"fmt"
"io"
"sort"
"strconv"
"strings"
"time"
"reflect"
)
// encodes a string to a TOML-compliant string value
func encodeTomlString(value string) string {
result := ""
for _, rr := range value {
switch rr {
case '\b':
result += "\\b"
case '\t':
result += "\\t"
case '\n':
result += "\\n"
case '\f':
result += "\\f"
case '\r':
result += "\\r"
case '"':
result += "\\\""
case '\\':
result += "\\\\"
default:
intRr := uint16(rr)
if intRr < 0x001F {
result += fmt.Sprintf("\\u%0.4X", intRr)
} else {
result += string(rr)
}
}
}
return result
}
func tomlValueStringRepresentation(v interface{}) (string, error) {
switch value := v.(type) {
case uint64:
return strconv.FormatUint(value, 10), nil
case int64:
return strconv.FormatInt(value, 10), nil
case float64:
return strconv.FormatFloat(value, 'f', -1, 32), nil
case string:
return "\"" + encodeTomlString(value) + "\"", nil
case bool:
if value {
return "true", nil
}
return "false", nil
case time.Time:
return value.Format(time.RFC3339), nil
case nil:
return "", nil
}
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Slice {
values := []string{}
for i := 0; i < rv.Len(); i++ {
item := rv.Index(i).Interface()
itemRepr, err := tomlValueStringRepresentation(item)
if err != nil {
return "", err
}
values = append(values, itemRepr)
}
return "[" + strings.Join(values, ",") + "]", nil
}
return "", fmt.Errorf("unsupported value type %T: %v", v, v)
}
func (t *TomlTree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) {
simpleValuesKeys := make([]string, 0)
complexValuesKeys := make([]string, 0)
for k := range t.values {
v := t.values[k]
switch v.(type) {
case *TomlTree, []*TomlTree:
complexValuesKeys = append(complexValuesKeys, k)
default:
simpleValuesKeys = append(simpleValuesKeys, k)
}
}
sort.Strings(simpleValuesKeys)
sort.Strings(complexValuesKeys)
for _, k := range simpleValuesKeys {
v, ok := t.values[k].(*tomlValue)
if !ok {
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
}
repr, err := tomlValueStringRepresentation(v.value)
if err != nil {
return bytesCount, err
}
kvRepr := fmt.Sprintf("%s%s = %s\n", indent, k, repr)
writtenBytesCount, err := w.Write([]byte(kvRepr))
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
}
}
for _, k := range complexValuesKeys {
v := t.values[k]
combinedKey := k
if keyspace != "" {
combinedKey = keyspace + "." + combinedKey
}
switch node := v.(type) {
// node has to be of those two types given how keys are sorted above
case *TomlTree:
tableName := fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
writtenBytesCount, err := w.Write([]byte(tableName))
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
}
bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount)
if err != nil {
return bytesCount, err
}
case []*TomlTree:
for _, subTree := range node {
if len(subTree.values) > 0 {
tableArrayName := fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey)
writtenBytesCount, err := w.Write([]byte(tableArrayName))
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
}
bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount)
if err != nil {
return bytesCount, err
}
}
}
}
}
return bytesCount, nil
}
// WriteTo encode the TomlTree as Toml and writes it to the writer w.
// Returns the number of bytes written in case of success, or an error if anything happened.
func (t *TomlTree) WriteTo(w io.Writer) (int64, error) {
return t.writeTo(w, "", "", 0)
}
// ToTomlString generates a human-readable representation of the current tree.
// Output spans multiple lines, and is suitable for ingest by a TOML parser.
// If the conversion cannot be performed, ToString returns a non-nil error.
func (t *TomlTree) ToTomlString() (string, error) {
var buf bytes.Buffer
_, err := t.WriteTo(&buf)
if err != nil {
return "", err
}
return buf.String(), nil
}
// String generates a human-readable representation of the current tree.
// Alias of ToString. Present to implement the fmt.Stringer interface.
func (t *TomlTree) String() string {
result, _ := t.ToTomlString()
return result
}
// ToMap recursively generates a representation of the tree using Go built-in structures.
// The following types are used:
// * uint64
// * int64
// * bool
// * string
// * time.Time
// * map[string]interface{} (where interface{} is any of this list)
// * []interface{} (where interface{} is any of this list)
func (t *TomlTree) ToMap() map[string]interface{} {
result := map[string]interface{}{}
for k, v := range t.values {
switch node := v.(type) {
case []*TomlTree:
var array []interface{}
for _, item := range node {
array = append(array, item.ToMap())
}
result[k] = array
case *TomlTree:
result[k] = node.ToMap()
case *tomlValue:
result[k] = node.value
}
}
return result
}

View File

@ -52,7 +52,7 @@ func validateBasePathName(name string) error {
// On Windows a common mistake would be to provide an absolute OS path
// We could strip out the base part, but that would not be very portable.
if filepath.IsAbs(name) {
return &os.PathError{"realPath", name, errors.New("got a real OS path instead of a virtual")}
return &os.PathError{Op: "realPath", Path: name, Err: errors.New("got a real OS path instead of a virtual")}
}
return nil
@ -60,14 +60,14 @@ func validateBasePathName(name string) error {
func (b *BasePathFs) Chtimes(name string, atime, mtime time.Time) (err error) {
if name, err = b.RealPath(name); err != nil {
return &os.PathError{"chtimes", name, err}
return &os.PathError{Op: "chtimes", Path: name, Err: err}
}
return b.source.Chtimes(name, atime, mtime)
}
func (b *BasePathFs) Chmod(name string, mode os.FileMode) (err error) {
if name, err = b.RealPath(name); err != nil {
return &os.PathError{"chmod", name, err}
return &os.PathError{Op: "chmod", Path: name, Err: err}
}
return b.source.Chmod(name, mode)
}
@ -78,66 +78,66 @@ func (b *BasePathFs) Name() string {
func (b *BasePathFs) Stat(name string) (fi os.FileInfo, err error) {
if name, err = b.RealPath(name); err != nil {
return nil, &os.PathError{"stat", name, err}
return nil, &os.PathError{Op: "stat", Path: name, Err: err}
}
return b.source.Stat(name)
}
func (b *BasePathFs) Rename(oldname, newname string) (err error) {
if oldname, err = b.RealPath(oldname); err != nil {
return &os.PathError{"rename", oldname, err}
return &os.PathError{Op: "rename", Path: oldname, Err: err}
}
if newname, err = b.RealPath(newname); err != nil {
return &os.PathError{"rename", newname, err}
return &os.PathError{Op: "rename", Path: newname, Err: err}
}
return b.source.Rename(oldname, newname)
}
func (b *BasePathFs) RemoveAll(name string) (err error) {
if name, err = b.RealPath(name); err != nil {
return &os.PathError{"remove_all", name, err}
return &os.PathError{Op: "remove_all", Path: name, Err: err}
}
return b.source.RemoveAll(name)
}
func (b *BasePathFs) Remove(name string) (err error) {
if name, err = b.RealPath(name); err != nil {
return &os.PathError{"remove", name, err}
return &os.PathError{Op: "remove", Path: name, Err: err}
}
return b.source.Remove(name)
}
func (b *BasePathFs) OpenFile(name string, flag int, mode os.FileMode) (f File, err error) {
if name, err = b.RealPath(name); err != nil {
return nil, &os.PathError{"openfile", name, err}
return nil, &os.PathError{Op: "openfile", Path: name, Err: err}
}
return b.source.OpenFile(name, flag, mode)
}
func (b *BasePathFs) Open(name string) (f File, err error) {
if name, err = b.RealPath(name); err != nil {
return nil, &os.PathError{"open", name, err}
return nil, &os.PathError{Op: "open", Path: name, Err: err}
}
return b.source.Open(name)
}
func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) {
if name, err = b.RealPath(name); err != nil {
return &os.PathError{"mkdir", name, err}
return &os.PathError{Op: "mkdir", Path: name, Err: err}
}
return b.source.Mkdir(name, mode)
}
func (b *BasePathFs) MkdirAll(name string, mode os.FileMode) (err error) {
if name, err = b.RealPath(name); err != nil {
return &os.PathError{"mkdir", name, err}
return &os.PathError{Op: "mkdir", Path: name, Err: err}
}
return b.source.MkdirAll(name, mode)
}
func (b *BasePathFs) Create(name string) (f File, err error) {
if name, err = b.RealPath(name); err != nil {
return nil, &os.PathError{"create", name, err}
return nil, &os.PathError{Op: "create", Path: name, Err: err}
}
return b.source.Create(name)
}

View File

@ -32,9 +32,8 @@ func NewCacheOnReadFs(base Fs, layer Fs, cacheTime time.Duration) Fs {
type cacheState int
const (
cacheUnknown cacheState = iota
// not present in the overlay, unknown if it exists in the base:
cacheMiss
cacheMiss cacheState = iota
// present in the overlay and in base, base file is newer:
cacheStale
// present in the overlay - with cache time == 0 it may exist in the base,

View File

@ -186,7 +186,7 @@ func (f *File) Truncate(size int64) error {
return ErrFileClosed
}
if f.readOnly {
return &os.PathError{"truncate", f.fileData.name, errors.New("file handle is read only")}
return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")}
}
if size < 0 {
return ErrOutOfRange
@ -218,7 +218,7 @@ func (f *File) Seek(offset int64, whence int) (int64, error) {
func (f *File) Write(b []byte) (n int, err error) {
if f.readOnly {
return 0, &os.PathError{"write", f.fileData.name, errors.New("file handle is read only")}
return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")}
}
n = len(b)
cur := atomic.LoadInt64(&f.at)

View File

@ -35,8 +35,6 @@ func NewMemMapFs() Fs {
return &MemMapFs{}
}
var memfsInit sync.Once
func (m *MemMapFs) getData() map[string]*mem.FileData {
m.init.Do(func() {
m.data = make(map[string]*mem.FileData)
@ -47,7 +45,7 @@ func (m *MemMapFs) getData() map[string]*mem.FileData {
return m.data
}
func (MemMapFs) Name() string { return "MemMapFS" }
func (*MemMapFs) Name() string { return "MemMapFS" }
func (m *MemMapFs) Create(name string) (File, error) {
name = normalizePath(name)
@ -110,7 +108,7 @@ func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {
x, ok := m.getData()[name]
if ok {
// Only return ErrFileExists if it's a file, not a directory.
i := mem.FileInfo{x}
i := mem.FileInfo{FileData: x}
if !i.IsDir() {
return ErrFileExists
}
@ -129,14 +127,17 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
_, ok := m.getData()[name]
m.mu.RUnlock()
if ok {
return &os.PathError{"mkdir", name, ErrFileExists}
} else {
return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
}
m.mu.Lock()
item := mem.CreateDir(name)
m.getData()[name] = item
m.registerWithParent(item)
m.mu.Unlock()
}
m.Chmod(name, perm)
return nil
}
@ -189,7 +190,7 @@ func (m *MemMapFs) open(name string) (*mem.FileData, error) {
f, ok := m.getData()[name]
m.mu.RUnlock()
if !ok {
return nil, &os.PathError{"open", name, ErrFileNotFound}
return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound}
}
return f, nil
}
@ -205,9 +206,11 @@ func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) {
}
func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
chmod := false
file, err := m.openWrite(name)
if os.IsNotExist(err) && (flag&os.O_CREATE > 0) {
file, err = m.Create(name)
chmod = true
}
if err != nil {
return nil, err
@ -229,6 +232,9 @@ func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, erro
return nil, err
}
}
if chmod {
m.Chmod(name, perm)
}
return file, nil
}
@ -241,11 +247,11 @@ func (m *MemMapFs) Remove(name string) error {
if _, ok := m.getData()[name]; ok {
err := m.unRegisterWithParent(name)
if err != nil {
return &os.PathError{"remove", name, err}
return &os.PathError{Op: "remove", Path: name, Err: err}
}
delete(m.getData(), name)
} else {
return &os.PathError{"remove", name, os.ErrNotExist}
return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist}
}
return nil
}
@ -293,7 +299,7 @@ func (m *MemMapFs) Rename(oldname, newname string) error {
m.mu.Unlock()
m.mu.RLock()
} else {
return &os.PathError{"rename", oldname, ErrFileNotFound}
return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound}
}
return nil
}
@ -309,9 +315,12 @@ func (m *MemMapFs) Stat(name string) (os.FileInfo, error) {
func (m *MemMapFs) Chmod(name string, mode os.FileMode) error {
name = normalizePath(name)
m.mu.RLock()
f, ok := m.getData()[name]
m.mu.RUnlock()
if !ok {
return &os.PathError{"chmod", name, ErrFileNotFound}
return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
}
m.mu.Lock()
@ -323,9 +332,12 @@ func (m *MemMapFs) Chmod(name string, mode os.FileMode) error {
func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
name = normalizePath(name)
m.mu.RLock()
f, ok := m.getData()[name]
m.mu.RUnlock()
if !ok {
return &os.PathError{"chtimes", name, ErrFileNotFound}
return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound}
}
m.mu.Lock()
@ -337,13 +349,13 @@ func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error
func (m *MemMapFs) List() {
for _, x := range m.data {
y := mem.FileInfo{x}
y := mem.FileInfo{FileData: x}
fmt.Println(x.Name(), y.Size())
}
}
func debugMemMapList(fs Fs) {
if x, ok := fs.(*MemMapFs); ok {
x.List()
}
}
// func debugMemMapList(fs Fs) {
// if x, ok := fs.(*MemMapFs); ok {
// x.List()
// }
// }

70
vendor/github.com/spf13/cast/cast.go generated vendored
View File

@ -3,80 +3,150 @@
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// Package cast provides easy and safe casting in Go.
package cast
import "time"
// ToBool casts an interface to a bool type.
func ToBool(i interface{}) bool {
v, _ := ToBoolE(i)
return v
}
// ToTime casts an interface to a time.Time type.
func ToTime(i interface{}) time.Time {
v, _ := ToTimeE(i)
return v
}
// ToDuration casts an interface to a time.Duration type.
func ToDuration(i interface{}) time.Duration {
v, _ := ToDurationE(i)
return v
}
// ToFloat64 casts an interface to a float64 type.
func ToFloat64(i interface{}) float64 {
v, _ := ToFloat64E(i)
return v
}
// ToFloat32 casts an interface to a float32 type.
func ToFloat32(i interface{}) float32 {
v, _ := ToFloat32E(i)
return v
}
// ToInt64 casts an interface to an int64 type.
func ToInt64(i interface{}) int64 {
v, _ := ToInt64E(i)
return v
}
// ToInt32 casts an interface to an int32 type.
func ToInt32(i interface{}) int32 {
v, _ := ToInt32E(i)
return v
}
// ToInt16 casts an interface to an int16 type.
func ToInt16(i interface{}) int16 {
v, _ := ToInt16E(i)
return v
}
// ToInt8 casts an interface to an int8 type.
func ToInt8(i interface{}) int8 {
v, _ := ToInt8E(i)
return v
}
// ToInt casts an interface to an int type.
func ToInt(i interface{}) int {
v, _ := ToIntE(i)
return v
}
// ToUint casts an interface to a uint type.
func ToUint(i interface{}) uint {
v, _ := ToUintE(i)
return v
}
// ToUint64 casts an interface to a uint64 type.
func ToUint64(i interface{}) uint64 {
v, _ := ToUint64E(i)
return v
}
// ToUint32 casts an interface to a uint32 type.
func ToUint32(i interface{}) uint32 {
v, _ := ToUint32E(i)
return v
}
// ToUint16 casts an interface to a uint16 type.
func ToUint16(i interface{}) uint16 {
v, _ := ToUint16E(i)
return v
}
// ToUint8 casts an interface to a uint8 type.
func ToUint8(i interface{}) uint8 {
v, _ := ToUint8E(i)
return v
}
// ToString casts an interface to a string type.
func ToString(i interface{}) string {
v, _ := ToStringE(i)
return v
}
// ToStringMapString casts an interface to a map[string]string type.
func ToStringMapString(i interface{}) map[string]string {
v, _ := ToStringMapStringE(i)
return v
}
// ToStringMapStringSlice casts an interface to a map[string][]string type.
func ToStringMapStringSlice(i interface{}) map[string][]string {
v, _ := ToStringMapStringSliceE(i)
return v
}
// ToStringMapBool casts an interface to a map[string]bool type.
func ToStringMapBool(i interface{}) map[string]bool {
v, _ := ToStringMapBoolE(i)
return v
}
// ToStringMap casts an interface to a map[string]interface{} type.
func ToStringMap(i interface{}) map[string]interface{} {
v, _ := ToStringMapE(i)
return v
}
// ToSlice casts an interface to a []interface{} type.
func ToSlice(i interface{}) []interface{} {
v, _ := ToSliceE(i)
return v
}
// ToBoolSlice casts an interface to a []bool type.
func ToBoolSlice(i interface{}) []bool {
v, _ := ToBoolSliceE(i)
return v
}
// ToStringSlice casts an interface to a []string type.
func ToStringSlice(i interface{}) []string {
v, _ := ToStringSliceE(i)
return v
}
// ToIntSlice casts an interface to a []int type.
func ToIntSlice(i interface{}) []int {
v, _ := ToIntSliceE(i)
return v

754
vendor/github.com/spf13/cast/caste.go generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,9 @@ import (
"github.com/spf13/pflag"
)
// Annotations for Bash completion.
const (
BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extentions"
BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions"
BashCompCustom = "cobra_annotation_bash_completion_custom"
BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag"
BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir"
@ -22,7 +23,7 @@ func preamble(out io.Writer, name string) error {
if err != nil {
return err
}
_, err = fmt.Fprint(out, `
preamStr := `
__debug()
{
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
@ -246,7 +247,8 @@ __handle_word()
__handle_word
}
`)
`
_, err = fmt.Fprint(out, preamStr)
return err
}
@ -401,10 +403,8 @@ func writeLocalNonPersistentFlag(flag *pflag.Flag, w io.Writer) error {
format += "="
}
format += "\")\n"
if _, err := fmt.Fprintf(w, format, name); err != nil {
_, err := fmt.Fprintf(w, format, name)
return err
}
return nil
}
func writeFlags(cmd *Command, w io.Writer) error {
@ -568,6 +568,7 @@ func gen(cmd *Command, w io.Writer) error {
return nil
}
// GenBashCompletion generates bash completion file and writes to the passed writer.
func (cmd *Command) GenBashCompletion(w io.Writer) error {
if err := preamble(w, cmd.Name()); err != nil {
return err
@ -587,6 +588,7 @@ func nonCompletableFlag(flag *pflag.Flag) bool {
return flag.Hidden || len(flag.Deprecated) > 0
}
// GenBashCompletionFile generates bash completion file.
func (cmd *Command) GenBashCompletionFile(filename string) error {
outFile, err := os.Create(filename)
if err != nil {

View File

@ -37,38 +37,37 @@ var templateFuncs = template.FuncMap{
var initializers []func()
// automatic prefix matching can be a dangerous thing to automatically enable in CLI tools.
// Set this to true to enable it
// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing
// to automatically enable in CLI tools.
// Set this to true to enable it.
var EnablePrefixMatching = false
//EnableCommandSorting controls sorting of the slice of commands, which is turned on by default.
//To disable sorting, set it to false.
// EnableCommandSorting controls sorting of the slice of commands, which is turned on by default.
// To disable sorting, set it to false.
var EnableCommandSorting = true
//AddTemplateFunc adds a template function that's available to Usage and Help
//template generation.
// AddTemplateFunc adds a template function that's available to Usage and Help
// template generation.
func AddTemplateFunc(name string, tmplFunc interface{}) {
templateFuncs[name] = tmplFunc
}
//AddTemplateFuncs adds multiple template functions availalble to Usage and
//Help template generation.
// AddTemplateFuncs adds multiple template functions availalble to Usage and
// Help template generation.
func AddTemplateFuncs(tmplFuncs template.FuncMap) {
for k, v := range tmplFuncs {
templateFuncs[k] = v
}
}
//OnInitialize takes a series of func() arguments and appends them to a slice of func().
// OnInitialize takes a series of func() arguments and appends them to a slice of func().
func OnInitialize(y ...func()) {
for _, x := range y {
initializers = append(initializers, x)
}
initializers = append(initializers, y...)
}
//Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans,
//Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
//ints and then compared.
// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans,
// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
// ints and then compared.
func Gt(a interface{}, b interface{}) bool {
var left, right int64
av := reflect.ValueOf(a)
@ -96,7 +95,7 @@ func Gt(a interface{}, b interface{}) bool {
return left > right
}
//Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic.
// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic.
func Eq(a interface{}, b interface{}) bool {
av := reflect.ValueOf(a)
bv := reflect.ValueOf(b)
@ -116,7 +115,7 @@ func trimRightSpace(s string) string {
return strings.TrimRightFunc(s, unicode.IsSpace)
}
// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s
// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s.
func appendIfNotPresent(s, stringToAppend string) string {
if strings.Contains(s, stringToAppend) {
return s
@ -124,7 +123,7 @@ func appendIfNotPresent(s, stringToAppend string) string {
return s + " " + stringToAppend
}
//rpad adds padding to the right of a string
// rpad adds padding to the right of a string.
func rpad(s string, padding int) string {
template := fmt.Sprintf("%%-%ds", padding)
return fmt.Sprintf(template, s)
@ -138,7 +137,7 @@ func tmpl(w io.Writer, text string, data interface{}) error {
return t.Execute(w, data)
}
// ld compares two strings and returns the levenshtein distance between them
// ld compares two strings and returns the levenshtein distance between them.
func ld(s, t string, ignoreCase bool) int {
if ignoreCase {
s = strings.ToLower(s)

View File

@ -57,6 +57,9 @@ type Command struct {
Deprecated string
// Is this command hidden and should NOT show up in the list of available commands?
Hidden bool
// Annotations are key/value pairs that can be used by applications to identify or
// group commands
Annotations map[string]string
// Full set of flags
flags *flag.FlagSet
// Set of flags childrens of this command will inherit
@ -113,6 +116,7 @@ type Command struct {
output *io.Writer // out writer if set in SetOutput(w)
usageFunc func(*Command) error // Usage can be defined by application
usageTemplate string // Can be defined by Application
flagErrorFunc func(*Command, error) error
helpTemplate string // Can be defined by Application
helpFunc func(*Command, []string) // Help can be defined by application
helpCommand *Command // The help command
@ -128,7 +132,7 @@ type Command struct {
DisableFlagParsing bool
}
// os.Args[1:] by default, if desired, can be overridden
// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
// particularly useful when testing.
func (c *Command) SetArgs(a []string) {
c.args = a
@ -140,26 +144,33 @@ func (c *Command) SetOutput(output io.Writer) {
c.output = &output
}
// Usage can be defined by application
// SetUsageFunc sets usage function. Usage can be defined by application.
func (c *Command) SetUsageFunc(f func(*Command) error) {
c.usageFunc = f
}
// Can be defined by Application
// SetUsageTemplate sets usage template. Can be defined by Application.
func (c *Command) SetUsageTemplate(s string) {
c.usageTemplate = s
}
// Can be defined by Application
// SetFlagErrorFunc sets a function to generate an error when flag parsing
// fails.
func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) {
c.flagErrorFunc = f
}
// SetHelpFunc sets help function. Can be defined by Application.
func (c *Command) SetHelpFunc(f func(*Command, []string)) {
c.helpFunc = f
}
// SetHelpCommand sets help command.
func (c *Command) SetHelpCommand(cmd *Command) {
c.helpCommand = cmd
}
// Can be defined by Application
// SetHelpTemplate sets help template to be used. Application can use it to set custom template.
func (c *Command) SetHelpTemplate(s string) {
c.helpTemplate = s
}
@ -176,10 +187,12 @@ func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string
}
}
// OutOrStdout returns output to stdout.
func (c *Command) OutOrStdout() io.Writer {
return c.getOut(os.Stdout)
}
// OutOrStderr returns output to stderr
func (c *Command) OutOrStderr() io.Writer {
return c.getOut(os.Stderr)
}
@ -195,7 +208,7 @@ func (c *Command) getOut(def io.Writer) io.Writer {
}
// UsageFunc returns either the function set by SetUsageFunc for this command
// or a parent, or it returns a default usage function
// or a parent, or it returns a default usage function.
func (c *Command) UsageFunc() (f func(*Command) error) {
if c.usageFunc != nil {
return c.usageFunc
@ -214,22 +227,18 @@ func (c *Command) UsageFunc() (f func(*Command) error) {
}
}
// Output the usage for the command
// Used when a user provides invalid input
// Can be defined by user by overriding UsageFunc
// Usage puts out the usage for the command.
// Used when a user provides invalid input.
// Can be defined by user by overriding UsageFunc.
func (c *Command) Usage() error {
return c.UsageFunc()(c)
}
// HelpFunc returns either the function set by SetHelpFunc for this command
// or a parent, or it returns a function with default help behavior
// or a parent, or it returns a function with default help behavior.
func (c *Command) HelpFunc() func(*Command, []string) {
cmd := c
for cmd != nil {
if cmd.helpFunc != nil {
return cmd.helpFunc
}
cmd = cmd.parent
if helpFunc := c.checkHelpFunc(); helpFunc != nil {
return helpFunc
}
return func(*Command, []string) {
c.mergePersistentFlags()
@ -240,14 +249,29 @@ func (c *Command) HelpFunc() func(*Command, []string) {
}
}
// Output the help for the command
// Used when a user calls help [command]
// Can be defined by user by overriding HelpFunc
// checkHelpFunc checks if there is helpFunc in ancestors of c.
func (c *Command) checkHelpFunc() func(*Command, []string) {
if c == nil {
return nil
}
if c.helpFunc != nil {
return c.helpFunc
}
if c.HasParent() {
return c.parent.checkHelpFunc()
}
return nil
}
// Help puts out the help for the command.
// Used when a user calls help [command].
// Can be defined by user by overriding HelpFunc.
func (c *Command) Help() error {
c.HelpFunc()(c, []string{})
return nil
}
// UsageString return usage string.
func (c *Command) UsageString() string {
tmpOutput := c.output
bb := new(bytes.Buffer)
@ -257,8 +281,25 @@ func (c *Command) UsageString() string {
return bb.String()
}
// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this
// command or a parent, or it returns a function which returns the original
// error.
func (c *Command) FlagErrorFunc() (f func(*Command, error) error) {
if c.flagErrorFunc != nil {
return c.flagErrorFunc
}
if c.HasParent() {
return c.parent.FlagErrorFunc()
}
return func(c *Command, err error) error {
return err
}
}
var minUsagePadding = 25
// UsagePadding return padding for the usage.
func (c *Command) UsagePadding() int {
if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen {
return minUsagePadding
@ -268,7 +309,7 @@ func (c *Command) UsagePadding() int {
var minCommandPathPadding = 11
//
// CommandPathPadding return padding for the command path.
func (c *Command) CommandPathPadding() int {
if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen {
return minCommandPathPadding
@ -278,6 +319,7 @@ func (c *Command) CommandPathPadding() int {
var minNamePadding = 11
// NamePadding returns padding for the name.
func (c *Command) NamePadding() int {
if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen {
return minNamePadding
@ -285,6 +327,7 @@ func (c *Command) NamePadding() int {
return c.parent.commandsMaxNameLen
}
// UsageTemplate returns usage template for the command.
func (c *Command) UsageTemplate() string {
if c.usageTemplate != "" {
return c.usageTemplate
@ -302,24 +345,25 @@ Aliases:
{{end}}{{if .HasExample}}
Examples:
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
{{ .Example }}{{end}}{{if .HasAvailableSubCommands}}
Available Commands:{{range .Commands}}{{if .IsAvailableCommand}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}}
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasAvailableInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }}
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`
}
// HelpTemplate return help template for the command.
func (c *Command) HelpTemplate() string {
if c.helpTemplate != "" {
return c.helpTemplate
@ -333,27 +377,25 @@ func (c *Command) HelpTemplate() string {
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
}
// Really only used when casting a command to a commander
// Really only used when casting a command to a commander.
func (c *Command) resetChildrensParents() {
for _, x := range c.commands {
x.parent = c
}
}
// Test if the named flag is a boolean flag.
func isBooleanFlag(name string, f *flag.FlagSet) bool {
func hasNoOptDefVal(name string, f *flag.FlagSet) bool {
flag := f.Lookup(name)
if flag == nil {
return false
}
return flag.Value.Type() == "bool"
return len(flag.NoOptDefVal) > 0
}
// Test if the named flag is a boolean flag.
func isBooleanShortFlag(name string, f *flag.FlagSet) bool {
func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool {
result := false
f.VisitAll(func(f *flag.Flag) {
if f.Shorthand == name && f.Value.Type() == "bool" {
fs.VisitAll(func(flag *flag.Flag) {
if flag.Shorthand == name && len(flag.NoOptDefVal) > 0 {
result = true
}
})
@ -379,8 +421,8 @@ func stripFlags(args []string, c *Command) []string {
inQuote = true
case strings.HasPrefix(y, "--") && !strings.Contains(y, "="):
// TODO: this isn't quite right, we should really check ahead for 'true' or 'false'
inFlag = !isBooleanFlag(y[2:], c.Flags())
case strings.HasPrefix(y, "-") && !strings.Contains(y, "=") && len(y) == 2 && !isBooleanShortFlag(y[1:], c.Flags()):
inFlag = !hasNoOptDefVal(y[2:], c.Flags())
case strings.HasPrefix(y, "-") && !strings.Contains(y, "=") && len(y) == 2 && !shortHasNoOptDefVal(y[1:], c.Flags()):
inFlag = true
case inFlag:
inFlag = false
@ -414,7 +456,7 @@ func argsMinusFirstX(args []string, x string) []string {
return args
}
// find the target command given the args and command tree
// Find the target command given the args and command tree
// Meant to be run on the highest node. Only searches down.
func (c *Command) Find(args []string) (*Command, []string, error) {
if c == nil {
@ -482,6 +524,7 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
return commandFound, a, nil
}
// SuggestionsFor provides suggestions for the typedName.
func (c *Command) SuggestionsFor(typedName string) []string {
suggestions := []string{}
for _, cmd := range c.commands {
@ -502,6 +545,7 @@ func (c *Command) SuggestionsFor(typedName string) []string {
return suggestions
}
// VisitParents visits all parents of the command and invokes fn on each parent.
func (c *Command) VisitParents(fn func(*Command)) {
var traverse func(*Command) *Command
@ -517,6 +561,7 @@ func (c *Command) VisitParents(fn func(*Command)) {
traverse(c)
}
// Root finds root command.
func (c *Command) Root() *Command {
var findRoot func(*Command) *Command
@ -553,7 +598,7 @@ func (c *Command) execute(a []string) (err error) {
err = c.ParseFlags(a)
if err != nil {
return err
return c.FlagErrorFunc()(c, err)
}
// If help is called, regardless of other flags, return we want help
// Also say we need help if the command isn't runnable.
@ -641,7 +686,7 @@ func (c *Command) errorMsgFromParse() string {
return ""
}
// Call execute to use the args (os.Args[1:] by default)
// Execute Call execute to use the args (os.Args[1:] by default)
// and run through the command tree finding appropriate matches
// for commands and then corresponding flags.
func (c *Command) Execute() error {
@ -649,8 +694,8 @@ func (c *Command) Execute() error {
return err
}
// ExecuteC executes the command.
func (c *Command) ExecuteC() (cmd *Command, err error) {
// Regardless of what command execute is called on, run on Root only
if c.HasParent() {
return c.Root().ExecuteC()
@ -712,6 +757,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
}
func (c *Command) initHelpFlag() {
c.mergePersistentFlags()
if c.Flags().Lookup("help") == nil {
c.Flags().BoolP("help", "h", false, "help for "+c.Name())
}
@ -734,7 +780,7 @@ func (c *Command) initHelpCmd() {
Run: func(c *Command, args []string) {
cmd, _, e := c.Root().Find(args)
if cmd == nil || e != nil {
c.Printf("Unknown help topic %#q.", args)
c.Printf("Unknown help topic %#q\n", args)
c.Root().Usage()
} else {
cmd.Help()
@ -742,16 +788,17 @@ func (c *Command) initHelpCmd() {
},
}
}
c.RemoveCommand(c.helpCommand)
c.AddCommand(c.helpCommand)
}
// Used for testing
// ResetCommands used for testing.
func (c *Command) ResetCommands() {
c.commands = nil
c.helpCommand = nil
}
// Sorts commands by their names
// Sorts commands by their names.
type commandSorterByName []*Command
func (c commandSorterByName) Len() int { return len(c) }
@ -831,18 +878,18 @@ main:
}
}
// Print is a convenience method to Print to the defined output, fallback to Stderr if not set
// Print is a convenience method to Print to the defined output, fallback to Stderr if not set.
func (c *Command) Print(i ...interface{}) {
fmt.Fprint(c.OutOrStderr(), i...)
}
// Println is a convenience method to Println to the defined output, fallback to Stderr if not set
// Println is a convenience method to Println to the defined output, fallback to Stderr if not set.
func (c *Command) Println(i ...interface{}) {
str := fmt.Sprintln(i...)
c.Print(str)
}
// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set
// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set.
func (c *Command) Printf(format string, i ...interface{}) {
str := fmt.Sprintf(format, i...)
c.Print(str)
@ -859,7 +906,7 @@ func (c *Command) CommandPath() string {
return str
}
//The full usage for a given command (including parents)
// UseLine puts out the full usage for a given command (including parents).
func (c *Command) UseLine() string {
str := ""
if c.HasParent() {
@ -868,8 +915,8 @@ func (c *Command) UseLine() string {
return str + c.Use
}
// For use in determining which flags have been assigned to which commands
// and which persist
// DebugFlags used to determine which flags have been assigned to which commands
// and which persist.
func (c *Command) DebugFlags() {
c.Println("DebugFlags called on", c.Name())
var debugflags func(*Command)
@ -923,7 +970,8 @@ func (c *Command) Name() string {
if i >= 0 {
name = name[:i]
}
return name
c.name = name
return c.name
}
// HasAlias determines if a given string is an alias of the command.
@ -936,26 +984,28 @@ func (c *Command) HasAlias(s string) bool {
return false
}
// NameAndAliases returns string containing name and all aliases
func (c *Command) NameAndAliases() string {
return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ")
}
// HasExample determines if the command has example.
func (c *Command) HasExample() bool {
return len(c.Example) > 0
}
// Runnable determines if the command is itself runnable
// Runnable determines if the command is itself runnable.
func (c *Command) Runnable() bool {
return c.Run != nil || c.RunE != nil
}
// HasSubCommands determines if the command has children commands
// HasSubCommands determines if the command has children commands.
func (c *Command) HasSubCommands() bool {
return len(c.commands) > 0
}
// IsAvailableCommand determines if a command is available as a non-help command
// (this includes all non deprecated/hidden commands)
// (this includes all non deprecated/hidden commands).
func (c *Command) IsAvailableCommand() bool {
if len(c.Deprecated) != 0 || c.Hidden {
return false
@ -972,11 +1022,12 @@ func (c *Command) IsAvailableCommand() bool {
return false
}
// IsHelpCommand determines if a command is a 'help' command; a help command is
// determined by the fact that it is NOT runnable/hidden/deprecated, and has no
// sub commands that are runnable/hidden/deprecated
func (c *Command) IsHelpCommand() bool {
// IsAdditionalHelpTopicCommand determines if a command is an additional
// help topic command; additional help topic command is determined by the
// fact that it is NOT runnable/hidden/deprecated, and has no sub commands that
// are runnable/hidden/deprecated.
// Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924.
func (c *Command) IsAdditionalHelpTopicCommand() bool {
// if a command is runnable, deprecated, or hidden it is not a 'help' command
if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden {
return false
@ -984,7 +1035,7 @@ func (c *Command) IsHelpCommand() bool {
// if any non-help sub commands are found, the command is not a 'help' command
for _, sub := range c.commands {
if !sub.IsHelpCommand() {
if !sub.IsAdditionalHelpTopicCommand() {
return false
}
}
@ -993,14 +1044,13 @@ func (c *Command) IsHelpCommand() bool {
return true
}
// HasHelpSubCommands determines if a command has any avilable 'help' sub commands
// HasHelpSubCommands determines if a command has any available 'help' sub commands
// that need to be shown in the usage/help default template under 'additional help
// topics'
// topics'.
func (c *Command) HasHelpSubCommands() bool {
// return true on the first found available 'help' sub command
for _, sub := range c.commands {
if sub.IsHelpCommand() {
if sub.IsAdditionalHelpTopicCommand() {
return true
}
}
@ -1010,9 +1060,8 @@ func (c *Command) HasHelpSubCommands() bool {
}
// HasAvailableSubCommands determines if a command has available sub commands that
// need to be shown in the usage/help default template under 'available commands'
// need to be shown in the usage/help default template under 'available commands'.
func (c *Command) HasAvailableSubCommands() bool {
// return true on the first found available (non deprecated/help/hidden)
// sub command
for _, sub := range c.commands {
@ -1026,17 +1075,18 @@ func (c *Command) HasAvailableSubCommands() bool {
return false
}
// Determine if the command is a child command
// HasParent determines if the command is a child command.
func (c *Command) HasParent() bool {
return c.parent != nil
}
// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists
// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists.
func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName {
return c.globNormFunc
}
// Get the complete FlagSet that applies to this command (local and persistent declared here and by all parents)
// Flags returns the complete FlagSet that applies
// to this command (local and persistent declared here and by all parents).
func (c *Command) Flags() *flag.FlagSet {
if c.flags == nil {
c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
@ -1048,7 +1098,7 @@ func (c *Command) Flags() *flag.FlagSet {
return c.flags
}
// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands
// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands.
func (c *Command) LocalNonPersistentFlags() *flag.FlagSet {
persistentFlags := c.PersistentFlags()
@ -1061,7 +1111,7 @@ func (c *Command) LocalNonPersistentFlags() *flag.FlagSet {
return out
}
// Get the local FlagSet specifically set in the current command
// LocalFlags returns the local FlagSet specifically set in the current command.
func (c *Command) LocalFlags() *flag.FlagSet {
c.mergePersistentFlags()
@ -1079,7 +1129,7 @@ func (c *Command) LocalFlags() *flag.FlagSet {
return local
}
// All Flags which were inherited from parents commands
// InheritedFlags returns all flags which were inherited from parents commands.
func (c *Command) InheritedFlags() *flag.FlagSet {
c.mergePersistentFlags()
@ -1108,12 +1158,12 @@ func (c *Command) InheritedFlags() *flag.FlagSet {
return inherited
}
// All Flags which were not inherited from parent commands
// NonInheritedFlags returns all flags which were not inherited from parent commands.
func (c *Command) NonInheritedFlags() *flag.FlagSet {
return c.LocalFlags()
}
// Get the Persistent FlagSet specifically set in the current command
// PersistentFlags returns the persistent FlagSet specifically set in the current command.
func (c *Command) PersistentFlags() *flag.FlagSet {
if c.pflags == nil {
c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
@ -1125,7 +1175,7 @@ func (c *Command) PersistentFlags() *flag.FlagSet {
return c.pflags
}
// For use in testing
// ResetFlags is used in testing.
func (c *Command) ResetFlags() {
c.flagErrorBuf = new(bytes.Buffer)
c.flagErrorBuf.Reset()
@ -1135,50 +1185,50 @@ func (c *Command) ResetFlags() {
c.pflags.SetOutput(c.flagErrorBuf)
}
// Does the command contain any flags (local plus persistent from the entire structure)
// HasFlags checks if the command contains any flags (local plus persistent from the entire structure).
func (c *Command) HasFlags() bool {
return c.Flags().HasFlags()
}
// Does the command contain persistent flags
// HasPersistentFlags checks if the command contains persistent flags.
func (c *Command) HasPersistentFlags() bool {
return c.PersistentFlags().HasFlags()
}
// Does the command has flags specifically declared locally
// HasLocalFlags checks if the command has flags specifically declared locally.
func (c *Command) HasLocalFlags() bool {
return c.LocalFlags().HasFlags()
}
// Does the command have flags inherited from its parent command
// HasInheritedFlags checks if the command has flags inherited from its parent command.
func (c *Command) HasInheritedFlags() bool {
return c.InheritedFlags().HasFlags()
}
// Does the command contain any flags (local plus persistent from the entire
// structure) which are not hidden or deprecated
// HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire
// structure) which are not hidden or deprecated.
func (c *Command) HasAvailableFlags() bool {
return c.Flags().HasAvailableFlags()
}
// Does the command contain persistent flags which are not hidden or deprecated
// HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated.
func (c *Command) HasAvailablePersistentFlags() bool {
return c.PersistentFlags().HasAvailableFlags()
}
// Does the command has flags specifically declared locally which are not hidden
// or deprecated
// HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden
// or deprecated.
func (c *Command) HasAvailableLocalFlags() bool {
return c.LocalFlags().HasAvailableFlags()
}
// Does the command have flags inherited from its parent command which are
// not hidden or deprecated
// HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are
// not hidden or deprecated.
func (c *Command) HasAvailableInheritedFlags() bool {
return c.InheritedFlags().HasAvailableFlags()
}
// Flag climbs up the command tree looking for matching flag
// Flag climbs up the command tree looking for matching flag.
func (c *Command) Flag(name string) (flag *flag.Flag) {
flag = c.Flags().Lookup(name)
@ -1189,7 +1239,7 @@ func (c *Command) Flag(name string) (flag *flag.Flag) {
return
}
// recursively find matching persistent flag
// Recursively find matching persistent flag.
func (c *Command) persistentFlag(name string) (flag *flag.Flag) {
if c.HasPersistentFlags() {
flag = c.PersistentFlags().Lookup(name)
@ -1201,7 +1251,7 @@ func (c *Command) persistentFlag(name string) (flag *flag.Flag) {
return
}
// ParseFlags parses persistent flag tree & local flags
// ParseFlags parses persistent flag tree and local flags.
func (c *Command) ParseFlags(args []string) (err error) {
if c.DisableFlagParsing {
return nil
@ -1211,7 +1261,7 @@ func (c *Command) ParseFlags(args []string) (err error) {
return
}
// Parent returns a commands parent command
// Parent returns a commands parent command.
func (c *Command) Parent() *Command {
return c.parent
}

View File

@ -0,0 +1,113 @@
// Copyright © 2016 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package jwalterweatherman
import (
"io"
"io/ioutil"
"log"
"os"
)
var (
TRACE *log.Logger
DEBUG *log.Logger
INFO *log.Logger
WARN *log.Logger
ERROR *log.Logger
CRITICAL *log.Logger
FATAL *log.Logger
LOG *log.Logger
FEEDBACK *Feedback
defaultNotepad *Notepad
)
func reloadDefaultNotepad() {
TRACE = defaultNotepad.TRACE
DEBUG = defaultNotepad.DEBUG
INFO = defaultNotepad.INFO
WARN = defaultNotepad.WARN
ERROR = defaultNotepad.ERROR
CRITICAL = defaultNotepad.CRITICAL
FATAL = defaultNotepad.FATAL
LOG = defaultNotepad.LOG
FEEDBACK = defaultNotepad.FEEDBACK
}
func init() {
defaultNotepad = NewNotepad(LevelError, LevelWarn, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
reloadDefaultNotepad()
}
// SetLogThreshold set the log threshold for the default notepad. Trace by default.
func SetLogThreshold(threshold Threshold) {
defaultNotepad.SetLogThreshold(threshold)
reloadDefaultNotepad()
}
// SetLogOutput set the log output for the default notepad. Discarded by default.
func SetLogOutput(handle io.Writer) {
defaultNotepad.SetLogOutput(handle)
reloadDefaultNotepad()
}
// SetStdoutThreshold set the standard output threshold for the default notepad.
// Info by default.
func SetStdoutThreshold(threshold Threshold) {
defaultNotepad.SetStdoutThreshold(threshold)
reloadDefaultNotepad()
}
// SetPrefix set the prefix for the default logger. Empty by default.
func SetPrefix(prefix string) {
defaultNotepad.SetPrefix(prefix)
reloadDefaultNotepad()
}
// SetFlags set the flags for the default logger. "log.Ldate | log.Ltime" by default.
func SetFlags(flags int) {
defaultNotepad.SetFlags(flags)
reloadDefaultNotepad()
}
// Level returns the current global log threshold.
func LogThreshold() Threshold {
return defaultNotepad.logThreshold
}
// Level returns the current global output threshold.
func StdoutThreshold() Threshold {
return defaultNotepad.stdoutThreshold
}
// GetStdoutThreshold returns the defined Treshold for the log logger.
func GetLogThreshold() Threshold {
return defaultNotepad.GetLogThreshold()
}
// GetStdoutThreshold returns the Treshold for the stdout logger.
func GetStdoutThreshold() Threshold {
return defaultNotepad.GetStdoutThreshold()
}
// LogCountForLevel returns the number of log invocations for a given threshold.
func LogCountForLevel(l Threshold) uint64 {
return defaultNotepad.LogCountForLevel(l)
}
// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations
// greater than or equal to a given threshold.
func LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 {
return defaultNotepad.LogCountForLevelsGreaterThanorEqualTo(threshold)
}
// ResetLogCounters resets the invocation counters for all levels.
func ResetLogCounters() {
defaultNotepad.ResetLogCounters()
}

View File

@ -0,0 +1,56 @@
// Copyright © 2016 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package jwalterweatherman
import (
"sync/atomic"
)
type logCounter struct {
counter uint64
}
func (c *logCounter) incr() {
atomic.AddUint64(&c.counter, 1)
}
func (c *logCounter) resetCounter() {
atomic.StoreUint64(&c.counter, 0)
}
func (c *logCounter) getCount() uint64 {
return atomic.LoadUint64(&c.counter)
}
func (c *logCounter) Write(p []byte) (n int, err error) {
c.incr()
return len(p), nil
}
// LogCountForLevel returns the number of log invocations for a given threshold.
func (n *Notepad) LogCountForLevel(l Threshold) uint64 {
return n.logCounters[l].getCount()
}
// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations
// greater than or equal to a given threshold.
func (n *Notepad) LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 {
var cnt uint64
for i := int(threshold); i < len(n.logCounters); i++ {
cnt += n.LogCountForLevel(Threshold(i))
}
return cnt
}
// ResetLogCounters resets the invocation counters for all levels.
func (n *Notepad) ResetLogCounters() {
for _, np := range n.logCounters {
np.resetCounter()
}
}

195
vendor/github.com/spf13/jwalterweatherman/notepad.go generated vendored Normal file
View File

@ -0,0 +1,195 @@
// Copyright © 2016 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package jwalterweatherman
import (
"fmt"
"io"
"log"
"os"
)
type Threshold int
func (t Threshold) String() string {
return prefixes[t]
}
const (
LevelTrace Threshold = iota
LevelDebug
LevelInfo
LevelWarn
LevelError
LevelCritical
LevelFatal
)
var prefixes map[Threshold]string = map[Threshold]string{
LevelTrace: "TRACE",
LevelDebug: "DEBUG",
LevelInfo: "INFO",
LevelWarn: "WARN",
LevelError: "ERROR",
LevelCritical: "CRITICAL",
LevelFatal: "FATAL",
}
func prefix(t Threshold) string {
return t.String() + " "
}
// Notepad is where you leave a note !
type Notepad struct {
TRACE *log.Logger
DEBUG *log.Logger
INFO *log.Logger
WARN *log.Logger
ERROR *log.Logger
CRITICAL *log.Logger
FATAL *log.Logger
LOG *log.Logger
FEEDBACK *Feedback
loggers []**log.Logger
logHandle io.Writer
outHandle io.Writer
logThreshold Threshold
stdoutThreshold Threshold
prefix string
flags int
// One per Threshold
logCounters [7]*logCounter
}
// NewNotepad create a new notepad.
func NewNotepad(outThreshold Threshold, logThreshold Threshold, outHandle, logHandle io.Writer, prefix string, flags int) *Notepad {
n := &Notepad{}
n.loggers = append(n.loggers, &n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL)
n.logHandle = logHandle
n.outHandle = outHandle
n.logThreshold = logThreshold
n.stdoutThreshold = outThreshold
if len(prefix) != 0 {
n.prefix = "[" + prefix + "] "
} else {
n.prefix = ""
}
n.flags = flags
n.LOG = log.New(n.logHandle,
"LOG: ",
n.flags)
n.FEEDBACK = &Feedback{n}
n.init()
return n
}
// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
type Feedback struct {
*Notepad
}
// init create the loggers for each level depending on the notepad thresholds
func (n *Notepad) init() {
bothHandle := io.MultiWriter(n.outHandle, n.logHandle)
for t, logger := range n.loggers {
threshold := Threshold(t)
counter := &logCounter{}
n.logCounters[t] = counter
switch {
case threshold >= n.logThreshold && threshold >= n.stdoutThreshold:
*logger = log.New(io.MultiWriter(counter, bothHandle), n.prefix+prefix(threshold), n.flags)
case threshold >= n.logThreshold:
*logger = log.New(io.MultiWriter(counter, n.logHandle), n.prefix+prefix(threshold), n.flags)
case threshold >= n.stdoutThreshold:
*logger = log.New(io.MultiWriter(counter, os.Stdout), n.prefix+prefix(threshold), n.flags)
default:
*logger = log.New(counter, n.prefix+prefix(threshold), n.flags)
}
}
}
// SetLogThreshold change the threshold above which messages are written to the
// log file
func (n *Notepad) SetLogThreshold(threshold Threshold) {
n.logThreshold = threshold
n.init()
}
// SetLogOutput change the file where log messages are written
func (n *Notepad) SetLogOutput(handle io.Writer) {
n.logHandle = handle
n.init()
}
// GetStdoutThreshold returns the defined Treshold for the log logger.
func (n *Notepad) GetLogThreshold() Threshold {
return n.logThreshold
}
// SetStdoutThreshold change the threshold above which messages are written to the
// standard output
func (n *Notepad) SetStdoutThreshold(threshold Threshold) {
n.stdoutThreshold = threshold
n.init()
}
// GetStdoutThreshold returns the Treshold for the stdout logger.
func (n *Notepad) GetStdoutThreshold() Threshold {
return n.stdoutThreshold
}
// SetPrefix change the prefix used by the notepad. Prefixes are displayed between
// brackets at the begining of the line. An empty prefix won't be displayed at all.
func (n *Notepad) SetPrefix(prefix string) {
if len(prefix) != 0 {
n.prefix = "[" + prefix + "] "
} else {
n.prefix = ""
}
n.init()
}
// SetFlags choose which flags the logger will display (after prefix and message
// level). See the package log for more informations on this.
func (n *Notepad) SetFlags(flags int) {
n.flags = flags
n.init()
}
// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
func (fb *Feedback) Println(v ...interface{}) {
s := fmt.Sprintln(v...)
fmt.Print(s)
fb.LOG.Output(2, s)
}
// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
func (fb *Feedback) Printf(format string, v ...interface{}) {
s := fmt.Sprintf(format, v...)
fmt.Print(s)
fb.LOG.Output(2, s)
}

View File

@ -1,256 +0,0 @@
// Copyright © 2016 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package jwalterweatherman
import (
"fmt"
"io"
"io/ioutil"
"log"
"os"
"sync/atomic"
)
// Level describes the chosen log level between
// debug and critical.
type Level int
type NotePad struct {
Handle io.Writer
Level Level
Prefix string
Logger **log.Logger
counter uint64
}
func (n *NotePad) incr() {
atomic.AddUint64(&n.counter, 1)
}
func (n *NotePad) resetCounter() {
atomic.StoreUint64(&n.counter, 0)
}
func (n *NotePad) getCount() uint64 {
return atomic.LoadUint64(&n.counter)
}
type countingWriter struct {
incrFunc func()
}
func (cw *countingWriter) Write(p []byte) (n int, err error) {
cw.incrFunc()
return 0, nil
}
// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
type Feedback struct{}
const (
LevelTrace Level = iota
LevelDebug
LevelInfo
LevelWarn
LevelError
LevelCritical
LevelFatal
DefaultLogThreshold = LevelWarn
DefaultStdoutThreshold = LevelError
)
var (
TRACE *log.Logger
DEBUG *log.Logger
INFO *log.Logger
WARN *log.Logger
ERROR *log.Logger
CRITICAL *log.Logger
FATAL *log.Logger
LOG *log.Logger
FEEDBACK Feedback
LogHandle io.Writer = ioutil.Discard
OutHandle io.Writer = os.Stdout
BothHandle io.Writer = io.MultiWriter(LogHandle, OutHandle)
NotePads []*NotePad = []*NotePad{trace, debug, info, warn, err, critical, fatal}
trace *NotePad = &NotePad{Level: LevelTrace, Handle: os.Stdout, Logger: &TRACE, Prefix: "TRACE: "}
debug *NotePad = &NotePad{Level: LevelDebug, Handle: os.Stdout, Logger: &DEBUG, Prefix: "DEBUG: "}
info *NotePad = &NotePad{Level: LevelInfo, Handle: os.Stdout, Logger: &INFO, Prefix: "INFO: "}
warn *NotePad = &NotePad{Level: LevelWarn, Handle: os.Stdout, Logger: &WARN, Prefix: "WARN: "}
err *NotePad = &NotePad{Level: LevelError, Handle: os.Stdout, Logger: &ERROR, Prefix: "ERROR: "}
critical *NotePad = &NotePad{Level: LevelCritical, Handle: os.Stdout, Logger: &CRITICAL, Prefix: "CRITICAL: "}
fatal *NotePad = &NotePad{Level: LevelFatal, Handle: os.Stdout, Logger: &FATAL, Prefix: "FATAL: "}
logThreshold Level = DefaultLogThreshold
outputThreshold Level = DefaultStdoutThreshold
)
const (
DATE = log.Ldate
TIME = log.Ltime
SFILE = log.Lshortfile
LFILE = log.Llongfile
MSEC = log.Lmicroseconds
)
var logFlags = DATE | TIME | SFILE
func init() {
SetStdoutThreshold(DefaultStdoutThreshold)
}
// initialize will setup the jWalterWeatherman standard approach of providing the user
// some feedback and logging a potentially different amount based on independent log and output thresholds.
// By default the output has a lower threshold than logged
// Don't use if you have manually set the Handles of the different levels as it will overwrite them.
func initialize() {
BothHandle = io.MultiWriter(LogHandle, OutHandle)
for _, n := range NotePads {
if n.Level < outputThreshold && n.Level < logThreshold {
n.Handle = ioutil.Discard
} else if n.Level >= outputThreshold && n.Level >= logThreshold {
n.Handle = BothHandle
} else if n.Level >= outputThreshold && n.Level < logThreshold {
n.Handle = OutHandle
} else {
n.Handle = LogHandle
}
}
for _, n := range NotePads {
n.Handle = io.MultiWriter(n.Handle, &countingWriter{n.incr})
*n.Logger = log.New(n.Handle, n.Prefix, logFlags)
}
LOG = log.New(LogHandle,
"LOG: ",
logFlags)
}
// Set the log Flags (Available flag: DATE, TIME, SFILE, LFILE and MSEC)
func SetLogFlag(flags int) {
logFlags = flags
initialize()
}
// Level returns the current global log threshold.
func LogThreshold() Level {
return logThreshold
}
// Level returns the current global output threshold.
func StdoutThreshold() Level {
return outputThreshold
}
// Ensures that the level provided is within the bounds of available levels
func levelCheck(level Level) Level {
switch {
case level <= LevelTrace:
return LevelTrace
case level >= LevelFatal:
return LevelFatal
default:
return level
}
}
// Establishes a threshold where anything matching or above will be logged
func SetLogThreshold(level Level) {
logThreshold = levelCheck(level)
initialize()
}
// Establishes a threshold where anything matching or above will be output
func SetStdoutThreshold(level Level) {
outputThreshold = levelCheck(level)
initialize()
}
// Conveniently Sets the Log Handle to a io.writer created for the file behind the given filepath
// Will only append to this file
func SetLogFile(path string) {
file, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
CRITICAL.Println("Failed to open log file:", path, err)
os.Exit(-1)
}
INFO.Println("Logging to", file.Name())
LogHandle = file
initialize()
}
// Conveniently Creates a temporary file and sets the Log Handle to a io.writer created for it
func UseTempLogFile(prefix string) {
file, err := ioutil.TempFile(os.TempDir(), prefix)
if err != nil {
CRITICAL.Println(err)
}
INFO.Println("Logging to", file.Name())
LogHandle = file
initialize()
}
// LogCountForLevel returns the number of log invocations for a given level.
func LogCountForLevel(l Level) uint64 {
for _, np := range NotePads {
if np.Level == l {
return np.getCount()
}
}
return 0
}
// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations
// greater than or equal to a given level threshold.
func LogCountForLevelsGreaterThanorEqualTo(threshold Level) uint64 {
var cnt uint64
for _, np := range NotePads {
if np.Level >= threshold {
cnt += np.getCount()
}
}
return cnt
}
// ResetLogCounters resets the invocation counters for all levels.
func ResetLogCounters() {
for _, np := range NotePads {
np.resetCounter()
}
}
// Disables logging for the entire JWW system
func DiscardLogging() {
LogHandle = ioutil.Discard
initialize()
}
// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
func (fb *Feedback) Println(v ...interface{}) {
s := fmt.Sprintln(v...)
fmt.Print(s)
LOG.Output(2, s)
}
// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
func (fb *Feedback) Printf(format string, v ...interface{}) {
s := fmt.Sprintf(format, v...)
fmt.Print(s)
LOG.Output(2, s)
}

147
vendor/github.com/spf13/pflag/bool_slice.go generated vendored Normal file
View File

@ -0,0 +1,147 @@
package pflag
import (
"io"
"strconv"
"strings"
)
// -- boolSlice Value
type boolSliceValue struct {
value *[]bool
changed bool
}
func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue {
bsv := new(boolSliceValue)
bsv.value = p
*bsv.value = val
return bsv
}
// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag.
// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended.
func (s *boolSliceValue) Set(val string) error {
// remove all quote characters
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
// read flag arguments with CSV parser
boolStrSlice, err := readAsCSV(rmQuote.Replace(val))
if err != nil && err != io.EOF {
return err
}
// parse boolean values into slice
out := make([]bool, 0, len(boolStrSlice))
for _, boolStr := range boolStrSlice {
b, err := strconv.ParseBool(strings.TrimSpace(boolStr))
if err != nil {
return err
}
out = append(out, b)
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
// Type returns a string that uniquely represents this flag's type.
func (s *boolSliceValue) Type() string {
return "boolSlice"
}
// String defines a "native" format for this boolean slice flag value.
func (s *boolSliceValue) String() string {
boolStrSlice := make([]string, len(*s.value))
for i, b := range *s.value {
boolStrSlice[i] = strconv.FormatBool(b)
}
out, _ := writeAsCSV(boolStrSlice)
return "[" + out + "]"
}
func boolSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []bool{}, nil
}
ss := strings.Split(val, ",")
out := make([]bool, len(ss))
for i, t := range ss {
var err error
out[i], err = strconv.ParseBool(t)
if err != nil {
return nil, err
}
}
return out, nil
}
// GetBoolSlice returns the []bool value of a flag with the given name.
func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) {
val, err := f.getFlagType(name, "boolSlice", boolSliceConv)
if err != nil {
return []bool{}, err
}
return val.([]bool), nil
}
// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string.
// The argument p points to a []bool variable in which to store the value of the flag.
func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
f.VarP(newBoolSliceValue(value, p), name, "", usage)
}
// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
f.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
}
// BoolSliceVar defines a []bool flag with specified name, default value, and usage string.
// The argument p points to a []bool variable in which to store the value of the flag.
func BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage)
}
// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
}
// BoolSlice defines a []bool flag with specified name, default value, and usage string.
// The return value is the address of a []bool variable that stores the value of the flag.
func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool {
p := []bool{}
f.BoolSliceVarP(&p, name, "", value, usage)
return &p
}
// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
p := []bool{}
f.BoolSliceVarP(&p, name, shorthand, value, usage)
return &p
}
// BoolSlice defines a []bool flag with specified name, default value, and usage string.
// The return value is the address of a []bool variable that stores the value of the flag.
func BoolSlice(name string, value []bool, usage string) *[]bool {
return CommandLine.BoolSliceP(name, "", value, usage)
}
// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
return CommandLine.BoolSliceP(name, shorthand, value, usage)
}

200
vendor/github.com/spf13/pflag/flag.go generated vendored
View File

@ -134,10 +134,16 @@ type FlagSet struct {
// a custom error handler.
Usage func()
// SortFlags is used to indicate, if user wants to have sorted flags in
// help/usage messages.
SortFlags bool
name string
parsed bool
actual map[NormalizedName]*Flag
orderedActual []*Flag
formal map[NormalizedName]*Flag
orderedFormal []*Flag
shorthands map[byte]*Flag
args []string // arguments after flags
argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no --
@ -156,7 +162,7 @@ type Flag struct {
Value Value // value as set
DefValue string // default value (as text); for usage message
Changed bool // If the user set the value (or if left to default)
NoOptDefVal string //default value (as text); if the flag is on the command line without any options
NoOptDefVal string // default value (as text); if the flag is on the command line without any options
Deprecated string // If this flag is deprecated, this string is the new or now thing to use
Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text
ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use
@ -194,10 +200,12 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
// "--getUrl" which may also be translated to "geturl" and everything will work.
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
f.normalizeNameFunc = n
f.orderedFormal = f.orderedFormal[:0]
for k, v := range f.formal {
delete(f.formal, k)
nname := f.normalizeFlagName(string(k))
f.formal[nname] = v
f.orderedFormal = append(f.orderedFormal, v)
v.Name = string(nname)
}
}
@ -229,10 +237,18 @@ func (f *FlagSet) SetOutput(output io.Writer) {
f.output = output
}
// VisitAll visits the flags in lexicographical order, calling fn for each.
// VisitAll visits the flags in lexicographical order or
// in primordial order if f.SortFlags is false, calling fn for each.
// It visits all flags, even those not set.
func (f *FlagSet) VisitAll(fn func(*Flag)) {
for _, flag := range sortFlags(f.formal) {
var flags []*Flag
if f.SortFlags {
flags = sortFlags(f.formal)
} else {
flags = f.orderedFormal
}
for _, flag := range flags {
fn(flag)
}
}
@ -253,22 +269,32 @@ func (f *FlagSet) HasAvailableFlags() bool {
return false
}
// VisitAll visits the command-line flags in lexicographical order, calling
// fn for each. It visits all flags, even those not set.
// VisitAll visits the command-line flags in lexicographical order or
// in primordial order if f.SortFlags is false, calling fn for each.
// It visits all flags, even those not set.
func VisitAll(fn func(*Flag)) {
CommandLine.VisitAll(fn)
}
// Visit visits the flags in lexicographical order, calling fn for each.
// Visit visits the flags in lexicographical order or
// in primordial order if f.SortFlags is false, calling fn for each.
// It visits only those flags that have been set.
func (f *FlagSet) Visit(fn func(*Flag)) {
for _, flag := range sortFlags(f.actual) {
var flags []*Flag
if f.SortFlags {
flags = sortFlags(f.actual)
} else {
flags = f.orderedActual
}
for _, flag := range flags {
fn(flag)
}
}
// Visit visits the command-line flags in lexicographical order, calling fn
// for each. It visits only those flags that have been set.
// Visit visits the command-line flags in lexicographical order or
// in primordial order if f.SortFlags is false, calling fn for each.
// It visits only those flags that have been set.
func Visit(fn func(*Flag)) {
CommandLine.Visit(fn)
}
@ -373,6 +399,7 @@ func (f *FlagSet) Set(name, value string) error {
f.actual = make(map[NormalizedName]*Flag)
}
f.actual[normalName] = flag
f.orderedActual = append(f.orderedActual, flag)
flag.Changed = true
if len(flag.Deprecated) > 0 {
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
@ -487,9 +514,76 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
return
}
// FlagUsages Returns a string containing the usage information for all flags in
// the FlagSet
func (f *FlagSet) FlagUsages() string {
// Splits the string `s` on whitespace into an initial substring up to
// `i` runes in length and the remainder. Will go `slop` over `i` if
// that encompasses the entire string (which allows the caller to
// avoid short orphan words on the final line).
func wrapN(i, slop int, s string) (string, string) {
if i+slop > len(s) {
return s, ""
}
w := strings.LastIndexAny(s[:i], " \t")
if w <= 0 {
return s, ""
}
return s[:w], s[w+1:]
}
// Wraps the string `s` to a maximum width `w` with leading indent
// `i`. The first line is not indented (this is assumed to be done by
// caller). Pass `w` == 0 to do no wrapping
func wrap(i, w int, s string) string {
if w == 0 {
return s
}
// space between indent i and end of line width w into which
// we should wrap the text.
wrap := w - i
var r, l string
// Not enough space for sensible wrapping. Wrap as a block on
// the next line instead.
if wrap < 24 {
i = 16
wrap = w - i
r += "\n" + strings.Repeat(" ", i)
}
// If still not enough space then don't even try to wrap.
if wrap < 24 {
return s
}
// Try to avoid short orphan words on the final line, by
// allowing wrapN to go a bit over if that would fit in the
// remainder of the line.
slop := 5
wrap = wrap - slop
// Handle first line, which is indented by the caller (or the
// special case above)
l, s = wrapN(wrap, slop, s)
r = r + l
// Now wrap the rest
for s != "" {
var t string
t, s = wrapN(wrap, slop, s)
r = r + "\n" + strings.Repeat(" ", i) + t
}
return r
}
// FlagUsagesWrapped returns a string containing the usage information
// for all flags in the FlagSet. Wrapped to `cols` columns (0 for no
// wrapping)
func (f *FlagSet) FlagUsagesWrapped(cols int) string {
x := new(bytes.Buffer)
lines := make([]string, 0, len(f.formal))
@ -534,7 +628,7 @@ func (f *FlagSet) FlagUsages() string {
line += usage
if !flag.defaultIsZeroValue() {
if flag.Value.Type() == "string" {
line += fmt.Sprintf(" (default \"%s\")", flag.DefValue)
line += fmt.Sprintf(" (default %q)", flag.DefValue)
} else {
line += fmt.Sprintf(" (default %s)", flag.DefValue)
}
@ -546,12 +640,19 @@ func (f *FlagSet) FlagUsages() string {
for _, line := range lines {
sidx := strings.Index(line, "\x00")
spacing := strings.Repeat(" ", maxlen-sidx)
fmt.Fprintln(x, line[:sidx], spacing, line[sidx+1:])
// maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx
fmt.Fprintln(x, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:]))
}
return x.String()
}
// FlagUsages returns a string containing the usage information for all flags in
// the FlagSet
func (f *FlagSet) FlagUsages() string {
return f.FlagUsagesWrapped(0)
}
// PrintDefaults prints to standard error the default values of all defined command-line flags.
func PrintDefaults() {
CommandLine.PrintDefaults()
@ -635,7 +736,7 @@ func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag {
// VarP is like Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
_ = f.VarPF(value, name, shorthand, usage)
f.VarPF(value, name, shorthand, usage)
}
// AddFlag will add the flag to the FlagSet
@ -655,6 +756,7 @@ func (f *FlagSet) AddFlag(flag *Flag) {
flag.Name = string(normalizedFlagName)
f.formal[normalizedFlagName] = flag
f.orderedFormal = append(f.orderedFormal, flag)
if len(flag.Shorthand) == 0 {
return
@ -733,6 +835,7 @@ func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error {
f.actual = make(map[NormalizedName]*Flag)
}
f.actual[f.normalizeFlagName(flag.Name)] = flag
f.orderedActual = append(f.orderedActual, flag)
flag.Changed = true
if len(flag.Deprecated) > 0 {
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
@ -752,7 +855,7 @@ func containsShorthand(arg, shorthand string) bool {
return strings.Contains(arg, shorthand)
}
func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error) {
func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {
a = args
name := s[2:]
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
@ -786,11 +889,11 @@ func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error)
err = f.failf("flag needs an argument: %s", s)
return
}
err = f.setFlag(flag, value, s)
err = fn(flag, value, s)
return
}
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShorts string, outArgs []string, err error) {
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) {
if strings.HasPrefix(shorthands, "test.") {
return
}
@ -825,16 +928,16 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShor
err = f.failf("flag needs an argument: %q in -%s", c, shorthands)
return
}
err = f.setFlag(flag, value, shorthands)
err = fn(flag, value, shorthands)
return
}
func (f *FlagSet) parseShortArg(s string, args []string) (a []string, err error) {
func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []string, err error) {
a = args
shorthands := s[1:]
for len(shorthands) > 0 {
shorthands, a, err = f.parseSingleShortArg(shorthands, args)
shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn)
if err != nil {
return
}
@ -843,7 +946,7 @@ func (f *FlagSet) parseShortArg(s string, args []string) (a []string, err error)
return
}
func (f *FlagSet) parseArgs(args []string) (err error) {
func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) {
for len(args) > 0 {
s := args[0]
args = args[1:]
@ -863,9 +966,9 @@ func (f *FlagSet) parseArgs(args []string) (err error) {
f.args = append(f.args, args...)
break
}
args, err = f.parseLongArg(s, args)
args, err = f.parseLongArg(s, args, fn)
} else {
args, err = f.parseShortArg(s, args)
args, err = f.parseShortArg(s, args, fn)
}
if err != nil {
return
@ -881,7 +984,41 @@ func (f *FlagSet) parseArgs(args []string) (err error) {
func (f *FlagSet) Parse(arguments []string) error {
f.parsed = true
f.args = make([]string, 0, len(arguments))
err := f.parseArgs(arguments)
assign := func(flag *Flag, value, origArg string) error {
return f.setFlag(flag, value, origArg)
}
err := f.parseArgs(arguments, assign)
if err != nil {
switch f.errorHandling {
case ContinueOnError:
return err
case ExitOnError:
os.Exit(2)
case PanicOnError:
panic(err)
}
}
return nil
}
type parseFunc func(flag *Flag, value, origArg string) error
// ParseAll parses flag definitions from the argument list, which should not
// include the command name. The arguments for fn are flag and value. Must be
// called after all flags in the FlagSet are defined and before flags are
// accessed by the program. The return value will be ErrHelp if -help was set
// but not defined.
func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) error) error {
f.parsed = true
f.args = make([]string, 0, len(arguments))
assign := func(flag *Flag, value, origArg string) error {
return fn(flag, value)
}
err := f.parseArgs(arguments, assign)
if err != nil {
switch f.errorHandling {
case ContinueOnError:
@ -907,6 +1044,14 @@ func Parse() {
CommandLine.Parse(os.Args[1:])
}
// ParseAll parses the command-line flags from os.Args[1:] and called fn for each.
// The arguments for fn are flag and value. Must be called after all flags are
// defined and before flags are accessed by the program.
func ParseAll(fn func(flag *Flag, value string) error) {
// Ignore errors; CommandLine is set for ExitOnError.
CommandLine.ParseAll(os.Args[1:], fn)
}
// SetInterspersed sets whether to support interspersed option/non-option arguments.
func SetInterspersed(interspersed bool) {
CommandLine.SetInterspersed(interspersed)
@ -920,14 +1065,15 @@ func Parsed() bool {
// CommandLine is the default set of command-line flags, parsed from os.Args.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// NewFlagSet returns a new, empty flag set with the specified name and
// error handling property.
// NewFlagSet returns a new, empty flag set with the specified name,
// error handling property and SortFlags set to true.
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
f := &FlagSet{
name: name,
errorHandling: errorHandling,
argsLenAtDash: -1,
interspersed: true,
SortFlags: true,
}
return f
}

View File

@ -6,13 +6,10 @@ package pflag
import (
goflag "flag"
"fmt"
"reflect"
"strings"
)
var _ = fmt.Print
// flagValueWrapper implements pflag.Value around a flag.Value. The main
// difference here is the addition of the Type method that returns a string
// name of the type. As this is generally unknown, we approximate that with

View File

@ -6,8 +6,6 @@ import (
"strings"
)
var _ = strings.TrimSpace
// -- net.IP value
type ipValue net.IP

148
vendor/github.com/spf13/pflag/ip_slice.go generated vendored Normal file
View File

@ -0,0 +1,148 @@
package pflag
import (
"fmt"
"io"
"net"
"strings"
)
// -- ipSlice Value
type ipSliceValue struct {
value *[]net.IP
changed bool
}
func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue {
ipsv := new(ipSliceValue)
ipsv.value = p
*ipsv.value = val
return ipsv
}
// Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag.
// If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended.
func (s *ipSliceValue) Set(val string) error {
// remove all quote characters
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
// read flag arguments with CSV parser
ipStrSlice, err := readAsCSV(rmQuote.Replace(val))
if err != nil && err != io.EOF {
return err
}
// parse ip values into slice
out := make([]net.IP, 0, len(ipStrSlice))
for _, ipStr := range ipStrSlice {
ip := net.ParseIP(strings.TrimSpace(ipStr))
if ip == nil {
return fmt.Errorf("invalid string being converted to IP address: %s", ipStr)
}
out = append(out, ip)
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
// Type returns a string that uniquely represents this flag's type.
func (s *ipSliceValue) Type() string {
return "ipSlice"
}
// String defines a "native" format for this net.IP slice flag value.
func (s *ipSliceValue) String() string {
ipStrSlice := make([]string, len(*s.value))
for i, ip := range *s.value {
ipStrSlice[i] = ip.String()
}
out, _ := writeAsCSV(ipStrSlice)
return "[" + out + "]"
}
func ipSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Emtpy string would cause a slice with one (empty) entry
if len(val) == 0 {
return []net.IP{}, nil
}
ss := strings.Split(val, ",")
out := make([]net.IP, len(ss))
for i, sval := range ss {
ip := net.ParseIP(strings.TrimSpace(sval))
if ip == nil {
return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval)
}
out[i] = ip
}
return out, nil
}
// GetIPSlice returns the []net.IP value of a flag with the given name
func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) {
val, err := f.getFlagType(name, "ipSlice", ipSliceConv)
if err != nil {
return []net.IP{}, err
}
return val.([]net.IP), nil
}
// IPSliceVar defines a ipSlice flag with specified name, default value, and usage string.
// The argument p points to a []net.IP variable in which to store the value of the flag.
func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
f.VarP(newIPSliceValue(value, p), name, "", usage)
}
// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
f.VarP(newIPSliceValue(value, p), name, shorthand, usage)
}
// IPSliceVar defines a []net.IP flag with specified name, default value, and usage string.
// The argument p points to a []net.IP variable in which to store the value of the flag.
func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
CommandLine.VarP(newIPSliceValue(value, p), name, "", usage)
}
// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage)
}
// IPSlice defines a []net.IP flag with specified name, default value, and usage string.
// The return value is the address of a []net.IP variable that stores the value of that flag.
func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP {
p := []net.IP{}
f.IPSliceVarP(&p, name, "", value, usage)
return &p
}
// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
p := []net.IP{}
f.IPSliceVarP(&p, name, shorthand, value, usage)
return &p
}
// IPSlice defines a []net.IP flag with specified name, default value, and usage string.
// The return value is the address of a []net.IP variable that stores the value of the flag.
func IPSlice(name string, value []net.IP, usage string) *[]net.IP {
return CommandLine.IPSliceP(name, "", value, usage)
}
// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
return CommandLine.IPSliceP(name, shorthand, value, usage)
}

View File

@ -27,8 +27,6 @@ func (*ipNetValue) Type() string {
return "ipNet"
}
var _ = strings.TrimSpace
func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue {
*p = val
return (*ipNetValue)(p)

View File

@ -1,11 +1,5 @@
package pflag
import (
"fmt"
)
var _ = fmt.Fprint
// -- stringArray Value
type stringArrayValue struct {
value *[]string

View File

@ -3,12 +3,9 @@ package pflag
import (
"bytes"
"encoding/csv"
"fmt"
"strings"
)
var _ = fmt.Fprint
// -- stringSlice Value
type stringSliceValue struct {
value *[]string
@ -39,7 +36,7 @@ func writeAsCSV(vals []string) (string, error) {
return "", err
}
w.Flush()
return strings.TrimSuffix(b.String(), fmt.Sprintln()), nil
return strings.TrimSuffix(b.String(), "\n"), nil
}
func (s *stringSliceValue) Set(val string) error {

126
vendor/github.com/spf13/pflag/uint_slice.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
package pflag
import (
"fmt"
"strconv"
"strings"
)
// -- uintSlice Value
type uintSliceValue struct {
value *[]uint
changed bool
}
func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue {
uisv := new(uintSliceValue)
uisv.value = p
*uisv.value = val
return uisv
}
func (s *uintSliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]uint, len(ss))
for i, d := range ss {
u, err := strconv.ParseUint(d, 10, 0)
if err != nil {
return err
}
out[i] = uint(u)
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
func (s *uintSliceValue) Type() string {
return "uintSlice"
}
func (s *uintSliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%d", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func uintSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []uint{}, nil
}
ss := strings.Split(val, ",")
out := make([]uint, len(ss))
for i, d := range ss {
u, err := strconv.ParseUint(d, 10, 0)
if err != nil {
return nil, err
}
out[i] = uint(u)
}
return out, nil
}
// GetUintSlice returns the []uint value of a flag with the given name.
func (f *FlagSet) GetUintSlice(name string) ([]uint, error) {
val, err := f.getFlagType(name, "uintSlice", uintSliceConv)
if err != nil {
return []uint{}, err
}
return val.([]uint), nil
}
// UintSliceVar defines a uintSlice flag with specified name, default value, and usage string.
// The argument p points to a []uint variable in which to store the value of the flag.
func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) {
f.VarP(newUintSliceValue(value, p), name, "", usage)
}
// UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) {
f.VarP(newUintSliceValue(value, p), name, shorthand, usage)
}
// UintSliceVar defines a uint[] flag with specified name, default value, and usage string.
// The argument p points to a uint[] variable in which to store the value of the flag.
func UintSliceVar(p *[]uint, name string, value []uint, usage string) {
CommandLine.VarP(newUintSliceValue(value, p), name, "", usage)
}
// UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash.
func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) {
CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage)
}
// UintSlice defines a []uint flag with specified name, default value, and usage string.
// The return value is the address of a []uint variable that stores the value of the flag.
func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint {
p := []uint{}
f.UintSliceVarP(&p, name, "", value, usage)
return &p
}
// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint {
p := []uint{}
f.UintSliceVarP(&p, name, shorthand, value, usage)
return &p
}
// UintSlice defines a []uint flag with specified name, default value, and usage string.
// The return value is the address of a []uint variable that stores the value of the flag.
func UintSlice(name string, value []uint, usage string) *[]uint {
return CommandLine.UintSliceP(name, "", value, usage)
}
// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash.
func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint {
return CommandLine.UintSliceP(name, shorthand, value, usage)
}

View File

@ -40,6 +40,11 @@ import (
var v *Viper
type RemoteResponse struct {
Value []byte
Error error
}
func init() {
v = New()
}
@ -47,6 +52,7 @@ func init() {
type remoteConfigFactory interface {
Get(rp RemoteProvider) (io.Reader, error)
Watch(rp RemoteProvider) (io.Reader, error)
WatchChannel(rp RemoteProvider)(<-chan *RemoteResponse, chan bool)
}
// RemoteConfig is optional, see the remote package
@ -1093,24 +1099,30 @@ func (v *Viper) ReadInConfig() error {
return err
}
v.config = make(map[string]interface{})
config := make(map[string]interface{})
return v.unmarshalReader(bytes.NewReader(file), v.config)
err = v.unmarshalReader(bytes.NewReader(file), config)
if err != nil {
return err
}
v.config = config
return nil
}
// MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() }
func (v *Viper) MergeInConfig() error {
jww.INFO.Println("Attempting to merge in config file")
if !stringInSlice(v.getConfigType(), SupportedExts) {
return UnsupportedConfigError(v.getConfigType())
}
filename, err := v.getConfigFile()
if err != nil {
return err
}
if !stringInSlice(v.getConfigType(), SupportedExts) {
return UnsupportedConfigError(v.getConfigType())
}
file, err := afero.ReadFile(v.fs, filename)
if err != nil {
return err
@ -1249,6 +1261,10 @@ func (v *Viper) WatchRemoteConfig() error {
return v.watchKeyValueConfig()
}
func (v *Viper) WatchRemoteConfigOnChannel() error {
return v.watchKeyValueConfigOnChannel()
}
// Unmarshall a Reader into a map.
// Should probably be an unexported function.
func unmarshalReader(in io.Reader, c map[string]interface{}) error {
@ -1292,6 +1308,23 @@ func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}
return v.kvstore, err
}
// Retrieve the first found remote configuration.
func (v *Viper) watchKeyValueConfigOnChannel() error {
for _, rp := range v.remoteProviders {
respc, _ := RemoteConfig.WatchChannel(rp)
//Todo: Add quit channel
go func(rc <-chan *RemoteResponse) {
for {
b := <-rc
reader := bytes.NewReader(b.Value)
v.unmarshalReader(reader, v.kvstore)
}
}(respc)
return nil
}
return RemoteConfigError("No Files Found")
}
// Retrieve the first found remote configuration.
func (v *Viper) watchKeyValueConfig() error {
for _, rp := range v.remoteProviders {

View File

@ -568,7 +568,7 @@ func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string
result.addError(
new(AdditionalPropertyNotAllowedError),
context,
value,
value[pk],
ErrorDetails{"property": pk},
)
}
@ -579,7 +579,7 @@ func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string
result.addError(
new(AdditionalPropertyNotAllowedError),
context,
value,
value[pk],
ErrorDetails{"property": pk},
)
}
@ -631,7 +631,7 @@ func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string
result.addError(
new(InvalidPropertyPatternError),
context,
value,
value[pk],
ErrorDetails{
"property": pk,
"pattern": currentSubSchema.PatternPropertiesString(),

10
vendor/golang.org/x/sys/unix/asm.s generated vendored
View File

@ -1,10 +0,0 @@
// 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.
// +build !gccgo
#include "textflag.h"
TEXT ·use(SB),NOSPLIT,$0
RET

View File

@ -1,29 +1,28 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
// +build mips64 mips64le
// +build !gccgo
#include "textflag.h"
//
// System call support for 386, FreeBSD
// System calls for mips64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-32
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-44
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-56
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-32
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

31
vendor/golang.org/x/sys/unix/asm_linux_mipsx.s generated vendored Normal file
View File

@ -0,0 +1,31 @@
// 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 linux
// +build mips mipsle
// +build !gccgo
#include "textflag.h"
//
// System calls for mips, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)

28
vendor/golang.org/x/sys/unix/asm_linux_s390x.s generated vendored Normal file
View File

@ -0,0 +1,28 @@
// 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 s390x
// +build linux
// +build !gccgo
#include "textflag.h"
//
// System calls for s390x, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
BR syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BR syscall·Syscall6(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
BR syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
BR syscall·RawSyscall6(SB)

35
vendor/golang.org/x/sys/unix/bluetooth_linux.go generated vendored Normal file
View File

@ -0,0 +1,35 @@
// 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.
// Bluetooth sockets and messages
package unix
// Bluetooth Protocols
const (
BTPROTO_L2CAP = 0
BTPROTO_HCI = 1
BTPROTO_SCO = 2
BTPROTO_RFCOMM = 3
BTPROTO_BNEP = 4
BTPROTO_CMTP = 5
BTPROTO_HIDP = 6
BTPROTO_AVDTP = 7
)
const (
HCI_CHANNEL_RAW = 0
HCI_CHANNEL_USER = 1
HCI_CHANNEL_MONITOR = 2
HCI_CHANNEL_CONTROL = 3
)
// Socketoption Level
const (
SOL_BLUETOOTH = 0x112
SOL_HCI = 0x0
SOL_L2CAP = 0x6
SOL_RFCOMM = 0x12
SOL_SCO = 0x11
)

102
vendor/golang.org/x/sys/unix/dirent.go generated vendored Normal file
View File

@ -0,0 +1,102 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package unix
import "unsafe"
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
if len(b) < int(off+size) {
return 0, false
}
if isBigEndian {
return readIntBE(b[off:], size), true
}
return readIntLE(b[off:], size), true
}
func readIntBE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[1]) | uint64(b[0])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
func readIntLE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
// ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number of
// bytes consumed from buf, the number of entries added
// to names, and the new names slice.
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
origlen := len(buf)
count = 0
for max != 0 && len(buf) > 0 {
reclen, ok := direntReclen(buf)
if !ok || reclen > uint64(len(buf)) {
return origlen, count, names
}
rec := buf[:reclen]
buf = buf[reclen:]
ino, ok := direntIno(rec)
if !ok {
break
}
if ino == 0 { // File absent in directory.
continue
}
const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
namlen, ok := direntNamlen(rec)
if !ok || namoff+namlen > uint64(len(rec)) {
break
}
name := rec[namoff : namoff+namlen]
for i, c := range name {
if c == 0 {
name = name[:i]
break
}
}
// Check for useless names before allocating a string.
if string(name) == "." || string(name) == ".." {
continue
}
max--
count++
names = append(names, string(name))
}
return origlen - len(buf), count, names
}

9
vendor/golang.org/x/sys/unix/endian_big.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// 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 ppc64 s390x mips64
package unix
const isBigEndian = true

9
vendor/golang.org/x/sys/unix/endian_little.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// 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 386 amd64 amd64p32 arm arm64 ppc64le mips64le
package unix
const isBigEndian = false

View File

@ -1,4 +1,4 @@
// +build linux,386 linux,arm
// +build linux,386 linux,arm linux,mips linux,mipsle
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style

20
vendor/golang.org/x/sys/unix/gccgo_linux_sparc64.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// 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 gccgo,linux,sparc64
package unix
import "syscall"
//extern sysconf
func realSysconf(name int) int64
func sysconf(name int) (n int64, err syscall.Errno) {
r := realSysconf(name)
if r < 0 {
return 0, syscall.GetErrno()
}
return r, 0
}

62
vendor/golang.org/x/sys/unix/mkpost.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
// 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 ignore
// mkpost processes the output of cgo -godefs to
// modify the generated types. It is used to clean up
// the sys API in an architecture specific manner.
//
// mkpost is run after cgo -godefs by mkall.sh.
package main
import (
"fmt"
"go/format"
"io/ioutil"
"log"
"os"
"regexp"
)
func main() {
b, err := ioutil.ReadAll(os.Stdin)
if err != nil {
log.Fatal(err)
}
s := string(b)
goarch := os.Getenv("GOARCH")
goos := os.Getenv("GOOS")
if goarch == "s390x" && goos == "linux" {
// Export the types of PtraceRegs fields.
re := regexp.MustCompile("ptrace(Psw|Fpregs|Per)")
s = re.ReplaceAllString(s, "Ptrace$1")
// Replace padding fields inserted by cgo with blank identifiers.
re = regexp.MustCompile("Pad_cgo[A-Za-z0-9_]*")
s = re.ReplaceAllString(s, "_")
// Replace other unwanted fields with blank identifiers.
re = regexp.MustCompile("X_[A-Za-z0-9_]*")
s = re.ReplaceAllString(s, "_")
// Replace the control_regs union with a blank identifier for now.
re = regexp.MustCompile("(Control_regs)\\s+\\[0\\]uint64")
s = re.ReplaceAllString(s, "_ [0]uint64")
}
// gofmt
b, err = format.Source([]byte(s))
if err != nil {
log.Fatal(err)
}
// Append this command to the header to show where the new file
// came from.
re := regexp.MustCompile("(cgo -godefs [a-zA-Z0-9_]+\\.go.*)")
b = re.ReplaceAll(b, []byte("$1 | go run mkpost.go"))
fmt.Printf("%s", b)
}

38
vendor/golang.org/x/sys/unix/openbsd_pledge.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// 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 openbsd
// +build 386 amd64 arm
package unix
import (
"syscall"
"unsafe"
)
const (
SYS_PLEDGE = 108
)
// Pledge implements the pledge syscall. For more information see pledge(2).
func Pledge(promises string, paths []string) error {
promisesPtr, err := syscall.BytePtrFromString(promises)
if err != nil {
return err
}
promisesUnsafe, pathsUnsafe := unsafe.Pointer(promisesPtr), unsafe.Pointer(nil)
if paths != nil {
var pathsPtr []*byte
if pathsPtr, err = syscall.SlicePtrFromStrings(paths); err != nil {
return err
}
pathsUnsafe = unsafe.Pointer(&pathsPtr[0])
}
_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(promisesUnsafe), uintptr(pathsUnsafe), 0)
if e != 0 {
return e
}
return nil
}

View File

@ -62,7 +62,7 @@ func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
return nil, nil, EINVAL
}
return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil

View File

@ -21,8 +21,6 @@
// holds a value of type syscall.Errno.
package unix // import "golang.org/x/sys/unix"
import "unsafe"
// ByteSliceFromString returns a NUL-terminated slice of bytes
// containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
@ -68,7 +66,4 @@ func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
}
// use is a no-op, but the compiler cannot see that it is.
// Calling use(p) ensures that p is kept live until that point.
//go:noescape
func use(p unsafe.Pointer)
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }

View File

@ -470,25 +470,11 @@ func Sysctl(name string) (string, error) {
}
func SysctlArgs(name string, args ...int) (string, error) {
mib, err := sysctlmib(name, args...)
buf, err := SysctlRaw(name, args...)
if err != nil {
return "", err
}
// Find size.
n := uintptr(0)
if err := sysctl(mib, nil, &n, nil, 0); err != nil {
return "", err
}
if n == 0 {
return "", nil
}
// Read into buffer of that size.
buf := make([]byte, n)
if err := sysctl(mib, &buf[0], &n, nil, 0); err != nil {
return "", err
}
n := len(buf)
// Throw away terminating NUL.
if n > 0 && buf[n-1] == '\x00' {

View File

@ -76,32 +76,16 @@ func nametomib(name string) (mib []_C_int, err error) {
return buf[0 : n/siz], nil
}
// ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number
// bytes consumed from buf, the number of entries added
// to names, and the new names slice.
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
origlen := len(buf)
for max != 0 && len(buf) > 0 {
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
if dirent.Reclen == 0 {
buf = nil
break
}
buf = buf[dirent.Reclen:]
if dirent.Ino == 0 { // File absent in directory.
continue
}
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
var name = string(bytes[0:dirent.Namlen])
if name == "." || name == ".." { // Useless names
continue
}
max--
count++
names = append(names, name)
}
return origlen - len(buf), count, names
func direntIno(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
}
func direntReclen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
}
func direntNamlen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)

View File

@ -21,8 +21,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -23,8 +23,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -19,8 +19,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -21,8 +21,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -56,29 +56,20 @@ func nametomib(name string) (mib []_C_int, err error) {
return buf[0 : n/siz], nil
}
// ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number
// bytes consumed from buf, the number of entries added
// to names, and the new names slice.
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
origlen := len(buf)
for max != 0 && len(buf) > 0 {
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
reclen := int(16+dirent.Namlen+1+7) & ^7
buf = buf[reclen:]
if dirent.Fileno == 0 { // File absent in directory.
continue
func direntIno(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
}
func direntReclen(buf []byte) (uint64, bool) {
namlen, ok := direntNamlen(buf)
if !ok {
return 0, false
}
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
var name = string(bytes[0:dirent.Namlen])
if name == "." || name == ".." { // Useless names
continue
}
max--
count++
names = append(names, name)
}
return origlen - len(buf), count, names
return (16 + namlen + 1 + 7) & ^7, true
}
func direntNamlen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
//sysnb pipe() (r int, w int, err error)

View File

@ -1,63 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build 386,dragonfly
package unix
import (
"syscall"
"unsafe"
)
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
ts.Sec = int32(nsec / 1e9)
ts.Nsec = int32(nsec % 1e9)
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3)
tv.Sec = int32(nsec / 1e9)
return
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint32(fd)
k.Filter = int16(mode)
k.Flags = uint16(flags)
}
func (iov *Iovec) SetLen(length int) {
iov.Len = uint32(length)
}
func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
var writtenOut uint64 = 0
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
written = int(writtenOut)
if e1 != 0 {
err = e1
}
return
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)

View File

@ -21,8 +21,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return
}
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond
tv.Usec = nsec % 1e9 / 1e3

View File

@ -54,32 +54,16 @@ func nametomib(name string) (mib []_C_int, err error) {
return buf[0 : n/siz], nil
}
// ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number
// bytes consumed from buf, the number of entries added
// to names, and the new names slice.
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
origlen := len(buf)
for max != 0 && len(buf) > 0 {
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
if dirent.Reclen == 0 {
buf = nil
break
}
buf = buf[dirent.Reclen:]
if dirent.Fileno == 0 { // File absent in directory.
continue
}
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
var name = string(bytes[0:dirent.Namlen])
if name == "." || name == ".." { // Useless names
continue
}
max--
count++
names = append(names, name)
}
return origlen - len(buf), count, names
func direntIno(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
}
func direntReclen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
}
func direntNamlen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
//sysnb pipe() (r int, w int, err error)

Some files were not shown because too many files have changed in this diff Show More