Resolve logrus and gojsonschema vendoring conflicts

Some vendoring is blocking other PR's due to changes to logrus (Sirupsen
vs sirupsen for lower-case) as well as a non-versioned gojsonschema in
glide.yaml

This updates glide.yaml to reflect the upper-case as well as lower-case
versions of logrus as well as adds a versionized gojsonschema in order
to get rid of the following error:

```sh
▶ make bin
go build -ldflags="-w -X github.com/kubernetes/kompose/cmd.GITCOMMIT=0e56b7d" -o kompose main.go
vendor/github.com/docker/cli/cli/compose/schema/schema.go:34: cannot use portsFormatChecker literal (type portsFormatChecker) as type gojsonschema.FormatChecker in argument to gojsonschema.FormatCheckers.Add:
        portsFormatChecker does not implement gojsonschema.FormatChecker (wrong type for IsFormat method)
                have IsFormat(string) bool
                want IsFormat(interface {}) bool
vendor/github.com/docker/cli/cli/compose/schema/schema.go:35: cannot use portsFormatChecker literal (type portsFormatChecker) as type gojsonschema.FormatChecker in argument to gojsonschema.FormatCheckers.Add:
        portsFormatChecker does not implement gojsonschema.FormatChecker (wrong type for IsFormat method)
                have IsFormat(string) bool
                want IsFormat(interface {}) bool
vendor/github.com/docker/cli/cli/compose/schema/schema.go:36: cannot use durationFormatChecker literal (type durationFormatChecker) as type gojsonschema.FormatChecker in argument to gojsonschema.FormatCheckers.Add:
        durationFormatChecker does not implement gojsonschema.FormatChecker (wrong type for IsFormat method)
                have IsFormat(string) bool
                want IsFormat(interface {}) bool
vendor/github.com/docker/libcompose/config/schema_helpers.go:60: cannot use environmentFormatChecker literal (type environmentFormatChecker) as type gojsonschema.FormatChecker in argument to gojsonschema.FormatCheckers.Add:
        environmentFormatChecker does not implement gojsonschema.FormatChecker (wrong type for IsFormat method)
                have IsFormat(string) bool
                want IsFormat(interface {}) bool
vendor/github.com/docker/libcompose/config/schema_helpers.go:61: cannot use portsFormatChecker literal (type portsFormatChecker) as type gojsonschema.FormatChecker in argument to gojsonschema.FormatCheckers.Add:
        portsFormatChecker does not implement gojsonschema.FormatChecker (wrong type for IsFormat method)
                have IsFormat(string) bool
                want IsFormat(interface {}) bool
vendor/github.com/docker/libcompose/config/schema_helpers.go:62: cannot use portsFormatChecker literal (type portsFormatChecker) as type gojsonschema.FormatChecker in argument to gojsonschema.FormatCheckers.Add:
        portsFormatChecker does not implement gojsonschema.FormatChecker (wrong type for IsFormat method)
                have IsFormat(string) bool
                want IsFormat(interface {}) bool
^CMakefile:29: recipe for target 'bin' failed
make: *** [bin] Interrupt
```
This commit is contained in:
Charlie Drage 2017-10-02 11:29:18 -04:00
parent 4d4cc3b017
commit 43b1ca0fe0
237 changed files with 64882 additions and 19790 deletions

44
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: dea9df7466c06608df2a07e688dfafcdb213c01074abb0add588123b0d382416 hash: 489e34fbf0634da520802fbaec2a52559a2e016b93022c34e8fd4bcc9c7f1130
updated: 2017-09-26T19:25:51.029980554+05:30 updated: 2017-10-02T11:27:54.826873322-04:00
imports: imports:
- name: cloud.google.com/go - name: cloud.google.com/go
version: 3b1ae45394a234c385be014e9a488f2bb6eef821 version: 3b1ae45394a234c385be014e9a488f2bb6eef821
@ -338,7 +338,7 @@ imports:
- runtime/internal - runtime/internal
- utilities - utilities
- name: github.com/hashicorp/hcl - name: github.com/hashicorp/hcl
version: 392dba7d905ed5d04a5794ba89f558b27e2ba1ca version: 68e816d1c783414e79bc65b3994d9ab6b0a722ab
subpackages: subpackages:
- hcl/ast - hcl/ast
- hcl/parser - hcl/parser
@ -357,7 +357,7 @@ imports:
- name: github.com/juju/ratelimit - name: github.com/juju/ratelimit
version: 77ed1c8a01217656d2080ad51981f6e99adaa177 version: 77ed1c8a01217656d2080ad51981f6e99adaa177
- name: github.com/magiconair/properties - name: github.com/magiconair/properties
version: 51463bfca2576e06c62a8504b5c0f06d61312647 version: 8d7837e64d3c1ee4e54a880c5a920ab4316fc90a
- name: github.com/mattn/go-shellwords - name: github.com/mattn/go-shellwords
version: 95c860c1895b21b58903abdd1d9c591560b0601c version: 95c860c1895b21b58903abdd1d9c591560b0601c
- name: github.com/matttproud/golang_protobuf_extensions - name: github.com/matttproud/golang_protobuf_extensions
@ -365,7 +365,7 @@ imports:
subpackages: subpackages:
- pbutil - pbutil
- name: github.com/mitchellh/mapstructure - name: github.com/mitchellh/mapstructure
version: db1efb556f84b25a0a13a04aad883943538ad2e0 version: d0303fe809921458f417bcf828397a65db30a7e4
- name: github.com/novln/docker-parser - name: github.com/novln/docker-parser
version: 6030251119d652af8ead44ac7907444227b64d56 version: 6030251119d652af8ead44ac7907444227b64d56
subpackages: subpackages:
@ -375,7 +375,7 @@ imports:
- name: github.com/opencontainers/go-digest - name: github.com/opencontainers/go-digest
version: 279bed98673dd5bef374d3b6e4b09e2af76183bf version: 279bed98673dd5bef374d3b6e4b09e2af76183bf
- name: github.com/opencontainers/image-spec - name: github.com/opencontainers/image-spec
version: ebd93fd0782379ca3d821f0fa74f0651a9347a3e version: 7c889fafd04a893f5c5f50b7ab9963d5d64e5242
subpackages: subpackages:
- specs-go - specs-go
- specs-go/v1 - specs-go/v1
@ -425,12 +425,10 @@ imports:
- pkg/version - pkg/version
- name: github.com/pborman/uuid - name: github.com/pborman/uuid
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4 version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- name: github.com/pelletier/go-buffruneio
version: c37440a7cf42ac63b919c752ca73a85067e05992
- name: github.com/pelletier/go-toml - name: github.com/pelletier/go-toml
version: 048765b4491bcff26505dfbb8a7b920133a19fd2 version: 2009e44b6f182e34d8ce081ac2767622937ea3d4
- name: github.com/pkg/errors - name: github.com/pkg/errors
version: 645ef00459ed84a119197bfb8d8205042c6df63d version: 2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb
- name: github.com/prometheus/client_golang - name: github.com/prometheus/client_golang
version: e51041b3fa41cece0dca035740ba6411905be473 version: e51041b3fa41cece0dca035740ba6411905be473
subpackages: subpackages:
@ -447,22 +445,26 @@ imports:
- model - model
- name: github.com/prometheus/procfs - name: github.com/prometheus/procfs
version: 454a56f35412459b5e684fd5ec0f9211b94f002a version: 454a56f35412459b5e684fd5ec0f9211b94f002a
- name: github.com/sirupsen/logrus
version: f006c2ac4710855cf0f916dd6b77acf6b048dc6e
- name: github.com/Sirupsen/logrus - name: github.com/Sirupsen/logrus
version: ba1b36c82c5e05c4f912a88eab0dcd91a171688f version: f006c2ac4710855cf0f916dd6b77acf6b048dc6e
repo: git@github.com:/sirupsen/logrus
vcs: git
- name: github.com/spf13/afero - name: github.com/spf13/afero
version: 9be650865eab0c12963d8753212f4f9c66cdcf12 version: ee1bd8ee15a1306d1f9201acc41ef39cd9f99a1b
subpackages: subpackages:
- mem - mem
- name: github.com/spf13/cast - name: github.com/spf13/cast
version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4 version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4
- name: github.com/spf13/cobra - name: github.com/spf13/cobra
version: e606913c4ee45fec232e67e70105fb6c866b95d9 version: 0dacccfbaabc71b872087c1719c5380d3e185173
- name: github.com/spf13/jwalterweatherman - name: github.com/spf13/jwalterweatherman
version: 0efa5202c04663c757d84f90f5219c1250baf94f version: 12bd96e66386c1960ab0f74ced1362f66f552f7b
- name: github.com/spf13/pflag - name: github.com/spf13/pflag
version: e57e3eeb33f795204c1ca35f56c44f83227c6e66 version: be7121dd7a937a85e1e4b1ddda6a3edce3466110
- name: github.com/spf13/viper - name: github.com/spf13/viper
version: 382f87b929b84ce13e9c8a375a4b217f224e6c65 version: d9cca5ef33035202efb1586825bdbb15ff9ec3ba
- name: github.com/ugorji/go - name: github.com/ugorji/go
version: f4485b318aadd133842532f841dc205a8e339d74 version: f4485b318aadd133842532f841dc205a8e339d74
subpackages: subpackages:
@ -472,7 +474,11 @@ imports:
- name: github.com/xeipuuv/gojsonreference - name: github.com/xeipuuv/gojsonreference
version: e02fc20de94c78484cd5ffb007f8af96be030a45 version: e02fc20de94c78484cd5ffb007f8af96be030a45
- name: github.com/xeipuuv/gojsonschema - name: github.com/xeipuuv/gojsonschema
version: 0c8571ac0ce161a5feb57375a9cdf148c98c0f70 version: 93e72a773fade158921402d6a24c819b48aba29d
- name: golang.org/x/crypto
version: 1f22c0103821b9390939b6776727195525381532
subpackages:
- ssh/terminal
- name: golang.org/x/net - name: golang.org/x/net
version: e90d6d0afc4c315a0d87a568ae68577cc15149a0 version: e90d6d0afc4c315a0d87a568ae68577cc15149a0
subpackages: subpackages:
@ -496,7 +502,7 @@ imports:
- jws - jws
- jwt - jwt
- name: golang.org/x/sys - name: golang.org/x/sys
version: d9157a9621b69ad1d8d77a1933590c416593f24f version: 314a259e304ff91bd6985da2a7149bbf91237993
subpackages: subpackages:
- unix - unix
- name: golang.org/x/text - name: golang.org/x/text
@ -538,7 +544,7 @@ imports:
- name: gopkg.in/inf.v0 - name: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/yaml.v2 - name: gopkg.in/yaml.v2
version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b version: eb3733d160e74a9c7e442f435eb3bea458e1d19f
- name: k8s.io/client-go - name: k8s.io/client-go
version: d72c0e162789e1bbb33c33cfa26858a1375efe01 version: d72c0e162789e1bbb33c33cfa26858a1375efe01
subpackages: subpackages:

View File

@ -4,8 +4,16 @@ licence: Apache-2.0
import: import:
- package: github.com/sirupsen/logrus
version: 1.0.3
- package: github.com/Sirupsen/logrus - package: github.com/Sirupsen/logrus
version: v0.11.5 repo: git@github.com:/sirupsen/logrus
vcs: git
version: 1.0.3
- package: github.com/xeipuuv/gojsonschema
version: 93e72a773fade158921402d6a24c819b48aba29d
- package: github.com/fatih/structs - package: github.com/fatih/structs
- package: github.com/ghodss/yaml - package: github.com/ghodss/yaml

View File

@ -1,7 +1,7 @@
package logrus package logrus
// The following code was sourced and modified from the // The following code was sourced and modified from the
// https://bitbucket.org/tebeka/atexit package governed by the following license: // https://github.com/tebeka/atexit package governed by the following license:
// //
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>. // Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
// //

View File

@ -7,7 +7,7 @@ The simplest way to use Logrus is simply the package-level exported logger:
package main package main
import ( import (
log "github.com/Sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func main() { func main() {
@ -21,6 +21,6 @@ The simplest way to use Logrus is simply the package-level exported logger:
Output: Output:
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 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 For a full guide visit https://github.com/sirupsen/logrus
*/ */
package logrus package logrus

View File

@ -35,6 +35,7 @@ type Entry struct {
Time time.Time Time time.Time
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
Level Level Level Level
// Message passed to Debug, Info, Warn, Error, Fatal or Panic // Message passed to Debug, Info, Warn, Error, Fatal or Panic
@ -126,7 +127,7 @@ func (entry Entry) log(level Level, msg string) {
} }
func (entry *Entry) Debug(args ...interface{}) { func (entry *Entry) Debug(args ...interface{}) {
if entry.Logger.Level >= DebugLevel { if entry.Logger.level() >= DebugLevel {
entry.log(DebugLevel, fmt.Sprint(args...)) entry.log(DebugLevel, fmt.Sprint(args...))
} }
} }
@ -136,13 +137,13 @@ func (entry *Entry) Print(args ...interface{}) {
} }
func (entry *Entry) Info(args ...interface{}) { func (entry *Entry) Info(args ...interface{}) {
if entry.Logger.Level >= InfoLevel { if entry.Logger.level() >= InfoLevel {
entry.log(InfoLevel, fmt.Sprint(args...)) entry.log(InfoLevel, fmt.Sprint(args...))
} }
} }
func (entry *Entry) Warn(args ...interface{}) { func (entry *Entry) Warn(args ...interface{}) {
if entry.Logger.Level >= WarnLevel { if entry.Logger.level() >= WarnLevel {
entry.log(WarnLevel, fmt.Sprint(args...)) entry.log(WarnLevel, fmt.Sprint(args...))
} }
} }
@ -152,20 +153,20 @@ func (entry *Entry) Warning(args ...interface{}) {
} }
func (entry *Entry) Error(args ...interface{}) { func (entry *Entry) Error(args ...interface{}) {
if entry.Logger.Level >= ErrorLevel { if entry.Logger.level() >= ErrorLevel {
entry.log(ErrorLevel, fmt.Sprint(args...)) entry.log(ErrorLevel, fmt.Sprint(args...))
} }
} }
func (entry *Entry) Fatal(args ...interface{}) { func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.Level >= FatalLevel { if entry.Logger.level() >= FatalLevel {
entry.log(FatalLevel, fmt.Sprint(args...)) entry.log(FatalLevel, fmt.Sprint(args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panic(args ...interface{}) { func (entry *Entry) Panic(args ...interface{}) {
if entry.Logger.Level >= PanicLevel { if entry.Logger.level() >= PanicLevel {
entry.log(PanicLevel, fmt.Sprint(args...)) entry.log(PanicLevel, fmt.Sprint(args...))
} }
panic(fmt.Sprint(args...)) panic(fmt.Sprint(args...))
@ -174,13 +175,13 @@ func (entry *Entry) Panic(args ...interface{}) {
// Entry Printf family functions // Entry Printf family functions
func (entry *Entry) Debugf(format string, args ...interface{}) { func (entry *Entry) Debugf(format string, args ...interface{}) {
if entry.Logger.Level >= DebugLevel { if entry.Logger.level() >= DebugLevel {
entry.Debug(fmt.Sprintf(format, args...)) entry.Debug(fmt.Sprintf(format, args...))
} }
} }
func (entry *Entry) Infof(format string, args ...interface{}) { func (entry *Entry) Infof(format string, args ...interface{}) {
if entry.Logger.Level >= InfoLevel { if entry.Logger.level() >= InfoLevel {
entry.Info(fmt.Sprintf(format, args...)) entry.Info(fmt.Sprintf(format, args...))
} }
} }
@ -190,7 +191,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
} }
func (entry *Entry) Warnf(format string, args ...interface{}) { func (entry *Entry) Warnf(format string, args ...interface{}) {
if entry.Logger.Level >= WarnLevel { if entry.Logger.level() >= WarnLevel {
entry.Warn(fmt.Sprintf(format, args...)) entry.Warn(fmt.Sprintf(format, args...))
} }
} }
@ -200,20 +201,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
} }
func (entry *Entry) Errorf(format string, args ...interface{}) { func (entry *Entry) Errorf(format string, args ...interface{}) {
if entry.Logger.Level >= ErrorLevel { if entry.Logger.level() >= ErrorLevel {
entry.Error(fmt.Sprintf(format, args...)) entry.Error(fmt.Sprintf(format, args...))
} }
} }
func (entry *Entry) Fatalf(format string, args ...interface{}) { func (entry *Entry) Fatalf(format string, args ...interface{}) {
if entry.Logger.Level >= FatalLevel { if entry.Logger.level() >= FatalLevel {
entry.Fatal(fmt.Sprintf(format, args...)) entry.Fatal(fmt.Sprintf(format, args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panicf(format string, args ...interface{}) { func (entry *Entry) Panicf(format string, args ...interface{}) {
if entry.Logger.Level >= PanicLevel { if entry.Logger.level() >= PanicLevel {
entry.Panic(fmt.Sprintf(format, args...)) entry.Panic(fmt.Sprintf(format, args...))
} }
} }
@ -221,13 +222,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) {
// Entry Println family functions // Entry Println family functions
func (entry *Entry) Debugln(args ...interface{}) { func (entry *Entry) Debugln(args ...interface{}) {
if entry.Logger.Level >= DebugLevel { if entry.Logger.level() >= DebugLevel {
entry.Debug(entry.sprintlnn(args...)) entry.Debug(entry.sprintlnn(args...))
} }
} }
func (entry *Entry) Infoln(args ...interface{}) { func (entry *Entry) Infoln(args ...interface{}) {
if entry.Logger.Level >= InfoLevel { if entry.Logger.level() >= InfoLevel {
entry.Info(entry.sprintlnn(args...)) entry.Info(entry.sprintlnn(args...))
} }
} }
@ -237,7 +238,7 @@ func (entry *Entry) Println(args ...interface{}) {
} }
func (entry *Entry) Warnln(args ...interface{}) { func (entry *Entry) Warnln(args ...interface{}) {
if entry.Logger.Level >= WarnLevel { if entry.Logger.level() >= WarnLevel {
entry.Warn(entry.sprintlnn(args...)) entry.Warn(entry.sprintlnn(args...))
} }
} }
@ -247,20 +248,20 @@ func (entry *Entry) Warningln(args ...interface{}) {
} }
func (entry *Entry) Errorln(args ...interface{}) { func (entry *Entry) Errorln(args ...interface{}) {
if entry.Logger.Level >= ErrorLevel { if entry.Logger.level() >= ErrorLevel {
entry.Error(entry.sprintlnn(args...)) entry.Error(entry.sprintlnn(args...))
} }
} }
func (entry *Entry) Fatalln(args ...interface{}) { func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.Level >= FatalLevel { if entry.Logger.level() >= FatalLevel {
entry.Fatal(entry.sprintlnn(args...)) entry.Fatal(entry.sprintlnn(args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panicln(args ...interface{}) { func (entry *Entry) Panicln(args ...interface{}) {
if entry.Logger.Level >= PanicLevel { if entry.Logger.level() >= PanicLevel {
entry.Panic(entry.sprintlnn(args...)) entry.Panic(entry.sprintlnn(args...))
} }
} }

View File

@ -31,14 +31,14 @@ func SetFormatter(formatter Formatter) {
func SetLevel(level Level) { func SetLevel(level Level) {
std.mu.Lock() std.mu.Lock()
defer std.mu.Unlock() defer std.mu.Unlock()
std.Level = level std.SetLevel(level)
} }
// GetLevel returns the standard logger level. // GetLevel returns the standard logger level.
func GetLevel() Level { func GetLevel() Level {
std.mu.Lock() std.mu.Lock()
defer std.mu.Unlock() defer std.mu.Unlock()
return std.Level return std.level()
} }
// AddHook adds a hook to the standard logger hooks. // AddHook adds a hook to the standard logger hooks.

View File

@ -2,7 +2,7 @@ package logrus
import "time" import "time"
const DefaultTimestampFormat = time.RFC3339 const defaultTimestampFormat = time.RFC3339
// The Formatter interface is used to implement a custom Formatter. It takes an // The Formatter interface is used to implement a custom Formatter. It takes an
// `Entry`. It exposes all the fields, including the default ones: // `Entry`. It exposes all the fields, including the default ones:

View File

@ -6,8 +6,11 @@ import (
) )
type fieldKey string type fieldKey string
// FieldMap allows customization of the key names for default fields.
type FieldMap map[fieldKey]string type FieldMap map[fieldKey]string
// Default key names for the default fields
const ( const (
FieldKeyMsg = "msg" FieldKeyMsg = "msg"
FieldKeyLevel = "level" FieldKeyLevel = "level"
@ -22,6 +25,7 @@ func (f FieldMap) resolve(key fieldKey) string {
return string(key) return string(key)
} }
// JSONFormatter formats logs into parsable json
type JSONFormatter struct { type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps. // TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string TimestampFormat string
@ -29,25 +33,26 @@ type JSONFormatter struct {
// DisableTimestamp allows disabling automatic timestamps in output // DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool DisableTimestamp bool
// FieldMap allows users to customize the names of keys for various fields. // FieldMap allows users to customize the names of keys for default fields.
// As an example: // As an example:
// formatter := &JSONFormatter{ // formatter := &JSONFormatter{
// FieldMap: FieldMap{ // FieldMap: FieldMap{
// FieldKeyTime: "@timestamp", // FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level", // FieldKeyLevel: "@level",
// FieldKeyLevel: "@message", // FieldKeyMsg: "@message",
// }, // },
// } // }
FieldMap FieldMap FieldMap FieldMap
} }
// Format renders a single log entry
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data := make(Fields, len(entry.Data)+3) data := make(Fields, len(entry.Data)+3)
for k, v := range entry.Data { for k, v := range entry.Data {
switch v := v.(type) { switch v := v.(type) {
case error: case error:
// Otherwise errors are ignored by `encoding/json` // Otherwise errors are ignored by `encoding/json`
// https://github.com/Sirupsen/logrus/issues/137 // https://github.com/sirupsen/logrus/issues/137
data[k] = v.Error() data[k] = v.Error()
default: default:
data[k] = v data[k] = v
@ -57,7 +62,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat := f.TimestampFormat timestampFormat := f.TimestampFormat
if timestampFormat == "" { if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat timestampFormat = defaultTimestampFormat
} }
if !f.DisableTimestamp { if !f.DisableTimestamp {

View File

@ -4,6 +4,7 @@ import (
"io" "io"
"os" "os"
"sync" "sync"
"sync/atomic"
) )
type Logger struct { type Logger struct {
@ -24,7 +25,7 @@ type Logger struct {
Formatter Formatter Formatter Formatter
// The logging level the logger should log at. This is typically (and defaults // The logging level the logger should log at. This is typically (and defaults
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
// logged. `logrus.Debug` is useful in // logged.
Level Level Level Level
// Used to sync writing to the log. Locking is enabled by Default // Used to sync writing to the log. Locking is enabled by Default
mu MutexWrap mu MutexWrap
@ -112,7 +113,7 @@ func (logger *Logger) WithError(err error) *Entry {
} }
func (logger *Logger) Debugf(format string, args ...interface{}) { func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.Level >= DebugLevel { if logger.level() >= DebugLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debugf(format, args...) entry.Debugf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -120,7 +121,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) {
} }
func (logger *Logger) Infof(format string, args ...interface{}) { func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.Level >= InfoLevel { if logger.level() >= InfoLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Infof(format, args...) entry.Infof(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -134,7 +135,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
} }
func (logger *Logger) Warnf(format string, args ...interface{}) { func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnf(format, args...) entry.Warnf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -142,7 +143,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) {
} }
func (logger *Logger) Warningf(format string, args ...interface{}) { func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnf(format, args...) entry.Warnf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -150,7 +151,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) {
} }
func (logger *Logger) Errorf(format string, args ...interface{}) { func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.Level >= ErrorLevel { if logger.level() >= ErrorLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Errorf(format, args...) entry.Errorf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -158,7 +159,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) {
} }
func (logger *Logger) Fatalf(format string, args ...interface{}) { func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.Level >= FatalLevel { if logger.level() >= FatalLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatalf(format, args...) entry.Fatalf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -167,7 +168,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) {
} }
func (logger *Logger) Panicf(format string, args ...interface{}) { func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.Level >= PanicLevel { if logger.level() >= PanicLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panicf(format, args...) entry.Panicf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -175,7 +176,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) {
} }
func (logger *Logger) Debug(args ...interface{}) { func (logger *Logger) Debug(args ...interface{}) {
if logger.Level >= DebugLevel { if logger.level() >= DebugLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debug(args...) entry.Debug(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -183,7 +184,7 @@ func (logger *Logger) Debug(args ...interface{}) {
} }
func (logger *Logger) Info(args ...interface{}) { func (logger *Logger) Info(args ...interface{}) {
if logger.Level >= InfoLevel { if logger.level() >= InfoLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Info(args...) entry.Info(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -197,7 +198,7 @@ func (logger *Logger) Print(args ...interface{}) {
} }
func (logger *Logger) Warn(args ...interface{}) { func (logger *Logger) Warn(args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warn(args...) entry.Warn(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -205,7 +206,7 @@ func (logger *Logger) Warn(args ...interface{}) {
} }
func (logger *Logger) Warning(args ...interface{}) { func (logger *Logger) Warning(args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warn(args...) entry.Warn(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -213,7 +214,7 @@ func (logger *Logger) Warning(args ...interface{}) {
} }
func (logger *Logger) Error(args ...interface{}) { func (logger *Logger) Error(args ...interface{}) {
if logger.Level >= ErrorLevel { if logger.level() >= ErrorLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Error(args...) entry.Error(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -221,7 +222,7 @@ func (logger *Logger) Error(args ...interface{}) {
} }
func (logger *Logger) Fatal(args ...interface{}) { func (logger *Logger) Fatal(args ...interface{}) {
if logger.Level >= FatalLevel { if logger.level() >= FatalLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatal(args...) entry.Fatal(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -230,7 +231,7 @@ func (logger *Logger) Fatal(args ...interface{}) {
} }
func (logger *Logger) Panic(args ...interface{}) { func (logger *Logger) Panic(args ...interface{}) {
if logger.Level >= PanicLevel { if logger.level() >= PanicLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panic(args...) entry.Panic(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -238,7 +239,7 @@ func (logger *Logger) Panic(args ...interface{}) {
} }
func (logger *Logger) Debugln(args ...interface{}) { func (logger *Logger) Debugln(args ...interface{}) {
if logger.Level >= DebugLevel { if logger.level() >= DebugLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debugln(args...) entry.Debugln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -246,7 +247,7 @@ func (logger *Logger) Debugln(args ...interface{}) {
} }
func (logger *Logger) Infoln(args ...interface{}) { func (logger *Logger) Infoln(args ...interface{}) {
if logger.Level >= InfoLevel { if logger.level() >= InfoLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Infoln(args...) entry.Infoln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -260,7 +261,7 @@ func (logger *Logger) Println(args ...interface{}) {
} }
func (logger *Logger) Warnln(args ...interface{}) { func (logger *Logger) Warnln(args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnln(args...) entry.Warnln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -268,7 +269,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
} }
func (logger *Logger) Warningln(args ...interface{}) { func (logger *Logger) Warningln(args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnln(args...) entry.Warnln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -276,7 +277,7 @@ func (logger *Logger) Warningln(args ...interface{}) {
} }
func (logger *Logger) Errorln(args ...interface{}) { func (logger *Logger) Errorln(args ...interface{}) {
if logger.Level >= ErrorLevel { if logger.level() >= ErrorLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Errorln(args...) entry.Errorln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -284,7 +285,7 @@ func (logger *Logger) Errorln(args ...interface{}) {
} }
func (logger *Logger) Fatalln(args ...interface{}) { func (logger *Logger) Fatalln(args ...interface{}) {
if logger.Level >= FatalLevel { if logger.level() >= FatalLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatalln(args...) entry.Fatalln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -293,7 +294,7 @@ func (logger *Logger) Fatalln(args ...interface{}) {
} }
func (logger *Logger) Panicln(args ...interface{}) { func (logger *Logger) Panicln(args ...interface{}) {
if logger.Level >= PanicLevel { if logger.level() >= PanicLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panicln(args...) entry.Panicln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -306,3 +307,11 @@ func (logger *Logger) Panicln(args ...interface{}) {
func (logger *Logger) SetNoLock() { func (logger *Logger) SetNoLock() {
logger.mu.Disable() logger.mu.Disable()
} }
func (logger *Logger) level() Level {
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}
func (logger *Logger) SetLevel(level Level) {
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}

View File

@ -10,7 +10,7 @@ import (
type Fields map[string]interface{} type Fields map[string]interface{}
// Level type // Level type
type Level uint8 type Level uint32
// Convert the Level to a string. E.g. PanicLevel becomes "panic". // Convert the Level to a string. E.g. PanicLevel becomes "panic".
func (level Level) String() string { func (level Level) String() string {

View File

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

View File

@ -3,8 +3,8 @@
package logrus package logrus
import "syscall" import "golang.org/x/sys/unix"
const ioctlReadTermios = syscall.TIOCGETA const ioctlReadTermios = unix.TIOCGETA
type Termios syscall.Termios type Termios unix.Termios

View File

@ -7,8 +7,8 @@
package logrus package logrus
import "syscall" import "golang.org/x/sys/unix"
const ioctlReadTermios = syscall.TCGETS const ioctlReadTermios = unix.TCGETS
type Termios syscall.Termios type Termios unix.Termios

View File

@ -1,28 +0,0 @@
// Based on ssh/terminal:
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
var termios Termios
switch v := f.(type) {
case *os.File:
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
default:
return false
}
}

View File

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

View File

@ -1,33 +0,0 @@
// Based on ssh/terminal:
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows,!appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
default:
return false
}
}

View File

@ -3,10 +3,14 @@ package logrus
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"os"
"sort" "sort"
"strings" "strings"
"sync" "sync"
"time" "time"
"golang.org/x/crypto/ssh/terminal"
) )
const ( const (
@ -14,7 +18,7 @@ const (
red = 31 red = 31
green = 32 green = 32
yellow = 33 yellow = 33
blue = 34 blue = 36
gray = 37 gray = 37
) )
@ -26,6 +30,7 @@ func init() {
baseTimestamp = time.Now() baseTimestamp = time.Now()
} }
// TextFormatter formats logs into text
type TextFormatter struct { type TextFormatter struct {
// Set to true to bypass checking for a TTY before outputting colors. // Set to true to bypass checking for a TTY before outputting colors.
ForceColors bool ForceColors bool
@ -52,10 +57,6 @@ type TextFormatter struct {
// QuoteEmptyFields will wrap empty fields in quotes if true // QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal // Whether the logger's out is to a terminal
isTerminal bool isTerminal bool
@ -63,14 +64,21 @@ type TextFormatter struct {
} }
func (f *TextFormatter) init(entry *Entry) { func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil { if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out) f.isTerminal = f.checkIfTerminal(entry.Logger.Out)
} }
} }
func (f *TextFormatter) checkIfTerminal(w io.Writer) bool {
switch v := w.(type) {
case *os.File:
return terminal.IsTerminal(int(v.Fd()))
default:
return false
}
}
// Format renders a single log entry
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer var b *bytes.Buffer
keys := make([]string, 0, len(entry.Data)) keys := make([]string, 0, len(entry.Data))
@ -95,7 +103,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat := f.TimestampFormat timestampFormat := f.TimestampFormat
if timestampFormat == "" { if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat timestampFormat = defaultTimestampFormat
} }
if isColored { if isColored {
f.printColored(b, entry, keys, timestampFormat) f.printColored(b, entry, keys, timestampFormat)
@ -153,7 +161,7 @@ func (f *TextFormatter) needsQuoting(text string) bool {
if !((ch >= 'a' && ch <= 'z') || if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') || (ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || (ch >= '0' && ch <= '9') ||
ch == '-' || ch == '.') { ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
return true return true
} }
} }
@ -161,29 +169,23 @@ func (f *TextFormatter) needsQuoting(text string) bool {
} }
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
if b.Len() > 0 {
b.WriteByte(' ')
}
b.WriteString(key) b.WriteString(key)
b.WriteByte('=') b.WriteByte('=')
f.appendValue(b, value) f.appendValue(b, value)
b.WriteByte(' ')
} }
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) { stringVal, ok := value.(string)
case string: if !ok {
if !f.needsQuoting(value) { stringVal = fmt.Sprint(value)
b.WriteString(value) }
} else {
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter) if !f.needsQuoting(stringVal) {
} b.WriteString(stringVal)
case error: } else {
errmsg := value.Error() b.WriteString(fmt.Sprintf("%q", stringVal))
if !f.needsQuoting(errmsg) {
b.WriteString(errmsg)
} else {
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
}
default:
fmt.Fprint(b, value)
} }
} }

View File

@ -137,7 +137,7 @@ func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) e
func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error {
switch n := node.(type) { switch n := node.(type) {
case *ast.LiteralType: case *ast.LiteralType:
if n.Token.Type == token.FLOAT { if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER {
v, err := strconv.ParseFloat(n.Token.Text, 64) v, err := strconv.ParseFloat(n.Token.Text, 64)
if err != nil { if err != nil {
return err return err

View File

@ -197,9 +197,12 @@ func (p *Parser) objectItem() (*ast.ObjectItem, error) {
keyStr = append(keyStr, k.Token.Text) keyStr = append(keyStr, k.Token.Text)
} }
return nil, fmt.Errorf( return nil, &PosError{
"key '%s' expected start of object ('{') or assignment ('=')", Pos: p.tok.Pos,
strings.Join(keyStr, " ")) Err: fmt.Errorf(
"key '%s' expected start of object ('{') or assignment ('=')",
strings.Join(keyStr, " ")),
}
} }
// do a look-ahead for line comment // do a look-ahead for line comment
@ -319,7 +322,10 @@ func (p *Parser) objectType() (*ast.ObjectType, error) {
// No error, scan and expect the ending to be a brace // No error, scan and expect the ending to be a brace
if tok := p.scan(); tok.Type != token.RBRACE { if tok := p.scan(); tok.Type != token.RBRACE {
return nil, fmt.Errorf("object expected closing RBRACE got: %s", tok.Type) return nil, &PosError{
Pos: tok.Pos,
Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type),
}
} }
o.List = l o.List = l

View File

@ -511,6 +511,9 @@ func (p *Properties) Set(key, value string) (prev string, ok bool, err error) {
if p.DisableExpansion { if p.DisableExpansion {
prev, ok = p.Get(key) prev, ok = p.Get(key)
p.m[key] = value p.m[key] = value
if !ok {
p.k = append(p.k, key)
}
return prev, ok, nil return prev, ok, nil
} }

View File

@ -38,12 +38,6 @@ func DecodeHookExec(
raw DecodeHookFunc, raw DecodeHookFunc,
from reflect.Type, to reflect.Type, from reflect.Type, to reflect.Type,
data interface{}) (interface{}, error) { data interface{}) (interface{}, error) {
// Build our arguments that reflect expects
argVals := make([]reflect.Value, 3)
argVals[0] = reflect.ValueOf(from)
argVals[1] = reflect.ValueOf(to)
argVals[2] = reflect.ValueOf(data)
switch f := typedDecodeHook(raw).(type) { switch f := typedDecodeHook(raw).(type) {
case DecodeHookFuncType: case DecodeHookFuncType:
return f(from, to, data) return f(from, to, data)
@ -121,6 +115,11 @@ func StringToTimeDurationHookFunc() DecodeHookFunc {
} }
} }
// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
// the decoder.
//
// Note that this is significantly different from the WeaklyTypedInput option
// of the DecoderConfig.
func WeaklyTypedHook( func WeaklyTypedHook(
f reflect.Kind, f reflect.Kind,
t reflect.Kind, t reflect.Kind,
@ -132,9 +131,8 @@ func WeaklyTypedHook(
case reflect.Bool: case reflect.Bool:
if dataVal.Bool() { if dataVal.Bool() {
return "1", nil return "1", nil
} else {
return "0", nil
} }
return "0", nil
case reflect.Float32: case reflect.Float32:
return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
case reflect.Int: case reflect.Int:

View File

@ -1,5 +1,5 @@
// The mapstructure package exposes functionality to convert an // Package mapstructure exposes functionality to convert an arbitrary
// arbitrary map[string]interface{} into a native Go structure. // map[string]interface{} into a native Go structure.
// //
// The Go structure can be arbitrarily complex, containing slices, // The Go structure can be arbitrarily complex, containing slices,
// other structs, etc. and the decoder will properly decode nested // other structs, etc. and the decoder will properly decode nested
@ -32,7 +32,12 @@ import (
// both. // both.
type DecodeHookFunc interface{} type DecodeHookFunc interface{}
// DecodeHookFuncType is a DecodeHookFunc which has complete information about
// the source and target types.
type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error)
// DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the
// source and target types.
type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error)
// DecoderConfig is the configuration that is used to create a new decoder // DecoderConfig is the configuration that is used to create a new decoder
@ -69,6 +74,9 @@ type DecoderConfig struct {
// - empty array = empty map and vice versa // - empty array = empty map and vice versa
// - negative numbers to overflowed uint values (base 10) // - negative numbers to overflowed uint values (base 10)
// - slice of maps to a merged map // - 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 WeaklyTypedInput bool
@ -433,7 +441,7 @@ func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value)
case dataKind == reflect.Uint: case dataKind == reflect.Uint:
val.SetFloat(float64(dataVal.Uint())) val.SetFloat(float64(dataVal.Uint()))
case dataKind == reflect.Float32: case dataKind == reflect.Float32:
val.SetFloat(float64(dataVal.Float())) val.SetFloat(dataVal.Float())
case dataKind == reflect.Bool && d.config.WeaklyTypedInput: case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
if dataVal.Bool() { if dataVal.Bool() {
val.SetFloat(1) val.SetFloat(1)
@ -584,17 +592,28 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
valSlice := val valSlice := val
if valSlice.IsNil() || d.config.ZeroFields { if valSlice.IsNil() || d.config.ZeroFields {
// Check input type // Check input type
if dataValKind != reflect.Array && dataValKind != reflect.Slice { if dataValKind != reflect.Array && dataValKind != reflect.Slice {
// Accept empty map instead of array/slice in weakly typed mode if d.config.WeaklyTypedInput {
if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 { switch {
val.Set(reflect.MakeSlice(sliceType, 0, 0)) // Empty maps turn into empty slices
return nil case dataValKind == reflect.Map:
} else { if dataVal.Len() == 0 {
return fmt.Errorf( val.Set(reflect.MakeSlice(sliceType, 0, 0))
"'%s': source data must be an array or slice, got %s", name, dataValKind) return nil
}
// 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. // Make a new slice to hold our result, same size as the original data.

View File

@ -1,117 +0,0 @@
// Package buffruneio is a wrapper around bufio to provide buffered runes access with unlimited unreads.
package buffruneio
import (
"bufio"
"container/list"
"errors"
"io"
)
// Rune to indicate end of file.
const (
EOF = -(iota + 1)
)
// ErrNoRuneToUnread is returned by UnreadRune() when the read index is already at the beginning of the buffer.
var ErrNoRuneToUnread = errors.New("no rune to unwind")
// Reader implements runes buffering for an io.Reader object.
type Reader struct {
buffer *list.List
current *list.Element
input *bufio.Reader
}
// NewReader returns a new Reader.
func NewReader(rd io.Reader) *Reader {
return &Reader{
buffer: list.New(),
input: bufio.NewReader(rd),
}
}
type runeWithSize struct {
r rune
size int
}
func (rd *Reader) feedBuffer() error {
r, size, err := rd.input.ReadRune()
if err != nil {
if err != io.EOF {
return err
}
r = EOF
}
newRuneWithSize := runeWithSize{r, size}
rd.buffer.PushBack(newRuneWithSize)
if rd.current == nil {
rd.current = rd.buffer.Back()
}
return nil
}
// ReadRune reads the next rune from buffer, or from the underlying reader if needed.
func (rd *Reader) ReadRune() (rune, int, error) {
if rd.current == rd.buffer.Back() || rd.current == nil {
err := rd.feedBuffer()
if err != nil {
return EOF, 0, err
}
}
runeWithSize := rd.current.Value.(runeWithSize)
rd.current = rd.current.Next()
return runeWithSize.r, runeWithSize.size, nil
}
// UnreadRune pushes back the previously read rune in the buffer, extending it if needed.
func (rd *Reader) UnreadRune() error {
if rd.current == rd.buffer.Front() {
return ErrNoRuneToUnread
}
if rd.current == nil {
rd.current = rd.buffer.Back()
} else {
rd.current = rd.current.Prev()
}
return nil
}
// Forget removes runes stored before the current stream position index.
func (rd *Reader) Forget() {
if rd.current == nil {
rd.current = rd.buffer.Back()
}
for ; rd.current != rd.buffer.Front(); rd.buffer.Remove(rd.current.Prev()) {
}
}
// 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) PeekRunes(n int) []rune {
res := make([]rune, 0, n)
cursor := rd.current
for i := 0; i < n; i++ {
if cursor == nil {
err := rd.feedBuffer()
if err != nil {
return res
}
cursor = rd.buffer.Back()
}
if cursor != nil {
r := cursor.Value.(runeWithSize).r
res = append(res, r)
if r == EOF {
return res
}
cursor = cursor.Next()
}
}
return res
}

View File

@ -1,79 +1,18 @@
// Package toml is a TOML markup language parser. // Package toml is a TOML parser and manipulation library.
// //
// This version supports the specification as described in // This version supports the specification as described in
// https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md // https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md
// //
// TOML Parsing // Marshaling
// //
// TOML data may be parsed in two ways: by file, or by string. // Go-toml can marshal and unmarshal TOML documents from and to data
// structures.
// //
// // load TOML data by filename // TOML document as a tree
// tree, err := toml.LoadFile("filename.toml")
// //
// // load TOML data stored in a string // Go-toml can operate on a TOML document as a tree. Use one of the Load*
// tree, err := toml.Load(stringContainingTomlData) // functions to parse TOML data and obtain a Tree instance, then one of its
// // methods to manipulate the tree.
// Either way, the result is a Tree object that can be used to navigate the
// structure and data within the original document.
//
//
// Getting data from the Tree
//
// After parsing TOML data with Load() or LoadFile(), use the Has() and Get()
// methods on the returned Tree, to find your way through the document data.
//
// if tree.Has("foo") {
// fmt.Println("foo is:", tree.Get("foo"))
// }
//
// Working with Paths
//
// Go-toml has support for basic dot-separated key paths on the Has(), Get(), Set()
// and GetDefault() methods. These are the same kind of key paths used within the
// TOML specification for struct tames.
//
// // looks for a key named 'baz', within struct 'bar', within struct 'foo'
// tree.Has("foo.bar.baz")
//
// // returns the key at this path, if it is there
// tree.Get("foo.bar.baz")
//
// TOML allows keys to contain '.', which can cause this syntax to be problematic
// for some documents. In such cases, use the GetPath(), HasPath(), and SetPath(),
// methods to explicitly define the path. This form is also faster, since
// 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"})
//
// // returns the key at this path, if it is there
// tree.GetPath([]string{"foo","bar","baz"})
//
// Note that this is distinct from the heavyweight query syntax supported by
// Tree.Query() and the Query() struct (see below).
//
// Position Support
//
// Each element within the Tree is stored with position metadata, which is
// invaluable for providing semantic feedback to a user. This helps in
// situations where the TOML file parses correctly, but contains data that is
// not correct for the application. In such cases, an error message can be
// generated that indicates the problem line and column number in the source
// TOML document.
//
// // load TOML data
// tree, _ := toml.Load("filename.toml")
//
// // get an entry and report an error if it's the wrong type
// element := tree.Get("foo")
// if value, ok := element.(int64); !ok {
// return fmt.Errorf("%v: Element 'foo' must be an integer", tree.GetPosition("foo"))
// }
//
// // report an error if an expected element is missing
// if !tree.Has("bar") {
// return fmt.Errorf("%v: Expected 'bar' element", tree.GetPosition(""))
// }
// //
// JSONPath-like queries // JSONPath-like queries
// //

View File

@ -6,14 +6,12 @@
package toml package toml
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"io"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/pelletier/go-buffruneio"
) )
var dateRegexp *regexp.Regexp var dateRegexp *regexp.Regexp
@ -23,29 +21,29 @@ type tomlLexStateFn func() tomlLexStateFn
// Define lexer // Define lexer
type tomlLexer struct { type tomlLexer struct {
input *buffruneio.Reader // Textual source inputIdx int
buffer []rune // Runes composing the current token input []rune // Textual source
tokens chan token currentTokenStart int
depth int currentTokenStop int
line int tokens []token
col int depth int
endbufferLine int line int
endbufferCol int col int
endbufferLine int
endbufferCol int
} }
// Basic read operations on input // Basic read operations on input
func (l *tomlLexer) read() rune { func (l *tomlLexer) read() rune {
r, _, err := l.input.ReadRune() r := l.peek()
if err != nil {
panic(err)
}
if r == '\n' { if r == '\n' {
l.endbufferLine++ l.endbufferLine++
l.endbufferCol = 1 l.endbufferCol = 1
} else { } else {
l.endbufferCol++ l.endbufferCol++
} }
l.inputIdx++
return r return r
} }
@ -53,13 +51,13 @@ func (l *tomlLexer) next() rune {
r := l.read() r := l.read()
if r != eof { if r != eof {
l.buffer = append(l.buffer, r) l.currentTokenStop++
} }
return r return r
} }
func (l *tomlLexer) ignore() { func (l *tomlLexer) ignore() {
l.buffer = make([]rune, 0) l.currentTokenStart = l.currentTokenStop
l.line = l.endbufferLine l.line = l.endbufferLine
l.col = l.endbufferCol l.col = l.endbufferCol
} }
@ -76,49 +74,46 @@ func (l *tomlLexer) fastForward(n int) {
} }
func (l *tomlLexer) emitWithValue(t tokenType, value string) { func (l *tomlLexer) emitWithValue(t tokenType, value string) {
l.tokens <- token{ l.tokens = append(l.tokens, token{
Position: Position{l.line, l.col}, Position: Position{l.line, l.col},
typ: t, typ: t,
val: value, val: value,
} })
l.ignore() l.ignore()
} }
func (l *tomlLexer) emit(t tokenType) { func (l *tomlLexer) emit(t tokenType) {
l.emitWithValue(t, string(l.buffer)) l.emitWithValue(t, string(l.input[l.currentTokenStart:l.currentTokenStop]))
} }
func (l *tomlLexer) peek() rune { func (l *tomlLexer) peek() rune {
r, _, err := l.input.ReadRune() if l.inputIdx >= len(l.input) {
if err != nil { return eof
panic(err)
} }
l.input.UnreadRune() return l.input[l.inputIdx]
return r }
func (l *tomlLexer) peekString(size int) string {
maxIdx := len(l.input)
upperIdx := l.inputIdx + size // FIXME: potential overflow
if upperIdx > maxIdx {
upperIdx = maxIdx
}
return string(l.input[l.inputIdx:upperIdx])
} }
func (l *tomlLexer) follow(next string) bool { func (l *tomlLexer) follow(next string) bool {
for _, expectedRune := range next { return next == l.peekString(len(next))
r, _, err := l.input.ReadRune()
defer l.input.UnreadRune()
if err != nil {
panic(err)
}
if expectedRune != r {
return false
}
}
return true
} }
// Error management // Error management
func (l *tomlLexer) errorf(format string, args ...interface{}) tomlLexStateFn { func (l *tomlLexer) errorf(format string, args ...interface{}) tomlLexStateFn {
l.tokens <- token{ l.tokens = append(l.tokens, token{
Position: Position{l.line, l.col}, Position: Position{l.line, l.col},
typ: tokenError, typ: tokenError,
val: fmt.Sprintf(format, args...), val: fmt.Sprintf(format, args...),
} })
return nil return nil
} }
@ -219,7 +214,7 @@ func (l *tomlLexer) lexRvalue() tomlLexStateFn {
break break
} }
possibleDate := string(l.input.PeekRunes(35)) possibleDate := l.peekString(35)
dateMatch := dateRegexp.FindString(possibleDate) dateMatch := dateRegexp.FindString(possibleDate)
if dateMatch != "" { if dateMatch != "" {
l.fastForward(len(dateMatch)) l.fastForward(len(dateMatch))
@ -536,7 +531,7 @@ func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
for r := l.peek(); r != eof; r = l.peek() { for r := l.peek(); r != eof; r = l.peek() {
switch r { switch r {
case ']': case ']':
if len(l.buffer) > 0 { if l.currentTokenStop > l.currentTokenStart {
l.emit(tokenKeyGroupArray) l.emit(tokenKeyGroupArray)
} }
l.next() l.next()
@ -559,7 +554,7 @@ func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn {
for r := l.peek(); r != eof; r = l.peek() { for r := l.peek(); r != eof; r = l.peek() {
switch r { switch r {
case ']': case ']':
if len(l.buffer) > 0 { if l.currentTokenStop > l.currentTokenStart {
l.emit(tokenKeyGroup) l.emit(tokenKeyGroup)
} }
l.next() l.next()
@ -634,7 +629,6 @@ func (l *tomlLexer) run() {
for state := l.lexVoid; state != nil; { for state := l.lexVoid; state != nil; {
state = state() state = state()
} }
close(l.tokens)
} }
func init() { func init() {
@ -642,16 +636,16 @@ func init() {
} }
// Entry point // Entry point
func lexToml(input io.Reader) chan token { func lexToml(inputBytes []byte) []token {
bufferedInput := buffruneio.NewReader(input) runes := bytes.Runes(inputBytes)
l := &tomlLexer{ l := &tomlLexer{
input: bufferedInput, input: runes,
tokens: make(chan token), tokens: make([]token, 0, 256),
line: 1, line: 1,
col: 1, col: 1,
endbufferLine: 1, endbufferLine: 1,
endbufferCol: 1, endbufferCol: 1,
} }
go l.run() l.run()
return l.tokens return l.tokens
} }

View File

@ -5,30 +5,15 @@ import (
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
"strconv"
"strings" "strings"
"time" "time"
) )
/*
Tree structural types and corresponding marshal types
-------------------------------------------------------------------------------
*Tree (*)struct, (*)map[string]interface{}
[]*Tree (*)[](*)struct, (*)[](*)map[string]interface{}
[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
interface{} (*)primitive
Tree 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 { type tomlOpts struct {
name string name string
comment string
commented bool
include bool include bool
omitempty bool omitempty bool
} }
@ -112,9 +97,32 @@ encoder, except that there is no concept of a Marshaler interface or MarshalTOML
function for sub-structs, and currently only definite types can be marshaled function for sub-structs, and currently only definite types can be marshaled
(i.e. no `interface{}`). (i.e. no `interface{}`).
The following struct annotations are supported:
toml:"Field" Overrides the field's name to output.
omitempty When set, empty values and groups are not emitted.
comment:"comment" Emits a # comment on the same line. This supports new lines.
commented:"true" Emits the value as commented.
Note that pointers are automatically assigned the "omitempty" option, as TOML Note that pointers are automatically assigned the "omitempty" option, as TOML
explicity does not handle null values (saying instead the label should be explicity does not handle null values (saying instead the label should be
dropped). dropped).
Tree structural types and corresponding marshal types:
*Tree (*)struct, (*)map[string]interface{}
[]*Tree (*)[](*)struct, (*)[](*)map[string]interface{}
[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
interface{} (*)primitive
Tree 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
*/ */
func Marshal(v interface{}) ([]byte, error) { func Marshal(v interface{}) ([]byte, error) {
mtype := reflect.TypeOf(v) mtype := reflect.TypeOf(v)
@ -149,7 +157,7 @@ func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
tval.Set(opts.name, val) tval.Set(opts.name, opts.comment, opts.commented, val)
} }
} }
case reflect.Map: case reflect.Map:
@ -159,7 +167,7 @@ func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
tval.Set(key.String(), val) tval.Set(key.String(), "", false, val)
} }
} }
return tval, nil return tval, nil
@ -247,6 +255,12 @@ func (t *Tree) Unmarshal(v interface{}) error {
// is no concept of an Unmarshaler interface or UnmarshalTOML function for // 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 // sub-structs, and currently only definite types can be unmarshaled to (i.e. no
// `interface{}`). // `interface{}`).
//
// The following struct annotations are supported:
//
// toml:"Field" Overrides the field's name to map to.
//
// See Marshal() documentation for types mapping table.
func Unmarshal(data []byte, v interface{}) error { func Unmarshal(data []byte, v interface{}) error {
t, err := LoadReader(bytes.NewReader(data)) t, err := LoadReader(bytes.NewReader(data))
if err != nil { if err != nil {
@ -268,15 +282,20 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
mtypef := mtype.Field(i) mtypef := mtype.Field(i)
opts := tomlOptions(mtypef) opts := tomlOptions(mtypef)
if opts.include { if opts.include {
key := opts.name baseKey := opts.name
exists := tval.Has(key) keysToTry := []string{baseKey, strings.ToLower(baseKey), strings.ToTitle(baseKey)}
if exists { for _, key := range keysToTry {
exists := tval.Has(key)
if !exists {
continue
}
val := tval.Get(key) val := tval.Get(key)
mvalf, err := valueFromToml(mtypef.Type, val) mvalf, err := valueFromToml(mtypef.Type, val)
if err != nil { if err != nil {
return mval, formatError(err, tval.GetPosition(key)) return mval, formatError(err, tval.GetPosition(key))
} }
mval.Field(i).Set(mvalf) mval.Field(i).Set(mvalf)
break
} }
} }
} }
@ -443,7 +462,12 @@ func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error)
func tomlOptions(vf reflect.StructField) tomlOpts { func tomlOptions(vf reflect.StructField) tomlOpts {
tag := vf.Tag.Get("toml") tag := vf.Tag.Get("toml")
parse := strings.Split(tag, ",") parse := strings.Split(tag, ",")
result := tomlOpts{vf.Name, true, false} var comment string
if c := vf.Tag.Get("comment"); c != "" {
comment = c
}
commented, _ := strconv.ParseBool(vf.Tag.Get("commented"))
result := tomlOpts{name: vf.Name, comment: comment, commented: commented, include: true, omitempty: false}
if parse[0] != "" { if parse[0] != "" {
if parse[0] == "-" && len(parse) == 1 { if parse[0] == "-" && len(parse) == 1 {
result.include = false result.include = false

View File

@ -13,9 +13,9 @@ import (
) )
type tomlParser struct { type tomlParser struct {
flow chan token flowIdx int
flow []token
tree *Tree tree *Tree
tokensBuffer []token
currentTable []string currentTable []string
seenTableKeys []string seenTableKeys []string
} }
@ -34,16 +34,10 @@ func (p *tomlParser) run() {
} }
func (p *tomlParser) peek() *token { func (p *tomlParser) peek() *token {
if len(p.tokensBuffer) != 0 { if p.flowIdx >= len(p.flow) {
return &(p.tokensBuffer[0])
}
tok, ok := <-p.flow
if !ok {
return nil return nil
} }
p.tokensBuffer = append(p.tokensBuffer, tok) return &p.flow[p.flowIdx]
return &tok
} }
func (p *tomlParser) assume(typ tokenType) { func (p *tomlParser) assume(typ tokenType) {
@ -57,16 +51,12 @@ func (p *tomlParser) assume(typ tokenType) {
} }
func (p *tomlParser) getToken() *token { func (p *tomlParser) getToken() *token {
if len(p.tokensBuffer) != 0 { tok := p.peek()
tok := p.tokensBuffer[0] if tok == nil {
p.tokensBuffer = p.tokensBuffer[1:]
return &tok
}
tok, ok := <-p.flow
if !ok {
return nil return nil
} }
return &tok p.flowIdx++
return tok
} }
func (p *tomlParser) parseStart() tomlParserStateFn { func (p *tomlParser) parseStart() tomlParserStateFn {
@ -120,7 +110,7 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
newTree := newTree() newTree := newTree()
newTree.position = startToken.Position newTree.position = startToken.Position
array = append(array, newTree) array = append(array, newTree)
p.tree.SetPath(p.currentTable, array) p.tree.SetPath(p.currentTable, "", false, array)
// remove all keys that were children of this table array // remove all keys that were children of this table array
prefix := key.val + "." prefix := key.val + "."
@ -215,7 +205,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
case *Tree, []*Tree: case *Tree, []*Tree:
toInsert = value toInsert = value
default: default:
toInsert = &tomlValue{value, key.Position} toInsert = &tomlValue{value: value, position: key.Position}
} }
targetNode.values[keyVal] = toInsert targetNode.values[keyVal] = toInsert
return p.parseStart return p.parseStart
@ -309,7 +299,7 @@ Loop:
key := p.getToken() key := p.getToken()
p.assume(tokenEqual) p.assume(tokenEqual)
value := p.parseRvalue() value := p.parseRvalue()
tree.Set(key.val, value) tree.Set(key.val, "", false, value)
case tokenComma: case tokenComma:
if previous == nil { if previous == nil {
p.raiseError(follow, "inline table cannot start with a comma") p.raiseError(follow, "inline table cannot start with a comma")
@ -374,13 +364,13 @@ func (p *tomlParser) parseArray() interface{} {
return array return array
} }
func parseToml(flow chan token) *Tree { func parseToml(flow []token) *Tree {
result := newTree() result := newTree()
result.position = Position{1, 1} result.position = Position{1, 1}
parser := &tomlParser{ parser := &tomlParser{
flowIdx: 0,
flow: flow, flow: flow,
tree: result, tree: result,
tokensBuffer: make([]token, 0),
currentTable: make([]string, 0), currentTable: make([]string, 0),
seenTableKeys: make([]string, 0), seenTableKeys: make([]string, 0),
} }

View File

@ -4,20 +4,25 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"runtime" "runtime"
"strings" "strings"
) )
type tomlValue struct { type tomlValue struct {
value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
position Position comment string
commented bool
position Position
} }
// Tree is the result of the parsing of a TOML file. // Tree is the result of the parsing of a TOML file.
type Tree struct { type Tree struct {
values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
position Position comment string
commented bool
position Position
} }
func newTree() *Tree { func newTree() *Tree {
@ -54,8 +59,7 @@ func (t *Tree) HasPath(keys []string) bool {
return t.GetPath(keys) != nil return t.GetPath(keys) != nil
} }
// Keys returns the keys of the toplevel tree. // Keys returns the keys of the toplevel tree (does not recurse).
// Warning: this is a costly operation.
func (t *Tree) Keys() []string { func (t *Tree) Keys() []string {
keys := make([]string, len(t.values)) keys := make([]string, len(t.values))
i := 0 i := 0
@ -177,14 +181,14 @@ func (t *Tree) GetDefault(key string, def interface{}) interface{} {
// Set an element in the tree. // Set an element in the tree.
// Key is a dot-separated path (e.g. a.b.c). // Key is a dot-separated path (e.g. a.b.c).
// Creates all necessary intermediate trees, if needed. // Creates all necessary intermediate trees, if needed.
func (t *Tree) Set(key string, value interface{}) { func (t *Tree) Set(key string, comment string, commented bool, value interface{}) {
t.SetPath(strings.Split(key, "."), value) t.SetPath(strings.Split(key, "."), comment, commented, value)
} }
// SetPath sets an element in the tree. // SetPath sets an element in the tree.
// Keys is an array of path elements (e.g. {"a","b","c"}). // Keys is an array of path elements (e.g. {"a","b","c"}).
// Creates all necessary intermediate trees, if needed. // Creates all necessary intermediate trees, if needed.
func (t *Tree) SetPath(keys []string, value interface{}) { func (t *Tree) SetPath(keys []string, comment string, commented bool, value interface{}) {
subtree := t subtree := t
for _, intermediateKey := range keys[:len(keys)-1] { for _, intermediateKey := range keys[:len(keys)-1] {
nextTree, exists := subtree.values[intermediateKey] nextTree, exists := subtree.values[intermediateKey]
@ -209,13 +213,17 @@ func (t *Tree) SetPath(keys []string, value interface{}) {
switch value.(type) { switch value.(type) {
case *Tree: case *Tree:
tt := value.(*Tree)
tt.comment = comment
toInsert = value toInsert = value
case []*Tree: case []*Tree:
toInsert = value toInsert = value
case *tomlValue: case *tomlValue:
toInsert = value tt := value.(*tomlValue)
tt.comment = comment
toInsert = tt
default: default:
toInsert = &tomlValue{value: value} toInsert = &tomlValue{value: value, comment: comment, commented: commented}
} }
subtree.values[keys[len(keys)-1]] = toInsert subtree.values[keys[len(keys)-1]] = toInsert
@ -252,8 +260,8 @@ func (t *Tree) createSubTree(keys []string, pos Position) error {
return nil return nil
} }
// LoadReader creates a Tree from any io.Reader. // LoadBytes creates a Tree from a []byte.
func LoadReader(reader io.Reader) (tree *Tree, err error) { func LoadBytes(b []byte) (tree *Tree, err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok { if _, ok := r.(runtime.Error); ok {
@ -262,13 +270,23 @@ func LoadReader(reader io.Reader) (tree *Tree, err error) {
err = errors.New(r.(string)) err = errors.New(r.(string))
} }
}() }()
tree = parseToml(lexToml(reader)) tree = parseToml(lexToml(b))
return
}
// LoadReader creates a Tree from any io.Reader.
func LoadReader(reader io.Reader) (tree *Tree, err error) {
inputBytes, err := ioutil.ReadAll(reader)
if err != nil {
return
}
tree, err = LoadBytes(inputBytes)
return return
} }
// Load creates a Tree from a string. // Load creates a Tree from a string.
func Load(content string) (tree *Tree, err error) { func Load(content string) (tree *Tree, err error) {
return LoadReader(strings.NewReader(content)) return LoadBytes([]byte(content))
} }
// LoadFile creates a Tree from a file. // LoadFile creates a Tree from a file.

View File

@ -104,7 +104,7 @@ func sliceToTree(object interface{}) (interface{}, error) {
} }
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue)) arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
} }
return &tomlValue{arrayValue.Interface(), Position{}}, nil return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
} }
func toTree(object interface{}) (interface{}, error) { func toTree(object interface{}) (interface{}, error) {
@ -127,7 +127,7 @@ func toTree(object interface{}) (interface{}, error) {
} }
values[key.String()] = newValue values[key.String()] = newValue
} }
return &Tree{values, Position{}}, nil return &Tree{values: values, position: Position{}}, nil
} }
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice { if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
@ -138,5 +138,5 @@ func toTree(object interface{}) (interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &tomlValue{simpleValue, Position{}}, nil return &tomlValue{value: simpleValue, position: Position{}}, nil
} }

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"math"
"reflect" "reflect"
"sort" "sort"
"strconv" "strconv"
@ -13,33 +14,34 @@ import (
// encodes a string to a TOML-compliant string value // encodes a string to a TOML-compliant string value
func encodeTomlString(value string) string { func encodeTomlString(value string) string {
result := "" var b bytes.Buffer
for _, rr := range value { for _, rr := range value {
switch rr { switch rr {
case '\b': case '\b':
result += "\\b" b.WriteString(`\b`)
case '\t': case '\t':
result += "\\t" b.WriteString(`\t`)
case '\n': case '\n':
result += "\\n" b.WriteString(`\n`)
case '\f': case '\f':
result += "\\f" b.WriteString(`\f`)
case '\r': case '\r':
result += "\\r" b.WriteString(`\r`)
case '"': case '"':
result += "\\\"" b.WriteString(`\"`)
case '\\': case '\\':
result += "\\\\" b.WriteString(`\\`)
default: default:
intRr := uint16(rr) intRr := uint16(rr)
if intRr < 0x001F { if intRr < 0x001F {
result += fmt.Sprintf("\\u%0.4X", intRr) b.WriteString(fmt.Sprintf("\\u%0.4X", intRr))
} else { } else {
result += string(rr) b.WriteRune(rr)
} }
} }
} }
return result return b.String()
} }
func tomlValueStringRepresentation(v interface{}) (string, error) { func tomlValueStringRepresentation(v interface{}) (string, error) {
@ -49,6 +51,11 @@ func tomlValueStringRepresentation(v interface{}) (string, error) {
case int64: case int64:
return strconv.FormatInt(value, 10), nil return strconv.FormatInt(value, 10), nil
case float64: case float64:
// Ensure a round float does contain a decimal point. Otherwise feeding
// the output back to the parser would convert to an integer.
if math.Trunc(value) == value {
return strconv.FormatFloat(value, 'f', 1, 32), nil
}
return strconv.FormatFloat(value, 'f', -1, 32), nil return strconv.FormatFloat(value, 'f', -1, 32), nil
case string: case string:
return "\"" + encodeTomlString(value) + "\"", nil return "\"" + encodeTomlString(value) + "\"", nil
@ -111,8 +118,24 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
return bytesCount, err return bytesCount, err
} }
kvRepr := fmt.Sprintf("%s%s = %s\n", indent, k, repr) if v.comment != "" {
writtenBytesCount, err := w.Write([]byte(kvRepr)) comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1)
start := "# "
if strings.HasPrefix(comment, "#") {
start = ""
}
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n")
bytesCount += int64(writtenBytesCountComment)
if errc != nil {
return bytesCount, errc
}
}
var commented string
if v.commented {
commented = "# "
}
writtenBytesCount, err := writeStrings(w, indent, commented, k, " = ", repr, "\n")
bytesCount += int64(writtenBytesCount) bytesCount += int64(writtenBytesCount)
if err != nil { if err != nil {
return bytesCount, err return bytesCount, err
@ -126,12 +149,31 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
if keyspace != "" { if keyspace != "" {
combinedKey = keyspace + "." + combinedKey combinedKey = keyspace + "." + combinedKey
} }
var commented string
if t.commented {
commented = "# "
}
switch node := v.(type) { switch node := v.(type) {
// node has to be of those two types given how keys are sorted above // node has to be of those two types given how keys are sorted above
case *Tree: case *Tree:
tableName := fmt.Sprintf("\n%s[%s]\n", indent, combinedKey) tv, ok := t.values[k].(*Tree)
writtenBytesCount, err := w.Write([]byte(tableName)) if !ok {
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
}
if tv.comment != "" {
comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1)
start := "# "
if strings.HasPrefix(comment, "#") {
start = ""
}
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment)
bytesCount += int64(writtenBytesCountComment)
if errc != nil {
return bytesCount, errc
}
}
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
bytesCount += int64(writtenBytesCount) bytesCount += int64(writtenBytesCount)
if err != nil { if err != nil {
return bytesCount, err return bytesCount, err
@ -142,18 +184,15 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
} }
case []*Tree: case []*Tree:
for _, subTree := range node { for _, subTree := range node {
if len(subTree.values) > 0 { writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
tableArrayName := fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey) bytesCount += int64(writtenBytesCount)
writtenBytesCount, err := w.Write([]byte(tableArrayName)) if err != nil {
bytesCount += int64(writtenBytesCount) return bytesCount, err
if err != nil { }
return bytesCount, err
}
bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount) bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount)
if err != nil { if err != nil {
return bytesCount, err return bytesCount, err
}
} }
} }
} }
@ -162,6 +201,18 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
return bytesCount, nil return bytesCount, nil
} }
func writeStrings(w io.Writer, s ...string) (int, error) {
var n int
for i := range s {
b, err := io.WriteString(w, s[i])
n += b
if err != nil {
return n, err
}
}
return n, nil
}
// WriteTo encode the Tree as Toml and writes it to the writer w. // WriteTo encode the Tree as Toml and writes it to the writer w.
// Returns the number of bytes written in case of success, or an error if anything happened. // Returns the number of bytes written in case of success, or an error if anything happened.
func (t *Tree) WriteTo(w io.Writer) (int64, error) { func (t *Tree) WriteTo(w io.Writer) (int64, error) {

View File

@ -79,6 +79,14 @@ func (f Frame) Format(s fmt.State, verb rune) {
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). // StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame type StackTrace []Frame
// Format formats the stack of Frames according to the fmt.Formatter interface.
//
// %s lists source files for each Frame in the stack
// %v lists the source file and line number for each Frame in the stack
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+v Prints filename, function, and line number for each Frame in the stack.
func (st StackTrace) Format(s fmt.State, verb rune) { func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb { switch verb {
case 'v': case 'v':

110
vendor/github.com/spf13/afero/match.go generated vendored Normal file
View File

@ -0,0 +1,110 @@
// Copyright © 2014 Steve Francia <spf@spf13.com>.
// Copyright 2009 The Go Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package afero
import (
"path/filepath"
"sort"
"strings"
)
// Glob returns the names of all files matching pattern or nil
// if there is no matching file. The syntax of patterns is the same
// as in Match. The pattern may describe hierarchical names such as
// /usr/*/bin/ed (assuming the Separator is '/').
//
// Glob ignores file system errors such as I/O errors reading directories.
// The only possible returned error is ErrBadPattern, when pattern
// is malformed.
//
// This was adapted from (http://golang.org/pkg/path/filepath) and uses several
// built-ins from that package.
func Glob(fs Fs, pattern string) (matches []string, err error) {
if !hasMeta(pattern) {
// afero does not support Lstat directly.
if _, err = lstatIfOs(fs, pattern); err != nil {
return nil, nil
}
return []string{pattern}, nil
}
dir, file := filepath.Split(pattern)
switch dir {
case "":
dir = "."
case string(filepath.Separator):
// nothing
default:
dir = dir[0 : len(dir)-1] // chop off trailing separator
}
if !hasMeta(dir) {
return glob(fs, dir, file, nil)
}
var m []string
m, err = Glob(fs, dir)
if err != nil {
return
}
for _, d := range m {
matches, err = glob(fs, d, file, matches)
if err != nil {
return
}
}
return
}
// glob searches for files matching pattern in the directory dir
// and appends them to matches. If the directory cannot be
// opened, it returns the existing matches. New matches are
// added in lexicographical order.
func glob(fs Fs, dir, pattern string, matches []string) (m []string, e error) {
m = matches
fi, err := fs.Stat(dir)
if err != nil {
return
}
if !fi.IsDir() {
return
}
d, err := fs.Open(dir)
if err != nil {
return
}
defer d.Close()
names, _ := d.Readdirnames(-1)
sort.Strings(names)
for _, n := range names {
matched, err := filepath.Match(pattern, n)
if err != nil {
return m, err
}
if matched {
m = append(m, filepath.Join(dir, n))
}
}
return
}
// hasMeta reports whether path contains any of the magic characters
// recognized by Match.
func hasMeta(path string) bool {
// TODO(niemeyer): Should other magic characters be added here?
return strings.IndexAny(path, "*?[") >= 0
}

View File

@ -66,7 +66,10 @@ func (m *MemMapFs) unRegisterWithParent(fileName string) error {
if parent == nil { if parent == nil {
log.Panic("parent of ", f.Name(), " is nil") log.Panic("parent of ", f.Name(), " is nil")
} }
parent.Lock()
mem.RemoveFromMemDir(parent, f) mem.RemoveFromMemDir(parent, f)
parent.Unlock()
return nil return nil
} }
@ -99,8 +102,10 @@ func (m *MemMapFs) registerWithParent(f *mem.FileData) {
} }
} }
parent.Lock()
mem.InitializeDir(parent) mem.InitializeDir(parent)
mem.AddToMemDir(parent, f) mem.AddToMemDir(parent, f)
parent.Unlock()
} }
func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error { func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {

98
vendor/github.com/spf13/cobra/args.go generated vendored Normal file
View File

@ -0,0 +1,98 @@
package cobra
import (
"fmt"
)
type PositionalArgs func(cmd *Command, args []string) error
// Legacy arg validation has the following behaviour:
// - root commands with no subcommands can take arbitrary arguments
// - root commands with subcommands will do subcommand validity checking
// - subcommands will always accept arbitrary arguments
func legacyArgs(cmd *Command, args []string) error {
// no subcommand, always take args
if !cmd.HasSubCommands() {
return nil
}
// root command with subcommands, do subcommand checking
if !cmd.HasParent() && len(args) > 0 {
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
}
return nil
}
// NoArgs returns an error if any args are included
func NoArgs(cmd *Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
}
return nil
}
// OnlyValidArgs returns an error if any args are not in the list of ValidArgs
func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 {
for _, v := range args {
if !stringInSlice(v, cmd.ValidArgs) {
return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
}
}
}
return nil
}
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
// ArbitraryArgs never returns an error
func ArbitraryArgs(cmd *Command, args []string) error {
return nil
}
// MinimumNArgs returns an error if there is not at least N args
func MinimumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) < n {
return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args))
}
return nil
}
}
// MaximumNArgs returns an error if there are more than N args
func MaximumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) > n {
return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args))
}
return nil
}
}
// ExactArgs returns an error if there are not exactly n args
func ExactArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) != n {
return fmt.Errorf("accepts %d arg(s), received %d", n, len(args))
}
return nil
}
}
// RangeArgs returns an error if the number of args is not within the expected range
func RangeArgs(min int, max int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) < min || len(args) > max {
return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args))
}
return nil
}
}

View File

@ -132,7 +132,10 @@ __handle_reply()
declare -F __custom_func >/dev/null && __custom_func declare -F __custom_func >/dev/null && __custom_func
fi fi
__ltrim_colon_completions "$cur" # available in bash-completion >= 2, not always present on macOS
if declare -F __ltrim_colon_completions >/dev/null; then
__ltrim_colon_completions "$cur"
fi
} }
# The arguments should be in the form "ext1|ext2|extn" # The arguments should be in the form "ext1|ext2|extn"
@ -460,14 +463,14 @@ func gen(buf *bytes.Buffer, cmd *Command) {
} }
// GenBashCompletion generates bash completion file and writes to the passed writer. // GenBashCompletion generates bash completion file and writes to the passed writer.
func (cmd *Command) GenBashCompletion(w io.Writer) error { func (c *Command) GenBashCompletion(w io.Writer) error {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
writePreamble(buf, cmd.Name()) writePreamble(buf, c.Name())
if len(cmd.BashCompletionFunction) > 0 { if len(c.BashCompletionFunction) > 0 {
buf.WriteString(cmd.BashCompletionFunction + "\n") buf.WriteString(c.BashCompletionFunction + "\n")
} }
gen(buf, cmd) gen(buf, c)
writePostscript(buf, cmd.Name()) writePostscript(buf, c.Name())
_, err := buf.WriteTo(w) _, err := buf.WriteTo(w)
return err return err
@ -478,24 +481,24 @@ func nonCompletableFlag(flag *pflag.Flag) bool {
} }
// GenBashCompletionFile generates bash completion file. // GenBashCompletionFile generates bash completion file.
func (cmd *Command) GenBashCompletionFile(filename string) error { func (c *Command) GenBashCompletionFile(filename string) error {
outFile, err := os.Create(filename) outFile, err := os.Create(filename)
if err != nil { if err != nil {
return err return err
} }
defer outFile.Close() defer outFile.Close()
return cmd.GenBashCompletion(outFile) return c.GenBashCompletion(outFile)
} }
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists. // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag, if it exists.
func (cmd *Command) MarkFlagRequired(name string) error { func (c *Command) MarkFlagRequired(name string) error {
return MarkFlagRequired(cmd.Flags(), name) return MarkFlagRequired(c.Flags(), name)
} }
// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists. // MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag, if it exists.
func (cmd *Command) MarkPersistentFlagRequired(name string) error { func (c *Command) MarkPersistentFlagRequired(name string) error {
return MarkFlagRequired(cmd.PersistentFlags(), name) return MarkFlagRequired(c.PersistentFlags(), name)
} }
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists. // MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag in the flag set, if it exists.
@ -505,20 +508,20 @@ func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
func (cmd *Command) MarkFlagFilename(name string, extensions ...string) error { func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
return MarkFlagFilename(cmd.Flags(), name, extensions...) return MarkFlagFilename(c.Flags(), name, extensions...)
} }
// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. // MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
// Generated bash autocompletion will call the bash function f for the flag. // Generated bash autocompletion will call the bash function f for the flag.
func (cmd *Command) MarkFlagCustom(name string, f string) error { func (c *Command) MarkFlagCustom(name string, f string) error {
return MarkFlagCustom(cmd.Flags(), name, f) return MarkFlagCustom(c.Flags(), name, f)
} }
// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists. // MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists.
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. // Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
func (cmd *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
return MarkFlagFilename(cmd.PersistentFlags(), name, extensions...) return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
} }
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. // MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists.

View File

@ -47,6 +47,15 @@ var EnablePrefixMatching = false
// To disable sorting, set it to false. // To disable sorting, set it to false.
var EnableCommandSorting = true var EnableCommandSorting = true
// MousetrapHelpText enables an information splash screen on Windows
// if the CLI is started from explorer.exe.
// To disable the mousetrap, just set this variable to blank string ("").
// Works only on Microsoft Windows.
var MousetrapHelpText string = `This is a command line tool.
You need to open cmd.exe and run it from there.
`
// AddTemplateFunc adds a template function that's available to Usage and Help // AddTemplateFunc adds a template function that's available to Usage and Help
// template generation. // template generation.
func AddTemplateFunc(name string, tmplFunc interface{}) { func AddTemplateFunc(name string, tmplFunc interface{}) {

View File

@ -54,6 +54,9 @@ type Command struct {
// ValidArgs is list of all valid non-flag arguments that are accepted in bash completions // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions
ValidArgs []string ValidArgs []string
// Expected arguments
Args PositionalArgs
// ArgAliases is List of aliases for ValidArgs. // ArgAliases is List of aliases for ValidArgs.
// These are not suggested to the user in the bash completion, // These are not suggested to the user in the bash completion,
// but accepted if entered manually. // but accepted if entered manually.
@ -513,33 +516,29 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
} }
commandFound, a := innerfind(c, args) commandFound, a := innerfind(c, args)
argsWOflags := stripFlags(a, commandFound) if commandFound.Args == nil {
return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound))
// no subcommand, always take args
if !commandFound.HasSubCommands() {
return commandFound, a, nil
} }
// root command with subcommands, do subcommand checking
if commandFound == c && len(argsWOflags) > 0 {
suggestionsString := ""
if !c.DisableSuggestions {
if c.SuggestionsMinimumDistance <= 0 {
c.SuggestionsMinimumDistance = 2
}
if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 {
suggestionsString += "\n\nDid you mean this?\n"
for _, s := range suggestions {
suggestionsString += fmt.Sprintf("\t%v\n", s)
}
}
}
return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestionsString)
}
return commandFound, a, nil return commandFound, a, nil
} }
func (c *Command) findSuggestions(arg string) string {
if c.DisableSuggestions {
return ""
}
if c.SuggestionsMinimumDistance <= 0 {
c.SuggestionsMinimumDistance = 2
}
suggestionsString := ""
if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 {
suggestionsString += "\n\nDid you mean this?\n"
for _, s := range suggestions {
suggestionsString += fmt.Sprintf("\t%v\n", s)
}
}
return suggestionsString
}
// SuggestionsFor provides suggestions for the typedName. // SuggestionsFor provides suggestions for the typedName.
func (c *Command) SuggestionsFor(typedName string) []string { func (c *Command) SuggestionsFor(typedName string) []string {
suggestions := []string{} suggestions := []string{}
@ -624,6 +623,10 @@ func (c *Command) execute(a []string) (err error) {
argWoFlags = a argWoFlags = a
} }
if err := c.ValidateArgs(argWoFlags); err != nil {
return err
}
for p := c; p != nil; p = p.Parent() { for p := c; p != nil; p = p.Parent() {
if p.PersistentPreRunE != nil { if p.PersistentPreRunE != nil {
if err := p.PersistentPreRunE(c, argWoFlags); err != nil { if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
@ -747,6 +750,13 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
return cmd, err return cmd, err
} }
func (c *Command) ValidateArgs(args []string) error {
if c.Args == nil {
return nil
}
return c.Args(c, args)
}
// InitDefaultHelpFlag adds default help flag to c. // InitDefaultHelpFlag adds default help flag to c.
// It is called automatically by executing the c or by calling help and usage. // It is called automatically by executing the c or by calling help and usage.
// If c already has help flag, it will do nothing. // If c already has help flag, it will do nothing.
@ -767,28 +777,28 @@ func (c *Command) InitDefaultHelpFlag() {
// It is called automatically by executing the c or by calling help and usage. // It is called automatically by executing the c or by calling help and usage.
// If c already has help command or c has no subcommands, it will do nothing. // If c already has help command or c has no subcommands, it will do nothing.
func (c *Command) InitDefaultHelpCmd() { func (c *Command) InitDefaultHelpCmd() {
if c.helpCommand != nil || !c.HasSubCommands() { if !c.HasSubCommands() {
return return
} }
c.helpCommand = &Command{ if c.helpCommand == nil {
Use: "help [command]", c.helpCommand = &Command{
Short: "Help about any command", Use: "help [command]",
Long: `Help provides help for any command in the application. Short: "Help about any command",
Simply type ` + c.Name() + ` help [path to command] for full details.`, Long: `Help provides help for any command in the application.
PersistentPreRun: func(cmd *Command, args []string) {}, Simply type ` + c.Name() + ` help [path to command] for full details.`,
PersistentPostRun: func(cmd *Command, args []string) {},
Run: func(c *Command, args []string) { Run: func(c *Command, args []string) {
cmd, _, e := c.Root().Find(args) cmd, _, e := c.Root().Find(args)
if cmd == nil || e != nil { if cmd == nil || e != nil {
c.Printf("Unknown help topic %#q\n", args) c.Printf("Unknown help topic %#q\n", args)
c.Root().Usage() c.Root().Usage()
} else { } else {
cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown
cmd.Help() cmd.Help()
} }
}, },
}
} }
c.RemoveCommand(c.helpCommand) c.RemoveCommand(c.helpCommand)
c.AddCommand(c.helpCommand) c.AddCommand(c.helpCommand)
@ -796,6 +806,7 @@ func (c *Command) InitDefaultHelpCmd() {
// ResetCommands used for testing. // ResetCommands used for testing.
func (c *Command) ResetCommands() { func (c *Command) ResetCommands() {
c.parent = nil
c.commands = nil c.commands = nil
c.helpCommand = nil c.helpCommand = nil
c.parentsPflags = nil c.parentsPflags = nil
@ -1122,6 +1133,9 @@ func (c *Command) LocalFlags() *flag.FlagSet {
c.lflags.SetOutput(c.flagErrorBuf) c.lflags.SetOutput(c.flagErrorBuf)
} }
c.lflags.SortFlags = c.Flags().SortFlags c.lflags.SortFlags = c.Flags().SortFlags
if c.globNormFunc != nil {
c.lflags.SetNormalizeFunc(c.globNormFunc)
}
addToLocal := func(f *flag.Flag) { addToLocal := func(f *flag.Flag) {
if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil { if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil {
@ -1146,6 +1160,10 @@ func (c *Command) InheritedFlags() *flag.FlagSet {
} }
local := c.LocalFlags() local := c.LocalFlags()
if c.globNormFunc != nil {
c.iflags.SetNormalizeFunc(c.globNormFunc)
}
c.parentsPflags.VisitAll(func(f *flag.Flag) { c.parentsPflags.VisitAll(func(f *flag.Flag) {
if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil { if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil {
c.iflags.AddFlag(f) c.iflags.AddFlag(f)
@ -1179,6 +1197,10 @@ func (c *Command) ResetFlags() {
c.flags.SetOutput(c.flagErrorBuf) c.flags.SetOutput(c.flagErrorBuf)
c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
c.pflags.SetOutput(c.flagErrorBuf) c.pflags.SetOutput(c.flagErrorBuf)
c.lflags = nil
c.iflags = nil
c.parentsPflags = nil
} }
// HasFlags checks if the command contains any flags (local plus persistent from the entire structure). // HasFlags checks if the command contains any flags (local plus persistent from the entire structure).
@ -1249,13 +1271,20 @@ func (c *Command) persistentFlag(name string) (flag *flag.Flag) {
} }
// ParseFlags parses persistent flag tree and local flags. // ParseFlags parses persistent flag tree and local flags.
func (c *Command) ParseFlags(args []string) (err error) { func (c *Command) ParseFlags(args []string) error {
if c.DisableFlagParsing { if c.DisableFlagParsing {
return nil return nil
} }
beforeErrorBufLen := c.flagErrorBuf.Len()
c.mergePersistentFlags() c.mergePersistentFlags()
err = c.Flags().Parse(args) err := c.Flags().Parse(args)
return // Print warnings if they occurred (e.g. deprecated flag messages).
if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil {
c.Print(c.flagErrorBuf.String())
}
return err
} }
// Parent returns a commands parent command. // Parent returns a commands parent command.
@ -1281,6 +1310,10 @@ func (c *Command) updateParentsPflags() {
c.parentsPflags.SortFlags = false c.parentsPflags.SortFlags = false
} }
if c.globNormFunc != nil {
c.parentsPflags.SetNormalizeFunc(c.globNormFunc)
}
c.Root().PersistentFlags().AddFlagSet(flag.CommandLine) c.Root().PersistentFlags().AddFlagSet(flag.CommandLine)
c.VisitParents(func(parent *Command) { c.VisitParents(func(parent *Command) {

View File

@ -11,14 +11,8 @@ import (
var preExecHookFn = preExecHook var preExecHookFn = preExecHook
// enables an information splash screen on Windows if the CLI is started from explorer.exe.
var MousetrapHelpText string = `This is a command line tool
You need to open cmd.exe and run it from there.
`
func preExecHook(c *Command) { func preExecHook(c *Command) {
if mousetrap.StartedByExplorer() { if MousetrapHelpText != "" && mousetrap.StartedByExplorer() {
c.Print(MousetrapHelpText) c.Print(MousetrapHelpText)
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
os.Exit(1) os.Exit(1)

126
vendor/github.com/spf13/cobra/zsh_completions.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
package cobra
import (
"bytes"
"fmt"
"io"
"os"
"strings"
)
// GenZshCompletionFile generates zsh completion file.
func (c *Command) GenZshCompletionFile(filename string) error {
outFile, err := os.Create(filename)
if err != nil {
return err
}
defer outFile.Close()
return c.GenZshCompletion(outFile)
}
// GenZshCompletion generates a zsh completion file and writes to the passed writer.
func (c *Command) GenZshCompletion(w io.Writer) error {
buf := new(bytes.Buffer)
writeHeader(buf, c)
maxDepth := maxDepth(c)
writeLevelMapping(buf, maxDepth)
writeLevelCases(buf, maxDepth, c)
_, err := buf.WriteTo(w)
return err
}
func writeHeader(w io.Writer, cmd *Command) {
fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name())
}
func maxDepth(c *Command) int {
if len(c.Commands()) == 0 {
return 0
}
maxDepthSub := 0
for _, s := range c.Commands() {
subDepth := maxDepth(s)
if subDepth > maxDepthSub {
maxDepthSub = subDepth
}
}
return 1 + maxDepthSub
}
func writeLevelMapping(w io.Writer, numLevels int) {
fmt.Fprintln(w, `_arguments \`)
for i := 1; i <= numLevels; i++ {
fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i)
fmt.Fprintln(w)
}
fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files")
fmt.Fprintln(w)
}
func writeLevelCases(w io.Writer, maxDepth int, root *Command) {
fmt.Fprintln(w, "case $state in")
defer fmt.Fprintln(w, "esac")
for i := 1; i <= maxDepth; i++ {
fmt.Fprintf(w, " level%d)\n", i)
writeLevel(w, root, i)
fmt.Fprintln(w, " ;;")
}
fmt.Fprintln(w, " *)")
fmt.Fprintln(w, " _arguments '*: :_files'")
fmt.Fprintln(w, " ;;")
}
func writeLevel(w io.Writer, root *Command, i int) {
fmt.Fprintf(w, " case $words[%d] in\n", i)
defer fmt.Fprintln(w, " esac")
commands := filterByLevel(root, i)
byParent := groupByParent(commands)
for p, c := range byParent {
names := names(c)
fmt.Fprintf(w, " %s)\n", p)
fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " "))
fmt.Fprintln(w, " ;;")
}
fmt.Fprintln(w, " *)")
fmt.Fprintln(w, " _arguments '*: :_files'")
fmt.Fprintln(w, " ;;")
}
func filterByLevel(c *Command, l int) []*Command {
cs := make([]*Command, 0)
if l == 0 {
cs = append(cs, c)
return cs
}
for _, s := range c.Commands() {
cs = append(cs, filterByLevel(s, l-1)...)
}
return cs
}
func groupByParent(commands []*Command) map[string][]*Command {
m := make(map[string][]*Command)
for _, c := range commands {
parent := c.Parent()
if parent == nil {
continue
}
m[parent.Name()] = append(m[parent.Name()], c)
}
return m
}
func names(commands []*Command) []string {
ns := make([]string, len(commands))
for i, c := range commands {
ns[i] = c.Name()
}
return ns
}

View File

@ -148,7 +148,7 @@ func (n *Notepad) GetStdoutThreshold() Threshold {
} }
// SetPrefix changes the prefix used by the notepad. Prefixes are displayed between // SetPrefix changes 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. // brackets at the beginning of the line. An empty prefix won't be displayed at all.
func (n *Notepad) SetPrefix(prefix string) { func (n *Notepad) SetPrefix(prefix string) {
if len(prefix) != 0 { if len(prefix) != 0 {
n.prefix = "[" + prefix + "] " n.prefix = "[" + prefix + "] "

View File

@ -202,12 +202,18 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
f.normalizeNameFunc = n f.normalizeNameFunc = n
f.sortedFormal = f.sortedFormal[:0] f.sortedFormal = f.sortedFormal[:0]
for k, v := range f.orderedFormal { for fname, flag := range f.formal {
delete(f.formal, NormalizedName(v.Name)) nname := f.normalizeFlagName(flag.Name)
nname := f.normalizeFlagName(v.Name) if fname == nname {
v.Name = string(nname) continue
f.formal[nname] = v }
f.orderedFormal[k] = v flag.Name = string(nname)
delete(f.formal, fname)
f.formal[nname] = flag
if _, set := f.actual[fname]; set {
delete(f.actual, fname)
f.actual[nname] = flag
}
} }
} }
@ -440,13 +446,15 @@ func (f *FlagSet) Set(name, value string) error {
return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err) return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
} }
if f.actual == nil { if !flag.Changed {
f.actual = make(map[NormalizedName]*Flag) if f.actual == nil {
} f.actual = make(map[NormalizedName]*Flag)
f.actual[normalName] = flag }
f.orderedActual = append(f.orderedActual, flag) f.actual[normalName] = flag
f.orderedActual = append(f.orderedActual, flag)
flag.Changed = true flag.Changed = true
}
if flag.Deprecated != "" { if flag.Deprecated != "" {
fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
@ -556,6 +564,10 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
name = "int" name = "int"
case "uint64": case "uint64":
name = "uint" name = "uint"
case "stringSlice":
name = "strings"
case "intSlice":
name = "ints"
} }
return return
@ -912,6 +924,9 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
} }
err = fn(flag, value) err = fn(flag, value)
if err != nil {
f.failf(err.Error())
}
return return
} }
@ -962,6 +977,9 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse
} }
err = fn(flag, value) err = fn(flag, value)
if err != nil {
f.failf(err.Error())
}
return return
} }

View File

@ -39,13 +39,58 @@ func (pe ConfigParseError) Error() string {
return fmt.Sprintf("While parsing config: %s", pe.err.Error()) return fmt.Sprintf("While parsing config: %s", pe.err.Error())
} }
// toCaseInsensitiveValue checks if the value is a map;
// if so, create a copy and lower-case the keys recursively.
func toCaseInsensitiveValue(value interface{}) interface{} {
switch v := value.(type) {
case map[interface{}]interface{}:
value = copyAndInsensitiviseMap(cast.ToStringMap(v))
case map[string]interface{}:
value = copyAndInsensitiviseMap(v)
}
return value
}
// copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of
// any map it makes case insensitive.
func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
nm := make(map[string]interface{})
for key, val := range m {
lkey := strings.ToLower(key)
switch v := val.(type) {
case map[interface{}]interface{}:
nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v))
case map[string]interface{}:
nm[lkey] = copyAndInsensitiviseMap(v)
default:
nm[lkey] = v
}
}
return nm
}
func insensitiviseMap(m map[string]interface{}) { func insensitiviseMap(m map[string]interface{}) {
for key, val := range m { for key, val := range m {
switch val.(type) {
case map[interface{}]interface{}:
// nested map: cast and recursively insensitivise
val = cast.ToStringMap(val)
insensitiviseMap(val.(map[string]interface{}))
case map[string]interface{}:
// nested map: recursively insensitivise
insensitiviseMap(val.(map[string]interface{}))
}
lower := strings.ToLower(key) lower := strings.ToLower(key)
if key != lower { if key != lower {
// remove old key (not lower-cased)
delete(m, key) delete(m, key)
m[lower] = val
} }
// update map
m[lower] = val
} }
} }
@ -149,7 +194,12 @@ func unmarshallConfigReader(in io.Reader, c map[string]interface{}, configType s
} }
for _, key := range p.Keys() { for _, key := range p.Keys() {
value, _ := p.Get(key) value, _ := p.Get(key)
c[key] = value // recursively build nested maps
path := strings.Split(key, ".")
lastKey := strings.ToLower(path[len(path)-1])
deepestMap := deepSearch(c, path[0:len(path)-1])
// set innermost value
deepestMap[lastKey] = value
} }
} }
@ -199,3 +249,34 @@ func parseSizeInBytes(sizeStr string) uint {
return safeMul(uint(size), multiplier) return safeMul(uint(size), multiplier)
} }
// deepSearch scans deep maps, following the key indexes listed in the
// sequence "path".
// The last value is expected to be another map, and is returned.
//
// In case intermediate keys do not exist, or map to a non-map value,
// a new map is created and inserted, and the search continues from there:
// the initial map "m" may be modified!
func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
for _, k := range path {
m2, ok := m[k]
if !ok {
// intermediate key does not exist
// => create it and continue from there
m3 := make(map[string]interface{})
m[k] = m3
m = m3
continue
}
m3, ok := m2.(map[string]interface{})
if !ok {
// intermediate key is a value
// => replace with a new map
m3 = make(map[string]interface{})
m[k] = m3
}
// continue search from here
m = m3
}
return m
}

View File

@ -21,6 +21,7 @@ package viper
import ( import (
"bytes" "bytes"
"encoding/csv"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -40,6 +41,11 @@ import (
var v *Viper var v *Viper
type RemoteResponse struct {
Value []byte
Error error
}
func init() { func init() {
v = New() v = New()
} }
@ -47,6 +53,7 @@ func init() {
type remoteConfigFactory interface { type remoteConfigFactory interface {
Get(rp RemoteProvider) (io.Reader, error) Get(rp RemoteProvider) (io.Reader, error)
Watch(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 // RemoteConfig is optional, see the remote package
@ -62,8 +69,7 @@ func (str UnsupportedConfigError) Error() string {
} }
// UnsupportedRemoteProviderError denotes encountering an unsupported remote // UnsupportedRemoteProviderError denotes encountering an unsupported remote
// provider. Currently only etcd and Consul are // provider. Currently only etcd and Consul are supported.
// supported.
type UnsupportedRemoteProviderError string type UnsupportedRemoteProviderError string
// Error returns the formatted remote provider error. // Error returns the formatted remote provider error.
@ -107,11 +113,11 @@ func (fnfe ConfigFileNotFoundError) Error() string {
// Defaults : { // Defaults : {
// "secret": "", // "secret": "",
// "user": "default", // "user": "default",
// "endpoint": "https://localhost" // "endpoint": "https://localhost"
// } // }
// Config : { // Config : {
// "user": "root" // "user": "root"
// "secret": "defaultsecret" // "secret": "defaultsecret"
// } // }
// Env : { // Env : {
// "secret": "somesecretkey" // "secret": "somesecretkey"
@ -241,7 +247,13 @@ func (v *Viper) WatchConfig() {
defer watcher.Close() defer watcher.Close()
// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way // we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
configFile := filepath.Clean(v.getConfigFile()) filename, err := v.getConfigFile()
if err != nil {
log.Println("error:", err)
return
}
configFile := filepath.Clean(filename)
configDir, _ := filepath.Split(configFile) configDir, _ := filepath.Split(configFile)
done := make(chan bool) done := make(chan bool)
@ -270,8 +282,8 @@ func (v *Viper) WatchConfig() {
}() }()
} }
// SetConfigFile explicitly defines the path, name and extension of the config file // SetConfigFile explicitly defines the path, name and extension of the config file.
// Viper will use this and not check any of the config paths // Viper will use this and not check any of the config paths.
func SetConfigFile(in string) { v.SetConfigFile(in) } func SetConfigFile(in string) { v.SetConfigFile(in) }
func (v *Viper) SetConfigFile(in string) { func (v *Viper) SetConfigFile(in string) {
if in != "" { if in != "" {
@ -280,8 +292,8 @@ func (v *Viper) SetConfigFile(in string) {
} }
// SetEnvPrefix defines a prefix that ENVIRONMENT variables will use. // SetEnvPrefix defines a prefix that ENVIRONMENT variables will use.
// E.g. if your prefix is "spf", the env registry // E.g. if your prefix is "spf", the env registry will look for env
// will look for env. variables that start with "SPF_" // variables that start with "SPF_".
func SetEnvPrefix(in string) { v.SetEnvPrefix(in) } func SetEnvPrefix(in string) { v.SetEnvPrefix(in) }
func (v *Viper) SetEnvPrefix(in string) { func (v *Viper) SetEnvPrefix(in string) {
if in != "" { if in != "" {
@ -299,11 +311,11 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
// TODO: should getEnv logic be moved into find(). Can generalize the use of // TODO: should getEnv logic be moved into find(). Can generalize the use of
// rewriting keys many things, Ex: Get('someKey') -> some_key // rewriting keys many things, Ex: Get('someKey') -> some_key
// (cammel case to snake case for JSON keys perhaps) // (camel case to snake case for JSON keys perhaps)
// getEnv is a wrapper around os.Getenv which replaces characters in the original // getEnv is a wrapper around os.Getenv which replaces characters in the original
// key. This allows env vars which have different keys then the config object // key. This allows env vars which have different keys than the config object
// keys // keys.
func (v *Viper) getEnv(key string) string { func (v *Viper) getEnv(key string) string {
if v.envKeyReplacer != nil { if v.envKeyReplacer != nil {
key = v.envKeyReplacer.Replace(key) key = v.envKeyReplacer.Replace(key)
@ -311,7 +323,7 @@ func (v *Viper) getEnv(key string) string {
return os.Getenv(key) return os.Getenv(key)
} }
// ConfigFileUsed returns the file used to populate the config registry // ConfigFileUsed returns the file used to populate the config registry.
func ConfigFileUsed() string { return v.ConfigFileUsed() } func ConfigFileUsed() string { return v.ConfigFileUsed() }
func (v *Viper) ConfigFileUsed() string { return v.configFile } func (v *Viper) ConfigFileUsed() string { return v.configFile }
@ -399,23 +411,22 @@ func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
return false return false
} }
// searchMap recursively searches for a value for path in source map.
// Returns nil if not found.
// Note: This assumes that the path entries and map keys are lower cased.
func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} {
if len(path) == 0 { if len(path) == 0 {
return source return source
} }
var ok bool next, ok := source[path[0]]
var next interface{}
for k, v := range source {
if strings.ToLower(k) == strings.ToLower(path[0]) {
ok = true
next = v
break
}
}
if ok { if ok {
// Fast path
if len(path) == 1 {
return next
}
// Nested case
switch next.(type) { switch next.(type) {
case map[interface{}]interface{}: case map[interface{}]interface{}:
return v.searchMap(cast.ToStringMap(next), path[1:]) return v.searchMap(cast.ToStringMap(next), path[1:])
@ -424,11 +435,126 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
// if the type of `next` is the same as the type being asserted // if the type of `next` is the same as the type being asserted
return v.searchMap(next.(map[string]interface{}), path[1:]) return v.searchMap(next.(map[string]interface{}), path[1:])
default: default:
return next // got a value but nested key expected, return "nil" for not found
return nil
} }
} else {
return nil
} }
return nil
}
// searchMapWithPathPrefixes recursively searches for a value for path in source map.
//
// While searchMap() considers each path element as a single map key, this
// function searches for, and prioritizes, merged path elements.
// e.g., if in the source, "foo" is defined with a sub-key "bar", and "foo.bar"
// is also defined, this latter value is returned for path ["foo", "bar"].
//
// This should be useful only at config level (other maps may not contain dots
// in their keys).
//
// Note: This assumes that the path entries and map keys are lower cased.
func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []string) interface{} {
if len(path) == 0 {
return source
}
// search for path prefixes, starting from the longest one
for i := len(path); i > 0; i-- {
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
next, ok := source[prefixKey]
if ok {
// Fast path
if i == len(path) {
return next
}
// Nested case
var val interface{}
switch next.(type) {
case map[interface{}]interface{}:
val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:])
case map[string]interface{}:
// Type assertion is safe here since it is only reached
// if the type of `next` is the same as the type being asserted
val = v.searchMapWithPathPrefixes(next.(map[string]interface{}), path[i:])
default:
// got a value but nested key expected, do nothing and look for next prefix
}
if val != nil {
return val
}
}
}
// not found
return nil
}
// isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere
// on its path in the map.
// e.g., if "foo.bar" has a value in the given map, it “shadows”
// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string {
var parentVal interface{}
for i := 1; i < len(path); i++ {
parentVal = v.searchMap(m, path[0:i])
if parentVal == nil {
// not found, no need to add more path elements
return ""
}
switch parentVal.(type) {
case map[interface{}]interface{}:
continue
case map[string]interface{}:
continue
default:
// parentVal is a regular value which shadows "path"
return strings.Join(path[0:i], v.keyDelim)
}
}
return ""
}
// isPathShadowedInFlatMap makes sure the given path is not shadowed somewhere
// in a sub-path of the map.
// e.g., if "foo.bar" has a value in the given map, it “shadows”
// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string {
// unify input map
var m map[string]interface{}
switch mi.(type) {
case map[string]string, map[string]FlagValue:
m = cast.ToStringMap(mi)
default:
return ""
}
// scan paths
var parentKey string
for i := 1; i < len(path); i++ {
parentKey = strings.Join(path[0:i], v.keyDelim)
if _, ok := m[parentKey]; ok {
return parentKey
}
}
return ""
}
// isPathShadowedInAutoEnv makes sure the given path is not shadowed somewhere
// in the environment, when automatic env is on.
// e.g., if "foo.bar" has a value in the environment, it “shadows”
// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
var parentKey string
var val string
for i := 1; i < len(path); i++ {
parentKey = strings.Join(path[0:i], v.keyDelim)
if val = v.getEnv(v.mergeWithEnvPrefix(parentKey)); val != "" {
return parentKey
}
}
return ""
} }
// SetTypeByDefaultValue enables or disables the inference of a key value's // SetTypeByDefaultValue enables or disables the inference of a key value's
@ -456,6 +582,7 @@ func GetViper() *Viper {
} }
// Get can retrieve any value given the key to use. // Get can retrieve any value given the key to use.
// Get is case-insensitive for a key.
// Get has the behavior of returning the value associated with the first // Get has the behavior of returning the value associated with the first
// place from where it is set. Viper will check in the following order: // place from where it is set. Viper will check in the following order:
// override, flag, env, config file, key/value store, default // override, flag, env, config file, key/value store, default
@ -465,73 +592,50 @@ func Get(key string) interface{} { return v.Get(key) }
func (v *Viper) Get(key string) interface{} { func (v *Viper) Get(key string) interface{} {
lcaseKey := strings.ToLower(key) lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey) val := v.find(lcaseKey)
if val == nil {
path := strings.Split(key, v.keyDelim)
source := v.find(strings.ToLower(path[0]))
if source != nil {
if reflect.TypeOf(source).Kind() == reflect.Map {
val = v.searchMap(cast.ToStringMap(source), path[1:])
}
}
}
// if no other value is returned and a flag does exist for the value,
// get the flag's value even if the flag's value has not changed
if val == nil {
if flag, exists := v.pflags[lcaseKey]; exists {
jww.TRACE.Println(key, "get pflag default", val)
switch flag.ValueType() {
case "int", "int8", "int16", "int32", "int64":
val = cast.ToInt(flag.ValueString())
case "bool":
val = cast.ToBool(flag.ValueString())
default:
val = flag.ValueString()
}
}
}
if val == nil { if val == nil {
return nil return nil
} }
var valType interface{} if v.typeByDefValue {
if !v.typeByDefValue { // TODO(bep) this branch isn't covered by a single test.
valType = val valType := val
} else { path := strings.Split(lcaseKey, v.keyDelim)
defVal, defExists := v.defaults[lcaseKey] defVal := v.searchMap(v.defaults, path)
if defExists { if defVal != nil {
valType = defVal valType = defVal
} else { }
valType = val
switch valType.(type) {
case bool:
return cast.ToBool(val)
case string:
return cast.ToString(val)
case int64, int32, int16, int8, int:
return cast.ToInt(val)
case float64, float32:
return cast.ToFloat64(val)
case time.Time:
return cast.ToTime(val)
case time.Duration:
return cast.ToDuration(val)
case []string:
return cast.ToStringSlice(val)
} }
} }
switch valType.(type) {
case bool:
return cast.ToBool(val)
case string:
return cast.ToString(val)
case int64, int32, int16, int8, int:
return cast.ToInt(val)
case float64, float32:
return cast.ToFloat64(val)
case time.Time:
return cast.ToTime(val)
case time.Duration:
return cast.ToDuration(val)
case []string:
return cast.ToStringSlice(val)
}
return val return val
} }
// Sub returns new Viper instance representing a sub tree of this instance. // Sub returns new Viper instance representing a sub tree of this instance.
// Sub is case-insensitive for a key.
func Sub(key string) *Viper { return v.Sub(key) } func Sub(key string) *Viper { return v.Sub(key) }
func (v *Viper) Sub(key string) *Viper { func (v *Viper) Sub(key string) *Viper {
subv := New() subv := New()
data := v.Get(key) data := v.Get(key)
if data == nil {
return nil
}
if reflect.TypeOf(data).Kind() == reflect.Map { if reflect.TypeOf(data).Kind() == reflect.Map {
subv.config = cast.ToStringMap(data) subv.config = cast.ToStringMap(data)
return subv return subv
@ -616,7 +720,15 @@ func (v *Viper) GetSizeInBytes(key string) uint {
// UnmarshalKey takes a single key and unmarshals it into a Struct. // UnmarshalKey takes a single key and unmarshals it into a Struct.
func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) } func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) }
func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error {
return mapstructure.Decode(v.Get(key), rawVal) err := decode(v.Get(key), defaultDecoderConfig(rawVal))
if err != nil {
return err
}
v.insensitiviseMaps()
return nil
} }
// Unmarshal unmarshals the config into a Struct. Make sure that the tags // Unmarshal unmarshals the config into a Struct. Make sure that the tags
@ -635,13 +747,16 @@ func (v *Viper) Unmarshal(rawVal interface{}) error {
} }
// defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot // defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot
// of time.Duration values // of time.Duration values & string slices
func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig { func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig {
return &mapstructure.DecoderConfig{ return &mapstructure.DecoderConfig{
Metadata: nil, Metadata: nil,
Result: output, Result: output,
WeaklyTypedInput: true, WeaklyTypedInput: true,
DecodeHook: mapstructure.StringToTimeDurationHookFunc(), DecodeHook: mapstructure.ComposeDecodeHookFunc(
mapstructure.StringToTimeDurationHookFunc(),
mapstructure.StringToSliceHookFunc(","),
),
} }
} }
@ -702,7 +817,7 @@ func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) {
} }
// BindFlagValue binds a specific key to a FlagValue. // BindFlagValue binds a specific key to a FlagValue.
// Example(where serverCmd is a Cobra instance): // Example (where serverCmd is a Cobra instance):
// //
// serverCmd.Flags().Int("port", 1138, "Port to run Application server on") // serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
// Viper.BindFlagValue("port", serverCmd.Flags().Lookup("port")) // Viper.BindFlagValue("port", serverCmd.Flags().Lookup("port"))
@ -744,15 +859,37 @@ func (v *Viper) BindEnv(input ...string) error {
// Viper will check in the following order: // Viper will check in the following order:
// flag, env, config file, key/value store, default. // flag, env, config file, key/value store, default.
// Viper will check to see if an alias exists first. // Viper will check to see if an alias exists first.
func (v *Viper) find(key string) interface{} { // Note: this assumes a lower-cased key given.
var val interface{} func (v *Viper) find(lcaseKey string) interface{} {
var exists bool
var (
val interface{}
exists bool
path = strings.Split(lcaseKey, v.keyDelim)
nested = len(path) > 1
)
// compute the path through the nested maps to the nested value
if nested && v.isPathShadowedInDeepMap(path, castMapStringToMapInterface(v.aliases)) != "" {
return nil
}
// if the requested key is an alias, then return the proper key // if the requested key is an alias, then return the proper key
key = v.realKey(key) lcaseKey = v.realKey(lcaseKey)
path = strings.Split(lcaseKey, v.keyDelim)
nested = len(path) > 1
// PFlag Override first // Set() override first
flag, exists := v.pflags[key] val = v.searchMap(v.override, path)
if val != nil {
return val
}
if nested && v.isPathShadowedInDeepMap(path, v.override) != "" {
return nil
}
// PFlag override next
flag, exists := v.pflags[lcaseKey]
if exists && flag.HasChanged() { if exists && flag.HasChanged() {
switch flag.ValueType() { switch flag.ValueType() {
case "int", "int8", "int16", "int32", "int64": case "int", "int8", "int16", "int32", "int64":
@ -761,82 +898,102 @@ func (v *Viper) find(key string) interface{} {
return cast.ToBool(flag.ValueString()) return cast.ToBool(flag.ValueString())
case "stringSlice": case "stringSlice":
s := strings.TrimPrefix(flag.ValueString(), "[") s := strings.TrimPrefix(flag.ValueString(), "[")
return strings.TrimSuffix(s, "]") s = strings.TrimSuffix(s, "]")
res, _ := readAsCSV(s)
return res
default: default:
return flag.ValueString() return flag.ValueString()
} }
} }
if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" {
val, exists = v.override[key] return nil
if exists {
return val
} }
// Env override next
if v.automaticEnvApplied { if v.automaticEnvApplied {
// even if it hasn't been registered, if automaticEnv is used, // even if it hasn't been registered, if automaticEnv is used,
// check any Get request // check any Get request
if val = v.getEnv(v.mergeWithEnvPrefix(key)); val != "" { if val = v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); val != "" {
return val return val
} }
if nested && v.isPathShadowedInAutoEnv(path) != "" {
return nil
}
} }
envkey, exists := v.env[lcaseKey]
envkey, exists := v.env[key]
if exists { if exists {
if val = v.getEnv(envkey); val != "" { if val = v.getEnv(envkey); val != "" {
return val return val
} }
} }
if nested && v.isPathShadowedInFlatMap(path, v.env) != "" {
val, exists = v.config[key] return nil
if exists {
return val
} }
// Test for nested config parameter // Config file next
if strings.Contains(key, v.keyDelim) { val = v.searchMapWithPathPrefixes(v.config, path)
path := strings.Split(key, v.keyDelim) if val != nil {
return val
}
if nested && v.isPathShadowedInDeepMap(path, v.config) != "" {
return nil
}
source := v.find(path[0]) // K/V store next
if source != nil { val = v.searchMap(v.kvstore, path)
if reflect.TypeOf(source).Kind() == reflect.Map { if val != nil {
val := v.searchMap(cast.ToStringMap(source), path[1:]) return val
if val != nil { }
return val if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" {
} return nil
} }
// Default next
val = v.searchMap(v.defaults, path)
if val != nil {
return val
}
if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" {
return nil
}
// last chance: if no other value is returned and a flag does exist for the value,
// get the flag's value even if the flag's value has not changed
if flag, exists := v.pflags[lcaseKey]; exists {
switch flag.ValueType() {
case "int", "int8", "int16", "int32", "int64":
return cast.ToInt(flag.ValueString())
case "bool":
return cast.ToBool(flag.ValueString())
case "stringSlice":
s := strings.TrimPrefix(flag.ValueString(), "[")
s = strings.TrimSuffix(s, "]")
res, _ := readAsCSV(s)
return res
default:
return flag.ValueString()
} }
} }
// last item, no need to check shadowing
val, exists = v.kvstore[key]
if exists {
return val
}
val, exists = v.defaults[key]
if exists {
return val
}
return nil return nil
} }
func readAsCSV(val string) ([]string, error) {
if val == "" {
return []string{}, nil
}
stringReader := strings.NewReader(val)
csvReader := csv.NewReader(stringReader)
return csvReader.Read()
}
// IsSet checks to see if the key has been set in any of the data locations. // IsSet checks to see if the key has been set in any of the data locations.
// IsSet is case-insensitive for a key.
func IsSet(key string) bool { return v.IsSet(key) } func IsSet(key string) bool { return v.IsSet(key) }
func (v *Viper) IsSet(key string) bool { func (v *Viper) IsSet(key string) bool {
path := strings.Split(key, v.keyDelim)
lcaseKey := strings.ToLower(key) lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey) val := v.find(lcaseKey)
if val == nil {
source := v.find(strings.ToLower(path[0]))
if source != nil {
if reflect.TypeOf(source).Kind() == reflect.Map {
val = v.searchMap(cast.ToStringMap(source), path[1:])
}
}
}
return val != nil return val != nil
} }
@ -914,22 +1071,38 @@ func (v *Viper) InConfig(key string) bool {
} }
// SetDefault sets the default value for this key. // SetDefault sets the default value for this key.
// SetDefault is case-insensitive for a key.
// Default only used when no value is provided by the user via flag, config or ENV. // Default only used when no value is provided by the user via flag, config or ENV.
func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } func SetDefault(key string, value interface{}) { v.SetDefault(key, value) }
func (v *Viper) SetDefault(key string, value interface{}) { func (v *Viper) SetDefault(key string, value interface{}) {
// If alias passed in, then set the proper default // If alias passed in, then set the proper default
key = v.realKey(strings.ToLower(key)) key = v.realKey(strings.ToLower(key))
v.defaults[key] = value value = toCaseInsensitiveValue(value)
path := strings.Split(key, v.keyDelim)
lastKey := strings.ToLower(path[len(path)-1])
deepestMap := deepSearch(v.defaults, path[0:len(path)-1])
// set innermost value
deepestMap[lastKey] = value
} }
// Set sets the value for the key in the override regiser. // Set sets the value for the key in the override regiser.
// Set is case-insensitive for a key.
// Will be used instead of values obtained via // Will be used instead of values obtained via
// flags, config file, ENV, default, or key/value store. // flags, config file, ENV, default, or key/value store.
func Set(key string, value interface{}) { v.Set(key, value) } func Set(key string, value interface{}) { v.Set(key, value) }
func (v *Viper) Set(key string, value interface{}) { func (v *Viper) Set(key string, value interface{}) {
// If alias passed in, then set the proper override // If alias passed in, then set the proper override
key = v.realKey(strings.ToLower(key)) key = v.realKey(strings.ToLower(key))
v.override[key] = value value = toCaseInsensitiveValue(value)
path := strings.Split(key, v.keyDelim)
lastKey := strings.ToLower(path[len(path)-1])
deepestMap := deepSearch(v.override, path[0:len(path)-1])
// set innermost value
deepestMap[lastKey] = value
} }
// ReadInConfig will discover and load the configuration file from disk // ReadInConfig will discover and load the configuration file from disk
@ -937,29 +1110,45 @@ func (v *Viper) Set(key string, value interface{}) {
func ReadInConfig() error { return v.ReadInConfig() } func ReadInConfig() error { return v.ReadInConfig() }
func (v *Viper) ReadInConfig() error { func (v *Viper) ReadInConfig() error {
jww.INFO.Println("Attempting to read in config file") jww.INFO.Println("Attempting to read in config file")
if !stringInSlice(v.getConfigType(), SupportedExts) { filename, err := v.getConfigFile()
return UnsupportedConfigError(v.getConfigType())
}
file, err := afero.ReadFile(v.fs, v.getConfigFile())
if err != nil { if err != nil {
return err return err
} }
v.config = make(map[string]interface{}) if !stringInSlice(v.getConfigType(), SupportedExts) {
return UnsupportedConfigError(v.getConfigType())
}
return v.unmarshalReader(bytes.NewReader(file), v.config) file, err := afero.ReadFile(v.fs, filename)
if err != nil {
return err
}
config := make(map[string]interface{})
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. // MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() } func MergeInConfig() error { return v.MergeInConfig() }
func (v *Viper) MergeInConfig() error { func (v *Viper) MergeInConfig() error {
jww.INFO.Println("Attempting to merge in config file") jww.INFO.Println("Attempting to merge in config file")
filename, err := v.getConfigFile()
if err != nil {
return err
}
if !stringInSlice(v.getConfigType(), SupportedExts) { if !stringInSlice(v.getConfigType(), SupportedExts) {
return UnsupportedConfigError(v.getConfigType()) return UnsupportedConfigError(v.getConfigType())
} }
file, err := afero.ReadFile(v.fs, v.getConfigFile()) file, err := afero.ReadFile(v.fs, filename)
if err != nil { if err != nil {
return err return err
} }
@ -1009,6 +1198,22 @@ func castToMapStringInterface(
return tgt return tgt
} }
func castMapStringToMapInterface(src map[string]string) map[string]interface{} {
tgt := map[string]interface{}{}
for k, v := range src {
tgt[k] = v
}
return tgt
}
func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} {
tgt := map[string]interface{}{}
for k, v := range src {
tgt[k] = v
}
return tgt
}
// mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's // mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's
// insistence on parsing nested structures as `map[interface{}]interface{}` // insistence on parsing nested structures as `map[interface{}]interface{}`
// instead of using a `string` as the key for nest structures beyond one level // instead of using a `string` as the key for nest structures beyond one level
@ -1081,7 +1286,11 @@ func (v *Viper) WatchRemoteConfig() error {
return v.watchKeyValueConfig() return v.watchKeyValueConfig()
} }
// Unmarshall a Reader into a map. func (v *Viper) WatchRemoteConfigOnChannel() error {
return v.watchKeyValueConfigOnChannel()
}
// Unmarshal a Reader into a map.
// Should probably be an unexported function. // Should probably be an unexported function.
func unmarshalReader(in io.Reader, c map[string]interface{}) error { func unmarshalReader(in io.Reader, c map[string]interface{}) error {
return v.unmarshalReader(in, c) return v.unmarshalReader(in, c)
@ -1124,6 +1333,23 @@ func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}
return v.kvstore, err 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. // Retrieve the first found remote configuration.
func (v *Viper) watchKeyValueConfig() error { func (v *Viper) watchKeyValueConfig() error {
for _, rp := range v.remoteProviders { for _, rp := range v.remoteProviders {
@ -1146,55 +1372,105 @@ func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface
return v.kvstore, err return v.kvstore, err
} }
// AllKeys returns all keys regardless where they are set. // AllKeys returns all keys holding a value, regardless of where they are set.
// Nested keys are returned with a v.keyDelim (= ".") separator
func AllKeys() []string { return v.AllKeys() } func AllKeys() []string { return v.AllKeys() }
func (v *Viper) AllKeys() []string { func (v *Viper) AllKeys() []string {
m := map[string]struct{}{} m := map[string]bool{}
// add all paths, by order of descending priority to ensure correct shadowing
for key := range v.defaults { m = v.flattenAndMergeMap(m, castMapStringToMapInterface(v.aliases), "")
m[strings.ToLower(key)] = struct{}{} m = v.flattenAndMergeMap(m, v.override, "")
} m = v.mergeFlatMap(m, castMapFlagToMapInterface(v.pflags))
m = v.mergeFlatMap(m, castMapStringToMapInterface(v.env))
for key := range v.pflags { m = v.flattenAndMergeMap(m, v.config, "")
m[strings.ToLower(key)] = struct{}{} m = v.flattenAndMergeMap(m, v.kvstore, "")
} m = v.flattenAndMergeMap(m, v.defaults, "")
for key := range v.env {
m[strings.ToLower(key)] = struct{}{}
}
for key := range v.config {
m[strings.ToLower(key)] = struct{}{}
}
for key := range v.kvstore {
m[strings.ToLower(key)] = struct{}{}
}
for key := range v.override {
m[strings.ToLower(key)] = struct{}{}
}
for key := range v.aliases {
m[strings.ToLower(key)] = struct{}{}
}
// convert set of paths to list
a := []string{} a := []string{}
for x := range m { for x := range m {
a = append(a, x) a = append(a, x)
} }
return a return a
} }
// AllSettings returns all settings as a map[string]interface{}. // flattenAndMergeMap recursively flattens the given map into a map[string]bool
// of key paths (used as a set, easier to manipulate than a []string):
// - each path is merged into a single key string, delimited with v.keyDelim (= ".")
// - if a path is shadowed by an earlier value in the initial shadow map,
// it is skipped.
// The resulting set of paths is merged to the given shadow set at the same time.
func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool {
if shadow != nil && prefix != "" && shadow[prefix] {
// prefix is shadowed => nothing more to flatten
return shadow
}
if shadow == nil {
shadow = make(map[string]bool)
}
var m2 map[string]interface{}
if prefix != "" {
prefix += v.keyDelim
}
for k, val := range m {
fullKey := prefix + k
switch val.(type) {
case map[string]interface{}:
m2 = val.(map[string]interface{})
case map[interface{}]interface{}:
m2 = cast.ToStringMap(val)
default:
// immediate value
shadow[strings.ToLower(fullKey)] = true
continue
}
// recursively merge to shadow map
shadow = v.flattenAndMergeMap(shadow, m2, fullKey)
}
return shadow
}
// mergeFlatMap merges the given maps, excluding values of the second map
// shadowed by values from the first map.
func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]interface{}) map[string]bool {
// scan keys
outer:
for k, _ := range m {
path := strings.Split(k, v.keyDelim)
// scan intermediate paths
var parentKey string
for i := 1; i < len(path); i++ {
parentKey = strings.Join(path[0:i], v.keyDelim)
if shadow[parentKey] {
// path is shadowed, continue
continue outer
}
}
// add key
shadow[strings.ToLower(k)] = true
}
return shadow
}
// AllSettings merges all settings and returns them as a map[string]interface{}.
func AllSettings() map[string]interface{} { return v.AllSettings() } func AllSettings() map[string]interface{} { return v.AllSettings() }
func (v *Viper) AllSettings() map[string]interface{} { func (v *Viper) AllSettings() map[string]interface{} {
m := map[string]interface{}{} m := map[string]interface{}{}
for _, x := range v.AllKeys() { // start from the list of keys, and construct the map one value at a time
m[x] = v.Get(x) for _, k := range v.AllKeys() {
value := v.Get(k)
if value == nil {
// should not happen, since AllKeys() returns only keys holding a value,
// check just in case anything changes
continue
}
path := strings.Split(k, v.keyDelim)
lastKey := strings.ToLower(path[len(path)-1])
deepestMap := deepSearch(m, path[0:len(path)-1])
// set innermost value
deepestMap[lastKey] = value
} }
return m return m
} }
@ -1228,7 +1504,11 @@ func (v *Viper) getConfigType() string {
return v.configType return v.configType
} }
cf := v.getConfigFile() cf, err := v.getConfigFile()
if err != nil {
return ""
}
ext := filepath.Ext(cf) ext := filepath.Ext(cf)
if len(ext) > 1 { if len(ext) > 1 {
@ -1238,15 +1518,15 @@ func (v *Viper) getConfigType() string {
return "" return ""
} }
func (v *Viper) getConfigFile() string { func (v *Viper) getConfigFile() (string, error) {
// if explicitly set, then use it // if explicitly set, then use it
if v.configFile != "" { if v.configFile != "" {
return v.configFile return v.configFile, nil
} }
cf, err := v.findConfigFile() cf, err := v.findConfigFile()
if err != nil { if err != nil {
return "" return "", err
} }
v.configFile = cf v.configFile = cf
@ -1269,7 +1549,6 @@ func (v *Viper) searchInPath(in string) (filename string) {
// Search all configPaths for any config file. // Search all configPaths for any config file.
// Returns the first path that exists (and is a config file). // Returns the first path that exists (and is a config file).
func (v *Viper) findConfigFile() (string, error) { func (v *Viper) findConfigFile() (string, error) {
jww.INFO.Println("Searching for config in ", v.configPaths) jww.INFO.Println("Searching for config in ", v.configPaths)
for _, cp := range v.configPaths { for _, cp := range v.configPaths {
@ -1285,7 +1564,6 @@ func (v *Viper) findConfigFile() (string, error) {
// purposes. // purposes.
func Debug() { v.Debug() } func Debug() { v.Debug() }
func (v *Viper) Debug() { func (v *Viper) Debug() {
fmt.Println("Aliases:")
fmt.Printf("Aliases:\n%#v\n", v.aliases) fmt.Printf("Aliases:\n%#v\n", v.aliases)
fmt.Printf("Override:\n%#v\n", v.override) fmt.Printf("Override:\n%#v\n", v.override)
fmt.Printf("PFlags:\n%#v\n", v.pflags) fmt.Printf("PFlags:\n%#v\n", v.pflags)

View File

@ -1,20 +1,10 @@
package gojsonschema package gojsonschema
import ( import (
"bytes" "fmt"
"sync" "strings"
"text/template"
) )
var errorTemplates errorTemplate = errorTemplate{template.New("errors-new"), sync.RWMutex{}}
// template.Template is not thread-safe for writing, so some locking is done
// sync.RWMutex is used for efficiently locking when new templates are created
type errorTemplate struct {
*template.Template
sync.RWMutex
}
type ( type (
// RequiredError. ErrorDetails: property string // RequiredError. ErrorDetails: property string
RequiredError struct { RequiredError struct {
@ -237,47 +227,16 @@ func newError(err ResultError, context *jsonContext, value interface{}, locale l
err.SetValue(value) err.SetValue(value)
err.SetDetails(details) err.SetDetails(details)
details["field"] = err.Field() details["field"] = err.Field()
if _, exists := details["context"]; !exists && context != nil {
details["context"] = context.String()
}
err.SetDescription(formatErrorDescription(d, details)) err.SetDescription(formatErrorDescription(d, details))
} }
// formatErrorDescription takes a string in the default text/template // formatErrorDescription takes a string in this format: %field% is required
// format and converts it to a string with replacements. The fields come // and converts it to a string with replacements. The fields come from
// from the ErrorDetails struct and vary for each type of error. // the ErrorDetails struct and vary for each type of error.
func formatErrorDescription(s string, details ErrorDetails) string { func formatErrorDescription(s string, details ErrorDetails) string {
for name, val := range details {
var tpl *template.Template s = strings.Replace(s, "%"+strings.ToLower(name)+"%", fmt.Sprintf("%v", val), -1)
var descrAsBuffer bytes.Buffer
var err error
errorTemplates.RLock()
tpl = errorTemplates.Lookup(s)
errorTemplates.RUnlock()
if tpl == nil {
errorTemplates.Lock()
tpl = errorTemplates.New(s)
if ErrorTemplateFuncs != nil {
tpl.Funcs(ErrorTemplateFuncs)
}
tpl, err = tpl.Parse(s)
errorTemplates.Unlock()
if err != nil {
return err.Error()
}
} }
err = tpl.Execute(&descrAsBuffer, details) return s
if err != nil {
return err.Error()
}
return descrAsBuffer.String()
} }

View File

@ -52,20 +52,14 @@ type (
// http://tools.ietf.org/html/rfc3339#section-5.6 // http://tools.ietf.org/html/rfc3339#section-5.6
DateTimeFormatChecker struct{} DateTimeFormatChecker struct{}
// URIFormatChecker validates a URI with a valid Scheme per RFC3986 // URIFormatCheckers validates a URI with a valid Scheme per RFC3986
URIFormatChecker struct{} URIFormatChecker struct{}
// URIReferenceFormatChecker validates a URI or relative-reference per RFC3986
URIReferenceFormatChecker struct{}
// HostnameFormatChecker validates a hostname is in the correct format // HostnameFormatChecker validates a hostname is in the correct format
HostnameFormatChecker struct{} HostnameFormatChecker struct{}
// UUIDFormatChecker validates a UUID is in the correct format // UUIDFormatChecker validates a UUID is in the correct format
UUIDFormatChecker struct{} UUIDFormatChecker struct{}
// RegexFormatChecker validates a regex is in the correct format
RegexFormatChecker struct{}
) )
var ( var (
@ -73,15 +67,13 @@ var (
// so library users can add custom formatters // so library users can add custom formatters
FormatCheckers = FormatCheckerChain{ FormatCheckers = FormatCheckerChain{
formatters: map[string]FormatChecker{ formatters: map[string]FormatChecker{
"date-time": DateTimeFormatChecker{}, "date-time": DateTimeFormatChecker{},
"hostname": HostnameFormatChecker{}, "hostname": HostnameFormatChecker{},
"email": EmailFormatChecker{}, "email": EmailFormatChecker{},
"ipv4": IPV4FormatChecker{}, "ipv4": IPV4FormatChecker{},
"ipv6": IPV6FormatChecker{}, "ipv6": IPV6FormatChecker{},
"uri": URIFormatChecker{}, "uri": URIFormatChecker{},
"uri-reference": URIReferenceFormatChecker{}, "uuid": UUIDFormatChecker{},
"uuid": UUIDFormatChecker{},
"regex": RegexFormatChecker{},
}, },
} }
@ -177,11 +169,6 @@ func (f URIFormatChecker) IsFormat(input string) bool {
return true return true
} }
func (f URIReferenceFormatChecker) IsFormat(input string) bool {
_, err := url.Parse(input)
return err == nil
}
func (f HostnameFormatChecker) IsFormat(input string) bool { func (f HostnameFormatChecker) IsFormat(input string) bool {
return rxHostname.MatchString(input) && len(input) < 256 return rxHostname.MatchString(input) && len(input) < 256
} }
@ -189,15 +176,3 @@ func (f HostnameFormatChecker) IsFormat(input string) bool {
func (f UUIDFormatChecker) IsFormat(input string) bool { func (f UUIDFormatChecker) IsFormat(input string) bool {
return rxUUID.MatchString(input) return rxUUID.MatchString(input)
} }
// IsFormat implements FormatChecker interface.
func (f RegexFormatChecker) IsFormat(input string) bool {
if input == "" {
return true
}
_, err := regexp.Compile(input)
if err != nil {
return false
}
return true
}

View File

@ -33,101 +33,41 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"github.com/xeipuuv/gojsonreference" "github.com/xeipuuv/gojsonreference"
) )
var osFS = osFileSystem(os.Open)
// JSON loader interface // JSON loader interface
type JSONLoader interface { type JSONLoader interface {
JsonSource() interface{} jsonSource() interface{}
LoadJSON() (interface{}, error) loadJSON() (interface{}, error)
JsonReference() (gojsonreference.JsonReference, error) loadSchema() (*Schema, error)
LoaderFactory() JSONLoaderFactory
}
type JSONLoaderFactory interface {
New(source string) JSONLoader
}
type DefaultJSONLoaderFactory struct {
}
type FileSystemJSONLoaderFactory struct {
fs http.FileSystem
}
func (d DefaultJSONLoaderFactory) New(source string) JSONLoader {
return &jsonReferenceLoader{
fs: osFS,
source: source,
}
}
func (f FileSystemJSONLoaderFactory) New(source string) JSONLoader {
return &jsonReferenceLoader{
fs: f.fs,
source: source,
}
}
// osFileSystem is a functional wrapper for os.Open that implements http.FileSystem.
type osFileSystem func(string) (*os.File, error)
func (o osFileSystem) Open(name string) (http.File, error) {
return o(name)
} }
// JSON Reference loader // JSON Reference loader
// references are used to load JSONs from files and HTTP // references are used to load JSONs from files and HTTP
type jsonReferenceLoader struct { type jsonReferenceLoader struct {
fs http.FileSystem
source string source string
} }
func (l *jsonReferenceLoader) JsonSource() interface{} { func (l *jsonReferenceLoader) jsonSource() interface{} {
return l.source return l.source
} }
func (l *jsonReferenceLoader) JsonReference() (gojsonreference.JsonReference, error) {
return gojsonreference.NewJsonReference(l.JsonSource().(string))
}
func (l *jsonReferenceLoader) LoaderFactory() JSONLoaderFactory {
return &FileSystemJSONLoaderFactory{
fs: l.fs,
}
}
// NewReferenceLoader returns a JSON reference loader using the given source and the local OS file system.
func NewReferenceLoader(source string) *jsonReferenceLoader { func NewReferenceLoader(source string) *jsonReferenceLoader {
return &jsonReferenceLoader{ return &jsonReferenceLoader{source: source}
fs: osFS,
source: source,
}
} }
// NewReferenceLoaderFileSystem returns a JSON reference loader using the given source and file system. func (l *jsonReferenceLoader) loadJSON() (interface{}, error) {
func NewReferenceLoaderFileSystem(source string, fs http.FileSystem) *jsonReferenceLoader {
return &jsonReferenceLoader{
fs: fs,
source: source,
}
}
func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
var err error var err error
reference, err := gojsonreference.NewJsonReference(l.JsonSource().(string)) reference, err := gojsonreference.NewJsonReference(l.jsonSource().(string))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -139,7 +79,7 @@ func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
if reference.HasFileScheme { if reference.HasFileScheme {
filename := strings.Replace(refToUrl.GetUrl().Path, "file://", "", -1) filename := strings.Replace(refToUrl.String(), "file://", "", -1)
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
// on Windows, a file URL may have an extra leading slash, use slashes // on Windows, a file URL may have an extra leading slash, use slashes
// instead of backslashes, and have spaces escaped // instead of backslashes, and have spaces escaped
@ -147,6 +87,7 @@ func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
filename = filename[1:] filename = filename[1:]
} }
filename = filepath.FromSlash(filename) filename = filepath.FromSlash(filename)
filename = strings.Replace(filename, "%20", " ", -1)
} }
document, err = l.loadFromFile(filename) document, err = l.loadFromFile(filename)
@ -167,6 +108,33 @@ func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
} }
func (l *jsonReferenceLoader) loadSchema() (*Schema, error) {
var err error
d := Schema{}
d.pool = newSchemaPool()
d.referencePool = newSchemaReferencePool()
d.documentReference, err = gojsonreference.NewJsonReference(l.jsonSource().(string))
if err != nil {
return nil, err
}
spd, err := d.pool.GetDocument(d.documentReference)
if err != nil {
return nil, err
}
err = d.parse(spd.Document)
if err != nil {
return nil, err
}
return &d, nil
}
func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) { func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) {
resp, err := http.Get(address) resp, err := http.Get(address)
@ -176,7 +144,7 @@ func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error)
// must return HTTP Status 200 OK // must return HTTP Status 200 OK
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return nil, errors.New(formatErrorDescription(Locale.HttpBadStatus(), ErrorDetails{"status": resp.Status})) return nil, errors.New(formatErrorDescription(Locale.httpBadStatus(), ErrorDetails{"status": resp.Status}))
} }
bodyBuff, err := ioutil.ReadAll(resp.Body) bodyBuff, err := ioutil.ReadAll(resp.Body)
@ -189,13 +157,8 @@ func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error)
} }
func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) { func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) {
f, err := l.fs.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
bodyBuff, err := ioutil.ReadAll(f) bodyBuff, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -210,52 +173,45 @@ type jsonStringLoader struct {
source string source string
} }
func (l *jsonStringLoader) JsonSource() interface{} { func (l *jsonStringLoader) jsonSource() interface{} {
return l.source return l.source
} }
func (l *jsonStringLoader) JsonReference() (gojsonreference.JsonReference, error) {
return gojsonreference.NewJsonReference("#")
}
func (l *jsonStringLoader) LoaderFactory() JSONLoaderFactory {
return &DefaultJSONLoaderFactory{}
}
func NewStringLoader(source string) *jsonStringLoader { func NewStringLoader(source string) *jsonStringLoader {
return &jsonStringLoader{source: source} return &jsonStringLoader{source: source}
} }
func (l *jsonStringLoader) LoadJSON() (interface{}, error) { func (l *jsonStringLoader) loadJSON() (interface{}, error) {
return decodeJsonUsingNumber(strings.NewReader(l.JsonSource().(string))) return decodeJsonUsingNumber(strings.NewReader(l.jsonSource().(string)))
} }
// JSON bytes loader func (l *jsonStringLoader) loadSchema() (*Schema, error) {
type jsonBytesLoader struct { var err error
source []byte
}
func (l *jsonBytesLoader) JsonSource() interface{} { document, err := l.loadJSON()
return l.source if err != nil {
} return nil, err
}
func (l *jsonBytesLoader) JsonReference() (gojsonreference.JsonReference, error) { d := Schema{}
return gojsonreference.NewJsonReference("#") d.pool = newSchemaPool()
} d.referencePool = newSchemaReferencePool()
d.documentReference, err = gojsonreference.NewJsonReference("#")
d.pool.SetStandaloneDocument(document)
if err != nil {
return nil, err
}
func (l *jsonBytesLoader) LoaderFactory() JSONLoaderFactory { err = d.parse(document)
return &DefaultJSONLoaderFactory{} if err != nil {
} return nil, err
}
func NewBytesLoader(source []byte) *jsonBytesLoader { return &d, nil
return &jsonBytesLoader{source: source}
}
func (l *jsonBytesLoader) LoadJSON() (interface{}, error) {
return decodeJsonUsingNumber(bytes.NewReader(l.JsonSource().([]byte)))
} }
// JSON Go (types) loader // JSON Go (types) loader
@ -265,27 +221,19 @@ type jsonGoLoader struct {
source interface{} source interface{}
} }
func (l *jsonGoLoader) JsonSource() interface{} { func (l *jsonGoLoader) jsonSource() interface{} {
return l.source return l.source
} }
func (l *jsonGoLoader) JsonReference() (gojsonreference.JsonReference, error) {
return gojsonreference.NewJsonReference("#")
}
func (l *jsonGoLoader) LoaderFactory() JSONLoaderFactory {
return &DefaultJSONLoaderFactory{}
}
func NewGoLoader(source interface{}) *jsonGoLoader { func NewGoLoader(source interface{}) *jsonGoLoader {
return &jsonGoLoader{source: source} return &jsonGoLoader{source: source}
} }
func (l *jsonGoLoader) LoadJSON() (interface{}, error) { func (l *jsonGoLoader) loadJSON() (interface{}, error) {
// convert it to a compliant JSON first to avoid types "mismatches" // convert it to a compliant JSON first to avoid types "mismatches"
jsonBytes, err := json.Marshal(l.JsonSource()) jsonBytes, err := json.Marshal(l.jsonSource())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -294,34 +242,31 @@ func (l *jsonGoLoader) LoadJSON() (interface{}, error) {
} }
type jsonIOLoader struct { func (l *jsonGoLoader) loadSchema() (*Schema, error) {
buf *bytes.Buffer
}
func NewReaderLoader(source io.Reader) (*jsonIOLoader, io.Reader) { var err error
buf := &bytes.Buffer{}
return &jsonIOLoader{buf: buf}, io.TeeReader(source, buf)
}
func NewWriterLoader(source io.Writer) (*jsonIOLoader, io.Writer) { document, err := l.loadJSON()
buf := &bytes.Buffer{} if err != nil {
return &jsonIOLoader{buf: buf}, io.MultiWriter(source, buf) return nil, err
} }
func (l *jsonIOLoader) JsonSource() interface{} { d := Schema{}
return l.buf.String() d.pool = newSchemaPool()
} d.referencePool = newSchemaReferencePool()
d.documentReference, err = gojsonreference.NewJsonReference("#")
d.pool.SetStandaloneDocument(document)
if err != nil {
return nil, err
}
func (l *jsonIOLoader) LoadJSON() (interface{}, error) { err = d.parse(document)
return decodeJsonUsingNumber(l.buf) if err != nil {
} return nil, err
}
func (l *jsonIOLoader) JsonReference() (gojsonreference.JsonReference, error) { return &d, nil
return gojsonreference.NewJsonReference("#")
}
func (l *jsonIOLoader) LoaderFactory() JSONLoaderFactory {
return &DefaultJSONLoaderFactory{}
} }
func decodeJsonUsingNumber(r io.Reader) (interface{}, error) { func decodeJsonUsingNumber(r io.Reader) (interface{}, error) {
@ -335,7 +280,7 @@ func decodeJsonUsingNumber(r io.Reader) (interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return document, nil return document, nil
} }

View File

@ -26,7 +26,7 @@
package gojsonschema package gojsonschema
type ( type (
// locale is an interface for defining custom error strings // locale is an interface for definining custom error strings
locale interface { locale interface {
Required() string Required() string
InvalidType() string InvalidType() string
@ -37,7 +37,6 @@ type (
MissingDependency() string MissingDependency() string
Internal() string Internal() string
Enum() string Enum() string
ArrayNotEnoughItems() string
ArrayNoAdditionalItems() string ArrayNoAdditionalItems() string
ArrayMinItems() string ArrayMinItems() string
ArrayMaxItems() string ArrayMaxItems() string
@ -73,8 +72,7 @@ type (
ReferenceMustBeCanonical() string ReferenceMustBeCanonical() string
NotAValidType() string NotAValidType() string
Duplicated() string Duplicated() string
HttpBadStatus() string httpBadStatus() string
ParseError() string
// ErrorFormat // ErrorFormat
ErrorFormat() string ErrorFormat() string
@ -85,11 +83,11 @@ type (
) )
func (l DefaultLocale) Required() string { func (l DefaultLocale) Required() string {
return `{{.property}} is required` return `%property% is required`
} }
func (l DefaultLocale) InvalidType() string { func (l DefaultLocale) InvalidType() string {
return `Invalid type. Expected: {{.expected}}, given: {{.given}}` return `Invalid type. Expected: %expected%, given: %given%`
} }
func (l DefaultLocale) NumberAnyOf() string { func (l DefaultLocale) NumberAnyOf() string {
@ -109,166 +107,157 @@ func (l DefaultLocale) NumberNot() string {
} }
func (l DefaultLocale) MissingDependency() string { func (l DefaultLocale) MissingDependency() string {
return `Has a dependency on {{.dependency}}` return `Has a dependency on %dependency%`
} }
func (l DefaultLocale) Internal() string { func (l DefaultLocale) Internal() string {
return `Internal Error {{.error}}` return `Internal Error %error%`
} }
func (l DefaultLocale) Enum() string { func (l DefaultLocale) Enum() string {
return `{{.field}} must be one of the following: {{.allowed}}` return `%field% must be one of the following: %allowed%`
} }
func (l DefaultLocale) ArrayNoAdditionalItems() string { func (l DefaultLocale) ArrayNoAdditionalItems() string {
return `No additional items allowed on array` return `No additional items allowed on array`
} }
func (l DefaultLocale) ArrayNotEnoughItems() string {
return `Not enough items on array to match positional list of schema`
}
func (l DefaultLocale) ArrayMinItems() string { func (l DefaultLocale) ArrayMinItems() string {
return `Array must have at least {{.min}} items` return `Array must have at least %min% items`
} }
func (l DefaultLocale) ArrayMaxItems() string { func (l DefaultLocale) ArrayMaxItems() string {
return `Array must have at most {{.max}} items` return `Array must have at most %max% items`
} }
func (l DefaultLocale) Unique() string { func (l DefaultLocale) Unique() string {
return `{{.type}} items must be unique` return `%type% items must be unique`
} }
func (l DefaultLocale) ArrayMinProperties() string { func (l DefaultLocale) ArrayMinProperties() string {
return `Must have at least {{.min}} properties` return `Must have at least %min% properties`
} }
func (l DefaultLocale) ArrayMaxProperties() string { func (l DefaultLocale) ArrayMaxProperties() string {
return `Must have at most {{.max}} properties` return `Must have at most %max% properties`
} }
func (l DefaultLocale) AdditionalPropertyNotAllowed() string { func (l DefaultLocale) AdditionalPropertyNotAllowed() string {
return `Additional property {{.property}} is not allowed` return `Additional property %property% is not allowed`
} }
func (l DefaultLocale) InvalidPropertyPattern() string { func (l DefaultLocale) InvalidPropertyPattern() string {
return `Property "{{.property}}" does not match pattern {{.pattern}}` return `Property "%property%" does not match pattern %pattern%`
} }
func (l DefaultLocale) StringGTE() string { func (l DefaultLocale) StringGTE() string {
return `String length must be greater than or equal to {{.min}}` return `String length must be greater than or equal to %min%`
} }
func (l DefaultLocale) StringLTE() string { func (l DefaultLocale) StringLTE() string {
return `String length must be less than or equal to {{.max}}` return `String length must be less than or equal to %max%`
} }
func (l DefaultLocale) DoesNotMatchPattern() string { func (l DefaultLocale) DoesNotMatchPattern() string {
return `Does not match pattern '{{.pattern}}'` return `Does not match pattern '%pattern%'`
} }
func (l DefaultLocale) DoesNotMatchFormat() string { func (l DefaultLocale) DoesNotMatchFormat() string {
return `Does not match format '{{.format}}'` return `Does not match format '%format%'`
} }
func (l DefaultLocale) MultipleOf() string { func (l DefaultLocale) MultipleOf() string {
return `Must be a multiple of {{.multiple}}` return `Must be a multiple of %multiple%`
} }
func (l DefaultLocale) NumberGTE() string { func (l DefaultLocale) NumberGTE() string {
return `Must be greater than or equal to {{.min}}` return `Must be greater than or equal to %min%`
} }
func (l DefaultLocale) NumberGT() string { func (l DefaultLocale) NumberGT() string {
return `Must be greater than {{.min}}` return `Must be greater than %min%`
} }
func (l DefaultLocale) NumberLTE() string { func (l DefaultLocale) NumberLTE() string {
return `Must be less than or equal to {{.max}}` return `Must be less than or equal to %max%`
} }
func (l DefaultLocale) NumberLT() string { func (l DefaultLocale) NumberLT() string {
return `Must be less than {{.max}}` return `Must be less than %max%`
} }
// Schema validators // Schema validators
func (l DefaultLocale) RegexPattern() string { func (l DefaultLocale) RegexPattern() string {
return `Invalid regex pattern '{{.pattern}}'` return `Invalid regex pattern '%pattern%'`
} }
func (l DefaultLocale) GreaterThanZero() string { func (l DefaultLocale) GreaterThanZero() string {
return `{{.number}} must be strictly greater than 0` return `%number% must be strictly greater than 0`
} }
func (l DefaultLocale) MustBeOfA() string { func (l DefaultLocale) MustBeOfA() string {
return `{{.x}} must be of a {{.y}}` return `%x% must be of a %y%`
} }
func (l DefaultLocale) MustBeOfAn() string { func (l DefaultLocale) MustBeOfAn() string {
return `{{.x}} must be of an {{.y}}` return `%x% must be of an %y%`
} }
func (l DefaultLocale) CannotBeUsedWithout() string { func (l DefaultLocale) CannotBeUsedWithout() string {
return `{{.x}} cannot be used without {{.y}}` return `%x% cannot be used without %y%`
} }
func (l DefaultLocale) CannotBeGT() string { func (l DefaultLocale) CannotBeGT() string {
return `{{.x}} cannot be greater than {{.y}}` return `%x% cannot be greater than %y%`
} }
func (l DefaultLocale) MustBeOfType() string { func (l DefaultLocale) MustBeOfType() string {
return `{{.key}} must be of type {{.type}}` return `%key% must be of type %type%`
} }
func (l DefaultLocale) MustBeValidRegex() string { func (l DefaultLocale) MustBeValidRegex() string {
return `{{.key}} must be a valid regex` return `%key% must be a valid regex`
} }
func (l DefaultLocale) MustBeValidFormat() string { func (l DefaultLocale) MustBeValidFormat() string {
return `{{.key}} must be a valid format {{.given}}` return `%key% must be a valid format %given%`
} }
func (l DefaultLocale) MustBeGTEZero() string { func (l DefaultLocale) MustBeGTEZero() string {
return `{{.key}} must be greater than or equal to 0` return `%key% must be greater than or equal to 0`
} }
func (l DefaultLocale) KeyCannotBeGreaterThan() string { func (l DefaultLocale) KeyCannotBeGreaterThan() string {
return `{{.key}} cannot be greater than {{.y}}` return `%key% cannot be greater than %y%`
} }
func (l DefaultLocale) KeyItemsMustBeOfType() string { func (l DefaultLocale) KeyItemsMustBeOfType() string {
return `{{.key}} items must be {{.type}}` return `%key% items must be %type%`
} }
func (l DefaultLocale) KeyItemsMustBeUnique() string { func (l DefaultLocale) KeyItemsMustBeUnique() string {
return `{{.key}} items must be unique` return `%key% items must be unique`
} }
func (l DefaultLocale) ReferenceMustBeCanonical() string { func (l DefaultLocale) ReferenceMustBeCanonical() string {
return `Reference {{.reference}} must be canonical` return `Reference %reference% must be canonical`
} }
func (l DefaultLocale) NotAValidType() string { func (l DefaultLocale) NotAValidType() string {
return `has a primitive type that is NOT VALID -- given: {{.given}} Expected valid values are:{{.expected}}` return `%type% is not a valid type -- `
} }
func (l DefaultLocale) Duplicated() string { func (l DefaultLocale) Duplicated() string {
return `{{.type}} type is duplicated` return `%type% type is duplicated`
} }
func (l DefaultLocale) HttpBadStatus() string { func (l DefaultLocale) httpBadStatus() string {
return `Could not read schema from HTTP, response status is {{.status}}` return `Could not read schema from HTTP, response status is %status%`
} }
// Replacement options: field, description, context, value // Replacement options: field, description, context, value
func (l DefaultLocale) ErrorFormat() string { func (l DefaultLocale) ErrorFormat() string {
return `{{.field}}: {{.description}}` return `%field%: %description%`
}
//Parse error
func (l DefaultLocale) ParseError() string {
return `Expected: %expected%, given: Invalid JSON`
} }
const ( const (

View File

@ -48,7 +48,6 @@ type (
Value() interface{} Value() interface{}
SetDetails(ErrorDetails) SetDetails(ErrorDetails)
Details() ErrorDetails Details() ErrorDetails
String() string
} }
// ResultErrorFields holds the fields for each ResultError implementation. // ResultErrorFields holds the fields for each ResultError implementation.

View File

@ -31,7 +31,6 @@ import (
"errors" "errors"
"reflect" "reflect"
"regexp" "regexp"
"text/template"
"github.com/xeipuuv/gojsonreference" "github.com/xeipuuv/gojsonreference"
) )
@ -40,45 +39,10 @@ var (
// Locale is the default locale to use // Locale is the default locale to use
// Library users can overwrite with their own implementation // Library users can overwrite with their own implementation
Locale locale = DefaultLocale{} Locale locale = DefaultLocale{}
// ErrorTemplateFuncs allows you to define custom template funcs for use in localization.
ErrorTemplateFuncs template.FuncMap
) )
func NewSchema(l JSONLoader) (*Schema, error) { func NewSchema(l JSONLoader) (*Schema, error) {
ref, err := l.JsonReference() return l.loadSchema()
if err != nil {
return nil, err
}
d := Schema{}
d.pool = newSchemaPool(l.LoaderFactory())
d.documentReference = ref
d.referencePool = newSchemaReferencePool()
var doc interface{}
if ref.String() != "" {
// Get document from schema pool
spd, err := d.pool.GetDocument(d.documentReference)
if err != nil {
return nil, err
}
doc = spd.Document
} else {
// Load JSON directly
doc, err = l.LoadJSON()
if err != nil {
return nil, err
}
d.pool.SetStandaloneDocument(doc)
}
err = d.parse(doc)
if err != nil {
return nil, err
}
return &d, nil
} }
type Schema struct { type Schema struct {
@ -107,9 +71,10 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
if !isKind(documentNode, reflect.Map) { if !isKind(documentNode, reflect.Map) {
return errors.New(formatErrorDescription( return errors.New(formatErrorDescription(
Locale.ParseError(), Locale.InvalidType(),
ErrorDetails{ ErrorDetails{
"expected": STRING_SCHEMA, "expected": TYPE_OBJECT,
"given": STRING_SCHEMA,
}, },
)) ))
} }
@ -151,27 +116,14 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
} }
if k, ok := m[KEY_REF].(string); ok { if k, ok := m[KEY_REF].(string); ok {
jsonReference, err := gojsonreference.NewJsonReference(k)
if err != nil {
return err
}
if jsonReference.HasFullUrl {
currentSchema.ref = &jsonReference
} else {
inheritedReference, err := currentSchema.ref.Inherits(jsonReference)
if err != nil {
return err
}
currentSchema.ref = inheritedReference
}
if sch, ok := d.referencePool.Get(currentSchema.ref.String() + k); ok { if sch, ok := d.referencePool.Get(currentSchema.ref.String() + k); ok {
currentSchema.refSchema = sch currentSchema.refSchema = sch
} else { } else {
err := d.parseReference(documentNode, currentSchema, k)
var err error
err = d.parseReference(documentNode, currentSchema, k)
if err != nil { if err != nil {
return err return err
} }
@ -803,11 +755,31 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
return nil return nil
} }
func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema, reference string) error { func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema, reference string) (e error) {
var refdDocumentNode interface{}
jsonPointer := currentSchema.ref.GetPointer() var err error
jsonReference, err := gojsonreference.NewJsonReference(reference)
if err != nil {
return err
}
standaloneDocument := d.pool.GetStandaloneDocument() standaloneDocument := d.pool.GetStandaloneDocument()
if jsonReference.HasFullUrl {
currentSchema.ref = &jsonReference
} else {
inheritedReference, err := currentSchema.ref.Inherits(jsonReference)
if err != nil {
return err
}
currentSchema.ref = inheritedReference
}
jsonPointer := currentSchema.ref.GetPointer()
var refdDocumentNode interface{}
if standaloneDocument != nil { if standaloneDocument != nil {
var err error var err error
@ -817,6 +789,8 @@ func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSche
} }
} else { } else {
var err error
dsp, err := d.pool.GetDocument(*currentSchema.ref) dsp, err := d.pool.GetDocument(*currentSchema.ref)
if err != nil { if err != nil {
return err return err
@ -838,10 +812,11 @@ func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSche
// returns the loaded referenced subSchema for the caller to update its current subSchema // returns the loaded referenced subSchema for the caller to update its current subSchema
newSchemaDocument := refdDocumentNode.(map[string]interface{}) newSchemaDocument := refdDocumentNode.(map[string]interface{})
newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref} newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref}
d.referencePool.Add(currentSchema.ref.String()+reference, newSchema) d.referencePool.Add(currentSchema.ref.String()+reference, newSchema)
err := d.parseSchema(newSchemaDocument, newSchema) err = d.parseSchema(newSchemaDocument, newSchema)
if err != nil { if err != nil {
return err return err
} }

View File

@ -39,15 +39,13 @@ type schemaPoolDocument struct {
type schemaPool struct { type schemaPool struct {
schemaPoolDocuments map[string]*schemaPoolDocument schemaPoolDocuments map[string]*schemaPoolDocument
standaloneDocument interface{} standaloneDocument interface{}
jsonLoaderFactory JSONLoaderFactory
} }
func newSchemaPool(f JSONLoaderFactory) *schemaPool { func newSchemaPool() *schemaPool {
p := &schemaPool{} p := &schemaPool{}
p.schemaPoolDocuments = make(map[string]*schemaPoolDocument) p.schemaPoolDocuments = make(map[string]*schemaPoolDocument)
p.standaloneDocument = nil p.standaloneDocument = nil
p.jsonLoaderFactory = f
return p return p
} }
@ -95,8 +93,8 @@ func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*sche
return spd, nil return spd, nil
} }
jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String()) jsonReferenceLoader := NewReferenceLoader(reference.String())
document, err := jsonReferenceLoader.LoadJSON() document, err := jsonReferenceLoader.loadJSON()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -44,7 +44,7 @@ func (t *jsonSchemaType) IsTyped() bool {
func (t *jsonSchemaType) Add(etype string) error { func (t *jsonSchemaType) Add(etype string) error {
if !isStringInSlice(JSON_TYPES, etype) { if !isStringInSlice(JSON_TYPES, etype) {
return errors.New(formatErrorDescription(Locale.NotAValidType(), ErrorDetails{"given": "/" + etype + "/", "expected": JSON_TYPES})) return errors.New(formatErrorDescription(Locale.NotAValidType(), ErrorDetails{"type": etype}))
} }
if t.Contains(etype) { if t.Contains(etype) {

View File

@ -214,7 +214,7 @@ func (s *subSchema) PatternPropertiesString() string {
} }
patternPropertiesKeySlice := []string{} patternPropertiesKeySlice := []string{}
for pk := range s.patternProperties { for pk, _ := range s.patternProperties {
patternPropertiesKeySlice = append(patternPropertiesKeySlice, `"`+pk+`"`) patternPropertiesKeySlice = append(patternPropertiesKeySlice, `"`+pk+`"`)
} }

View File

@ -34,12 +34,7 @@ import (
) )
func isKind(what interface{}, kind reflect.Kind) bool { func isKind(what interface{}, kind reflect.Kind) bool {
target := what return reflect.ValueOf(what).Kind() == kind
if isJsonNumber(what) {
// JSON Numbers are strings!
target = *mustBeNumber(what)
}
return reflect.ValueOf(target).Kind() == kind
} }
func existsMapKey(m map[string]interface{}, k string) bool { func existsMapKey(m map[string]interface{}, k string) bool {
@ -82,14 +77,13 @@ func checkJsonNumber(what interface{}) (isValidFloat64 bool, isValidInt64 bool,
jsonNumber := what.(json.Number) jsonNumber := what.(json.Number)
f64, errFloat64 := jsonNumber.Float64() _, errFloat64 := jsonNumber.Float64()
s64 := strconv.FormatFloat(f64, 'f', -1, 64) _, errInt64 := jsonNumber.Int64()
_, errInt64 := strconv.ParseInt(s64, 10, 64)
isValidFloat64 = errFloat64 == nil isValidFloat64 = errFloat64 == nil
isValidInt64 = errInt64 == nil isValidInt64 = errInt64 == nil
_, errInt32 := strconv.ParseInt(s64, 10, 32) _, errInt32 := strconv.ParseInt(jsonNumber.String(), 10, 32)
isValidInt32 = isValidInt64 && errInt32 == nil isValidInt32 = isValidInt64 && errInt32 == nil
return return

View File

@ -55,7 +55,7 @@ func (v *Schema) Validate(l JSONLoader) (*Result, error) {
// load document // load document
root, err := l.LoadJSON() root, err := l.loadJSON()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -412,7 +412,7 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
internalLog(" %v", value) internalLog(" %v", value)
} }
nbValues := len(value) nbItems := len(value)
// TODO explain // TODO explain
if currentSubSchema.itemsChildrenIsSingleSchema { if currentSubSchema.itemsChildrenIsSingleSchema {
@ -425,18 +425,15 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
if currentSubSchema.itemsChildren != nil && len(currentSubSchema.itemsChildren) > 0 { if currentSubSchema.itemsChildren != nil && len(currentSubSchema.itemsChildren) > 0 {
nbItems := len(currentSubSchema.itemsChildren) nbItems := len(currentSubSchema.itemsChildren)
nbValues := len(value)
// while we have both schemas and values, check them against each other if nbItems == nbValues {
for i := 0; i != nbItems && i != nbValues; i++ { for i := 0; i != nbItems; i++ {
subContext := newJsonContext(strconv.Itoa(i), context) subContext := newJsonContext(strconv.Itoa(i), context)
validationResult := currentSubSchema.itemsChildren[i].subValidateWithContext(value[i], subContext) validationResult := currentSubSchema.itemsChildren[i].subValidateWithContext(value[i], subContext)
result.mergeErrors(validationResult) result.mergeErrors(validationResult)
} }
} else if nbItems < nbValues {
if nbItems < nbValues {
// we have less schemas than elements in the instance array,
// but that might be ok if "additionalItems" is specified.
switch currentSubSchema.additionalItems.(type) { switch currentSubSchema.additionalItems.(type) {
case bool: case bool:
if !currentSubSchema.additionalItems.(bool) { if !currentSubSchema.additionalItems.(bool) {
@ -456,7 +453,7 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
// minItems & maxItems // minItems & maxItems
if currentSubSchema.minItems != nil { if currentSubSchema.minItems != nil {
if nbValues < int(*currentSubSchema.minItems) { if nbItems < int(*currentSubSchema.minItems) {
result.addError( result.addError(
new(ArrayMinItemsError), new(ArrayMinItemsError),
context, context,
@ -466,7 +463,7 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
} }
} }
if currentSubSchema.maxItems != nil { if currentSubSchema.maxItems != nil {
if nbValues > int(*currentSubSchema.maxItems) { if nbItems > int(*currentSubSchema.maxItems) {
result.addError( result.addError(
new(ArrayMaxItemsError), new(ArrayMaxItemsError),
context, context,
@ -568,7 +565,7 @@ func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string
result.addError( result.addError(
new(AdditionalPropertyNotAllowedError), new(AdditionalPropertyNotAllowedError),
context, context,
value[pk], value,
ErrorDetails{"property": pk}, ErrorDetails{"property": pk},
) )
} }
@ -579,7 +576,7 @@ func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string
result.addError( result.addError(
new(AdditionalPropertyNotAllowedError), new(AdditionalPropertyNotAllowedError),
context, context,
value[pk], value,
ErrorDetails{"property": pk}, ErrorDetails{"property": pk},
) )
} }
@ -631,7 +628,7 @@ func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string
result.addError( result.addError(
new(InvalidPropertyPatternError), new(InvalidPropertyPatternError),
context, context,
value[pk], value,
ErrorDetails{ ErrorDetails{
"property": pk, "property": pk,
"pattern": currentSubSchema.PatternPropertiesString(), "pattern": currentSubSchema.PatternPropertiesString(),

27
vendor/golang.org/x/crypto/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/crypto/PATENTS generated vendored Normal file
View File

@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

892
vendor/golang.org/x/crypto/ssh/terminal/terminal.go generated vendored Normal file
View File

@ -0,0 +1,892 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package terminal
import (
"bytes"
"io"
"sync"
"unicode/utf8"
)
// EscapeCodes contains escape sequences that can be written to the terminal in
// order to achieve different styles of text.
type EscapeCodes struct {
// Foreground colors
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
// Reset all attributes
Reset []byte
}
var vt100EscapeCodes = EscapeCodes{
Black: []byte{keyEscape, '[', '3', '0', 'm'},
Red: []byte{keyEscape, '[', '3', '1', 'm'},
Green: []byte{keyEscape, '[', '3', '2', 'm'},
Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
Blue: []byte{keyEscape, '[', '3', '4', 'm'},
Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
White: []byte{keyEscape, '[', '3', '7', 'm'},
Reset: []byte{keyEscape, '[', '0', 'm'},
}
// Terminal contains the state for running a VT100 terminal that is capable of
// reading lines of input.
type Terminal struct {
// AutoCompleteCallback, if non-null, is called for each keypress with
// the full input line and the current position of the cursor (in
// bytes, as an index into |line|). If it returns ok=false, the key
// press is processed normally. Otherwise it returns a replacement line
// and the new cursor position.
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
// Escape contains a pointer to the escape codes for this terminal.
// It's always a valid pointer, although the escape codes themselves
// may be empty if the terminal doesn't support them.
Escape *EscapeCodes
// lock protects the terminal and the state in this object from
// concurrent processing of a key press and a Write() call.
lock sync.Mutex
c io.ReadWriter
prompt []rune
// line is the current line being entered.
line []rune
// pos is the logical position of the cursor in line
pos int
// echo is true if local echo is enabled
echo bool
// pasteActive is true iff there is a bracketed paste operation in
// progress.
pasteActive bool
// cursorX contains the current X value of the cursor where the left
// edge is 0. cursorY contains the row number where the first row of
// the current line is 0.
cursorX, cursorY int
// maxLine is the greatest value of cursorY so far.
maxLine int
termWidth, termHeight int
// outBuf contains the terminal data to be sent.
outBuf []byte
// remainder contains the remainder of any partial key sequences after
// a read. It aliases into inBuf.
remainder []byte
inBuf [256]byte
// history contains previously entered commands so that they can be
// accessed with the up and down keys.
history stRingBuffer
// historyIndex stores the currently accessed history entry, where zero
// means the immediately previous entry.
historyIndex int
// When navigating up and down the history it's possible to return to
// the incomplete, initial line. That value is stored in
// historyPending.
historyPending string
}
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
// a local terminal, that terminal must first have been put into raw mode.
// prompt is a string that is written at the start of each input line (i.e.
// "> ").
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
return &Terminal{
Escape: &vt100EscapeCodes,
c: c,
prompt: []rune(prompt),
termWidth: 80,
termHeight: 24,
echo: true,
historyIndex: -1,
}
}
const (
keyCtrlD = 4
keyCtrlU = 21
keyEnter = '\r'
keyEscape = 27
keyBackspace = 127
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
keyUp
keyDown
keyLeft
keyRight
keyAltLeft
keyAltRight
keyHome
keyEnd
keyDeleteWord
keyDeleteLine
keyClearScreen
keyPasteStart
keyPasteEnd
)
var pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
var pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
// bytesToKey tries to parse a key sequence from b. If successful, it returns
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
if len(b) == 0 {
return utf8.RuneError, nil
}
if !pasteActive {
switch b[0] {
case 1: // ^A
return keyHome, b[1:]
case 5: // ^E
return keyEnd, b[1:]
case 8: // ^H
return keyBackspace, b[1:]
case 11: // ^K
return keyDeleteLine, b[1:]
case 12: // ^L
return keyClearScreen, b[1:]
case 23: // ^W
return keyDeleteWord, b[1:]
}
}
if b[0] != keyEscape {
if !utf8.FullRune(b) {
return utf8.RuneError, b
}
r, l := utf8.DecodeRune(b)
return r, b[l:]
}
if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
switch b[2] {
case 'A':
return keyUp, b[3:]
case 'B':
return keyDown, b[3:]
case 'C':
return keyRight, b[3:]
case 'D':
return keyLeft, b[3:]
case 'H':
return keyHome, b[3:]
case 'F':
return keyEnd, b[3:]
}
}
if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
switch b[5] {
case 'C':
return keyAltRight, b[6:]
case 'D':
return keyAltLeft, b[6:]
}
}
if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
return keyPasteStart, b[6:]
}
if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
return keyPasteEnd, b[6:]
}
// If we get here then we have a key that we don't recognise, or a
// partial sequence. It's not clear how one should find the end of a
// sequence without knowing them all, but it seems that [a-zA-Z~] only
// appears at the end of a sequence.
for i, c := range b[0:] {
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
return keyUnknown, b[i+1:]
}
}
return utf8.RuneError, b
}
// queue appends data to the end of t.outBuf
func (t *Terminal) queue(data []rune) {
t.outBuf = append(t.outBuf, []byte(string(data))...)
}
var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
var space = []rune{' '}
func isPrintable(key rune) bool {
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
return key >= 32 && !isInSurrogateArea
}
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
// given, logical position in the text.
func (t *Terminal) moveCursorToPos(pos int) {
if !t.echo {
return
}
x := visualLength(t.prompt) + pos
y := x / t.termWidth
x = x % t.termWidth
up := 0
if y < t.cursorY {
up = t.cursorY - y
}
down := 0
if y > t.cursorY {
down = y - t.cursorY
}
left := 0
if x < t.cursorX {
left = t.cursorX - x
}
right := 0
if x > t.cursorX {
right = x - t.cursorX
}
t.cursorX = x
t.cursorY = y
t.move(up, down, left, right)
}
func (t *Terminal) move(up, down, left, right int) {
movement := make([]rune, 3*(up+down+left+right))
m := movement
for i := 0; i < up; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'A'
m = m[3:]
}
for i := 0; i < down; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'B'
m = m[3:]
}
for i := 0; i < left; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'D'
m = m[3:]
}
for i := 0; i < right; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'C'
m = m[3:]
}
t.queue(movement)
}
func (t *Terminal) clearLineToRight() {
op := []rune{keyEscape, '[', 'K'}
t.queue(op)
}
const maxLineLength = 4096
func (t *Terminal) setLine(newLine []rune, newPos int) {
if t.echo {
t.moveCursorToPos(0)
t.writeLine(newLine)
for i := len(newLine); i < len(t.line); i++ {
t.writeLine(space)
}
t.moveCursorToPos(newPos)
}
t.line = newLine
t.pos = newPos
}
func (t *Terminal) advanceCursor(places int) {
t.cursorX += places
t.cursorY += t.cursorX / t.termWidth
if t.cursorY > t.maxLine {
t.maxLine = t.cursorY
}
t.cursorX = t.cursorX % t.termWidth
if places > 0 && t.cursorX == 0 {
// Normally terminals will advance the current position
// when writing a character. But that doesn't happen
// for the last character in a line. However, when
// writing a character (except a new line) that causes
// a line wrap, the position will be advanced two
// places.
//
// So, if we are stopping at the end of a line, we
// need to write a newline so that our cursor can be
// advanced to the next line.
t.outBuf = append(t.outBuf, '\n')
}
}
func (t *Terminal) eraseNPreviousChars(n int) {
if n == 0 {
return
}
if t.pos < n {
n = t.pos
}
t.pos -= n
t.moveCursorToPos(t.pos)
copy(t.line[t.pos:], t.line[n+t.pos:])
t.line = t.line[:len(t.line)-n]
if t.echo {
t.writeLine(t.line[t.pos:])
for i := 0; i < n; i++ {
t.queue(space)
}
t.advanceCursor(n)
t.moveCursorToPos(t.pos)
}
}
// countToLeftWord returns then number of characters from the cursor to the
// start of the previous word.
func (t *Terminal) countToLeftWord() int {
if t.pos == 0 {
return 0
}
pos := t.pos - 1
for pos > 0 {
if t.line[pos] != ' ' {
break
}
pos--
}
for pos > 0 {
if t.line[pos] == ' ' {
pos++
break
}
pos--
}
return t.pos - pos
}
// countToRightWord returns then number of characters from the cursor to the
// start of the next word.
func (t *Terminal) countToRightWord() int {
pos := t.pos
for pos < len(t.line) {
if t.line[pos] == ' ' {
break
}
pos++
}
for pos < len(t.line) {
if t.line[pos] != ' ' {
break
}
pos++
}
return pos - t.pos
}
// visualLength returns the number of visible glyphs in s.
func visualLength(runes []rune) int {
inEscapeSeq := false
length := 0
for _, r := range runes {
switch {
case inEscapeSeq:
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
inEscapeSeq = false
}
case r == '\x1b':
inEscapeSeq = true
default:
length++
}
}
return length
}
// handleKey processes the given key and, optionally, returns a line of text
// that the user has entered.
func (t *Terminal) handleKey(key rune) (line string, ok bool) {
if t.pasteActive && key != keyEnter {
t.addKeyToLine(key)
return
}
switch key {
case keyBackspace:
if t.pos == 0 {
return
}
t.eraseNPreviousChars(1)
case keyAltLeft:
// move left by a word.
t.pos -= t.countToLeftWord()
t.moveCursorToPos(t.pos)
case keyAltRight:
// move right by a word.
t.pos += t.countToRightWord()
t.moveCursorToPos(t.pos)
case keyLeft:
if t.pos == 0 {
return
}
t.pos--
t.moveCursorToPos(t.pos)
case keyRight:
if t.pos == len(t.line) {
return
}
t.pos++
t.moveCursorToPos(t.pos)
case keyHome:
if t.pos == 0 {
return
}
t.pos = 0
t.moveCursorToPos(t.pos)
case keyEnd:
if t.pos == len(t.line) {
return
}
t.pos = len(t.line)
t.moveCursorToPos(t.pos)
case keyUp:
entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
if !ok {
return "", false
}
if t.historyIndex == -1 {
t.historyPending = string(t.line)
}
t.historyIndex++
runes := []rune(entry)
t.setLine(runes, len(runes))
case keyDown:
switch t.historyIndex {
case -1:
return
case 0:
runes := []rune(t.historyPending)
t.setLine(runes, len(runes))
t.historyIndex--
default:
entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
if ok {
t.historyIndex--
runes := []rune(entry)
t.setLine(runes, len(runes))
}
}
case keyEnter:
t.moveCursorToPos(len(t.line))
t.queue([]rune("\r\n"))
line = string(t.line)
ok = true
t.line = t.line[:0]
t.pos = 0
t.cursorX = 0
t.cursorY = 0
t.maxLine = 0
case keyDeleteWord:
// Delete zero or more spaces and then one or more characters.
t.eraseNPreviousChars(t.countToLeftWord())
case keyDeleteLine:
// Delete everything from the current cursor position to the
// end of line.
for i := t.pos; i < len(t.line); i++ {
t.queue(space)
t.advanceCursor(1)
}
t.line = t.line[:t.pos]
t.moveCursorToPos(t.pos)
case keyCtrlD:
// Erase the character under the current position.
// The EOF case when the line is empty is handled in
// readLine().
if t.pos < len(t.line) {
t.pos++
t.eraseNPreviousChars(1)
}
case keyCtrlU:
t.eraseNPreviousChars(t.pos)
case keyClearScreen:
// Erases the screen and moves the cursor to the home position.
t.queue([]rune("\x1b[2J\x1b[H"))
t.queue(t.prompt)
t.cursorX, t.cursorY = 0, 0
t.advanceCursor(visualLength(t.prompt))
t.setLine(t.line, t.pos)
default:
if t.AutoCompleteCallback != nil {
prefix := string(t.line[:t.pos])
suffix := string(t.line[t.pos:])
t.lock.Unlock()
newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
t.lock.Lock()
if completeOk {
t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
return
}
}
if !isPrintable(key) {
return
}
if len(t.line) == maxLineLength {
return
}
t.addKeyToLine(key)
}
return
}
// addKeyToLine inserts the given key at the current position in the current
// line.
func (t *Terminal) addKeyToLine(key rune) {
if len(t.line) == cap(t.line) {
newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
copy(newLine, t.line)
t.line = newLine
}
t.line = t.line[:len(t.line)+1]
copy(t.line[t.pos+1:], t.line[t.pos:])
t.line[t.pos] = key
if t.echo {
t.writeLine(t.line[t.pos:])
}
t.pos++
t.moveCursorToPos(t.pos)
}
func (t *Terminal) writeLine(line []rune) {
for len(line) != 0 {
remainingOnLine := t.termWidth - t.cursorX
todo := len(line)
if todo > remainingOnLine {
todo = remainingOnLine
}
t.queue(line[:todo])
t.advanceCursor(visualLength(line[:todo]))
line = line[todo:]
}
}
func (t *Terminal) Write(buf []byte) (n int, err error) {
t.lock.Lock()
defer t.lock.Unlock()
if t.cursorX == 0 && t.cursorY == 0 {
// This is the easy case: there's nothing on the screen that we
// have to move out of the way.
return t.c.Write(buf)
}
// We have a prompt and possibly user input on the screen. We
// have to clear it first.
t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
t.cursorX = 0
t.clearLineToRight()
for t.cursorY > 0 {
t.move(1 /* up */, 0, 0, 0)
t.cursorY--
t.clearLineToRight()
}
if _, err = t.c.Write(t.outBuf); err != nil {
return
}
t.outBuf = t.outBuf[:0]
if n, err = t.c.Write(buf); err != nil {
return
}
t.writeLine(t.prompt)
if t.echo {
t.writeLine(t.line)
}
t.moveCursorToPos(t.pos)
if _, err = t.c.Write(t.outBuf); err != nil {
return
}
t.outBuf = t.outBuf[:0]
return
}
// ReadPassword temporarily changes the prompt and reads a password, without
// echo, from the terminal.
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()
oldPrompt := t.prompt
t.prompt = []rune(prompt)
t.echo = false
line, err = t.readLine()
t.prompt = oldPrompt
t.echo = true
return
}
// ReadLine returns a line of input from the terminal.
func (t *Terminal) ReadLine() (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()
return t.readLine()
}
func (t *Terminal) readLine() (line string, err error) {
// t.lock must be held at this point
if t.cursorX == 0 && t.cursorY == 0 {
t.writeLine(t.prompt)
t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
}
lineIsPasted := t.pasteActive
for {
rest := t.remainder
lineOk := false
for !lineOk {
var key rune
key, rest = bytesToKey(rest, t.pasteActive)
if key == utf8.RuneError {
break
}
if !t.pasteActive {
if key == keyCtrlD {
if len(t.line) == 0 {
return "", io.EOF
}
}
if key == keyPasteStart {
t.pasteActive = true
if len(t.line) == 0 {
lineIsPasted = true
}
continue
}
} else if key == keyPasteEnd {
t.pasteActive = false
continue
}
if !t.pasteActive {
lineIsPasted = false
}
line, lineOk = t.handleKey(key)
}
if len(rest) > 0 {
n := copy(t.inBuf[:], rest)
t.remainder = t.inBuf[:n]
} else {
t.remainder = nil
}
t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
if lineOk {
if t.echo {
t.historyIndex = -1
t.history.Add(line)
}
if lineIsPasted {
err = ErrPasteIndicator
}
return
}
// t.remainder is a slice at the beginning of t.inBuf
// containing a partial key sequence
readBuf := t.inBuf[len(t.remainder):]
var n int
t.lock.Unlock()
n, err = t.c.Read(readBuf)
t.lock.Lock()
if err != nil {
return
}
t.remainder = t.inBuf[:n+len(t.remainder)]
}
panic("unreachable") // for Go 1.0.
}
// SetPrompt sets the prompt to be used when reading subsequent lines.
func (t *Terminal) SetPrompt(prompt string) {
t.lock.Lock()
defer t.lock.Unlock()
t.prompt = []rune(prompt)
}
func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
// Move cursor to column zero at the start of the line.
t.move(t.cursorY, 0, t.cursorX, 0)
t.cursorX, t.cursorY = 0, 0
t.clearLineToRight()
for t.cursorY < numPrevLines {
// Move down a line
t.move(0, 1, 0, 0)
t.cursorY++
t.clearLineToRight()
}
// Move back to beginning.
t.move(t.cursorY, 0, 0, 0)
t.cursorX, t.cursorY = 0, 0
t.queue(t.prompt)
t.advanceCursor(visualLength(t.prompt))
t.writeLine(t.line)
t.moveCursorToPos(t.pos)
}
func (t *Terminal) SetSize(width, height int) error {
t.lock.Lock()
defer t.lock.Unlock()
if width == 0 {
width = 1
}
oldWidth := t.termWidth
t.termWidth, t.termHeight = width, height
switch {
case width == oldWidth:
// If the width didn't change then nothing else needs to be
// done.
return nil
case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
// If there is nothing on current line and no prompt printed,
// just do nothing
return nil
case width < oldWidth:
// Some terminals (e.g. xterm) will truncate lines that were
// too long when shinking. Others, (e.g. gnome-terminal) will
// attempt to wrap them. For the former, repainting t.maxLine
// works great, but that behaviour goes badly wrong in the case
// of the latter because they have doubled every full line.
// We assume that we are working on a terminal that wraps lines
// and adjust the cursor position based on every previous line
// wrapping and turning into two. This causes the prompt on
// xterms to move upwards, which isn't great, but it avoids a
// huge mess with gnome-terminal.
if t.cursorX >= t.termWidth {
t.cursorX = t.termWidth - 1
}
t.cursorY *= 2
t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
case width > oldWidth:
// If the terminal expands then our position calculations will
// be wrong in the future because we think the cursor is
// |t.pos| chars into the string, but there will be a gap at
// the end of any wrapped line.
//
// But the position will actually be correct until we move, so
// we can move back to the beginning and repaint everything.
t.clearAndRepaintLinePlusNPrevious(t.maxLine)
}
_, err := t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
return err
}
type pasteIndicatorError struct{}
func (pasteIndicatorError) Error() string {
return "terminal: ErrPasteIndicator not correctly handled"
}
// ErrPasteIndicator may be returned from ReadLine as the error, in addition
// to valid line data. It indicates that bracketed paste mode is enabled and
// that the returned line consists only of pasted data. Programs may wish to
// interpret pasted data more literally than typed data.
var ErrPasteIndicator = pasteIndicatorError{}
// SetBracketedPasteMode requests that the terminal bracket paste operations
// with markers. Not all terminals support this but, if it is supported, then
// enabling this mode will stop any autocomplete callback from running due to
// pastes. Additionally, any lines that are completely pasted will be returned
// from ReadLine with the error set to ErrPasteIndicator.
func (t *Terminal) SetBracketedPasteMode(on bool) {
if on {
io.WriteString(t.c, "\x1b[?2004h")
} else {
io.WriteString(t.c, "\x1b[?2004l")
}
}
// stRingBuffer is a ring buffer of strings.
type stRingBuffer struct {
// entries contains max elements.
entries []string
max int
// head contains the index of the element most recently added to the ring.
head int
// size contains the number of elements in the ring.
size int
}
func (s *stRingBuffer) Add(a string) {
if s.entries == nil {
const defaultNumEntries = 100
s.entries = make([]string, defaultNumEntries)
s.max = defaultNumEntries
}
s.head = (s.head + 1) % s.max
s.entries[s.head] = a
if s.size < s.max {
s.size++
}
}
// NthPreviousEntry returns the value passed to the nth previous call to Add.
// If n is zero then the immediately prior value is returned, if one, then the
// next most recent, and so on. If such an element doesn't exist then ok is
// false.
func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
if n >= s.size {
return "", false
}
index := s.head - n
if index < 0 {
index += s.max
}
return s.entries[index], true
}

128
vendor/golang.org/x/crypto/ssh/terminal/util.go generated vendored Normal file
View File

@ -0,0 +1,128 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Putting a terminal into raw mode is the most common requirement:
//
// oldState, err := terminal.MakeRaw(0)
// if err != nil {
// panic(err)
// }
// defer terminal.Restore(0, oldState)
package terminal // import "golang.org/x/crypto/ssh/terminal"
import (
"io"
"syscall"
"unsafe"
)
// State contains the state of a terminal.
type State struct {
termios syscall.Termios
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}
// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
var oldState State
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
return nil, err
}
newState := oldState.termios
newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
return nil, err
}
return &oldState, nil
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
var oldState State
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
return nil, err
}
return &oldState, nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
return err
}
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
var dimensions [4]uint16
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 {
return -1, -1, err
}
return int(dimensions[1]), int(dimensions[0]), nil
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
var oldState syscall.Termios
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 {
return nil, err
}
newState := oldState
newState.Lflag &^= syscall.ECHO
newState.Lflag |= syscall.ICANON | syscall.ISIG
newState.Iflag |= syscall.ICRNL
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
return nil, err
}
defer func() {
syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0)
}()
var buf [16]byte
var ret []byte
for {
n, err := syscall.Read(fd, buf[:])
if err != nil {
return nil, err
}
if n == 0 {
if len(ret) == 0 {
return nil, io.EOF
}
break
}
if buf[n-1] == '\n' {
n--
}
ret = append(ret, buf[:n]...)
if n < len(buf) {
break
}
}
return ret, nil
}

12
vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd netbsd openbsd
package terminal
import "syscall"
const ioctlReadTermios = syscall.TIOCGETA
const ioctlWriteTermios = syscall.TIOCSETA

11
vendor/golang.org/x/crypto/ssh/terminal/util_linux.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
// 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 terminal
// These constants are declared here, rather than importing
// them from the syscall package as some syscall packages, even
// on linux, for example gccgo, do not declare them.
const ioctlReadTermios = 0x5401 // syscall.TCGETS
const ioctlWriteTermios = 0x5402 // syscall.TCSETS

174
vendor/golang.org/x/crypto/ssh/terminal/util_windows.go generated vendored Normal file
View File

@ -0,0 +1,174 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Putting a terminal into raw mode is the most common requirement:
//
// oldState, err := terminal.MakeRaw(0)
// if err != nil {
// panic(err)
// }
// defer terminal.Restore(0, oldState)
package terminal
import (
"io"
"syscall"
"unsafe"
)
const (
enableLineInput = 2
enableEchoInput = 4
enableProcessedInput = 1
enableWindowInput = 8
enableMouseInput = 16
enableInsertMode = 32
enableQuickEditMode = 64
enableExtendedFlags = 128
enableAutoPosition = 256
enableProcessedOutput = 1
enableWrapAtEolOutput = 2
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
)
type (
short int16
word uint16
coord struct {
x short
y short
}
smallRect struct {
left short
top short
right short
bottom short
}
consoleScreenBufferInfo struct {
size coord
cursorPosition coord
attributes word
window smallRect
maximumWindowSize coord
}
)
type State struct {
mode uint32
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
st &^= (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
if e != 0 {
return nil, error(e)
}
return &State{st}, nil
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
return &State{st}, nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
_, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
return err
}
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
var info consoleScreenBufferInfo
_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
if e != 0 {
return 0, 0, error(e)
}
return int(info.size.x), int(info.size.y), nil
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
old := st
st &^= (enableEchoInput)
st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
if e != 0 {
return nil, error(e)
}
defer func() {
syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
}()
var buf [16]byte
var ret []byte
for {
n, err := syscall.Read(syscall.Handle(fd), buf[:])
if err != nil {
return nil, err
}
if n == 0 {
if len(ret) == 0 {
return nil, io.EOF
}
break
}
if buf[n-1] == '\n' {
n--
}
if n > 0 && buf[n-1] == '\r' {
n--
}
ret = append(ret, buf[:n]...)
if n < len(buf) {
break
}
}
return ret, nil
}

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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux
// +build mips64 mips64le
// +build !gccgo // +build !gccgo
#include "textflag.h" #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. // Just jump to package syscall's implementation for all these functions.
// The runtime may know about them. // The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-32 TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB) JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-44 TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB) JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-56 TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-32
JMP syscall·RawSyscall(SB) JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-44 TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB) 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)

29
vendor/golang.org/x/sys/unix/asm_openbsd_arm.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
#include "textflag.h"
//
// System call support for ARM, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)

View File

@ -10,8 +10,8 @@
// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go // System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go
// //
TEXT ·sysvicall6(SB),NOSPLIT,$0-64 TEXT ·sysvicall6(SB),NOSPLIT,$0-88
JMP syscall·sysvicall6(SB) JMP syscall·sysvicall6(SB)
TEXT ·rawSysvicall6(SB),NOSPLIT,$0-64 TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88
JMP syscall·rawSysvicall6(SB) JMP syscall·rawSysvicall6(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
)

195
vendor/golang.org/x/sys/unix/cap_freebsd.go generated vendored Normal file
View File

@ -0,0 +1,195 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build freebsd
package unix
import (
errorspkg "errors"
"fmt"
)
// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
const (
// This is the version of CapRights this package understands. See C implementation for parallels.
capRightsGoVersion = CAP_RIGHTS_VERSION_00
capArSizeMin = CAP_RIGHTS_VERSION_00 + 2
capArSizeMax = capRightsGoVersion + 2
)
var (
bit2idx = []int{
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
}
)
func capidxbit(right uint64) int {
return int((right >> 57) & 0x1f)
}
func rightToIndex(right uint64) (int, error) {
idx := capidxbit(right)
if idx < 0 || idx >= len(bit2idx) {
return -2, fmt.Errorf("index for right 0x%x out of range", right)
}
return bit2idx[idx], nil
}
func caprver(right uint64) int {
return int(right >> 62)
}
func capver(rights *CapRights) int {
return caprver(rights.Rights[0])
}
func caparsize(rights *CapRights) int {
return capver(rights) + 2
}
// CapRightsSet sets the permissions in setrights in rights.
func CapRightsSet(rights *CapRights, setrights []uint64) error {
// This is essentially a copy of cap_rights_vset()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return errorspkg.New("bad rights size")
}
for _, right := range setrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return errorspkg.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return err
}
if i >= n {
return errorspkg.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errorspkg.New("index mismatch")
}
rights.Rights[i] |= right
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errorspkg.New("index mismatch (after assign)")
}
}
return nil
}
// CapRightsClear clears the permissions in clearrights from rights.
func CapRightsClear(rights *CapRights, clearrights []uint64) error {
// This is essentially a copy of cap_rights_vclear()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return errorspkg.New("bad rights size")
}
for _, right := range clearrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return errorspkg.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return err
}
if i >= n {
return errorspkg.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errorspkg.New("index mismatch")
}
rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errorspkg.New("index mismatch (after assign)")
}
}
return nil
}
// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
// This is essentially a copy of cap_rights_is_vset()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return false, fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return false, errorspkg.New("bad rights size")
}
for _, right := range setrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return false, errorspkg.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return false, err
}
if i >= n {
return false, errorspkg.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return false, errorspkg.New("index mismatch")
}
if (rights.Rights[i] & right) != right {
return false, nil
}
}
return true, nil
}
func capright(idx uint64, bit uint64) uint64 {
return ((1 << (57 + idx)) | bit)
}
// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
// See man cap_rights_init(3) and rights(4).
func CapRightsInit(rights []uint64) (*CapRights, error) {
var r CapRights
r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
r.Rights[1] = capright(1, 0)
err := CapRightsSet(&r, rights)
if err != nil {
return nil, err
}
return &r, nil
}
// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
// The capability rights on fd can never be increased by CapRightsLimit.
// See man cap_rights_limit(2) and rights(4).
func CapRightsLimit(fd uintptr, rights *CapRights) error {
return capRightsLimit(int(fd), rights)
}
// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
// See man cap_rights_get(3) and rights(4).
func CapRightsGet(fd uintptr) (*CapRights, error) {
r, err := CapRightsInit(nil)
if err != nil {
return nil, err
}
err = capRightsGet(capRightsGoVersion, int(fd), r)
if err != nil {
return nil, err
}
return r, nil
}

24
vendor/golang.org/x/sys/unix/dev_darwin.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Functions to access/create device major and minor numbers matching the
// encoding used in Darwin's sys/types.h header.
package unix
// Major returns the major component of a Darwin device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 24) & 0xff)
}
// Minor returns the minor component of a Darwin device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffffff)
}
// Mkdev returns a Darwin device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 24) | uint64(minor)
}

30
vendor/golang.org/x/sys/unix/dev_dragonfly.go generated vendored Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Functions to access/create device major and minor numbers matching the
// encoding used in Dragonfly's sys/types.h header.
//
// The information below is extracted and adapted from sys/types.h:
//
// Minor gives a cookie instead of an index since in order to avoid changing the
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
// devices that don't use them.
package unix
// Major returns the major component of a DragonFlyBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 8) & 0xff)
}
// Minor returns the minor component of a DragonFlyBSD device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff00ff)
}
// Mkdev returns a DragonFlyBSD device number generated from the given major and
// minor components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 8) | uint64(minor)
}

30
vendor/golang.org/x/sys/unix/dev_freebsd.go generated vendored Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Functions to access/create device major and minor numbers matching the
// encoding used in FreeBSD's sys/types.h header.
//
// The information below is extracted and adapted from sys/types.h:
//
// Minor gives a cookie instead of an index since in order to avoid changing the
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
// devices that don't use them.
package unix
// Major returns the major component of a FreeBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 8) & 0xff)
}
// Minor returns the minor component of a FreeBSD device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff00ff)
}
// Mkdev returns a FreeBSD device number generated from the given major and
// minor components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 8) | uint64(minor)
}

42
vendor/golang.org/x/sys/unix/dev_linux.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Functions to access/create device major and minor numbers matching the
// encoding used by the Linux kernel and glibc.
//
// The information below is extracted and adapted from bits/sysmacros.h in the
// glibc sources:
//
// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
// number and m is a hex digit of the minor number. This is backward compatible
// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
// backward compatible with the Linux kernel, which for some architectures uses
// 32-bit dev_t, encoded as mmmM MMmm.
package unix
// Major returns the major component of a Linux device number.
func Major(dev uint64) uint32 {
major := uint32((dev & 0x00000000000fff00) >> 8)
major |= uint32((dev & 0xfffff00000000000) >> 32)
return major
}
// Minor returns the minor component of a Linux device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x00000000000000ff) >> 0)
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
return minor
}
// Mkdev returns a Linux device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) & 0x00000fff) << 8
dev |= (uint64(major) & 0xfffff000) << 32
dev |= (uint64(minor) & 0x000000ff) << 0
dev |= (uint64(minor) & 0xffffff00) << 12
return dev
}

29
vendor/golang.org/x/sys/unix/dev_netbsd.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Functions to access/create device major and minor numbers matching the
// encoding used in NetBSD's sys/types.h header.
package unix
// Major returns the major component of a NetBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev & 0x000fff00) >> 8)
}
// Minor returns the minor component of a NetBSD device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x000000ff) >> 0)
minor |= uint32((dev & 0xfff00000) >> 12)
return minor
}
// Mkdev returns a NetBSD device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) << 8) & 0x000fff00
dev |= (uint64(minor) << 12) & 0xfff00000
dev |= (uint64(minor) << 0) & 0x000000ff
return dev
}

29
vendor/golang.org/x/sys/unix/dev_openbsd.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Functions to access/create device major and minor numbers matching the
// encoding used in OpenBSD's sys/types.h header.
package unix
// Major returns the major component of an OpenBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev & 0x0000ff00) >> 8)
}
// Minor returns the minor component of an OpenBSD device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x000000ff) >> 0)
minor |= uint32((dev & 0xffff0000) >> 8)
return minor
}
// Mkdev returns an OpenBSD device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) << 8) & 0x0000ff00
dev |= (uint64(minor) << 8) & 0xffff0000
dev |= (uint64(minor) << 0) & 0x000000ff
return dev
}

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 mips 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 mipsle mips64le
package unix
const isBigEndian = false

227
vendor/golang.org/x/sys/unix/errors_freebsd_386.go generated vendored Normal file
View File

@ -0,0 +1,227 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
// them here for backwards compatibility.
package unix
const (
IFF_SMART = 0x20
IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82
IFT_AAL2 = 0xbb
IFT_AAL5 = 0x31
IFT_ADSL = 0x5e
IFT_AFLANE8023 = 0x3b
IFT_AFLANE8025 = 0x3c
IFT_ARAP = 0x58
IFT_ARCNET = 0x23
IFT_ARCNETPLUS = 0x24
IFT_ASYNC = 0x54
IFT_ATM = 0x25
IFT_ATMDXI = 0x69
IFT_ATMFUNI = 0x6a
IFT_ATMIMA = 0x6b
IFT_ATMLOGICAL = 0x50
IFT_ATMRADIO = 0xbd
IFT_ATMSUBINTERFACE = 0x86
IFT_ATMVCIENDPT = 0xc2
IFT_ATMVIRTUAL = 0x95
IFT_BGPPOLICYACCOUNTING = 0xa2
IFT_BSC = 0x53
IFT_CCTEMUL = 0x3d
IFT_CEPT = 0x13
IFT_CES = 0x85
IFT_CHANNEL = 0x46
IFT_CNR = 0x55
IFT_COFFEE = 0x84
IFT_COMPOSITELINK = 0x9b
IFT_DCN = 0x8d
IFT_DIGITALPOWERLINE = 0x8a
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
IFT_DLSW = 0x4a
IFT_DOCSCABLEDOWNSTREAM = 0x80
IFT_DOCSCABLEMACLAYER = 0x7f
IFT_DOCSCABLEUPSTREAM = 0x81
IFT_DS0 = 0x51
IFT_DS0BUNDLE = 0x52
IFT_DS1FDL = 0xaa
IFT_DS3 = 0x1e
IFT_DTM = 0x8c
IFT_DVBASILN = 0xac
IFT_DVBASIOUT = 0xad
IFT_DVBRCCDOWNSTREAM = 0x93
IFT_DVBRCCMACLAYER = 0x92
IFT_DVBRCCUPSTREAM = 0x94
IFT_ENC = 0xf4
IFT_EON = 0x19
IFT_EPLRS = 0x57
IFT_ESCON = 0x49
IFT_ETHER = 0x6
IFT_FAITH = 0xf2
IFT_FAST = 0x7d
IFT_FASTETHER = 0x3e
IFT_FASTETHERFX = 0x45
IFT_FDDI = 0xf
IFT_FIBRECHANNEL = 0x38
IFT_FRAMERELAYINTERCONNECT = 0x3a
IFT_FRAMERELAYMPI = 0x5c
IFT_FRDLCIENDPT = 0xc1
IFT_FRELAY = 0x20
IFT_FRELAYDCE = 0x2c
IFT_FRF16MFRBUNDLE = 0xa3
IFT_FRFORWARD = 0x9e
IFT_G703AT2MB = 0x43
IFT_G703AT64K = 0x42
IFT_GIF = 0xf0
IFT_GIGABITETHERNET = 0x75
IFT_GR303IDT = 0xb2
IFT_GR303RDT = 0xb1
IFT_H323GATEKEEPER = 0xa4
IFT_H323PROXY = 0xa5
IFT_HDH1822 = 0x3
IFT_HDLC = 0x76
IFT_HDSL2 = 0xa8
IFT_HIPERLAN2 = 0xb7
IFT_HIPPI = 0x2f
IFT_HIPPIINTERFACE = 0x39
IFT_HOSTPAD = 0x5a
IFT_HSSI = 0x2e
IFT_HY = 0xe
IFT_IBM370PARCHAN = 0x48
IFT_IDSL = 0x9a
IFT_IEEE80211 = 0x47
IFT_IEEE80212 = 0x37
IFT_IEEE8023ADLAG = 0xa1
IFT_IFGSN = 0x91
IFT_IMT = 0xbe
IFT_INTERLEAVE = 0x7c
IFT_IP = 0x7e
IFT_IPFORWARD = 0x8e
IFT_IPOVERATM = 0x72
IFT_IPOVERCDLC = 0x6d
IFT_IPOVERCLAW = 0x6e
IFT_IPSWITCH = 0x4e
IFT_IPXIP = 0xf9
IFT_ISDN = 0x3f
IFT_ISDNBASIC = 0x14
IFT_ISDNPRIMARY = 0x15
IFT_ISDNS = 0x4b
IFT_ISDNU = 0x4c
IFT_ISO88022LLC = 0x29
IFT_ISO88023 = 0x7
IFT_ISO88024 = 0x8
IFT_ISO88025 = 0x9
IFT_ISO88025CRFPINT = 0x62
IFT_ISO88025DTR = 0x56
IFT_ISO88025FIBER = 0x73
IFT_ISO88026 = 0xa
IFT_ISUP = 0xb3
IFT_L3IPXVLAN = 0x89
IFT_LAPB = 0x10
IFT_LAPD = 0x4d
IFT_LAPF = 0x77
IFT_LOCALTALK = 0x2a
IFT_LOOP = 0x18
IFT_MEDIAMAILOVERIP = 0x8b
IFT_MFSIGLINK = 0xa7
IFT_MIOX25 = 0x26
IFT_MODEM = 0x30
IFT_MPC = 0x71
IFT_MPLS = 0xa6
IFT_MPLSTUNNEL = 0x96
IFT_MSDSL = 0x8f
IFT_MVL = 0xbf
IFT_MYRINET = 0x63
IFT_NFAS = 0xaf
IFT_NSIP = 0x1b
IFT_OPTICALCHANNEL = 0xc3
IFT_OPTICALTRANSPORT = 0xc4
IFT_OTHER = 0x1
IFT_P10 = 0xc
IFT_P80 = 0xd
IFT_PARA = 0x22
IFT_PFLOG = 0xf6
IFT_PFSYNC = 0xf7
IFT_PLC = 0xae
IFT_POS = 0xab
IFT_PPPMULTILINKBUNDLE = 0x6c
IFT_PROPBWAP2MP = 0xb8
IFT_PROPCNLS = 0x59
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
IFT_PROPMUX = 0x36
IFT_PROPWIRELESSP2P = 0x9d
IFT_PTPSERIAL = 0x16
IFT_PVC = 0xf1
IFT_QLLC = 0x44
IFT_RADIOMAC = 0xbc
IFT_RADSL = 0x5f
IFT_REACHDSL = 0xc0
IFT_RFC1483 = 0x9f
IFT_RS232 = 0x21
IFT_RSRB = 0x4f
IFT_SDLC = 0x11
IFT_SDSL = 0x60
IFT_SHDSL = 0xa9
IFT_SIP = 0x1f
IFT_SLIP = 0x1c
IFT_SMDSDXI = 0x2b
IFT_SMDSICIP = 0x34
IFT_SONET = 0x27
IFT_SONETOVERHEADCHANNEL = 0xb9
IFT_SONETPATH = 0x32
IFT_SONETVT = 0x33
IFT_SRP = 0x97
IFT_SS7SIGLINK = 0x9c
IFT_STACKTOSTACK = 0x6f
IFT_STARLAN = 0xb
IFT_STF = 0xd7
IFT_T1 = 0x12
IFT_TDLC = 0x74
IFT_TERMPAD = 0x5b
IFT_TR008 = 0xb0
IFT_TRANSPHDLC = 0x7b
IFT_TUNNEL = 0x83
IFT_ULTRA = 0x1d
IFT_USB = 0xa0
IFT_V11 = 0x40
IFT_V35 = 0x2d
IFT_V36 = 0x41
IFT_V37 = 0x78
IFT_VDSL = 0x61
IFT_VIRTUALIPADDRESS = 0x70
IFT_VOICEEM = 0x64
IFT_VOICEENCAP = 0x67
IFT_VOICEFXO = 0x65
IFT_VOICEFXS = 0x66
IFT_VOICEOVERATM = 0x98
IFT_VOICEOVERFRAMERELAY = 0x99
IFT_VOICEOVERIP = 0x68
IFT_X213 = 0x5d
IFT_X25 = 0x5
IFT_X25DDN = 0x4
IFT_X25HUNTGROUP = 0x7a
IFT_X25MLP = 0x79
IFT_X25PLE = 0x28
IFT_XETHER = 0x1a
IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d
IP_FAITH = 0x16
MAP_NORESERVE = 0x40
MAP_RENAME = 0x20
NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa
SIOCADDRT = 0x8030720a
SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8030720b
SIOCDLIFADDR = 0x8118691d
SIOCGLIFADDR = 0xc118691c
SIOCGLIFPHYADDR = 0xc118694b
SIOCSLIFPHYADDR = 0x8118694a
)

227
vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go generated vendored Normal file
View File

@ -0,0 +1,227 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
// them here for backwards compatibility.
package unix
const (
IFF_SMART = 0x20
IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82
IFT_AAL2 = 0xbb
IFT_AAL5 = 0x31
IFT_ADSL = 0x5e
IFT_AFLANE8023 = 0x3b
IFT_AFLANE8025 = 0x3c
IFT_ARAP = 0x58
IFT_ARCNET = 0x23
IFT_ARCNETPLUS = 0x24
IFT_ASYNC = 0x54
IFT_ATM = 0x25
IFT_ATMDXI = 0x69
IFT_ATMFUNI = 0x6a
IFT_ATMIMA = 0x6b
IFT_ATMLOGICAL = 0x50
IFT_ATMRADIO = 0xbd
IFT_ATMSUBINTERFACE = 0x86
IFT_ATMVCIENDPT = 0xc2
IFT_ATMVIRTUAL = 0x95
IFT_BGPPOLICYACCOUNTING = 0xa2
IFT_BSC = 0x53
IFT_CCTEMUL = 0x3d
IFT_CEPT = 0x13
IFT_CES = 0x85
IFT_CHANNEL = 0x46
IFT_CNR = 0x55
IFT_COFFEE = 0x84
IFT_COMPOSITELINK = 0x9b
IFT_DCN = 0x8d
IFT_DIGITALPOWERLINE = 0x8a
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
IFT_DLSW = 0x4a
IFT_DOCSCABLEDOWNSTREAM = 0x80
IFT_DOCSCABLEMACLAYER = 0x7f
IFT_DOCSCABLEUPSTREAM = 0x81
IFT_DS0 = 0x51
IFT_DS0BUNDLE = 0x52
IFT_DS1FDL = 0xaa
IFT_DS3 = 0x1e
IFT_DTM = 0x8c
IFT_DVBASILN = 0xac
IFT_DVBASIOUT = 0xad
IFT_DVBRCCDOWNSTREAM = 0x93
IFT_DVBRCCMACLAYER = 0x92
IFT_DVBRCCUPSTREAM = 0x94
IFT_ENC = 0xf4
IFT_EON = 0x19
IFT_EPLRS = 0x57
IFT_ESCON = 0x49
IFT_ETHER = 0x6
IFT_FAITH = 0xf2
IFT_FAST = 0x7d
IFT_FASTETHER = 0x3e
IFT_FASTETHERFX = 0x45
IFT_FDDI = 0xf
IFT_FIBRECHANNEL = 0x38
IFT_FRAMERELAYINTERCONNECT = 0x3a
IFT_FRAMERELAYMPI = 0x5c
IFT_FRDLCIENDPT = 0xc1
IFT_FRELAY = 0x20
IFT_FRELAYDCE = 0x2c
IFT_FRF16MFRBUNDLE = 0xa3
IFT_FRFORWARD = 0x9e
IFT_G703AT2MB = 0x43
IFT_G703AT64K = 0x42
IFT_GIF = 0xf0
IFT_GIGABITETHERNET = 0x75
IFT_GR303IDT = 0xb2
IFT_GR303RDT = 0xb1
IFT_H323GATEKEEPER = 0xa4
IFT_H323PROXY = 0xa5
IFT_HDH1822 = 0x3
IFT_HDLC = 0x76
IFT_HDSL2 = 0xa8
IFT_HIPERLAN2 = 0xb7
IFT_HIPPI = 0x2f
IFT_HIPPIINTERFACE = 0x39
IFT_HOSTPAD = 0x5a
IFT_HSSI = 0x2e
IFT_HY = 0xe
IFT_IBM370PARCHAN = 0x48
IFT_IDSL = 0x9a
IFT_IEEE80211 = 0x47
IFT_IEEE80212 = 0x37
IFT_IEEE8023ADLAG = 0xa1
IFT_IFGSN = 0x91
IFT_IMT = 0xbe
IFT_INTERLEAVE = 0x7c
IFT_IP = 0x7e
IFT_IPFORWARD = 0x8e
IFT_IPOVERATM = 0x72
IFT_IPOVERCDLC = 0x6d
IFT_IPOVERCLAW = 0x6e
IFT_IPSWITCH = 0x4e
IFT_IPXIP = 0xf9
IFT_ISDN = 0x3f
IFT_ISDNBASIC = 0x14
IFT_ISDNPRIMARY = 0x15
IFT_ISDNS = 0x4b
IFT_ISDNU = 0x4c
IFT_ISO88022LLC = 0x29
IFT_ISO88023 = 0x7
IFT_ISO88024 = 0x8
IFT_ISO88025 = 0x9
IFT_ISO88025CRFPINT = 0x62
IFT_ISO88025DTR = 0x56
IFT_ISO88025FIBER = 0x73
IFT_ISO88026 = 0xa
IFT_ISUP = 0xb3
IFT_L3IPXVLAN = 0x89
IFT_LAPB = 0x10
IFT_LAPD = 0x4d
IFT_LAPF = 0x77
IFT_LOCALTALK = 0x2a
IFT_LOOP = 0x18
IFT_MEDIAMAILOVERIP = 0x8b
IFT_MFSIGLINK = 0xa7
IFT_MIOX25 = 0x26
IFT_MODEM = 0x30
IFT_MPC = 0x71
IFT_MPLS = 0xa6
IFT_MPLSTUNNEL = 0x96
IFT_MSDSL = 0x8f
IFT_MVL = 0xbf
IFT_MYRINET = 0x63
IFT_NFAS = 0xaf
IFT_NSIP = 0x1b
IFT_OPTICALCHANNEL = 0xc3
IFT_OPTICALTRANSPORT = 0xc4
IFT_OTHER = 0x1
IFT_P10 = 0xc
IFT_P80 = 0xd
IFT_PARA = 0x22
IFT_PFLOG = 0xf6
IFT_PFSYNC = 0xf7
IFT_PLC = 0xae
IFT_POS = 0xab
IFT_PPPMULTILINKBUNDLE = 0x6c
IFT_PROPBWAP2MP = 0xb8
IFT_PROPCNLS = 0x59
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
IFT_PROPMUX = 0x36
IFT_PROPWIRELESSP2P = 0x9d
IFT_PTPSERIAL = 0x16
IFT_PVC = 0xf1
IFT_QLLC = 0x44
IFT_RADIOMAC = 0xbc
IFT_RADSL = 0x5f
IFT_REACHDSL = 0xc0
IFT_RFC1483 = 0x9f
IFT_RS232 = 0x21
IFT_RSRB = 0x4f
IFT_SDLC = 0x11
IFT_SDSL = 0x60
IFT_SHDSL = 0xa9
IFT_SIP = 0x1f
IFT_SLIP = 0x1c
IFT_SMDSDXI = 0x2b
IFT_SMDSICIP = 0x34
IFT_SONET = 0x27
IFT_SONETOVERHEADCHANNEL = 0xb9
IFT_SONETPATH = 0x32
IFT_SONETVT = 0x33
IFT_SRP = 0x97
IFT_SS7SIGLINK = 0x9c
IFT_STACKTOSTACK = 0x6f
IFT_STARLAN = 0xb
IFT_STF = 0xd7
IFT_T1 = 0x12
IFT_TDLC = 0x74
IFT_TERMPAD = 0x5b
IFT_TR008 = 0xb0
IFT_TRANSPHDLC = 0x7b
IFT_TUNNEL = 0x83
IFT_ULTRA = 0x1d
IFT_USB = 0xa0
IFT_V11 = 0x40
IFT_V35 = 0x2d
IFT_V36 = 0x41
IFT_V37 = 0x78
IFT_VDSL = 0x61
IFT_VIRTUALIPADDRESS = 0x70
IFT_VOICEEM = 0x64
IFT_VOICEENCAP = 0x67
IFT_VOICEFXO = 0x65
IFT_VOICEFXS = 0x66
IFT_VOICEOVERATM = 0x98
IFT_VOICEOVERFRAMERELAY = 0x99
IFT_VOICEOVERIP = 0x68
IFT_X213 = 0x5d
IFT_X25 = 0x5
IFT_X25DDN = 0x4
IFT_X25HUNTGROUP = 0x7a
IFT_X25MLP = 0x79
IFT_X25PLE = 0x28
IFT_XETHER = 0x1a
IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d
IP_FAITH = 0x16
MAP_NORESERVE = 0x40
MAP_RENAME = 0x20
NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa
SIOCADDRT = 0x8040720a
SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8040720b
SIOCDLIFADDR = 0x8118691d
SIOCGLIFADDR = 0xc118691c
SIOCGLIFPHYADDR = 0xc118694b
SIOCSLIFPHYADDR = 0x8118694a
)

226
vendor/golang.org/x/sys/unix/errors_freebsd_arm.go generated vendored Normal file
View File

@ -0,0 +1,226 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package unix
const (
IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82
IFT_AAL2 = 0xbb
IFT_AAL5 = 0x31
IFT_ADSL = 0x5e
IFT_AFLANE8023 = 0x3b
IFT_AFLANE8025 = 0x3c
IFT_ARAP = 0x58
IFT_ARCNET = 0x23
IFT_ARCNETPLUS = 0x24
IFT_ASYNC = 0x54
IFT_ATM = 0x25
IFT_ATMDXI = 0x69
IFT_ATMFUNI = 0x6a
IFT_ATMIMA = 0x6b
IFT_ATMLOGICAL = 0x50
IFT_ATMRADIO = 0xbd
IFT_ATMSUBINTERFACE = 0x86
IFT_ATMVCIENDPT = 0xc2
IFT_ATMVIRTUAL = 0x95
IFT_BGPPOLICYACCOUNTING = 0xa2
IFT_BSC = 0x53
IFT_CCTEMUL = 0x3d
IFT_CEPT = 0x13
IFT_CES = 0x85
IFT_CHANNEL = 0x46
IFT_CNR = 0x55
IFT_COFFEE = 0x84
IFT_COMPOSITELINK = 0x9b
IFT_DCN = 0x8d
IFT_DIGITALPOWERLINE = 0x8a
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
IFT_DLSW = 0x4a
IFT_DOCSCABLEDOWNSTREAM = 0x80
IFT_DOCSCABLEMACLAYER = 0x7f
IFT_DOCSCABLEUPSTREAM = 0x81
IFT_DS0 = 0x51
IFT_DS0BUNDLE = 0x52
IFT_DS1FDL = 0xaa
IFT_DS3 = 0x1e
IFT_DTM = 0x8c
IFT_DVBASILN = 0xac
IFT_DVBASIOUT = 0xad
IFT_DVBRCCDOWNSTREAM = 0x93
IFT_DVBRCCMACLAYER = 0x92
IFT_DVBRCCUPSTREAM = 0x94
IFT_ENC = 0xf4
IFT_EON = 0x19
IFT_EPLRS = 0x57
IFT_ESCON = 0x49
IFT_ETHER = 0x6
IFT_FAST = 0x7d
IFT_FASTETHER = 0x3e
IFT_FASTETHERFX = 0x45
IFT_FDDI = 0xf
IFT_FIBRECHANNEL = 0x38
IFT_FRAMERELAYINTERCONNECT = 0x3a
IFT_FRAMERELAYMPI = 0x5c
IFT_FRDLCIENDPT = 0xc1
IFT_FRELAY = 0x20
IFT_FRELAYDCE = 0x2c
IFT_FRF16MFRBUNDLE = 0xa3
IFT_FRFORWARD = 0x9e
IFT_G703AT2MB = 0x43
IFT_G703AT64K = 0x42
IFT_GIF = 0xf0
IFT_GIGABITETHERNET = 0x75
IFT_GR303IDT = 0xb2
IFT_GR303RDT = 0xb1
IFT_H323GATEKEEPER = 0xa4
IFT_H323PROXY = 0xa5
IFT_HDH1822 = 0x3
IFT_HDLC = 0x76
IFT_HDSL2 = 0xa8
IFT_HIPERLAN2 = 0xb7
IFT_HIPPI = 0x2f
IFT_HIPPIINTERFACE = 0x39
IFT_HOSTPAD = 0x5a
IFT_HSSI = 0x2e
IFT_HY = 0xe
IFT_IBM370PARCHAN = 0x48
IFT_IDSL = 0x9a
IFT_IEEE80211 = 0x47
IFT_IEEE80212 = 0x37
IFT_IEEE8023ADLAG = 0xa1
IFT_IFGSN = 0x91
IFT_IMT = 0xbe
IFT_INTERLEAVE = 0x7c
IFT_IP = 0x7e
IFT_IPFORWARD = 0x8e
IFT_IPOVERATM = 0x72
IFT_IPOVERCDLC = 0x6d
IFT_IPOVERCLAW = 0x6e
IFT_IPSWITCH = 0x4e
IFT_ISDN = 0x3f
IFT_ISDNBASIC = 0x14
IFT_ISDNPRIMARY = 0x15
IFT_ISDNS = 0x4b
IFT_ISDNU = 0x4c
IFT_ISO88022LLC = 0x29
IFT_ISO88023 = 0x7
IFT_ISO88024 = 0x8
IFT_ISO88025 = 0x9
IFT_ISO88025CRFPINT = 0x62
IFT_ISO88025DTR = 0x56
IFT_ISO88025FIBER = 0x73
IFT_ISO88026 = 0xa
IFT_ISUP = 0xb3
IFT_L3IPXVLAN = 0x89
IFT_LAPB = 0x10
IFT_LAPD = 0x4d
IFT_LAPF = 0x77
IFT_LOCALTALK = 0x2a
IFT_LOOP = 0x18
IFT_MEDIAMAILOVERIP = 0x8b
IFT_MFSIGLINK = 0xa7
IFT_MIOX25 = 0x26
IFT_MODEM = 0x30
IFT_MPC = 0x71
IFT_MPLS = 0xa6
IFT_MPLSTUNNEL = 0x96
IFT_MSDSL = 0x8f
IFT_MVL = 0xbf
IFT_MYRINET = 0x63
IFT_NFAS = 0xaf
IFT_NSIP = 0x1b
IFT_OPTICALCHANNEL = 0xc3
IFT_OPTICALTRANSPORT = 0xc4
IFT_OTHER = 0x1
IFT_P10 = 0xc
IFT_P80 = 0xd
IFT_PARA = 0x22
IFT_PFLOG = 0xf6
IFT_PFSYNC = 0xf7
IFT_PLC = 0xae
IFT_POS = 0xab
IFT_PPPMULTILINKBUNDLE = 0x6c
IFT_PROPBWAP2MP = 0xb8
IFT_PROPCNLS = 0x59
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
IFT_PROPMUX = 0x36
IFT_PROPWIRELESSP2P = 0x9d
IFT_PTPSERIAL = 0x16
IFT_PVC = 0xf1
IFT_QLLC = 0x44
IFT_RADIOMAC = 0xbc
IFT_RADSL = 0x5f
IFT_REACHDSL = 0xc0
IFT_RFC1483 = 0x9f
IFT_RS232 = 0x21
IFT_RSRB = 0x4f
IFT_SDLC = 0x11
IFT_SDSL = 0x60
IFT_SHDSL = 0xa9
IFT_SIP = 0x1f
IFT_SLIP = 0x1c
IFT_SMDSDXI = 0x2b
IFT_SMDSICIP = 0x34
IFT_SONET = 0x27
IFT_SONETOVERHEADCHANNEL = 0xb9
IFT_SONETPATH = 0x32
IFT_SONETVT = 0x33
IFT_SRP = 0x97
IFT_SS7SIGLINK = 0x9c
IFT_STACKTOSTACK = 0x6f
IFT_STARLAN = 0xb
IFT_STF = 0xd7
IFT_T1 = 0x12
IFT_TDLC = 0x74
IFT_TERMPAD = 0x5b
IFT_TR008 = 0xb0
IFT_TRANSPHDLC = 0x7b
IFT_TUNNEL = 0x83
IFT_ULTRA = 0x1d
IFT_USB = 0xa0
IFT_V11 = 0x40
IFT_V35 = 0x2d
IFT_V36 = 0x41
IFT_V37 = 0x78
IFT_VDSL = 0x61
IFT_VIRTUALIPADDRESS = 0x70
IFT_VOICEEM = 0x64
IFT_VOICEENCAP = 0x67
IFT_VOICEFXO = 0x65
IFT_VOICEFXS = 0x66
IFT_VOICEOVERATM = 0x98
IFT_VOICEOVERFRAMERELAY = 0x99
IFT_VOICEOVERIP = 0x68
IFT_X213 = 0x5d
IFT_X25 = 0x5
IFT_X25DDN = 0x4
IFT_X25HUNTGROUP = 0x7a
IFT_X25MLP = 0x79
IFT_X25PLE = 0x28
IFT_XETHER = 0x1a
// missing constants on FreeBSD-11.1-RELEASE, copied from old values in ztypes_freebsd_arm.go
IFF_SMART = 0x20
IFT_FAITH = 0xf2
IFT_IPXIP = 0xf9
IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d
IP_FAITH = 0x16
MAP_NORESERVE = 0x40
MAP_RENAME = 0x20
NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa
SIOCADDRT = 0x8030720a
SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8030720b
SIOCDLIFADDR = 0x8118691d
SIOCGLIFADDR = 0xc118691c
SIOCGLIFPHYADDR = 0xc118694b
SIOCSLIFPHYADDR = 0x8118694a
)

27
vendor/golang.org/x/sys/unix/file_unix.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package unix
import (
"os"
"syscall"
)
// FIXME: unexported function from os
// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
func syscallMode(i os.FileMode) (o uint32) {
o |= uint32(i.Perm())
if i&os.ModeSetuid != 0 {
o |= syscall.S_ISUID
}
if i&os.ModeSetgid != 0 {
o |= syscall.S_ISGID
}
if i&os.ModeSticky != 0 {
o |= syscall.S_ISVTX
}
// No mapping for Go's ModeTemporary (plan9 only).
return
}

View File

@ -1,5 +1,3 @@
// +build linux darwin freebsd openbsd netbsd dragonfly
// Copyright 2014 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.

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. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style

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

@ -0,0 +1,88 @@
// 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; see README.md.
package main
import (
"bytes"
"fmt"
"go/format"
"io/ioutil"
"log"
"os"
"regexp"
)
func main() {
// Get the OS and architecture (using GOARCH_TARGET if it exists)
goos := os.Getenv("GOOS")
goarch := os.Getenv("GOARCH_TARGET")
if goarch == "" {
goarch = os.Getenv("GOARCH")
}
// Check that we are using the new build system if we should be.
if goos == "linux" && goarch != "sparc64" {
if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
os.Stderr.WriteString("In the new build system, mkpost should not be called directly.\n")
os.Stderr.WriteString("See README.md\n")
os.Exit(1)
}
}
b, err := ioutil.ReadAll(os.Stdin)
if err != nil {
log.Fatal(err)
}
// If we have empty Ptrace structs, we should delete them. Only s390x emits
// nonempty Ptrace structs.
ptraceRexexp := regexp.MustCompile(`type Ptrace((Psw|Fpregs|Per) struct {\s*})`)
b = ptraceRexexp.ReplaceAll(b, nil)
// Replace the control_regs union with a blank identifier for now.
controlRegsRegex := regexp.MustCompile(`(Control_regs)\s+\[0\]uint64`)
b = controlRegsRegex.ReplaceAll(b, []byte("_ [0]uint64"))
// Remove fields that are added by glibc
// Note that this is unstable as the identifers are private.
removeFieldsRegex := regexp.MustCompile(`X__glibc\S*`)
b = removeFieldsRegex.ReplaceAll(b, []byte("_"))
// We refuse to export private fields on s390x
if goarch == "s390x" && goos == "linux" {
// Remove cgo padding fields
removeFieldsRegex := regexp.MustCompile(`Pad_cgo_\d+`)
b = removeFieldsRegex.ReplaceAll(b, []byte("_"))
// Remove padding, hidden, or unused fields
removeFieldsRegex = regexp.MustCompile(`X_\S+`)
b = removeFieldsRegex.ReplaceAll(b, []byte("_"))
}
// Remove the first line of warning from cgo
b = b[bytes.IndexByte(b, '\n')+1:]
// Modify the command in the header to include:
// mkpost, our own warning, and a build tag.
replacement := fmt.Sprintf(`$1 | go run mkpost.go
// Code generated by the command above; see README.md. DO NOT EDIT.
// +build %s,%s`, goarch, goos)
cgoCommandRegex := regexp.MustCompile(`(cgo -godefs .*)`)
b = cgoCommandRegex.ReplaceAll(b, []byte(replacement))
// gofmt
b, err = format.Source(b)
if err != nil {
log.Fatal(err)
}
os.Stdout.Write(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
}

15
vendor/golang.org/x/sys/unix/pagesize_unix.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
// For Unix, get the pagesize from the runtime.
package unix
import "syscall"
func Getpagesize() int {
return syscall.Getpagesize()
}

View File

@ -1,4 +1,4 @@
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -13,9 +13,10 @@ import "unsafe"
// Round the length of a raw sockaddr up to align it properly. // Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int { func cmsgAlignOf(salen int) int {
salign := sizeofPtr salign := sizeofPtr
// NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels // NOTE: It seems like 64-bit Darwin, DragonFly BSD and
// still require 32-bit aligned access to network subsystem. // Solaris kernels still require 32-bit aligned access to
if darwin64Bit || dragonfly64Bit { // network subsystem.
if darwin64Bit || dragonfly64Bit || solaris64Bit {
salign = 4 salign = 4
} }
return (salen + salign - 1) & ^(salign - 1) return (salen + salign - 1) & ^(salign - 1)
@ -62,7 +63,7 @@ func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) { func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
h := (*Cmsghdr)(unsafe.Pointer(&b[0])) 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 nil, nil, EINVAL
} }
return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil

View File

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

View File

@ -470,25 +470,11 @@ func Sysctl(name string) (string, error) {
} }
func SysctlArgs(name string, args ...int) (string, error) { func SysctlArgs(name string, args ...int) (string, error) {
mib, err := sysctlmib(name, args...) buf, err := SysctlRaw(name, args...)
if err != nil { if err != nil {
return "", err return "", err
} }
n := len(buf)
// 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
}
// Throw away terminating NUL. // Throw away terminating NUL.
if n > 0 && buf[n-1] == '\x00' { if n > 0 && buf[n-1] == '\x00' {
@ -575,13 +561,19 @@ func Utimes(path string, tv []Timeval) error {
func UtimesNano(path string, ts []Timespec) error { func UtimesNano(path string, ts []Timespec) error {
if ts == nil { if ts == nil {
err := utimensat(AT_FDCWD, path, nil, 0)
if err != ENOSYS {
return err
}
return utimes(path, nil) return utimes(path, nil)
} }
// TODO: The BSDs can do utimensat with SYS_UTIMENSAT but it
// isn't supported by darwin so this uses utimes instead
if len(ts) != 2 { if len(ts) != 2 {
return EINVAL return EINVAL
} }
err := utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
if err != ENOSYS {
return err
}
// Not as efficient as it could be because Timespec and // Not as efficient as it could be because Timespec and
// Timeval have different types in the different OSes // Timeval have different types in the different OSes
tv := [2]Timeval{ tv := [2]Timeval{
@ -591,6 +583,16 @@ func UtimesNano(path string, ts []Timespec) error {
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
} }
func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
if ts == nil {
return utimensat(dirfd, path, nil, flags)
}
if len(ts) != 2 {
return EINVAL
}
return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
}
//sys futimes(fd int, timeval *[2]Timeval) (err error) //sys futimes(fd int, timeval *[2]Timeval) (err error)
func Futimes(fd int, tv []Timeval) error { func Futimes(fd int, tv []Timeval) error {
@ -608,9 +610,6 @@ func Futimes(fd int, tv []Timeval) error {
// TODO: wrap // TODO: wrap
// Acct(name nil-string) (err error) // Acct(name nil-string) (err error)
// Gethostuuid(uuid *byte, timeout *Timespec) (err error) // Gethostuuid(uuid *byte, timeout *Timespec) (err error)
// Madvise(addr *byte, len int, behav int) (err error)
// Mprotect(addr *byte, len int, prot int) (err error)
// Msync(addr *byte, len int, flags int) (err error)
// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, err error) // Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, err error)
var mapper = &mmapper{ var mapper = &mmapper{
@ -626,3 +625,11 @@ func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, e
func Munmap(b []byte) (err error) { func Munmap(b []byte) (err error) {
return mapper.Munmap(b) return mapper.Munmap(b)
} }
//sys Madvise(b []byte, behav int) (err error)
//sys Mlock(b []byte) (err error)
//sys Mlockall(flags int) (err error)
//sys Mprotect(b []byte, prot int) (err error)
//sys Msync(b []byte, flags int) (err error)
//sys Munlock(b []byte) (err error)
//sys Munlockall() (err error)

View File

@ -76,32 +76,16 @@ func nametomib(name string) (mib []_C_int, err error) {
return buf[0 : n/siz], nil return buf[0 : n/siz], nil
} }
// ParseDirent parses up to max directory entries in buf, func direntIno(buf []byte) (uint64, bool) {
// appending the names to names. It returns the number return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
// 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) { func direntReclen(buf []byte) (uint64, bool) {
origlen := len(buf) return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
for max != 0 && len(buf) > 0 { }
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
if dirent.Reclen == 0 { func direntNamlen(buf []byte) (uint64, bool) {
buf = nil return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
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
} }
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) //sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
@ -203,6 +187,11 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
return return
} }
func utimensat(dirfd int, path string, times *[2]Timespec, flags int) error {
// Darwin doesn't support SYS_UTIMENSAT
return ENOSYS
}
/* /*
* Wrapped * Wrapped
*/ */
@ -211,6 +200,45 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(signum), 1) } func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(signum), 1) }
//sys ioctl(fd int, req uint, arg uintptr) (err error)
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
func IoctlSetInt(fd int, req uint, value int) error {
return ioctl(fd, req, uintptr(value))
}
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
}
func IoctlSetTermios(fd int, req uint, value *Termios) error {
return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
}
// IoctlGetInt performs an ioctl operation which gets an integer value
// from fd, using the specified request number.
func IoctlGetInt(fd int, req uint) (int, error) {
var value int
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
return value, err
}
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
var value Winsize
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
return &value, err
}
func IoctlGetTermios(fd int, req uint) (*Termios, error) {
var value Termios
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
return &value, err
}
/* /*
* Exposed directly * Exposed directly
*/ */
@ -226,10 +254,13 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig
//sys Dup2(from int, to int) (err error) //sys Dup2(from int, to int) (err error)
//sys Exchangedata(path1 string, path2 string, options int) (err error) //sys Exchangedata(path1 string, path2 string, options int) (err error)
//sys Exit(code int) //sys Exit(code int)
//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchdir(fd int) (err error) //sys Fchdir(fd int) (err error)
//sys Fchflags(fd int, flags int) (err error) //sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error) //sys Fchmod(fd int, mode uint32) (err error)
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchown(fd int, uid int, gid int) (err error) //sys Fchown(fd int, uid int, gid int) (err error)
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Flock(fd int, how int) (err error) //sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error) //sys Fpathconf(fd int, name int) (val int, err error)
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
@ -254,23 +285,23 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig
//sys Kqueue() (fd int, err error) //sys Kqueue() (fd int, err error)
//sys Lchown(path string, uid int, gid int) (err error) //sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error) //sys Link(path string, link string) (err error)
//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
//sys Listen(s int, backlog int) (err error) //sys Listen(s int, backlog int) (err error)
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 //sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
//sys Mkdir(path string, mode uint32) (err error) //sys Mkdir(path string, mode uint32) (err error)
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error) //sys Mkfifo(path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error) //sys Mknod(path string, mode uint32, dev int) (err error)
//sys Mlock(b []byte) (err error)
//sys Mlockall(flags int) (err error)
//sys Mprotect(b []byte, prot int) (err error)
//sys Munlock(b []byte) (err error)
//sys Munlockall() (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error) //sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error) //sys Pathconf(path string, name int) (val int, err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error)
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) //sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//sys read(fd int, p []byte) (n int, err error) //sys read(fd int, p []byte) (n int, err error)
//sys Readlink(path string, buf []byte) (n int, err error) //sys Readlink(path string, buf []byte) (n int, err error)
//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error)
//sys Rename(from string, to string) (err error) //sys Rename(from string, to string) (err error)
//sys Renameat(fromfd int, from string, tofd int, to string) (err error)
//sys Revoke(path string) (err error) //sys Revoke(path string) (err error)
//sys Rmdir(path string) (err error) //sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK //sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
@ -291,11 +322,13 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 //sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
//sys Symlink(path string, link string) (err error) //sys Symlink(path string, link string) (err error)
//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
//sys Sync() (err error) //sys Sync() (err error)
//sys Truncate(path string, length int64) (err error) //sys Truncate(path string, length int64) (err error)
//sys Umask(newmask int) (oldmask int) //sys Umask(newmask int) (oldmask int)
//sys Undelete(path string) (err error) //sys Undelete(path string) (err error)
//sys Unlink(path string) (err error) //sys Unlink(path string) (err error)
//sys Unlinkat(dirfd int, path string, flags int) (err error)
//sys Unmount(path string, flags int) (err error) //sys Unmount(path string, flags int) (err error)
//sys write(fd int, p []byte) (n int, err error) //sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
@ -335,9 +368,6 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig
// Add_profil // Add_profil
// Kdebug_trace // Kdebug_trace
// Sigreturn // Sigreturn
// Mmap
// Mlock
// Munlock
// Atsocket // Atsocket
// Kqueue_from_portset_np // Kqueue_from_portset_np
// Kqueue_portset // Kqueue_portset
@ -430,8 +460,6 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig
// Lio_listio // Lio_listio
// __pthread_cond_wait // __pthread_cond_wait
// Iopolicysys // Iopolicysys
// Mlockall
// Munlockall
// __pthread_kill // __pthread_kill
// __pthread_sigmask // __pthread_sigmask
// __sigwait // __sigwait
@ -485,7 +513,6 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig
// Sendmsg_nocancel // Sendmsg_nocancel
// Recvfrom_nocancel // Recvfrom_nocancel
// Accept_nocancel // Accept_nocancel
// Msync_nocancel
// Fcntl_nocancel // Fcntl_nocancel
// Select_nocancel // Select_nocancel
// Fsync_nocancel // Fsync_nocancel

View File

@ -11,8 +11,6 @@ import (
"unsafe" "unsafe"
) )
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) { func NsecToTimespec(nsec int64) (ts Timespec) {
@ -21,8 +19,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return return
} }
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) { func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3) tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -11,10 +11,6 @@ import (
"unsafe" "unsafe"
) )
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) { func NsecToTimespec(nsec int64) (ts Timespec) {
@ -23,8 +19,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return return
} }
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) { func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3) tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -9,8 +9,6 @@ import (
"unsafe" "unsafe"
) )
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) { func NsecToTimespec(nsec int64) (ts Timespec) {
@ -19,8 +17,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return return
} }
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) { func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3) tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -11,8 +11,6 @@ import (
"unsafe" "unsafe"
) )
func Getpagesize() int { return 16384 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) { func NsecToTimespec(nsec int64) (ts Timespec) {
@ -21,8 +19,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return return
} }
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) { func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3) tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -1,8 +1,8 @@
// Copyright 2009,2010 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// FreeBSD system calls. // DragonFly BSD system calls.
// This file is compiled as ordinary Go code, // This file is compiled as ordinary Go code,
// but it is also input to mksyscall, // but it is also input to mksyscall,
// which parses the //sys lines and generates system call stubs. // which parses the //sys lines and generates system call stubs.
@ -34,7 +34,7 @@ func nametomib(name string) (mib []_C_int, err error) {
// NOTE(rsc): It seems strange to set the buffer to have // NOTE(rsc): It seems strange to set the buffer to have
// size CTL_MAXNAME+2 but use only CTL_MAXNAME // size CTL_MAXNAME+2 but use only CTL_MAXNAME
// as the size. I don't know why the +2 is here, but the // as the size. I don't know why the +2 is here, but the
// kernel uses +2 for its own implementation of this function. // kernel uses +2 for its own implementation of this function.
// I am scared that if we don't include the +2 here, the kernel // I am scared that if we don't include the +2 here, the kernel
// will silently write 2 words farther than we specify // will silently write 2 words farther than we specify
@ -56,29 +56,20 @@ func nametomib(name string) (mib []_C_int, err error) {
return buf[0 : n/siz], nil return buf[0 : n/siz], nil
} }
// ParseDirent parses up to max directory entries in buf, func direntIno(buf []byte) (uint64, bool) {
// appending the names to names. It returns the number return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
// 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) { func direntReclen(buf []byte) (uint64, bool) {
origlen := len(buf) namlen, ok := direntNamlen(buf)
for max != 0 && len(buf) > 0 { if !ok {
dirent := (*Dirent)(unsafe.Pointer(&buf[0])) return 0, false
reclen := int(16+dirent.Namlen+1+7) & ^7
buf = buf[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 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) //sysnb pipe() (r int, w int, err error)
@ -101,6 +92,24 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
return extpwrite(fd, p, 0, offset) return extpwrite(fd, p, 0, offset)
} }
func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
nfd, err = accept4(fd, &rsa, &len, flags)
if err != nil {
return
}
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
sa, err = anyToSockaddr(&rsa)
if err != nil {
Close(nfd)
nfd = 0
}
return
}
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
var _p0 unsafe.Pointer var _p0 unsafe.Pointer
var bufsize uintptr var bufsize uintptr
@ -165,11 +174,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sys Mkdir(path string, mode uint32) (err error) //sys Mkdir(path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error) //sys Mkfifo(path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error) //sys Mknod(path string, mode uint32, dev int) (err error)
//sys Mlock(b []byte) (err error)
//sys Mlockall(flags int) (err error)
//sys Mprotect(b []byte, prot int) (err error)
//sys Munlock(b []byte) (err error)
//sys Munlockall() (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error) //sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error) //sys Pathconf(path string, name int) (val int, err error)
@ -208,6 +212,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sys munmap(addr uintptr, length uintptr) (err error) //sys munmap(addr uintptr, length uintptr) (err error)
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ //sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE //sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
//sys accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error)
//sys utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
/* /*
* Unimplemented * Unimplemented
@ -242,7 +248,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// Add_profil // Add_profil
// Kdebug_trace // Kdebug_trace
// Sigreturn // Sigreturn
// Mmap
// Atsocket // Atsocket
// Kqueue_from_portset_np // Kqueue_from_portset_np
// Kqueue_portset // Kqueue_portset
@ -387,7 +392,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// Sendmsg_nocancel // Sendmsg_nocancel
// Recvfrom_nocancel // Recvfrom_nocancel
// Accept_nocancel // Accept_nocancel
// Msync_nocancel
// Fcntl_nocancel // Fcntl_nocancel
// Select_nocancel // Select_nocancel
// Fsync_nocancel // Fsync_nocancel

View File

@ -11,8 +11,6 @@ import (
"unsafe" "unsafe"
) )
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) { func NsecToTimespec(nsec int64) (ts Timespec) {
@ -21,8 +19,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return return
} }
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) { func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond nsec += 999 // round up to microsecond
tv.Usec = nsec % 1e9 / 1e3 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 return buf[0 : n/siz], nil
} }
// ParseDirent parses up to max directory entries in buf, func direntIno(buf []byte) (uint64, bool) {
// appending the names to names. It returns the number return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
// 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) { func direntReclen(buf []byte) (uint64, bool) {
origlen := len(buf) return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
for max != 0 && len(buf) > 0 { }
dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
if dirent.Reclen == 0 { func direntNamlen(buf []byte) (uint64, bool) {
buf = nil return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
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
} }
//sysnb pipe() (r int, w int, err error) //sysnb pipe() (r int, w int, err error)
@ -368,11 +352,53 @@ func Llistxattr(link string, dest []byte) (sz int, err error) {
return s, e return s, e
} }
//sys ioctl(fd int, req uint, arg uintptr) (err error)
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
func IoctlSetInt(fd int, req uint, value int) error {
return ioctl(fd, req, uintptr(value))
}
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
}
func IoctlSetTermios(fd int, req uint, value *Termios) error {
return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
}
// IoctlGetInt performs an ioctl operation which gets an integer value
// from fd, using the specified request number.
func IoctlGetInt(fd int, req uint) (int, error) {
var value int
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
return value, err
}
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
var value Winsize
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
return &value, err
}
func IoctlGetTermios(fd int, req uint) (*Termios, error) {
var value Termios
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
return &value, err
}
/* /*
* Exposed directly * Exposed directly
*/ */
//sys Access(path string, mode uint32) (err error) //sys Access(path string, mode uint32) (err error)
//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error) //sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
//sys CapEnter() (err error)
//sys capRightsGet(version int, fd int, rightsp *CapRights) (err error) = SYS___CAP_RIGHTS_GET
//sys capRightsLimit(fd int, rightsp *CapRights) (err error)
//sys Chdir(path string) (err error) //sys Chdir(path string) (err error)
//sys Chflags(path string, flags int) (err error) //sys Chflags(path string, flags int) (err error)
//sys Chmod(path string, mode uint32) (err error) //sys Chmod(path string, mode uint32) (err error)
@ -395,10 +421,13 @@ func Llistxattr(link string, dest []byte) (sz int, err error) {
//sys ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) //sys ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error)
//sys ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) //sys ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_POSIX_FADVISE //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_POSIX_FADVISE
//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchdir(fd int) (err error) //sys Fchdir(fd int) (err error)
//sys Fchflags(fd int, flags int) (err error) //sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error) //sys Fchmod(fd int, mode uint32) (err error)
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchown(fd int, uid int, gid int) (err error) //sys Fchown(fd int, uid int, gid int) (err error)
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Flock(fd int, how int) (err error) //sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error) //sys Fpathconf(fd int, name int) (val int, err error)
//sys Fstat(fd int, stat *Stat_t) (err error) //sys Fstat(fd int, stat *Stat_t) (err error)
@ -425,24 +454,24 @@ func Llistxattr(link string, dest []byte) (sz int, err error) {
//sys Kqueue() (fd int, err error) //sys Kqueue() (fd int, err error)
//sys Lchown(path string, uid int, gid int) (err error) //sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error) //sys Link(path string, link string) (err error)
//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
//sys Listen(s int, backlog int) (err error) //sys Listen(s int, backlog int) (err error)
//sys Lstat(path string, stat *Stat_t) (err error) //sys Lstat(path string, stat *Stat_t) (err error)
//sys Mkdir(path string, mode uint32) (err error) //sys Mkdir(path string, mode uint32) (err error)
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error) //sys Mkfifo(path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error) //sys Mknod(path string, mode uint32, dev int) (err error)
//sys Mlock(b []byte) (err error)
//sys Mlockall(flags int) (err error)
//sys Mprotect(b []byte, prot int) (err error)
//sys Munlock(b []byte) (err error)
//sys Munlockall() (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error) //sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Openat(fdat int, path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error) //sys Pathconf(path string, name int) (val int, err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) //sys Pread(fd int, p []byte, offset int64) (n int, err error)
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) //sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//sys read(fd int, p []byte) (n int, err error) //sys read(fd int, p []byte) (n int, err error)
//sys Readlink(path string, buf []byte) (n int, err error) //sys Readlink(path string, buf []byte) (n int, err error)
//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error)
//sys Rename(from string, to string) (err error) //sys Rename(from string, to string) (err error)
//sys Renameat(fromfd int, from string, tofd int, to string) (err error)
//sys Revoke(path string) (err error) //sys Revoke(path string) (err error)
//sys Rmdir(path string) (err error) //sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK //sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
@ -464,11 +493,13 @@ func Llistxattr(link string, dest []byte) (sz int, err error) {
//sys Stat(path string, stat *Stat_t) (err error) //sys Stat(path string, stat *Stat_t) (err error)
//sys Statfs(path string, stat *Statfs_t) (err error) //sys Statfs(path string, stat *Statfs_t) (err error)
//sys Symlink(path string, link string) (err error) //sys Symlink(path string, link string) (err error)
//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
//sys Sync() (err error) //sys Sync() (err error)
//sys Truncate(path string, length int64) (err error) //sys Truncate(path string, length int64) (err error)
//sys Umask(newmask int) (oldmask int) //sys Umask(newmask int) (oldmask int)
//sys Undelete(path string) (err error) //sys Undelete(path string) (err error)
//sys Unlink(path string) (err error) //sys Unlink(path string) (err error)
//sys Unlinkat(dirfd int, path string, flags int) (err error)
//sys Unmount(path string, flags int) (err error) //sys Unmount(path string, flags int) (err error)
//sys write(fd int, p []byte) (n int, err error) //sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
@ -476,6 +507,7 @@ func Llistxattr(link string, dest []byte) (sz int, err error) {
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ //sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE //sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
//sys accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) //sys accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error)
//sys utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
/* /*
* Unimplemented * Unimplemented
@ -509,9 +541,6 @@ func Llistxattr(link string, dest []byte) (sz int, err error) {
// Add_profil // Add_profil
// Kdebug_trace // Kdebug_trace
// Sigreturn // Sigreturn
// Mmap
// Mlock
// Munlock
// Atsocket // Atsocket
// Kqueue_from_portset_np // Kqueue_from_portset_np
// Kqueue_portset // Kqueue_portset
@ -604,8 +633,6 @@ func Llistxattr(link string, dest []byte) (sz int, err error) {
// Lio_listio // Lio_listio
// __pthread_cond_wait // __pthread_cond_wait
// Iopolicysys // Iopolicysys
// Mlockall
// Munlockall
// __pthread_kill // __pthread_kill
// __pthread_sigmask // __pthread_sigmask
// __sigwait // __sigwait
@ -658,7 +685,6 @@ func Llistxattr(link string, dest []byte) (sz int, err error) {
// Sendmsg_nocancel // Sendmsg_nocancel
// Recvfrom_nocancel // Recvfrom_nocancel
// Accept_nocancel // Accept_nocancel
// Msync_nocancel
// Fcntl_nocancel // Fcntl_nocancel
// Select_nocancel // Select_nocancel
// Fsync_nocancel // Fsync_nocancel

View File

@ -11,8 +11,6 @@ import (
"unsafe" "unsafe"
) )
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) { func NsecToTimespec(nsec int64) (ts Timespec) {
@ -21,8 +19,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return return
} }
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) { func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond nsec += 999 // round up to microsecond
tv.Usec = int32(nsec % 1e9 / 1e3) tv.Usec = int32(nsec % 1e9 / 1e3)

View File

@ -11,8 +11,6 @@ import (
"unsafe" "unsafe"
) )
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) { func NsecToTimespec(nsec int64) (ts Timespec) {
@ -21,8 +19,6 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
return return
} }
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
func NsecToTimeval(nsec int64) (tv Timeval) { func NsecToTimeval(nsec int64) (tv Timeval) {
nsec += 999 // round up to microsecond nsec += 999 // round up to microsecond
tv.Usec = nsec % 1e9 / 1e3 tv.Usec = nsec % 1e9 / 1e3

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