Update vendor.sh to use fix hashes
This ensure that users can reproduce a containerd build exactly as it was done during release. Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
@@ -2,6 +2,8 @@ language: go
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- tip
|
||||
install:
|
||||
- go get -t ./...
|
||||
script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
# 0.9.0 (Unreleased)
|
||||
# 0.10.0
|
||||
|
||||
* feature: Add a test hook (#180)
|
||||
* feature: `ParseLevel` is now case-insensitive (#326)
|
||||
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
|
||||
* performance: avoid re-allocations on `WithFields` (#335)
|
||||
|
||||
# 0.9.0
|
||||
|
||||
* logrus/text_formatter: don't emit empty msg
|
||||
* logrus/hooks/airbrake: move out of main repository
|
||||
* logrus/hooks/sentry: move out of main repository
|
||||
* logrus/hooks/papertrail: move out of main repository
|
||||
* logrus/hooks/bugsnag: move out of main repository
|
||||
* logrus/core: run tests with `-race`
|
||||
* logrus/core: detect TTY based on `stderr`
|
||||
* logrus/core: support `WithError` on logger
|
||||
* logrus/core: Solaris support
|
||||
|
||||
# 0.8.7
|
||||
|
||||
|
||||
31
vendor/src/github.com/Sirupsen/logrus/README.md
vendored
31
vendor/src/github.com/Sirupsen/logrus/README.md
vendored
@@ -1,4 +1,4 @@
|
||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/Sirupsen/logrus) [][godoc]
|
||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/Sirupsen/logrus) [](https://godoc.org/github.com/Sirupsen/logrus)
|
||||
|
||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||
@@ -12,7 +12,7 @@ plain text):
|
||||
|
||||

|
||||
|
||||
With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
|
||||
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
|
||||
or Splunk:
|
||||
|
||||
```json
|
||||
@@ -32,7 +32,7 @@ ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||
```
|
||||
|
||||
With the default `log.Formatter = new(&log.TextFormatter{})` when a TTY is not
|
||||
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
|
||||
attached, the output is compatible with the
|
||||
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||
|
||||
@@ -221,6 +221,12 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
|
||||
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
||||
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
||||
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
|
||||
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
||||
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
||||
|
||||
|
||||
#### Level logging
|
||||
|
||||
@@ -362,4 +368,21 @@ entries. It should not be a feature of the application-level logger.
|
||||
| ---- | ----------- |
|
||||
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|
||||
|
||||
[godoc]: https://godoc.org/github.com/Sirupsen/logrus
|
||||
#### Testing
|
||||
|
||||
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
|
||||
|
||||
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
|
||||
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
|
||||
|
||||
```go
|
||||
logger, hook := NewNullLogger()
|
||||
logger.Error("Hello error")
|
||||
|
||||
assert.Equal(1, len(hook.Entries))
|
||||
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||
|
||||
hook.Reset()
|
||||
assert.Nil(hook.LastEntry())
|
||||
```
|
||||
|
||||
@@ -68,7 +68,7 @@ func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||
|
||||
// Add a map of fields to the Entry.
|
||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||
data := Fields{}
|
||||
data := make(Fields, len(entry.Data)+len(fields))
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
|
||||
47
vendor/src/github.com/Sirupsen/logrus/logrus.go
vendored
47
vendor/src/github.com/Sirupsen/logrus/logrus.go
vendored
@@ -3,6 +3,7 @@ package logrus
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Fields type, used to pass to `WithFields`.
|
||||
@@ -33,7 +34,7 @@ func (level Level) String() string {
|
||||
|
||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
func ParseLevel(lvl string) (Level, error) {
|
||||
switch lvl {
|
||||
switch strings.ToLower(lvl) {
|
||||
case "panic":
|
||||
return PanicLevel, nil
|
||||
case "fatal":
|
||||
@@ -52,6 +53,16 @@ func ParseLevel(lvl string) (Level, error) {
|
||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||
}
|
||||
|
||||
// A constant exposing all logging levels
|
||||
var AllLevels = []Level{
|
||||
PanicLevel,
|
||||
FatalLevel,
|
||||
ErrorLevel,
|
||||
WarnLevel,
|
||||
InfoLevel,
|
||||
DebugLevel,
|
||||
}
|
||||
|
||||
// These are the different logging levels. You can set the logging level to log
|
||||
// on your instance of logger, obtained with `logrus.New()`.
|
||||
const (
|
||||
@@ -96,3 +107,37 @@ type StdLogger interface {
|
||||
Panicf(string, ...interface{})
|
||||
Panicln(...interface{})
|
||||
}
|
||||
|
||||
// The FieldLogger interface generalizes the Entry and Logger types
|
||||
type FieldLogger interface {
|
||||
WithField(key string, value interface{}) *Entry
|
||||
WithFields(fields Fields) *Entry
|
||||
WithError(err error) *Entry
|
||||
|
||||
Debugf(format string, args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Printf(format string, args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Warningf(format string, args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
Panicf(format string, args ...interface{})
|
||||
|
||||
Debug(args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Print(args ...interface{})
|
||||
Warn(args ...interface{})
|
||||
Warning(args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Fatal(args ...interface{})
|
||||
Panic(args ...interface{})
|
||||
|
||||
Debugln(args ...interface{})
|
||||
Infoln(args ...interface{})
|
||||
Println(args ...interface{})
|
||||
Warnln(args ...interface{})
|
||||
Warningln(args ...interface{})
|
||||
Errorln(args ...interface{})
|
||||
Fatalln(args ...interface{})
|
||||
Panicln(args ...interface{})
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ language: go
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.0.3
|
||||
- 1.1.2
|
||||
- 1.2.2
|
||||
- 1.3.3
|
||||
|
||||
70
vendor/src/github.com/codegangsta/cli/README.md
vendored
70
vendor/src/github.com/codegangsta/cli/README.md
vendored
@@ -1,16 +1,20 @@
|
||||
[](http://gocover.io/github.com/codegangsta/cli)
|
||||
[](https://travis-ci.org/codegangsta/cli)
|
||||
[](https://travis-ci.org/codegangsta/cli)
|
||||
[](https://godoc.org/github.com/codegangsta/cli)
|
||||
[](https://codebeat.co/projects/github-com-codegangsta-cli)
|
||||
|
||||
# cli.go
|
||||
|
||||
`cli.go` is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
|
||||
|
||||
## Overview
|
||||
|
||||
Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
|
||||
|
||||
**This is where `cli.go` comes into play.** `cli.go` makes command line programming fun, organized, and expressive!
|
||||
|
||||
## Installation
|
||||
|
||||
Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html).
|
||||
|
||||
To install `cli.go`, simply run:
|
||||
@@ -24,7 +28,8 @@ export PATH=$PATH:$GOPATH/bin
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`.
|
||||
|
||||
One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`.
|
||||
|
||||
``` go
|
||||
package main
|
||||
@@ -56,7 +61,7 @@ func main() {
|
||||
app.Action = func(c *cli.Context) {
|
||||
println("boom! I say!")
|
||||
}
|
||||
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
```
|
||||
@@ -123,6 +128,7 @@ GLOBAL OPTIONS
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
You can lookup arguments by calling the `Args` function on `cli.Context`.
|
||||
|
||||
``` go
|
||||
@@ -134,7 +140,9 @@ app.Action = func(c *cli.Context) {
|
||||
```
|
||||
|
||||
### Flags
|
||||
|
||||
Setting and querying flags is simple.
|
||||
|
||||
``` go
|
||||
...
|
||||
app.Flags = []cli.Flag {
|
||||
@@ -146,7 +154,7 @@ app.Flags = []cli.Flag {
|
||||
}
|
||||
app.Action = func(c *cli.Context) {
|
||||
name := "someone"
|
||||
if len(c.Args()) > 0 {
|
||||
if c.NArg() > 0 {
|
||||
name = c.Args()[0]
|
||||
}
|
||||
if c.String("lang") == "spanish" {
|
||||
@@ -159,6 +167,7 @@ app.Action = func(c *cli.Context) {
|
||||
```
|
||||
|
||||
You can also set a destination variable for a flag, to which the content will be scanned.
|
||||
|
||||
``` go
|
||||
...
|
||||
var language string
|
||||
@@ -172,7 +181,7 @@ app.Flags = []cli.Flag {
|
||||
}
|
||||
app.Action = func(c *cli.Context) {
|
||||
name := "someone"
|
||||
if len(c.Args()) > 0 {
|
||||
if c.NArg() > 0 {
|
||||
name = c.Args()[0]
|
||||
}
|
||||
if language == "spanish" {
|
||||
@@ -230,9 +239,52 @@ app.Flags = []cli.Flag {
|
||||
}
|
||||
```
|
||||
|
||||
#### Values from alternate input sources (YAML and others)
|
||||
|
||||
There is a separate package altsrc that adds support for getting flag values from other input sources like YAML.
|
||||
|
||||
In order to get values for a flag from an alternate input source the following code would be added to wrap an existing cli.Flag like below:
|
||||
|
||||
``` go
|
||||
altsrc.NewIntFlag(cli.IntFlag{Name: "test"})
|
||||
```
|
||||
|
||||
Initialization must also occur for these flags. Below is an example initializing getting data from a yaml file below.
|
||||
|
||||
``` go
|
||||
command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
```
|
||||
|
||||
The code above will use the "load" string as a flag name to get the file name of a yaml file from the cli.Context.
|
||||
It will then use that file name to initialize the yaml input source for any flags that are defined on that command.
|
||||
As a note the "load" flag used would also have to be defined on the command flags in order for this code snipped to work.
|
||||
|
||||
Currently only YAML files are supported but developers can add support for other input sources by implementing the
|
||||
altsrc.InputSourceContext for their given sources.
|
||||
|
||||
Here is a more complete sample of a command using YAML support:
|
||||
|
||||
``` go
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) {
|
||||
// Action to run
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||
cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c)
|
||||
```
|
||||
|
||||
### Subcommands
|
||||
|
||||
Subcommands can be defined for a more git-like command line app.
|
||||
|
||||
```go
|
||||
...
|
||||
app.Commands = []cli.Command{
|
||||
@@ -283,6 +335,7 @@ You can enable completion commands by setting the `EnableBashCompletion`
|
||||
flag on the `App` object. By default, this setting will only auto-complete to
|
||||
show an app's subcommands, but you can write your own completion methods for
|
||||
the App or its subcommands.
|
||||
|
||||
```go
|
||||
...
|
||||
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
|
||||
@@ -298,7 +351,7 @@ app.Commands = []cli.Command{
|
||||
},
|
||||
BashComplete: func(c *cli.Context) {
|
||||
// This will complete if no args are passed
|
||||
if len(c.Args()) > 0 {
|
||||
if c.NArg() > 0 {
|
||||
return
|
||||
}
|
||||
for _, t := range tasks {
|
||||
@@ -325,8 +378,8 @@ automatically install it there if you are distributing a package). Don't forget
|
||||
to source the file to make it active in the current shell.
|
||||
|
||||
```
|
||||
sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
|
||||
source /etc/bash_completion.d/<myprogram>
|
||||
sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
|
||||
source /etc/bash_completion.d/<myprogram>
|
||||
```
|
||||
|
||||
Alternatively, you can just document that users should source the generic
|
||||
@@ -334,6 +387,7 @@ Alternatively, you can just document that users should source the generic
|
||||
to the name of their program (as above).
|
||||
|
||||
## Contribution Guidelines
|
||||
|
||||
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
|
||||
|
||||
If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
|
||||
|
||||
45
vendor/src/github.com/codegangsta/cli/app.go
vendored
45
vendor/src/github.com/codegangsta/cli/app.go
vendored
@@ -9,7 +9,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// App is the main structure of a cli application. It is recomended that
|
||||
// App is the main structure of a cli application. It is recommended that
|
||||
// an app be created with the cli.NewApp() function
|
||||
type App struct {
|
||||
// The name of the program. Defaults to path.Base(os.Args[0])
|
||||
@@ -18,6 +18,8 @@ type App struct {
|
||||
HelpName string
|
||||
// Description of the program.
|
||||
Usage string
|
||||
// Text to override the USAGE section of help
|
||||
UsageText string
|
||||
// Description of the program argument format.
|
||||
ArgsUsage string
|
||||
// Version of the program
|
||||
@@ -30,7 +32,7 @@ type App struct {
|
||||
EnableBashCompletion bool
|
||||
// Boolean to hide built-in help command
|
||||
HideHelp bool
|
||||
// Boolean to hide built-in version flag
|
||||
// Boolean to hide built-in version flag and the VERSION section of help
|
||||
HideVersion bool
|
||||
// An action to execute when the bash-completion flag is set
|
||||
BashComplete func(context *Context)
|
||||
@@ -44,6 +46,10 @@ type App struct {
|
||||
Action func(context *Context)
|
||||
// Execute this function if the proper command cannot be found
|
||||
CommandNotFound func(context *Context, command string)
|
||||
// Execute this function, if an usage error occurs. This is useful for displaying customized usage error messages.
|
||||
// This function is able to replace the original error messages.
|
||||
// If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted.
|
||||
OnUsageError func(context *Context, err error, isSubcommand bool) error
|
||||
// Compilation date
|
||||
Compiled time.Time
|
||||
// List of all authors who contributed
|
||||
@@ -74,6 +80,7 @@ func NewApp() *App {
|
||||
Name: path.Base(os.Args[0]),
|
||||
HelpName: path.Base(os.Args[0]),
|
||||
Usage: "A new cli application",
|
||||
UsageText: "",
|
||||
Version: "0.0.0",
|
||||
BashComplete: DefaultAppComplete,
|
||||
Action: helpCommand.Action,
|
||||
@@ -119,23 +126,26 @@ func (a *App) Run(arguments []string) (err error) {
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err = set.Parse(arguments[1:])
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
context := NewContext(a, set, nil)
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
context := NewContext(a, set, nil)
|
||||
ShowAppHelp(context)
|
||||
return nerr
|
||||
}
|
||||
context := NewContext(a, set, nil)
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(a.Writer, "Incorrect Usage.")
|
||||
fmt.Fprintln(a.Writer)
|
||||
ShowAppHelp(context)
|
||||
return err
|
||||
if a.OnUsageError != nil {
|
||||
err := a.OnUsageError(context, err, false)
|
||||
return err
|
||||
} else {
|
||||
fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
|
||||
ShowAppHelp(context)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !a.HideHelp && checkHelp(context) {
|
||||
@@ -150,8 +160,7 @@ func (a *App) Run(arguments []string) (err error) {
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
afterErr := a.After(context)
|
||||
if afterErr != nil {
|
||||
if afterErr := a.After(context); afterErr != nil {
|
||||
if err != nil {
|
||||
err = NewMultiError(err, afterErr)
|
||||
} else {
|
||||
@@ -162,8 +171,10 @@ func (a *App) Run(arguments []string) (err error) {
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
err = a.Before(context)
|
||||
if err != nil {
|
||||
fmt.Fprintf(a.Writer, "%v\n\n", err)
|
||||
ShowAppHelp(context)
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -239,10 +250,14 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(a.Writer, "Incorrect Usage.")
|
||||
fmt.Fprintln(a.Writer)
|
||||
ShowSubcommandHelp(context)
|
||||
return err
|
||||
if a.OnUsageError != nil {
|
||||
err = a.OnUsageError(context, err, true)
|
||||
return err
|
||||
} else {
|
||||
fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
|
||||
ShowSubcommandHelp(context)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(a.Commands) > 0 {
|
||||
|
||||
16
vendor/src/github.com/codegangsta/cli/appveyor.yml
vendored
Normal file
16
vendor/src/github.com/codegangsta/cli/appveyor.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
version: "{build}"
|
||||
|
||||
os: Windows Server 2012 R2
|
||||
|
||||
install:
|
||||
- go version
|
||||
- go env
|
||||
|
||||
build_script:
|
||||
- cd %APPVEYOR_BUILD_FOLDER%
|
||||
- go vet ./...
|
||||
- go test -v ./...
|
||||
|
||||
test: off
|
||||
|
||||
deploy: off
|
||||
62
vendor/src/github.com/codegangsta/cli/command.go
vendored
62
vendor/src/github.com/codegangsta/cli/command.go
vendored
@@ -16,6 +16,8 @@ type Command struct {
|
||||
Aliases []string
|
||||
// A short description of the usage of this command
|
||||
Usage string
|
||||
// Custom text to show on USAGE section of help
|
||||
UsageText string
|
||||
// A longer explanation of how the command works
|
||||
Description string
|
||||
// A short description of the arguments of this command
|
||||
@@ -25,11 +27,15 @@ type Command struct {
|
||||
// An action to execute before any sub-subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no sub-subcommands are run
|
||||
Before func(context *Context) error
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// An action to execute after any subcommands are run, but before the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After func(context *Context) error
|
||||
// The function to call when this command is invoked
|
||||
Action func(context *Context)
|
||||
// Execute this function, if an usage error occurs. This is useful for displaying customized usage error messages.
|
||||
// This function is able to replace the original error messages.
|
||||
// If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted.
|
||||
OnUsageError func(context *Context, err error) error
|
||||
// List of child commands
|
||||
Subcommands []Command
|
||||
// List of flags to parse
|
||||
@@ -54,8 +60,8 @@ func (c Command) FullName() string {
|
||||
}
|
||||
|
||||
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (c Command) Run(ctx *Context) error {
|
||||
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
|
||||
func (c Command) Run(ctx *Context) (err error) {
|
||||
if len(c.Subcommands) > 0 {
|
||||
return c.startApp(ctx)
|
||||
}
|
||||
|
||||
@@ -74,7 +80,6 @@ func (c Command) Run(ctx *Context) error {
|
||||
set := flagSet(c.Name, c.Flags)
|
||||
set.SetOutput(ioutil.Discard)
|
||||
|
||||
var err error
|
||||
if !c.SkipFlagParsing {
|
||||
firstFlagIndex := -1
|
||||
terminatorIndex := -1
|
||||
@@ -82,6 +87,9 @@ func (c Command) Run(ctx *Context) error {
|
||||
if arg == "--" {
|
||||
terminatorIndex = index
|
||||
break
|
||||
} else if arg == "-" {
|
||||
// Do nothing. A dash alone is not really a flag.
|
||||
continue
|
||||
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
|
||||
firstFlagIndex = index
|
||||
}
|
||||
@@ -111,10 +119,15 @@ func (c Command) Run(ctx *Context) error {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
return err
|
||||
if c.OnUsageError != nil {
|
||||
err := c.OnUsageError(ctx, err)
|
||||
return err
|
||||
} else {
|
||||
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
nerr := normalizeFlags(c.Flags, set)
|
||||
@@ -133,6 +146,30 @@ func (c Command) Run(ctx *Context) error {
|
||||
if checkCommandHelp(context, c.Name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.After != nil {
|
||||
defer func() {
|
||||
afterErr := c.After(context)
|
||||
if afterErr != nil {
|
||||
if err != nil {
|
||||
err = NewMultiError(err, afterErr)
|
||||
} else {
|
||||
err = afterErr
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if c.Before != nil {
|
||||
err := c.Before(context)
|
||||
if err != nil {
|
||||
fmt.Fprintln(ctx.App.Writer, err)
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
context.Command = c
|
||||
c.Action(context)
|
||||
return nil
|
||||
@@ -166,7 +203,7 @@ func (c Command) startApp(ctx *Context) error {
|
||||
if c.HelpName == "" {
|
||||
app.HelpName = c.HelpName
|
||||
} else {
|
||||
app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
|
||||
app.HelpName = app.Name
|
||||
}
|
||||
|
||||
if c.Description != "" {
|
||||
@@ -205,12 +242,9 @@ func (c Command) startApp(ctx *Context) error {
|
||||
app.Action = helpSubcommand.Action
|
||||
}
|
||||
|
||||
var newCmds []Command
|
||||
for _, cc := range app.Commands {
|
||||
cc.commandNamePath = []string{c.Name, cc.Name}
|
||||
newCmds = append(newCmds, cc)
|
||||
for index, cc := range app.Commands {
|
||||
app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
|
||||
}
|
||||
app.Commands = newCmds
|
||||
|
||||
return app.RunAsSubcommand(ctx)
|
||||
}
|
||||
|
||||
@@ -197,6 +197,11 @@ func (c *Context) Args() Args {
|
||||
return args
|
||||
}
|
||||
|
||||
// Returns the number of the command line arguments.
|
||||
func (c *Context) NArg() int {
|
||||
return len(c.Args())
|
||||
}
|
||||
|
||||
// Returns the nth argument, or else a blank string
|
||||
func (a Args) Get(n int) string {
|
||||
if len(a) > n {
|
||||
|
||||
41
vendor/src/github.com/codegangsta/cli/flag.go
vendored
41
vendor/src/github.com/codegangsta/cli/flag.go
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -29,7 +30,7 @@ var HelpFlag = BoolFlag{
|
||||
}
|
||||
|
||||
// Flag is a common interface related to parsing flags in cli.
|
||||
// For more advanced flag parsing techniques, it is recomended that
|
||||
// For more advanced flag parsing techniques, it is recommended that
|
||||
// this interface be implemented.
|
||||
type Flag interface {
|
||||
fmt.Stringer
|
||||
@@ -73,7 +74,18 @@ type GenericFlag struct {
|
||||
// help text to the user (uses the String() method of the generic flag to show
|
||||
// the value)
|
||||
func (f GenericFlag) String() string {
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name), f.FormatValueHelp(), f.Usage))
|
||||
}
|
||||
|
||||
func (f GenericFlag) FormatValueHelp() string {
|
||||
if f.Value == nil {
|
||||
return ""
|
||||
}
|
||||
s := f.Value.String()
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("\"%s\"", s)
|
||||
}
|
||||
|
||||
// Apply takes the flagset and calls Set on the generic flag with the value
|
||||
@@ -331,16 +343,15 @@ type StringFlag struct {
|
||||
|
||||
// String returns the usage
|
||||
func (f StringFlag) String() string {
|
||||
var fmtString string
|
||||
fmtString = "%s %v\t%v"
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name), f.FormatValueHelp(), f.Usage))
|
||||
}
|
||||
|
||||
if len(f.Value) > 0 {
|
||||
fmtString = "%s \"%v\"\t%v"
|
||||
} else {
|
||||
fmtString = "%s %v\t%v"
|
||||
func (f StringFlag) FormatValueHelp() string {
|
||||
s := f.Value
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
|
||||
return fmt.Sprintf("\"%s\"", s)
|
||||
}
|
||||
|
||||
// Apply populates the flag given the flag set and environment
|
||||
@@ -521,7 +532,15 @@ func prefixedNames(fullName string) (prefixed string) {
|
||||
func withEnvHint(envVar, str string) string {
|
||||
envText := ""
|
||||
if envVar != "" {
|
||||
envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
|
||||
prefix := "$"
|
||||
suffix := ""
|
||||
sep := ", $"
|
||||
if runtime.GOOS == "windows" {
|
||||
prefix = "%"
|
||||
suffix = "%"
|
||||
sep = "%, %"
|
||||
}
|
||||
envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix)
|
||||
}
|
||||
return str + envText
|
||||
}
|
||||
|
||||
10
vendor/src/github.com/codegangsta/cli/help.go
vendored
10
vendor/src/github.com/codegangsta/cli/help.go
vendored
@@ -15,11 +15,11 @@ var AppHelpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
|
||||
USAGE:
|
||||
{{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||
{{if .Version}}
|
||||
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
|
||||
{{if .Version}}{{if not .HideVersion}}
|
||||
VERSION:
|
||||
{{.Version}}
|
||||
{{end}}{{if len .Authors}}
|
||||
{{end}}{{end}}{{if len .Authors}}
|
||||
AUTHOR(S):
|
||||
{{range .Authors}}{{ . }}{{end}}
|
||||
{{end}}{{if .Commands}}
|
||||
@@ -180,7 +180,9 @@ func printHelp(out io.Writer, templ string, data interface{}) {
|
||||
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
||||
err := t.Execute(w, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
// If the writer is closed, t.Execute will fail, and there's nothing
|
||||
// we can do to recover. We could send this to os.Stderr if we need.
|
||||
return
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build !linux,!freebsd freebsd,!cgo
|
||||
// +build !windows,!linux,!freebsd freebsd,!cgo
|
||||
|
||||
package mount
|
||||
|
||||
|
||||
6
vendor/src/github.com/docker/docker/pkg/mount/mountinfo_windows.go
vendored
Normal file
6
vendor/src/github.com/docker/docker/pkg/mount/mountinfo_windows.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package mount
|
||||
|
||||
func parseMountTable() ([]*Info, error) {
|
||||
// Do NOT return an error!
|
||||
return nil, nil
|
||||
}
|
||||
@@ -61,8 +61,7 @@ func ensureMountedAs(mountPoint, options string) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
mounted, err = Mounted(mountPoint)
|
||||
if err != nil {
|
||||
if _, err = Mounted(mountPoint); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@ func toShort(path string) (string, error) {
|
||||
}
|
||||
if n > uint32(len(b)) {
|
||||
b = make([]uint16, n)
|
||||
n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
|
||||
if err != nil {
|
||||
if _, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,5 +43,10 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Take platform specific action for setting create time.
|
||||
if err := setCTime(name, mtime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
14
vendor/src/github.com/docker/docker/pkg/system/chtimes_unix.go
vendored
Normal file
14
vendor/src/github.com/docker/docker/pkg/system/chtimes_unix.go
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build !windows
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
//setCTime will set the create time on a file. On Unix, the create
|
||||
//time is updated as a side effect of setting the modified time, so
|
||||
//no action is required.
|
||||
func setCTime(path string, ctime time.Time) error {
|
||||
return nil
|
||||
}
|
||||
27
vendor/src/github.com/docker/docker/pkg/system/chtimes_windows.go
vendored
Normal file
27
vendor/src/github.com/docker/docker/pkg/system/chtimes_windows.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// +build windows
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
//setCTime will set the create time on a file. On Windows, this requires
|
||||
//calling SetFileTime and explicitly including the create time.
|
||||
func setCTime(path string, ctime time.Time) error {
|
||||
ctimespec := syscall.NsecToTimespec(ctime.UnixNano())
|
||||
pathp, e := syscall.UTF16PtrFromString(path)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
h, e := syscall.CreateFile(pathp,
|
||||
syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil,
|
||||
syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer syscall.Close(h)
|
||||
c := syscall.NsecToFiletime(syscall.TimespecToNsec(ctimespec))
|
||||
return syscall.SetFileTime(h, &c, nil, nil)
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// ReadMemInfo retrieves memory statistics of the host system and returns a
|
||||
// MemInfo type.
|
||||
// MemInfo type.
|
||||
func ReadMemInfo() (*MemInfo, error) {
|
||||
file, err := os.Open("/proc/meminfo")
|
||||
if err != nil {
|
||||
@@ -22,8 +22,7 @@ func ReadMemInfo() (*MemInfo, error) {
|
||||
}
|
||||
|
||||
// parseMemInfo parses the /proc/meminfo file into
|
||||
// a MemInfo object given a io.Reader to the file.
|
||||
//
|
||||
// a MemInfo object given an io.Reader to the file.
|
||||
// Throws error if there are problems reading from the file
|
||||
func parseMemInfo(reader io.Reader) (*MemInfo, error) {
|
||||
meminfo := &MemInfo{}
|
||||
|
||||
15
vendor/src/github.com/docker/docker/pkg/system/stat_openbsd.go
vendored
Normal file
15
vendor/src/github.com/docker/docker/pkg/system/stat_openbsd.go
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// fromStatT creates a system.StatT type from a syscall.Stat_t type
|
||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
||||
return &StatT{size: s.Size,
|
||||
mode: uint32(s.Mode),
|
||||
uid: s.Uid,
|
||||
gid: s.Gid,
|
||||
rdev: uint64(s.Rdev),
|
||||
mtim: s.Mtim}, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build !linux,!windows,!freebsd,!solaris
|
||||
// +build !linux,!windows,!freebsd,!solaris,!openbsd
|
||||
|
||||
package system
|
||||
|
||||
|
||||
@@ -9,3 +9,9 @@ import "syscall"
|
||||
func Unmount(dest string) error {
|
||||
return syscall.Unmount(dest, 0)
|
||||
}
|
||||
|
||||
// CommandLineToArgv should not be used on Unix.
|
||||
// It simply returns commandLine in the only element in the returned array.
|
||||
func CommandLineToArgv(commandLine string) ([]string, error) {
|
||||
return []string{commandLine}, nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package system
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// OSVersion is a wrapper for Windows version information
|
||||
@@ -34,3 +35,26 @@ func GetOSVersion() (OSVersion, error) {
|
||||
func Unmount(dest string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommandLineToArgv wraps the Windows syscall to turn a commandline into an argument array.
|
||||
func CommandLineToArgv(commandLine string) ([]string, error) {
|
||||
var argc int32
|
||||
|
||||
argsPtr, err := syscall.UTF16PtrFromString(commandLine)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
argv, err := syscall.CommandLineToArgv(argsPtr, &argc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
|
||||
|
||||
newArgs := make([]string, argc)
|
||||
for i, v := range (*argv)[:argc] {
|
||||
newArgs[i] = string(syscall.UTF16ToString((*v)[:]))
|
||||
}
|
||||
|
||||
return newArgs, nil
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ func MakeRaw(fd uintptr) (*State, error) {
|
||||
newState := oldState.termios
|
||||
|
||||
C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&newState)))
|
||||
newState.Oflag = newState.Oflag | C.OPOST
|
||||
if err := tcset(fd, &newState); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -127,6 +127,5 @@ func handleInterrupt(fd uintptr, state *State) {
|
||||
go func() {
|
||||
_ = <-sigchan
|
||||
RestoreTerminal(fd, state)
|
||||
os.Exit(0)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -3,21 +3,20 @@
|
||||
package term
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/Azure/go-ansiterm/winterm"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/pkg/term/windows"
|
||||
)
|
||||
|
||||
// State holds the console mode for the terminal.
|
||||
type State struct {
|
||||
mode uint32
|
||||
inMode, outMode uint32
|
||||
inHandle, outHandle syscall.Handle
|
||||
}
|
||||
|
||||
// Winsize is used for window size.
|
||||
@@ -28,17 +27,27 @@ type Winsize struct {
|
||||
y uint16
|
||||
}
|
||||
|
||||
const (
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
|
||||
enableVirtualTerminalInput = 0x0200
|
||||
enableVirtualTerminalProcessing = 0x0004
|
||||
)
|
||||
|
||||
// usingNativeConsole is true if we are using the Windows native console
|
||||
var usingNativeConsole bool
|
||||
|
||||
// StdStreams returns the standard streams (stdin, stdout, stedrr).
|
||||
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
switch {
|
||||
case os.Getenv("ConEmuANSI") == "ON":
|
||||
// The ConEmu shell emulates ANSI well by default.
|
||||
return os.Stdin, os.Stdout, os.Stderr
|
||||
// The ConEmu terminal emulates ANSI on output streams well.
|
||||
return windows.ConEmuStreams()
|
||||
case os.Getenv("MSYSTEM") != "":
|
||||
// MSYS (mingw) does not emulate ANSI well.
|
||||
return windows.ConsoleStreams()
|
||||
default:
|
||||
if useNativeConsole() {
|
||||
usingNativeConsole = true
|
||||
return os.Stdin, os.Stdout, os.Stderr
|
||||
}
|
||||
return windows.ConsoleStreams()
|
||||
@@ -54,7 +63,7 @@ func useNativeConsole() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Native console is not available major version 10
|
||||
// Native console is not available before major version 10
|
||||
if osv.MajorVersion < 10 {
|
||||
return false
|
||||
}
|
||||
@@ -64,6 +73,17 @@ func useNativeConsole() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get the console modes. If this fails, we can't use the native console
|
||||
state, err := getNativeConsole()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Probe the console to see if it can be enabled.
|
||||
if nil != probeNativeConsole(state) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Environment variable override
|
||||
if e := os.Getenv("USE_NATIVE_CONSOLE"); e != "" {
|
||||
if e == "1" {
|
||||
@@ -72,32 +92,86 @@ func useNativeConsole() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get the handle to stdout
|
||||
stdOutHandle, err := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Get the console mode from the consoles stdout handle
|
||||
var mode uint32
|
||||
if err := syscall.GetConsoleMode(stdOutHandle, &mode); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Legacy mode does not have native ANSI emulation.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
|
||||
const enableVirtualTerminalProcessing = 0x0004
|
||||
if mode&enableVirtualTerminalProcessing == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO Windows (Post TP4). The native emulator still has issues which
|
||||
// TODO Windows. The native emulator still has issues which
|
||||
// mean it shouldn't be enabled for everyone. Change this next line to true
|
||||
// to change the default to "enable if available". In the meantime, users
|
||||
// can still try it out by using USE_NATIVE_CONSOLE env variable.
|
||||
return false
|
||||
}
|
||||
|
||||
// getNativeConsole returns the console modes ('state') for the native Windows console
|
||||
func getNativeConsole() (State, error) {
|
||||
var (
|
||||
err error
|
||||
state State
|
||||
)
|
||||
|
||||
// Get the handle to stdout
|
||||
if state.outHandle, err = syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE); err != nil {
|
||||
return state, err
|
||||
}
|
||||
|
||||
// Get the console mode from the consoles stdout handle
|
||||
if err = syscall.GetConsoleMode(state.outHandle, &state.outMode); err != nil {
|
||||
return state, err
|
||||
}
|
||||
|
||||
// Get the handle to stdin
|
||||
if state.inHandle, err = syscall.GetStdHandle(syscall.STD_INPUT_HANDLE); err != nil {
|
||||
return state, err
|
||||
}
|
||||
|
||||
// Get the console mode from the consoles stdin handle
|
||||
if err = syscall.GetConsoleMode(state.inHandle, &state.inMode); err != nil {
|
||||
return state, err
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// probeNativeConsole probes the console to determine if native can be supported,
|
||||
func probeNativeConsole(state State) error {
|
||||
if err := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode|enableVirtualTerminalProcessing); err != nil {
|
||||
return err
|
||||
}
|
||||
defer winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode)
|
||||
|
||||
if err := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode|enableVirtualTerminalInput); err != nil {
|
||||
return err
|
||||
}
|
||||
defer winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// enableNativeConsole turns on native console mode
|
||||
func enableNativeConsole(state State) error {
|
||||
if err := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode|enableVirtualTerminalProcessing); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode|enableVirtualTerminalInput); err != nil {
|
||||
winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode) // restore out if we can
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// disableNativeConsole turns off native console mode
|
||||
func disableNativeConsole(state *State) error {
|
||||
// Try and restore both in an out before error checking.
|
||||
errout := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode)
|
||||
errin := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode)
|
||||
if errout != nil {
|
||||
return errout
|
||||
}
|
||||
if errin != nil {
|
||||
return errin
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
|
||||
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||
return windows.GetHandleInfo(in)
|
||||
@@ -105,7 +179,6 @@ func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||
|
||||
// GetWinsize returns the window size based on the specified file descriptor.
|
||||
func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||
|
||||
info, err := winterm.GetConsoleScreenBufferInfo(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -117,58 +190,9 @@ func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||
x: 0,
|
||||
y: 0}
|
||||
|
||||
// Note: GetWinsize is called frequently -- uncomment only for excessive details
|
||||
// logrus.Debugf("[windows] GetWinsize: Console(%v)", info.String())
|
||||
// logrus.Debugf("[windows] GetWinsize: Width(%v), Height(%v), x(%v), y(%v)", winsize.Width, winsize.Height, winsize.x, winsize.y)
|
||||
return winsize, nil
|
||||
}
|
||||
|
||||
// SetWinsize tries to set the specified window size for the specified file descriptor.
|
||||
func SetWinsize(fd uintptr, ws *Winsize) error {
|
||||
|
||||
// Ensure the requested dimensions are no larger than the maximum window size
|
||||
info, err := winterm.GetConsoleScreenBufferInfo(fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ws.Width == 0 || ws.Height == 0 || ws.Width > uint16(info.MaximumWindowSize.X) || ws.Height > uint16(info.MaximumWindowSize.Y) {
|
||||
return fmt.Errorf("Illegal window size: (%v,%v) -- Maximum allow: (%v,%v)",
|
||||
ws.Width, ws.Height, info.MaximumWindowSize.X, info.MaximumWindowSize.Y)
|
||||
}
|
||||
|
||||
// Narrow the sizes to that used by Windows
|
||||
width := winterm.SHORT(ws.Width)
|
||||
height := winterm.SHORT(ws.Height)
|
||||
|
||||
// Set the dimensions while ensuring they remain within the bounds of the backing console buffer
|
||||
// -- Shrinking will always succeed. Growing may push the edges past the buffer boundary. When that occurs,
|
||||
// shift the upper left just enough to keep the new window within the buffer.
|
||||
rect := info.Window
|
||||
if width < rect.Right-rect.Left+1 {
|
||||
rect.Right = rect.Left + width - 1
|
||||
} else if width > rect.Right-rect.Left+1 {
|
||||
rect.Right = rect.Left + width - 1
|
||||
if rect.Right >= info.Size.X {
|
||||
rect.Left = info.Size.X - width
|
||||
rect.Right = info.Size.X - 1
|
||||
}
|
||||
}
|
||||
|
||||
if height < rect.Bottom-rect.Top+1 {
|
||||
rect.Bottom = rect.Top + height - 1
|
||||
} else if height > rect.Bottom-rect.Top+1 {
|
||||
rect.Bottom = rect.Top + height - 1
|
||||
if rect.Bottom >= info.Size.Y {
|
||||
rect.Top = info.Size.Y - height
|
||||
rect.Bottom = info.Size.Y - 1
|
||||
}
|
||||
}
|
||||
logrus.Debugf("[windows] SetWinsize: Requested((%v,%v)) Actual(%v)", ws.Width, ws.Height, rect)
|
||||
|
||||
return winterm.SetConsoleWindowInfo(fd, true, rect)
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
return windows.IsConsole(fd)
|
||||
@@ -177,25 +201,36 @@ func IsTerminal(fd uintptr) bool {
|
||||
// RestoreTerminal restores the terminal connected to the given file descriptor
|
||||
// to a previous state.
|
||||
func RestoreTerminal(fd uintptr, state *State) error {
|
||||
return winterm.SetConsoleMode(fd, state.mode)
|
||||
if usingNativeConsole {
|
||||
return disableNativeConsole(state)
|
||||
}
|
||||
return winterm.SetConsoleMode(fd, state.outMode)
|
||||
}
|
||||
|
||||
// SaveState saves the state of the terminal connected to the given file descriptor.
|
||||
func SaveState(fd uintptr) (*State, error) {
|
||||
if usingNativeConsole {
|
||||
state, err := getNativeConsole()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &state, nil
|
||||
}
|
||||
|
||||
mode, e := winterm.GetConsoleMode(fd)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return &State{mode}, nil
|
||||
|
||||
return &State{outMode: mode}, nil
|
||||
}
|
||||
|
||||
// DisableEcho disables echo for the terminal connected to the given file descriptor.
|
||||
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
func DisableEcho(fd uintptr, state *State) error {
|
||||
mode := state.mode
|
||||
mode := state.inMode
|
||||
mode &^= winterm.ENABLE_ECHO_INPUT
|
||||
mode |= winterm.ENABLE_PROCESSED_INPUT | winterm.ENABLE_LINE_INPUT
|
||||
|
||||
err := winterm.SetConsoleMode(fd, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -227,10 +262,17 @@ func MakeRaw(fd uintptr) (*State, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mode := state.inMode
|
||||
if usingNativeConsole {
|
||||
if err := enableNativeConsole(*state); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode |= enableVirtualTerminalInput
|
||||
}
|
||||
|
||||
// See
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
mode := state.mode
|
||||
|
||||
// Disable these modes
|
||||
mode &^= winterm.ENABLE_ECHO_INPUT
|
||||
|
||||
69
vendor/src/github.com/docker/docker/pkg/term/termios_openbsd.go
vendored
Normal file
69
vendor/src/github.com/docker/docker/pkg/term/termios_openbsd.go
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package term
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
getTermios = syscall.TIOCGETA
|
||||
setTermios = syscall.TIOCSETA
|
||||
)
|
||||
|
||||
// Termios magic numbers, passthrough to the ones defined in syscall.
|
||||
const (
|
||||
IGNBRK = syscall.IGNBRK
|
||||
PARMRK = syscall.PARMRK
|
||||
INLCR = syscall.INLCR
|
||||
IGNCR = syscall.IGNCR
|
||||
ECHONL = syscall.ECHONL
|
||||
CSIZE = syscall.CSIZE
|
||||
ICRNL = syscall.ICRNL
|
||||
ISTRIP = syscall.ISTRIP
|
||||
PARENB = syscall.PARENB
|
||||
ECHO = syscall.ECHO
|
||||
ICANON = syscall.ICANON
|
||||
ISIG = syscall.ISIG
|
||||
IXON = syscall.IXON
|
||||
BRKINT = syscall.BRKINT
|
||||
INPCK = syscall.INPCK
|
||||
OPOST = syscall.OPOST
|
||||
CS8 = syscall.CS8
|
||||
IEXTEN = syscall.IEXTEN
|
||||
)
|
||||
|
||||
// Termios is the Unix API for terminal I/O.
|
||||
type Termios struct {
|
||||
Iflag uint32
|
||||
Oflag uint32
|
||||
Cflag uint32
|
||||
Lflag uint32
|
||||
Cc [20]byte
|
||||
Ispeed uint32
|
||||
Ospeed uint32
|
||||
}
|
||||
|
||||
// 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 uintptr) (*State, error) {
|
||||
var oldState State
|
||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newState := oldState.termios
|
||||
newState.Iflag &^= (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON)
|
||||
newState.Oflag &^= OPOST
|
||||
newState.Lflag &^= (ECHO | ECHONL | ICANON | ISIG | IEXTEN)
|
||||
newState.Cflag &^= (CSIZE | PARENB)
|
||||
newState.Cflag |= CS8
|
||||
newState.Cc[syscall.VMIN] = 1
|
||||
newState.Cc[syscall.VTIME] = 0
|
||||
|
||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&newState))); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oldState, nil
|
||||
}
|
||||
@@ -8,8 +8,44 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/Azure/go-ansiterm/winterm"
|
||||
|
||||
ansiterm "github.com/Azure/go-ansiterm"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// ConEmuStreams returns prepared versions of console streams,
|
||||
// for proper use in ConEmu terminal.
|
||||
// The ConEmu terminal emulates ANSI on output streams well by default.
|
||||
func ConEmuStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
if IsConsole(os.Stdin.Fd()) {
|
||||
stdIn = newAnsiReader(syscall.STD_INPUT_HANDLE)
|
||||
} else {
|
||||
stdIn = os.Stdin
|
||||
}
|
||||
|
||||
stdOut = os.Stdout
|
||||
stdErr = os.Stderr
|
||||
|
||||
// WARNING (BEGIN): sourced from newAnsiWriter
|
||||
|
||||
logFile := ioutil.Discard
|
||||
|
||||
if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
|
||||
logFile, _ = os.Create("ansiReaderWriter.log")
|
||||
}
|
||||
|
||||
logger = &logrus.Logger{
|
||||
Out: logFile,
|
||||
Formatter: new(logrus.TextFormatter),
|
||||
Level: logrus.DebugLevel,
|
||||
}
|
||||
|
||||
// WARNING (END): sourced from newAnsiWriter
|
||||
|
||||
return stdIn, stdOut, stdErr
|
||||
}
|
||||
|
||||
// ConsoleStreams returns a wrapped version for each standard stream referencing a console,
|
||||
// that handles ANSI character sequences.
|
||||
func ConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
|
||||
12
vendor/src/github.com/docker/go-units/size.go
vendored
12
vendor/src/github.com/docker/go-units/size.go
vendored
@@ -31,7 +31,7 @@ type unitMap map[string]int64
|
||||
var (
|
||||
decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
|
||||
binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
|
||||
sizeRegex = regexp.MustCompile(`^(\d+)([kKmMgGtTpP])?[bB]?$`)
|
||||
sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[bB]?$`)
|
||||
)
|
||||
|
||||
var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
||||
@@ -77,19 +77,19 @@ func RAMInBytes(size string) (int64, error) {
|
||||
// Parses the human-readable size string into the amount it represents.
|
||||
func parseSize(sizeStr string, uMap unitMap) (int64, error) {
|
||||
matches := sizeRegex.FindStringSubmatch(sizeStr)
|
||||
if len(matches) != 3 {
|
||||
if len(matches) != 4 {
|
||||
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
|
||||
}
|
||||
|
||||
size, err := strconv.ParseInt(matches[1], 10, 0)
|
||||
size, err := strconv.ParseFloat(matches[1], 64)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
unitPrefix := strings.ToLower(matches[2])
|
||||
unitPrefix := strings.ToLower(matches[3])
|
||||
if mul, ok := uMap[unitPrefix]; ok {
|
||||
size *= mul
|
||||
size *= float64(mul)
|
||||
}
|
||||
|
||||
return size, nil
|
||||
return int64(size), nil
|
||||
}
|
||||
|
||||
21
vendor/src/github.com/godbus/dbus/conn.go
vendored
21
vendor/src/github.com/godbus/dbus/conn.go
vendored
@@ -46,7 +46,7 @@ type Conn struct {
|
||||
calls map[uint32]*Call
|
||||
callsLck sync.RWMutex
|
||||
|
||||
handlers map[ObjectPath]map[string]exportWithMapping
|
||||
handlers map[ObjectPath]map[string]exportedObj
|
||||
handlersLck sync.RWMutex
|
||||
|
||||
out chan *Message
|
||||
@@ -157,7 +157,7 @@ func newConn(tr transport) (*Conn, error) {
|
||||
conn.transport = tr
|
||||
conn.calls = make(map[uint32]*Call)
|
||||
conn.out = make(chan *Message, 10)
|
||||
conn.handlers = make(map[ObjectPath]map[string]exportWithMapping)
|
||||
conn.handlers = make(map[ObjectPath]map[string]exportedObj)
|
||||
conn.nextSerial = 1
|
||||
conn.serialUsed = map[uint32]bool{0: true}
|
||||
conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
|
||||
@@ -499,9 +499,7 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
|
||||
// The caller has to make sure that ch is sufficiently buffered; if a message
|
||||
// arrives when a write to c is not possible, it is discarded.
|
||||
//
|
||||
// Multiple of these channels can be registered at the same time. Passing a
|
||||
// channel that already is registered will remove it from the list of the
|
||||
// registered channels.
|
||||
// Multiple of these channels can be registered at the same time.
|
||||
//
|
||||
// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
|
||||
// channel for eavesdropped messages, this channel receives all signals, and
|
||||
@@ -512,6 +510,19 @@ func (conn *Conn) Signal(ch chan<- *Signal) {
|
||||
conn.signalsLck.Unlock()
|
||||
}
|
||||
|
||||
// RemoveSignal removes the given channel from the list of the registered channels.
|
||||
func (conn *Conn) RemoveSignal(ch chan<- *Signal) {
|
||||
conn.signalsLck.Lock()
|
||||
for i := len(conn.signals) - 1; i >= 0; i-- {
|
||||
if ch == conn.signals[i] {
|
||||
copy(conn.signals[i:], conn.signals[i+1:])
|
||||
conn.signals[len(conn.signals)-1] = nil
|
||||
conn.signals = conn.signals[:len(conn.signals)-1]
|
||||
}
|
||||
}
|
||||
conn.signalsLck.Unlock()
|
||||
}
|
||||
|
||||
// SupportsUnixFDs returns whether the underlying transport supports passing of
|
||||
// unix file descriptors. If this is false, method calls containing unix file
|
||||
// descriptors will return an error and emitted signals containing them will
|
||||
|
||||
167
vendor/src/github.com/godbus/dbus/export.go
vendored
167
vendor/src/github.com/godbus/dbus/export.go
vendored
@@ -1,6 +1,7 @@
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -22,67 +23,60 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// exportWithMapping represents an exported struct along with a method name
|
||||
// mapping to allow for exporting lower-case methods, etc.
|
||||
type exportWithMapping struct {
|
||||
export interface{}
|
||||
|
||||
// Method name mapping; key -> struct method, value -> dbus method.
|
||||
mapping map[string]string
|
||||
// exportedObj represents an exported object. It stores a precomputed
|
||||
// method table that represents the methods exported on the bus.
|
||||
type exportedObj struct {
|
||||
methods map[string]reflect.Value
|
||||
|
||||
// Whether or not this export is for the entire subtree
|
||||
includeSubtree bool
|
||||
}
|
||||
|
||||
func (obj exportedObj) Method(name string) (reflect.Value, bool) {
|
||||
out, exists := obj.methods[name]
|
||||
return out, exists
|
||||
}
|
||||
|
||||
// Sender is a type which can be used in exported methods to receive the message
|
||||
// sender.
|
||||
type Sender string
|
||||
|
||||
func exportedMethod(export exportWithMapping, name string) reflect.Value {
|
||||
if export.export == nil {
|
||||
return reflect.Value{}
|
||||
func computeMethodName(name string, mapping map[string]string) string {
|
||||
newname, ok := mapping[name]
|
||||
if ok {
|
||||
name = newname
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// If a mapping was included in the export, check the map to see if we
|
||||
// should be looking for a different method in the export.
|
||||
if export.mapping != nil {
|
||||
for key, value := range export.mapping {
|
||||
if value == name {
|
||||
name = key
|
||||
break
|
||||
}
|
||||
|
||||
// Catch the case where a method is aliased but the client is calling
|
||||
// the original, e.g. the "Foo" method was exported mapped to
|
||||
// "foo," and dbus client called the original "Foo."
|
||||
if key == name {
|
||||
return reflect.Value{}
|
||||
}
|
||||
func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
methods := make(map[string]reflect.Value)
|
||||
val := reflect.ValueOf(in)
|
||||
typ := val.Type()
|
||||
for i := 0; i < typ.NumMethod(); i++ {
|
||||
methtype := typ.Method(i)
|
||||
method := val.Method(i)
|
||||
t := method.Type()
|
||||
// only track valid methods must return *Error as last arg
|
||||
// and must be exported
|
||||
if t.NumOut() == 0 ||
|
||||
t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) ||
|
||||
methtype.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
// map names while building table
|
||||
methods[computeMethodName(methtype.Name, mapping)] = method
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(export.export)
|
||||
m := value.MethodByName(name)
|
||||
|
||||
// Catch the case of attempting to call an unexported method
|
||||
method, ok := value.Type().MethodByName(name)
|
||||
|
||||
if !m.IsValid() || !ok || method.PkgPath != "" {
|
||||
return reflect.Value{}
|
||||
}
|
||||
t := m.Type()
|
||||
if t.NumOut() == 0 ||
|
||||
t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) {
|
||||
|
||||
return reflect.Value{}
|
||||
}
|
||||
return m
|
||||
return methods
|
||||
}
|
||||
|
||||
// searchHandlers will look through all registered handlers looking for one
|
||||
// to handle the given path. If a verbatim one isn't found, it will check for
|
||||
// a subtree registration for the path as well.
|
||||
func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping, bool) {
|
||||
func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportedObj, bool) {
|
||||
conn.handlersLck.RLock()
|
||||
defer conn.handlersLck.RUnlock()
|
||||
|
||||
@@ -93,10 +87,10 @@ func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping,
|
||||
|
||||
// If handlers weren't found for this exact path, look for a matching subtree
|
||||
// registration
|
||||
handlers = make(map[string]exportWithMapping)
|
||||
handlers = make(map[string]exportedObj)
|
||||
path = path[:strings.LastIndex(string(path), "/")]
|
||||
for len(path) > 0 {
|
||||
var subtreeHandlers map[string]exportWithMapping
|
||||
var subtreeHandlers map[string]exportedObj
|
||||
subtreeHandlers, ok = conn.handlers[path]
|
||||
if ok {
|
||||
for iface, handler := range subtreeHandlers {
|
||||
@@ -133,6 +127,28 @@ func (conn *Conn) handleCall(msg *Message) {
|
||||
conn.sendError(errmsgUnknownMethod, sender, serial)
|
||||
}
|
||||
return
|
||||
} else if ifaceName == "org.freedesktop.DBus.Introspectable" && name == "Introspect" {
|
||||
if _, ok := conn.handlers[path]; !ok {
|
||||
subpath := make(map[string]struct{})
|
||||
var xml bytes.Buffer
|
||||
xml.WriteString("<node>")
|
||||
for h, _ := range conn.handlers {
|
||||
p := string(path)
|
||||
if p != "/" {
|
||||
p += "/"
|
||||
}
|
||||
if strings.HasPrefix(string(h), p) {
|
||||
node_name := strings.Split(string(h[len(p):]), "/")[0]
|
||||
subpath[node_name] = struct{}{}
|
||||
}
|
||||
}
|
||||
for s, _ := range subpath {
|
||||
xml.WriteString("\n\t<node name=\"" + s + "\"/>")
|
||||
}
|
||||
xml.WriteString("\n</node>")
|
||||
conn.sendReply(sender, serial, xml.String())
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(name) == 0 {
|
||||
conn.sendError(errmsgUnknownMethod, sender, serial)
|
||||
@@ -146,19 +162,20 @@ func (conn *Conn) handleCall(msg *Message) {
|
||||
}
|
||||
|
||||
var m reflect.Value
|
||||
var exists bool
|
||||
if hasIface {
|
||||
iface := handlers[ifaceName]
|
||||
m = exportedMethod(iface, name)
|
||||
m, exists = iface.Method(name)
|
||||
} else {
|
||||
for _, v := range handlers {
|
||||
m = exportedMethod(v, name)
|
||||
if m.IsValid() {
|
||||
m, exists = v.Method(name)
|
||||
if exists {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !m.IsValid() {
|
||||
if !exists {
|
||||
conn.sendError(errmsgUnknownMethod, sender, serial)
|
||||
return
|
||||
}
|
||||
@@ -303,7 +320,7 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
|
||||
// The keys in the map are the real method names (exported on the struct), and
|
||||
// the values are the method names to be exported on DBus.
|
||||
func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
|
||||
return conn.exportWithMap(v, mapping, path, iface, false)
|
||||
return conn.export(getMethods(v, mapping), path, iface, false)
|
||||
}
|
||||
|
||||
// ExportSubtree works exactly like Export but registers the given value for
|
||||
@@ -326,11 +343,48 @@ func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) er
|
||||
// The keys in the map are the real method names (exported on the struct), and
|
||||
// the values are the method names to be exported on DBus.
|
||||
func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error {
|
||||
return conn.exportWithMap(v, mapping, path, iface, true)
|
||||
return conn.export(getMethods(v, mapping), path, iface, true)
|
||||
}
|
||||
|
||||
// ExportMethodTable like Export registers the given methods as an object
|
||||
// on the message bus. Unlike Export the it uses a method table to define
|
||||
// the object instead of a native go object.
|
||||
//
|
||||
// The method table is a map from method name to function closure
|
||||
// representing the method. This allows an object exported on the bus to not
|
||||
// necessarily be a native go object. It can be useful for generating exposed
|
||||
// methods on the fly.
|
||||
//
|
||||
// Any non-function objects in the method table are ignored.
|
||||
func (conn *Conn) ExportMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
|
||||
return conn.exportMethodTable(methods, path, iface, false)
|
||||
}
|
||||
|
||||
// Like ExportSubtree, but with the same caveats as ExportMethodTable.
|
||||
func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path ObjectPath, iface string) error {
|
||||
return conn.exportMethodTable(methods, path, iface, true)
|
||||
}
|
||||
|
||||
func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error {
|
||||
out := make(map[string]reflect.Value)
|
||||
for name, method := range methods {
|
||||
rval := reflect.ValueOf(method)
|
||||
if rval.Kind() != reflect.Func {
|
||||
continue
|
||||
}
|
||||
t := rval.Type()
|
||||
// only track valid methods must return *Error as last arg
|
||||
if t.NumOut() == 0 ||
|
||||
t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) {
|
||||
continue
|
||||
}
|
||||
out[name] = rval
|
||||
}
|
||||
return conn.export(out, path, iface, includeSubtree)
|
||||
}
|
||||
|
||||
// exportWithMap is the worker function for all exports/registrations.
|
||||
func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string, includeSubtree bool) error {
|
||||
func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error {
|
||||
if !path.IsValid() {
|
||||
return fmt.Errorf(`dbus: Invalid path name: "%s"`, path)
|
||||
}
|
||||
@@ -339,7 +393,7 @@ func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path O
|
||||
defer conn.handlersLck.Unlock()
|
||||
|
||||
// Remove a previous export if the interface is nil
|
||||
if v == nil {
|
||||
if methods == nil {
|
||||
if _, ok := conn.handlers[path]; ok {
|
||||
delete(conn.handlers[path], iface)
|
||||
if len(conn.handlers[path]) == 0 {
|
||||
@@ -353,11 +407,14 @@ func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path O
|
||||
// If this is the first handler for this path, make a new map to hold all
|
||||
// handlers for this path.
|
||||
if _, ok := conn.handlers[path]; !ok {
|
||||
conn.handlers[path] = make(map[string]exportWithMapping)
|
||||
conn.handlers[path] = make(map[string]exportedObj)
|
||||
}
|
||||
|
||||
// Finally, save this handler
|
||||
conn.handlers[path][iface] = exportWithMapping{export: v, mapping: mapping, includeSubtree: includeSubtree}
|
||||
conn.handlers[path][iface] = exportedObj{
|
||||
methods: methods,
|
||||
includeSubtree: includeSubtree,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build !windows
|
||||
//+build !windows,!solaris
|
||||
|
||||
package dbus
|
||||
|
||||
|
||||
@@ -39,5 +39,5 @@ test: install generate-test-pbs
|
||||
generate-test-pbs:
|
||||
make install
|
||||
make -C testdata
|
||||
protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata:. proto3_proto/proto3.proto
|
||||
protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto
|
||||
make
|
||||
|
||||
@@ -768,10 +768,11 @@ func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
|
||||
}
|
||||
}
|
||||
keyelem, valelem := keyptr.Elem(), valptr.Elem()
|
||||
if !keyelem.IsValid() || !valelem.IsValid() {
|
||||
// We did not decode the key or the value in the map entry.
|
||||
// Either way, it's an invalid map entry.
|
||||
return fmt.Errorf("proto: bad map data: missing key/val")
|
||||
if !keyelem.IsValid() {
|
||||
keyelem = reflect.Zero(p.mtype.Key())
|
||||
}
|
||||
if !valelem.IsValid() {
|
||||
valelem = reflect.Zero(p.mtype.Elem())
|
||||
}
|
||||
|
||||
v.SetMapIndex(keyelem, valelem)
|
||||
|
||||
@@ -64,6 +64,10 @@ var (
|
||||
// a struct with a repeated field containing a nil element.
|
||||
errRepeatedHasNil = errors.New("proto: repeated field has nil element")
|
||||
|
||||
// errOneofHasNil is the error returned if Marshal is called with
|
||||
// a struct with a oneof field containing a nil element.
|
||||
errOneofHasNil = errors.New("proto: oneof field has nil value")
|
||||
|
||||
// ErrNil is the error returned if Marshal is called with nil.
|
||||
ErrNil = errors.New("proto: Marshal called with nil")
|
||||
)
|
||||
@@ -1222,7 +1226,9 @@ func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error {
|
||||
// Do oneof fields.
|
||||
if prop.oneofMarshaler != nil {
|
||||
m := structPointer_Interface(base, prop.stype).(Message)
|
||||
if err := prop.oneofMarshaler(m, o); err != nil {
|
||||
if err := prop.oneofMarshaler(m, o); err == ErrNil {
|
||||
return errOneofHasNil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +235,7 @@ To create and play with a Test object:
|
||||
test := &pb.Test{
|
||||
Label: proto.String("hello"),
|
||||
Type: proto.Int32(17),
|
||||
Reps: []int64{1, 2, 3},
|
||||
Optionalgroup: &pb.Test_OptionalGroup{
|
||||
RequiredField: proto.String("good bye"),
|
||||
},
|
||||
@@ -887,3 +888,7 @@ func isProto3Zero(v reflect.Value) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
|
||||
// to assert that that code is compatible with this version of the proto package.
|
||||
const ProtoPackageIsVersion1 = true
|
||||
|
||||
@@ -173,6 +173,7 @@ func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order
|
||||
type Properties struct {
|
||||
Name string // name of the field, for error messages
|
||||
OrigName string // original name before protocol compiler (always set)
|
||||
JSONName string // name to use for JSON; determined by protoc
|
||||
Wire string
|
||||
WireType int
|
||||
Tag int
|
||||
@@ -229,8 +230,9 @@ func (p *Properties) String() string {
|
||||
if p.Packed {
|
||||
s += ",packed"
|
||||
}
|
||||
if p.OrigName != p.Name {
|
||||
s += ",name=" + p.OrigName
|
||||
s += ",name=" + p.OrigName
|
||||
if p.JSONName != p.OrigName {
|
||||
s += ",json=" + p.JSONName
|
||||
}
|
||||
if p.proto3 {
|
||||
s += ",proto3"
|
||||
@@ -310,6 +312,8 @@ func (p *Properties) Parse(s string) {
|
||||
p.Packed = true
|
||||
case strings.HasPrefix(f, "name="):
|
||||
p.OrigName = f[5:]
|
||||
case strings.HasPrefix(f, "json="):
|
||||
p.JSONName = f[5:]
|
||||
case strings.HasPrefix(f, "enum="):
|
||||
p.Enum = f[5:]
|
||||
case f == "proto3":
|
||||
|
||||
166
vendor/src/github.com/golang/protobuf/proto/text.go
vendored
166
vendor/src/github.com/golang/protobuf/proto/text.go
vendored
@@ -175,7 +175,93 @@ type raw interface {
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
func requiresQuotes(u string) bool {
|
||||
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
|
||||
for _, ch := range u {
|
||||
switch {
|
||||
case ch == '.' || ch == '/' || ch == '_':
|
||||
continue
|
||||
case '0' <= ch && ch <= '9':
|
||||
continue
|
||||
case 'A' <= ch && ch <= 'Z':
|
||||
continue
|
||||
case 'a' <= ch && ch <= 'z':
|
||||
continue
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isAny reports whether sv is a google.protobuf.Any message
|
||||
func isAny(sv reflect.Value) bool {
|
||||
type wkt interface {
|
||||
XXX_WellKnownType() string
|
||||
}
|
||||
t, ok := sv.Addr().Interface().(wkt)
|
||||
return ok && t.XXX_WellKnownType() == "Any"
|
||||
}
|
||||
|
||||
// writeProto3Any writes an expanded google.protobuf.Any message.
|
||||
//
|
||||
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
|
||||
// required messages are not linked in).
|
||||
//
|
||||
// It returns (true, error) when sv was written in expanded format or an error
|
||||
// was encountered.
|
||||
func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) {
|
||||
turl := sv.FieldByName("TypeUrl")
|
||||
val := sv.FieldByName("Value")
|
||||
if !turl.IsValid() || !val.IsValid() {
|
||||
return true, errors.New("proto: invalid google.protobuf.Any message")
|
||||
}
|
||||
|
||||
b, ok := val.Interface().([]byte)
|
||||
if !ok {
|
||||
return true, errors.New("proto: invalid google.protobuf.Any message")
|
||||
}
|
||||
|
||||
parts := strings.Split(turl.String(), "/")
|
||||
mt := MessageType(parts[len(parts)-1])
|
||||
if mt == nil {
|
||||
return false, nil
|
||||
}
|
||||
m := reflect.New(mt.Elem())
|
||||
if err := Unmarshal(b, m.Interface().(Message)); err != nil {
|
||||
return false, nil
|
||||
}
|
||||
w.Write([]byte("["))
|
||||
u := turl.String()
|
||||
if requiresQuotes(u) {
|
||||
writeString(w, u)
|
||||
} else {
|
||||
w.Write([]byte(u))
|
||||
}
|
||||
if w.compact {
|
||||
w.Write([]byte("]:<"))
|
||||
} else {
|
||||
w.Write([]byte("]: <\n"))
|
||||
w.ind++
|
||||
}
|
||||
if err := tm.writeStruct(w, m.Elem()); err != nil {
|
||||
return true, err
|
||||
}
|
||||
if w.compact {
|
||||
w.Write([]byte("> "))
|
||||
} else {
|
||||
w.ind--
|
||||
w.Write([]byte(">\n"))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
if tm.ExpandAny && isAny(sv) {
|
||||
if canExpand, err := tm.writeProto3Any(w, sv); canExpand {
|
||||
return err
|
||||
}
|
||||
}
|
||||
st := sv.Type()
|
||||
sprops := GetProperties(st)
|
||||
for i := 0; i < sv.NumField(); i++ {
|
||||
@@ -227,7 +313,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err := writeAny(w, v, props); err != nil {
|
||||
if err := tm.writeAny(w, v, props); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
@@ -269,7 +355,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := writeAny(w, key, props.mkeyprop); err != nil {
|
||||
if err := tm.writeAny(w, key, props.mkeyprop); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
@@ -286,7 +372,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := writeAny(w, val, props.mvalprop); err != nil {
|
||||
if err := tm.writeAny(w, val, props.mvalprop); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
@@ -358,7 +444,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
}
|
||||
|
||||
// Enums have a String method, so writeAny will work fine.
|
||||
if err := writeAny(w, fv, props); err != nil {
|
||||
if err := tm.writeAny(w, fv, props); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -370,7 +456,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
// Extensions (the XXX_extensions field).
|
||||
pv := sv.Addr()
|
||||
if pv.Type().Implements(extendableProtoType) {
|
||||
if err := writeExtensions(w, pv); err != nil {
|
||||
if err := tm.writeExtensions(w, pv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -400,7 +486,7 @@ func writeRaw(w *textWriter, b []byte) error {
|
||||
}
|
||||
|
||||
// writeAny writes an arbitrary field.
|
||||
func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||
v = reflect.Indirect(v)
|
||||
|
||||
// Floats have special cases.
|
||||
@@ -449,15 +535,15 @@ func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||
}
|
||||
}
|
||||
w.indent()
|
||||
if tm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||
text, err := tm.MarshalText()
|
||||
if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||
text, err := etm.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = w.Write(text); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := writeStruct(w, v); err != nil {
|
||||
} else if err := tm.writeStruct(w, v); err != nil {
|
||||
return err
|
||||
}
|
||||
w.unindent()
|
||||
@@ -601,7 +687,7 @@ func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// writeExtensions writes all the extensions in pv.
|
||||
// pv is assumed to be a pointer to a protocol message struct that is extendable.
|
||||
func writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||
func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||
emap := extensionMaps[pv.Type().Elem()]
|
||||
ep := pv.Interface().(extendableProto)
|
||||
|
||||
@@ -636,13 +722,13 @@ func writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||
|
||||
// Repeated extensions will appear as a slice.
|
||||
if !desc.repeated() {
|
||||
if err := writeExtension(w, desc.Name, pb); err != nil {
|
||||
if err := tm.writeExtension(w, desc.Name, pb); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
v := reflect.ValueOf(pb)
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
|
||||
if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -651,7 +737,7 @@ func writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeExtension(w *textWriter, name string, pb interface{}) error {
|
||||
func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error {
|
||||
if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -660,7 +746,7 @@ func writeExtension(w *textWriter, name string, pb interface{}) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil {
|
||||
if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
@@ -685,7 +771,15 @@ func (w *textWriter) writeIndent() {
|
||||
w.complete = false
|
||||
}
|
||||
|
||||
func marshalText(w io.Writer, pb Message, compact bool) error {
|
||||
// TextMarshaler is a configurable text format marshaler.
|
||||
type TextMarshaler struct {
|
||||
Compact bool // use compact text format (one line).
|
||||
ExpandAny bool // expand google.protobuf.Any messages of known types
|
||||
}
|
||||
|
||||
// Marshal writes a given protocol buffer in text format.
|
||||
// The only errors returned are from w.
|
||||
func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error {
|
||||
val := reflect.ValueOf(pb)
|
||||
if pb == nil || val.IsNil() {
|
||||
w.Write([]byte("<nil>"))
|
||||
@@ -700,11 +794,11 @@ func marshalText(w io.Writer, pb Message, compact bool) error {
|
||||
aw := &textWriter{
|
||||
w: ww,
|
||||
complete: true,
|
||||
compact: compact,
|
||||
compact: tm.Compact,
|
||||
}
|
||||
|
||||
if tm, ok := pb.(encoding.TextMarshaler); ok {
|
||||
text, err := tm.MarshalText()
|
||||
if etm, ok := pb.(encoding.TextMarshaler); ok {
|
||||
text, err := etm.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -718,7 +812,7 @@ func marshalText(w io.Writer, pb Message, compact bool) error {
|
||||
}
|
||||
// Dereference the received pointer so we don't have outer < and >.
|
||||
v := reflect.Indirect(val)
|
||||
if err := writeStruct(aw, v); err != nil {
|
||||
if err := tm.writeStruct(aw, v); err != nil {
|
||||
return err
|
||||
}
|
||||
if bw != nil {
|
||||
@@ -727,25 +821,29 @@ func marshalText(w io.Writer, pb Message, compact bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Text is the same as Marshal, but returns the string directly.
|
||||
func (tm *TextMarshaler) Text(pb Message) string {
|
||||
var buf bytes.Buffer
|
||||
tm.Marshal(&buf, pb)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
var (
|
||||
defaultTextMarshaler = TextMarshaler{}
|
||||
compactTextMarshaler = TextMarshaler{Compact: true}
|
||||
)
|
||||
|
||||
// TODO: consider removing some of the Marshal functions below.
|
||||
|
||||
// MarshalText writes a given protocol buffer in text format.
|
||||
// The only errors returned are from w.
|
||||
func MarshalText(w io.Writer, pb Message) error {
|
||||
return marshalText(w, pb, false)
|
||||
}
|
||||
func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }
|
||||
|
||||
// MarshalTextString is the same as MarshalText, but returns the string directly.
|
||||
func MarshalTextString(pb Message) string {
|
||||
var buf bytes.Buffer
|
||||
marshalText(&buf, pb, false)
|
||||
return buf.String()
|
||||
}
|
||||
func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }
|
||||
|
||||
// CompactText writes a given protocol buffer in compact text format (one line).
|
||||
func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) }
|
||||
func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }
|
||||
|
||||
// CompactTextString is the same as CompactText, but returns the string directly.
|
||||
func CompactTextString(pb Message) string {
|
||||
var buf bytes.Buffer
|
||||
marshalText(&buf, pb, true)
|
||||
return buf.String()
|
||||
}
|
||||
func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }
|
||||
|
||||
@@ -119,6 +119,14 @@ func isWhitespace(c byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isQuote(c byte) bool {
|
||||
switch c {
|
||||
case '"', '\'':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *textParser) skipWhitespace() {
|
||||
i := 0
|
||||
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
|
||||
@@ -155,7 +163,7 @@ func (p *textParser) advance() {
|
||||
p.cur.offset, p.cur.line = p.offset, p.line
|
||||
p.cur.unquoted = ""
|
||||
switch p.s[0] {
|
||||
case '<', '>', '{', '}', ':', '[', ']', ';', ',':
|
||||
case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/':
|
||||
// Single symbol
|
||||
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
|
||||
case '"', '\'':
|
||||
@@ -333,13 +341,13 @@ func (p *textParser) next() *token {
|
||||
p.advance()
|
||||
if p.done {
|
||||
p.cur.value = ""
|
||||
} else if len(p.cur.value) > 0 && p.cur.value[0] == '"' {
|
||||
} else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
|
||||
// Look for multiple quoted strings separated by whitespace,
|
||||
// and concatenate them.
|
||||
cat := p.cur
|
||||
for {
|
||||
p.skipWhitespace()
|
||||
if p.done || p.s[0] != '"' {
|
||||
if p.done || !isQuote(p.s[0]) {
|
||||
break
|
||||
}
|
||||
p.advance()
|
||||
@@ -443,7 +451,10 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||
fieldSet := make(map[string]bool)
|
||||
// A struct is a sequence of "name: value", terminated by one of
|
||||
// '>' or '}', or the end of the input. A name may also be
|
||||
// "[extension]".
|
||||
// "[extension]" or "[type/url]".
|
||||
//
|
||||
// The whole struct can also be an expanded Any message, like:
|
||||
// [type/url] < ... struct contents ... >
|
||||
for {
|
||||
tok := p.next()
|
||||
if tok.err != nil {
|
||||
@@ -453,33 +464,66 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||
break
|
||||
}
|
||||
if tok.value == "[" {
|
||||
// Looks like an extension.
|
||||
// Looks like an extension or an Any.
|
||||
//
|
||||
// TODO: Check whether we need to handle
|
||||
// namespace rooted names (e.g. ".something.Foo").
|
||||
tok = p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
extName, err := p.consumeExtName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s := strings.LastIndex(extName, "/"); s >= 0 {
|
||||
// If it contains a slash, it's an Any type URL.
|
||||
messageName := extName[s+1:]
|
||||
mt := MessageType(messageName)
|
||||
if mt == nil {
|
||||
return p.errorf("unrecognized message %q in google.protobuf.Any", messageName)
|
||||
}
|
||||
tok = p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
// consume an optional colon
|
||||
if tok.value == ":" {
|
||||
tok = p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
}
|
||||
var terminator string
|
||||
switch tok.value {
|
||||
case "<":
|
||||
terminator = ">"
|
||||
case "{":
|
||||
terminator = "}"
|
||||
default:
|
||||
return p.errorf("expected '{' or '<', found %q", tok.value)
|
||||
}
|
||||
v := reflect.New(mt.Elem())
|
||||
if pe := p.readStruct(v.Elem(), terminator); pe != nil {
|
||||
return pe
|
||||
}
|
||||
b, err := Marshal(v.Interface().(Message))
|
||||
if err != nil {
|
||||
return p.errorf("failed to marshal message of type %q: %v", messageName, err)
|
||||
}
|
||||
sv.FieldByName("TypeUrl").SetString(extName)
|
||||
sv.FieldByName("Value").SetBytes(b)
|
||||
continue
|
||||
}
|
||||
|
||||
var desc *ExtensionDesc
|
||||
// This could be faster, but it's functional.
|
||||
// TODO: Do something smarter than a linear scan.
|
||||
for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) {
|
||||
if d.Name == tok.value {
|
||||
if d.Name == extName {
|
||||
desc = d
|
||||
break
|
||||
}
|
||||
}
|
||||
if desc == nil {
|
||||
return p.errorf("unrecognized extension %q", tok.value)
|
||||
}
|
||||
// Check the extension terminator.
|
||||
tok = p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
if tok.value != "]" {
|
||||
return p.errorf("unrecognized extension terminator %q", tok.value)
|
||||
return p.errorf("unrecognized extension %q", extName)
|
||||
}
|
||||
|
||||
props := &Properties{}
|
||||
@@ -635,6 +679,35 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||
return reqFieldErr
|
||||
}
|
||||
|
||||
// consumeExtName consumes extension name or expanded Any type URL and the
|
||||
// following ']'. It returns the name or URL consumed.
|
||||
func (p *textParser) consumeExtName() (string, error) {
|
||||
tok := p.next()
|
||||
if tok.err != nil {
|
||||
return "", tok.err
|
||||
}
|
||||
|
||||
// If extension name or type url is quoted, it's a single token.
|
||||
if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] {
|
||||
name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0]))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return name, p.consumeToken("]")
|
||||
}
|
||||
|
||||
// Consume everything up to "]"
|
||||
var parts []string
|
||||
for tok.value != "]" {
|
||||
parts = append(parts, tok.value)
|
||||
tok = p.next()
|
||||
if tok.err != nil {
|
||||
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
|
||||
}
|
||||
}
|
||||
return strings.Join(parts, ""), nil
|
||||
}
|
||||
|
||||
// consumeOptionalSeparator consumes an optional semicolon or comma.
|
||||
// It is used in readStruct to provide backward compatibility.
|
||||
func (p *textParser) consumeOptionalSeparator() error {
|
||||
|
||||
@@ -103,6 +103,19 @@ import "github.com/rcrowley/go-metrics/stathat"
|
||||
go stathat.Stathat(metrics.DefaultRegistry, 10e9, "example@example.com")
|
||||
```
|
||||
|
||||
Maintain all metrics along with expvars at `/debug/metrics`:
|
||||
|
||||
This uses the same mechanism as [the official expvar](http://golang.org/pkg/expvar/)
|
||||
but exposed under `/debug/metrics`, which shows a json representation of all your usual expvars
|
||||
as well as all your go-metrics.
|
||||
|
||||
|
||||
```go
|
||||
import "github.com/rcrowley/go-metrics/exp"
|
||||
|
||||
exp.Exp(metrics.DefaultRegistry)
|
||||
```
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package metrics
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -39,6 +40,7 @@ var (
|
||||
}
|
||||
NumCgoCall Gauge
|
||||
NumGoroutine Gauge
|
||||
NumThread Gauge
|
||||
ReadMemStats Timer
|
||||
}
|
||||
frees uint64
|
||||
@@ -46,6 +48,8 @@ var (
|
||||
mallocs uint64
|
||||
numGC uint32
|
||||
numCgoCalls int64
|
||||
|
||||
threadCreateProfile = pprof.Lookup("threadcreate")
|
||||
)
|
||||
|
||||
// Capture new values for the Go runtime statistics exported in
|
||||
@@ -134,6 +138,8 @@ func CaptureRuntimeMemStatsOnce(r Registry) {
|
||||
numCgoCalls = currentNumCgoCalls
|
||||
|
||||
runtimeMetrics.NumGoroutine.Update(int64(runtime.NumGoroutine()))
|
||||
|
||||
runtimeMetrics.NumThread.Update(int64(threadCreateProfile.Count()))
|
||||
}
|
||||
|
||||
// Register runtimeMetrics for the Go runtime statistics exported in runtime and
|
||||
@@ -169,6 +175,7 @@ func RegisterRuntimeMemStats(r Registry) {
|
||||
runtimeMetrics.MemStats.TotalAlloc = NewGauge()
|
||||
runtimeMetrics.NumCgoCall = NewGauge()
|
||||
runtimeMetrics.NumGoroutine = NewGauge()
|
||||
runtimeMetrics.NumThread = NewGauge()
|
||||
runtimeMetrics.ReadMemStats = NewTimer()
|
||||
|
||||
r.Register("runtime.MemStats.Alloc", runtimeMetrics.MemStats.Alloc)
|
||||
@@ -200,5 +207,6 @@ func RegisterRuntimeMemStats(r Registry) {
|
||||
r.Register("runtime.MemStats.TotalAlloc", runtimeMetrics.MemStats.TotalAlloc)
|
||||
r.Register("runtime.NumCgoCall", runtimeMetrics.NumCgoCall)
|
||||
r.Register("runtime.NumGoroutine", runtimeMetrics.NumGoroutine)
|
||||
r.Register("runtime.NumThread", runtimeMetrics.NumThread)
|
||||
r.Register("runtime.ReadMemStats", runtimeMetrics.ReadMemStats)
|
||||
}
|
||||
|
||||
2
vendor/src/github.com/satori/go.uuid/LICENSE
vendored
2
vendor/src/github.com/satori/go.uuid/LICENSE
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
|
||||
Copyright (C) 2013-2016 by Maxim Bublis <b@codemonkey.ru>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -11,7 +11,7 @@ goroot = $(addprefix ../../../,$(1))
|
||||
unroot = $(subst ../../../,,$(1))
|
||||
fmt = $(addprefix fmt-,$(1))
|
||||
|
||||
all: fmt test
|
||||
all: test
|
||||
|
||||
$(call goroot,$(DEPS)):
|
||||
go get $(call unroot,$@)
|
||||
|
||||
@@ -2,6 +2,7 @@ package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -85,58 +86,124 @@ func AddrList(link Link, family int) ([]Addr, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
index := 0
|
||||
indexFilter := 0
|
||||
if link != nil {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
index = base.Index
|
||||
indexFilter = base.Index
|
||||
}
|
||||
|
||||
var res []Addr
|
||||
for _, m := range msgs {
|
||||
msg := nl.DeserializeIfAddrmsg(m)
|
||||
addr, family, ifindex, err := parseAddr(m)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if link != nil && msg.Index != uint32(index) {
|
||||
if link != nil && ifindex != indexFilter {
|
||||
// Ignore messages from other interfaces
|
||||
continue
|
||||
}
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if family != FAMILY_ALL && msg.Family != uint8(family) {
|
||||
continue
|
||||
}
|
||||
|
||||
var local, dst *net.IPNet
|
||||
var addr Addr
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case syscall.IFA_ADDRESS:
|
||||
dst = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||
}
|
||||
case syscall.IFA_LOCAL:
|
||||
local = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||
}
|
||||
case syscall.IFA_LABEL:
|
||||
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
||||
case IFA_FLAGS:
|
||||
addr.Flags = int(native.Uint32(attr.Value[0:4]))
|
||||
}
|
||||
}
|
||||
|
||||
// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
|
||||
if local != nil {
|
||||
addr.IPNet = local
|
||||
} else {
|
||||
addr.IPNet = dst
|
||||
}
|
||||
addr.Scope = int(msg.Scope)
|
||||
|
||||
res = append(res, addr)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseAddr(m []byte) (addr Addr, family, index int, err error) {
|
||||
msg := nl.DeserializeIfAddrmsg(m)
|
||||
|
||||
family = -1
|
||||
index = -1
|
||||
|
||||
attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
|
||||
if err1 != nil {
|
||||
err = err1
|
||||
return
|
||||
}
|
||||
|
||||
index = int(msg.Index)
|
||||
|
||||
var local, dst *net.IPNet
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case syscall.IFA_ADDRESS:
|
||||
dst = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||
}
|
||||
case syscall.IFA_LOCAL:
|
||||
local = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||
}
|
||||
case syscall.IFA_LABEL:
|
||||
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
||||
case IFA_FLAGS:
|
||||
addr.Flags = int(native.Uint32(attr.Value[0:4]))
|
||||
}
|
||||
}
|
||||
|
||||
// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
|
||||
if local != nil {
|
||||
addr.IPNet = local
|
||||
} else {
|
||||
addr.IPNet = dst
|
||||
}
|
||||
addr.Scope = int(msg.Scope)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type AddrUpdate struct {
|
||||
LinkAddress net.IPNet
|
||||
LinkIndex int
|
||||
NewAddr bool // true=added false=deleted
|
||||
}
|
||||
|
||||
// AddrSubscribe takes a chan down which notifications will be sent
|
||||
// when addresses change. Close the 'done' chan to stop subscription.
|
||||
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
|
||||
s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if done != nil {
|
||||
go func() {
|
||||
<-done
|
||||
s.Close()
|
||||
}()
|
||||
}
|
||||
go func() {
|
||||
defer close(ch)
|
||||
for {
|
||||
msgs, err := s.Receive()
|
||||
if err != nil {
|
||||
log.Printf("netlink.AddrSubscribe: Receive() error: %v", err)
|
||||
return
|
||||
}
|
||||
for _, m := range msgs {
|
||||
msgType := m.Header.Type
|
||||
if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
|
||||
log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType)
|
||||
continue
|
||||
}
|
||||
|
||||
addr, _, ifindex, err := parseAddr(m.Data)
|
||||
if err != nil {
|
||||
log.Printf("netlink.AddrSubscribe: could not parse address: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
ch <- AddrUpdate{LinkAddress: *addr.IPNet, LinkIndex: ifindex, NewAddr: msgType == syscall.RTM_NEWADDR}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
60
vendor/src/github.com/vishvananda/netlink/bpf_linux.go
vendored
Normal file
60
vendor/src/github.com/vishvananda/netlink/bpf_linux.go
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package netlink
|
||||
|
||||
/*
|
||||
#include <asm/types.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int load_simple_bpf(int prog_type) {
|
||||
#ifdef __NR_bpf
|
||||
// { return 1; }
|
||||
__u64 __attribute__((aligned(8))) insns[] = {
|
||||
0x00000001000000b7ull,
|
||||
0x0000000000000095ull,
|
||||
};
|
||||
__u8 __attribute__((aligned(8))) license[] = "ASL2";
|
||||
// Copied from a header file since libc is notoriously slow to update.
|
||||
// The call will succeed or fail and that will be our indication on
|
||||
// whether or not it is supported.
|
||||
struct {
|
||||
__u32 prog_type;
|
||||
__u32 insn_cnt;
|
||||
__u64 insns;
|
||||
__u64 license;
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
__u64 log_buf;
|
||||
__u32 kern_version;
|
||||
} __attribute__((aligned(8))) attr = {
|
||||
.prog_type = prog_type,
|
||||
.insn_cnt = 2,
|
||||
.insns = (uintptr_t)&insns,
|
||||
.license = (uintptr_t)&license,
|
||||
};
|
||||
return syscall(__NR_bpf, 5, &attr, sizeof(attr));
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type BpfProgType C.int
|
||||
|
||||
const (
|
||||
BPF_PROG_TYPE_UNSPEC BpfProgType = iota
|
||||
BPF_PROG_TYPE_SOCKET_FILTER
|
||||
BPF_PROG_TYPE_KPROBE
|
||||
BPF_PROG_TYPE_SCHED_CLS
|
||||
BPF_PROG_TYPE_SCHED_ACT
|
||||
)
|
||||
|
||||
// loadSimpleBpf loads a trivial bpf program for testing purposes
|
||||
func loadSimpleBpf(progType BpfProgType) (int, error) {
|
||||
fd, err := C.load_simple_bpf(C.int(progType))
|
||||
return int(fd), err
|
||||
}
|
||||
@@ -9,7 +9,7 @@ type Class interface {
|
||||
Type() string
|
||||
}
|
||||
|
||||
// Class represents a netlink class. A filter is associated with a link,
|
||||
// ClassAttrs represents a netlink class. A filter is associated with a link,
|
||||
// has a handle and a parent. The root filter of a device should have a
|
||||
// parent == HANDLE_ROOT.
|
||||
type ClassAttrs struct {
|
||||
@@ -20,7 +20,7 @@ type ClassAttrs struct {
|
||||
}
|
||||
|
||||
func (q ClassAttrs) String() string {
|
||||
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf)
|
||||
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf)
|
||||
}
|
||||
|
||||
type HtbClassAttrs struct {
|
||||
@@ -38,7 +38,7 @@ func (q HtbClassAttrs) String() string {
|
||||
return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer)
|
||||
}
|
||||
|
||||
// Htb class
|
||||
// HtbClass represents an Htb class
|
||||
type HtbClass struct {
|
||||
ClassAttrs
|
||||
Rate uint64
|
||||
@@ -56,6 +56,7 @@ func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
|
||||
ceil := cattrs.Ceil / 8
|
||||
buffer := cattrs.Buffer
|
||||
cbuffer := cattrs.Cbuffer
|
||||
|
||||
if ceil == 0 {
|
||||
ceil = rate
|
||||
}
|
||||
@@ -86,11 +87,11 @@ func (q HtbClass) String() string {
|
||||
return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer)
|
||||
}
|
||||
|
||||
func (class *HtbClass) Attrs() *ClassAttrs {
|
||||
return &class.ClassAttrs
|
||||
func (q *HtbClass) Attrs() *ClassAttrs {
|
||||
return &q.ClassAttrs
|
||||
}
|
||||
|
||||
func (class *HtbClass) Type() string {
|
||||
func (q *HtbClass) Type() string {
|
||||
return "htb"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
@@ -65,15 +66,32 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
|
||||
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
|
||||
if htb, ok := class.(*HtbClass); ok {
|
||||
opt := nl.TcHtbCopt{}
|
||||
opt.Rate.Rate = uint32(htb.Rate)
|
||||
opt.Ceil.Rate = uint32(htb.Ceil)
|
||||
opt.Buffer = htb.Buffer
|
||||
opt.Cbuffer = htb.Cbuffer
|
||||
opt.Quantum = htb.Quantum
|
||||
opt.Level = htb.Level
|
||||
opt.Prio = htb.Prio
|
||||
// TODO: Handle Debug properly. For now default to 0
|
||||
/* Calculate {R,C}Tab and set Rate and Ceil */
|
||||
cellLog := -1
|
||||
ccellLog := -1
|
||||
linklayer := nl.LINKLAYER_ETHERNET
|
||||
mtu := 1600
|
||||
var rtab [256]uint32
|
||||
var ctab [256]uint32
|
||||
tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)}
|
||||
if CalcRtable(&tcrate, rtab, cellLog, uint32(mtu), linklayer) < 0 {
|
||||
return errors.New("HTB: failed to calculate rate table")
|
||||
}
|
||||
opt.Rate = tcrate
|
||||
tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)}
|
||||
if CalcRtable(&tcceil, ctab, ccellLog, uint32(mtu), linklayer) < 0 {
|
||||
return errors.New("HTB: failed to calculate ceil rate table")
|
||||
}
|
||||
opt.Ceil = tcceil
|
||||
nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize())
|
||||
nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab))
|
||||
nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab))
|
||||
}
|
||||
req.AddData(options)
|
||||
return nil
|
||||
|
||||
@@ -11,7 +11,7 @@ type Filter interface {
|
||||
Type() string
|
||||
}
|
||||
|
||||
// Filter represents a netlink filter. A filter is associated with a link,
|
||||
// FilterAttrs represents a netlink filter. A filter is associated with a link,
|
||||
// has a handle and a parent. The root filter of a device should have a
|
||||
// parent == HANDLE_ROOT.
|
||||
type FilterAttrs struct {
|
||||
@@ -26,11 +26,45 @@ func (q FilterAttrs) String() string {
|
||||
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Priority: %d, Protocol: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Priority, q.Protocol)
|
||||
}
|
||||
|
||||
// Action represents an action in any supported filter.
|
||||
type Action interface {
|
||||
Type() string
|
||||
}
|
||||
|
||||
type BpfAction struct {
|
||||
nl.TcActBpf
|
||||
Fd int
|
||||
Name string
|
||||
}
|
||||
|
||||
func (action *BpfAction) Type() string {
|
||||
return "bpf"
|
||||
}
|
||||
|
||||
type MirredAction struct {
|
||||
nl.TcMirred
|
||||
}
|
||||
|
||||
func (action *MirredAction) Type() string {
|
||||
return "mirred"
|
||||
}
|
||||
|
||||
func NewMirredAction(redirIndex int) *MirredAction {
|
||||
return &MirredAction{
|
||||
TcMirred: nl.TcMirred{
|
||||
TcGen: nl.TcGen{Action: nl.TC_ACT_STOLEN},
|
||||
Eaction: nl.TCA_EGRESS_REDIR,
|
||||
Ifindex: uint32(redirIndex),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// U32 filters on many packet related properties
|
||||
type U32 struct {
|
||||
FilterAttrs
|
||||
// Currently only supports redirecting to another interface
|
||||
ClassId uint32
|
||||
RedirIndex int
|
||||
Actions []Action
|
||||
}
|
||||
|
||||
func (filter *U32) Attrs() *FilterAttrs {
|
||||
@@ -57,7 +91,7 @@ type FilterFwAttrs struct {
|
||||
LinkLayer int
|
||||
}
|
||||
|
||||
// FwFilter filters on firewall marks
|
||||
// Fw filter filters on firewall marks
|
||||
type Fw struct {
|
||||
FilterAttrs
|
||||
ClassId uint32
|
||||
@@ -73,8 +107,8 @@ type Fw struct {
|
||||
func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
|
||||
var rtab [256]uint32
|
||||
var ptab [256]uint32
|
||||
rcell_log := -1
|
||||
pcell_log := -1
|
||||
rcellLog := -1
|
||||
pcellLog := -1
|
||||
avrate := fattrs.AvRate / 8
|
||||
police := nl.TcPolice{}
|
||||
police.Rate.Rate = fattrs.Rate / 8
|
||||
@@ -90,8 +124,8 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
|
||||
if police.Rate.Rate != 0 {
|
||||
police.Rate.Mpu = fattrs.Mpu
|
||||
police.Rate.Overhead = fattrs.Overhead
|
||||
if CalcRtable(&police.Rate, rtab, rcell_log, fattrs.Mtu, linklayer) < 0 {
|
||||
return nil, errors.New("TBF: failed to calculate rate table.")
|
||||
if CalcRtable(&police.Rate, rtab, rcellLog, fattrs.Mtu, linklayer) < 0 {
|
||||
return nil, errors.New("TBF: failed to calculate rate table")
|
||||
}
|
||||
police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer)))
|
||||
}
|
||||
@@ -99,8 +133,8 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
|
||||
if police.PeakRate.Rate != 0 {
|
||||
police.PeakRate.Mpu = fattrs.Mpu
|
||||
police.PeakRate.Overhead = fattrs.Overhead
|
||||
if CalcRtable(&police.PeakRate, ptab, pcell_log, fattrs.Mtu, linklayer) < 0 {
|
||||
return nil, errors.New("POLICE: failed to calculate peak rate table.")
|
||||
if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 {
|
||||
return nil, errors.New("POLICE: failed to calculate peak rate table")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +158,22 @@ func (filter *Fw) Type() string {
|
||||
return "fw"
|
||||
}
|
||||
|
||||
type BpfFilter struct {
|
||||
FilterAttrs
|
||||
ClassId uint32
|
||||
Fd int
|
||||
Name string
|
||||
DirectAction bool
|
||||
}
|
||||
|
||||
func (filter *BpfFilter) Type() string {
|
||||
return "bpf"
|
||||
}
|
||||
|
||||
func (filter *BpfFilter) Attrs() *FilterAttrs {
|
||||
return &filter.FilterAttrs
|
||||
}
|
||||
|
||||
// GenericFilter filters represent types that are not currently understood
|
||||
// by this netlink library.
|
||||
type GenericFilter struct {
|
||||
|
||||
@@ -52,17 +52,17 @@ func FilterAdd(filter Filter) error {
|
||||
}
|
||||
sel.Keys = append(sel.Keys, nl.TcU32Key{})
|
||||
nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
|
||||
actions := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
|
||||
table := nl.NewRtAttrChild(actions, nl.TCA_ACT_TAB, nil)
|
||||
nl.NewRtAttrChild(table, nl.TCA_KIND, nl.ZeroTerminated("mirred"))
|
||||
// redirect to other interface
|
||||
mir := nl.TcMirred{
|
||||
Action: nl.TC_ACT_STOLEN,
|
||||
Eaction: nl.TCA_EGRESS_REDIR,
|
||||
Ifindex: uint32(u32.RedirIndex),
|
||||
if u32.ClassId != 0 {
|
||||
nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(u32.ClassId))
|
||||
}
|
||||
actionsAttr := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
|
||||
// backwards compatibility
|
||||
if u32.RedirIndex != 0 {
|
||||
u32.Actions = append([]Action{NewMirredAction(u32.RedirIndex)}, u32.Actions...)
|
||||
}
|
||||
if err := encodeActions(actionsAttr, u32.Actions); err != nil {
|
||||
return err
|
||||
}
|
||||
aopts := nl.NewRtAttrChild(table, nl.TCA_OPTIONS, nil)
|
||||
nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mir.Serialize())
|
||||
} else if fw, ok := filter.(*Fw); ok {
|
||||
if fw.Mask != 0 {
|
||||
b := make([]byte, 4)
|
||||
@@ -90,6 +90,21 @@ func FilterAdd(filter Filter) error {
|
||||
native.PutUint32(b, fw.ClassId)
|
||||
nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b)
|
||||
}
|
||||
} else if bpf, ok := filter.(*BpfFilter); ok {
|
||||
var bpfFlags uint32
|
||||
if bpf.ClassId != 0 {
|
||||
nl.NewRtAttrChild(options, nl.TCA_BPF_CLASSID, nl.Uint32Attr(bpf.ClassId))
|
||||
}
|
||||
if bpf.Fd >= 0 {
|
||||
nl.NewRtAttrChild(options, nl.TCA_BPF_FD, nl.Uint32Attr((uint32(bpf.Fd))))
|
||||
}
|
||||
if bpf.Name != "" {
|
||||
nl.NewRtAttrChild(options, nl.TCA_BPF_NAME, nl.ZeroTerminated(bpf.Name))
|
||||
}
|
||||
if bpf.DirectAction {
|
||||
bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT
|
||||
}
|
||||
nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
|
||||
}
|
||||
|
||||
req.AddData(options)
|
||||
@@ -147,26 +162,29 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
|
||||
filter = &U32{}
|
||||
case "fw":
|
||||
filter = &Fw{}
|
||||
case "bpf":
|
||||
filter = &BpfFilter{}
|
||||
default:
|
||||
filter = &GenericFilter{FilterType: filterType}
|
||||
}
|
||||
case nl.TCA_OPTIONS:
|
||||
data, err := nl.ParseRouteAttr(attr.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch filterType {
|
||||
case "u32":
|
||||
data, err := nl.ParseRouteAttr(attr.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
detailed, err = parseU32Data(filter, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "fw":
|
||||
data, err := nl.ParseRouteAttr(attr.Value)
|
||||
detailed, err = parseFwData(filter, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
detailed, err = parseFwData(filter, data)
|
||||
case "bpf":
|
||||
detailed, err = parseBpfData(filter, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -183,6 +201,85 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func encodeActions(attr *nl.RtAttr, actions []Action) error {
|
||||
tabIndex := int(nl.TCA_ACT_TAB)
|
||||
|
||||
for _, action := range actions {
|
||||
switch action := action.(type) {
|
||||
default:
|
||||
return fmt.Errorf("unknown action type %s", action.Type())
|
||||
case *MirredAction:
|
||||
table := nl.NewRtAttrChild(attr, tabIndex, nil)
|
||||
tabIndex++
|
||||
nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
|
||||
aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
|
||||
nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, action.Serialize())
|
||||
case *BpfAction:
|
||||
table := nl.NewRtAttrChild(attr, tabIndex, nil)
|
||||
tabIndex++
|
||||
nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
|
||||
aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
|
||||
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_PARMS, action.Serialize())
|
||||
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
|
||||
nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
||||
var actions []Action
|
||||
for _, table := range tables {
|
||||
var action Action
|
||||
var actionType string
|
||||
aattrs, err := nl.ParseRouteAttr(table.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nextattr:
|
||||
for _, aattr := range aattrs {
|
||||
switch aattr.Attr.Type {
|
||||
case nl.TCA_KIND:
|
||||
actionType = string(aattr.Value[:len(aattr.Value)-1])
|
||||
// only parse if the action is mirred or bpf
|
||||
switch actionType {
|
||||
case "mirred":
|
||||
action = &MirredAction{}
|
||||
case "bpf":
|
||||
action = &BpfAction{}
|
||||
default:
|
||||
break nextattr
|
||||
}
|
||||
case nl.TCA_OPTIONS:
|
||||
adata, err := nl.ParseRouteAttr(aattr.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, adatum := range adata {
|
||||
switch actionType {
|
||||
case "mirred":
|
||||
switch adatum.Attr.Type {
|
||||
case nl.TCA_MIRRED_PARMS:
|
||||
action.(*MirredAction).TcMirred = *nl.DeserializeTcMirred(adatum.Value)
|
||||
}
|
||||
case "bpf":
|
||||
switch adatum.Attr.Type {
|
||||
case nl.TCA_ACT_BPF_PARMS:
|
||||
action.(*BpfAction).TcActBpf = *nl.DeserializeTcActBpf(adatum.Value)
|
||||
case nl.TCA_ACT_BPF_FD:
|
||||
action.(*BpfAction).Fd = int(native.Uint32(adatum.Value[0:4]))
|
||||
case nl.TCA_ACT_BPF_NAME:
|
||||
action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
actions = append(actions, action)
|
||||
}
|
||||
return actions, nil
|
||||
}
|
||||
|
||||
func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
|
||||
native = nl.NativeEndian()
|
||||
u32 := filter.(*U32)
|
||||
@@ -197,34 +294,17 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
|
||||
return detailed, nil
|
||||
}
|
||||
case nl.TCA_U32_ACT:
|
||||
table, err := nl.ParseRouteAttr(datum.Value)
|
||||
tables, err := nl.ParseRouteAttr(datum.Value)
|
||||
if err != nil {
|
||||
return detailed, err
|
||||
}
|
||||
if len(table) != 1 || table[0].Attr.Type != nl.TCA_ACT_TAB {
|
||||
return detailed, fmt.Errorf("Action table not formed properly")
|
||||
u32.Actions, err = parseActions(tables)
|
||||
if err != nil {
|
||||
return detailed, err
|
||||
}
|
||||
aattrs, err := nl.ParseRouteAttr(table[0].Value)
|
||||
for _, aattr := range aattrs {
|
||||
switch aattr.Attr.Type {
|
||||
case nl.TCA_KIND:
|
||||
actionType := string(aattr.Value[:len(aattr.Value)-1])
|
||||
// only parse if the action is mirred
|
||||
if actionType != "mirred" {
|
||||
return detailed, nil
|
||||
}
|
||||
case nl.TCA_OPTIONS:
|
||||
adata, err := nl.ParseRouteAttr(aattr.Value)
|
||||
if err != nil {
|
||||
return detailed, err
|
||||
}
|
||||
for _, adatum := range adata {
|
||||
switch adatum.Attr.Type {
|
||||
case nl.TCA_MIRRED_PARMS:
|
||||
mir := nl.DeserializeTcMirred(adatum.Value)
|
||||
u32.RedirIndex = int(mir.Ifindex)
|
||||
}
|
||||
}
|
||||
for _, action := range u32.Actions {
|
||||
if action, ok := action.(*MirredAction); ok {
|
||||
u32.RedirIndex = int(action.Ifindex)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,6 +341,28 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
|
||||
return detailed, nil
|
||||
}
|
||||
|
||||
func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
|
||||
native = nl.NativeEndian()
|
||||
bpf := filter.(*BpfFilter)
|
||||
detailed := true
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.TCA_BPF_FD:
|
||||
bpf.Fd = int(native.Uint32(datum.Value[0:4]))
|
||||
case nl.TCA_BPF_NAME:
|
||||
bpf.Name = string(datum.Value[:len(datum.Value)-1])
|
||||
case nl.TCA_BPF_CLASSID:
|
||||
bpf.ClassId = native.Uint32(datum.Value[0:4])
|
||||
case nl.TCA_BPF_FLAGS:
|
||||
flags := native.Uint32(datum.Value[0:4])
|
||||
if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 {
|
||||
bpf.DirectAction = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return detailed, nil
|
||||
}
|
||||
|
||||
func AlignToAtm(size uint) uint {
|
||||
var linksize, cells int
|
||||
cells = int(size / nl.ATM_CELL_PAYLOAD)
|
||||
@@ -283,27 +385,27 @@ func AdjustSize(sz uint, mpu uint, linklayer int) uint {
|
||||
}
|
||||
}
|
||||
|
||||
func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cell_log int, mtu uint32, linklayer int) int {
|
||||
func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cellLog int, mtu uint32, linklayer int) int {
|
||||
bps := rate.Rate
|
||||
mpu := rate.Mpu
|
||||
var sz uint
|
||||
if mtu == 0 {
|
||||
mtu = 2047
|
||||
}
|
||||
if cell_log < 0 {
|
||||
cell_log = 0
|
||||
for (mtu >> uint(cell_log)) > 255 {
|
||||
cell_log++
|
||||
if cellLog < 0 {
|
||||
cellLog = 0
|
||||
for (mtu >> uint(cellLog)) > 255 {
|
||||
cellLog++
|
||||
}
|
||||
}
|
||||
for i := 0; i < 256; i++ {
|
||||
sz = AdjustSize(uint((i+1)<<uint32(cell_log)), uint(mpu), linklayer)
|
||||
sz = AdjustSize(uint((i+1)<<uint32(cellLog)), uint(mpu), linklayer)
|
||||
rtab[i] = uint32(Xmittime(uint64(bps), uint32(sz)))
|
||||
}
|
||||
rate.CellAlign = -1
|
||||
rate.CellLog = uint8(cell_log)
|
||||
rate.CellLog = uint8(cellLog)
|
||||
rate.Linklayer = uint8(linklayer & nl.TC_LINKLAYER_MASK)
|
||||
return cell_log
|
||||
return cellLog
|
||||
}
|
||||
|
||||
func DeserializeRtab(b []byte) [256]uint32 {
|
||||
|
||||
@@ -204,6 +204,7 @@ type Vxlan struct {
|
||||
RSC bool
|
||||
L2miss bool
|
||||
L3miss bool
|
||||
UDPCSum bool
|
||||
NoAge bool
|
||||
GBP bool
|
||||
Age int
|
||||
@@ -424,7 +425,7 @@ const (
|
||||
BOND_AD_SELECT_COUNT
|
||||
)
|
||||
|
||||
// BondAdInfo
|
||||
// BondAdInfo represents ad info for bond
|
||||
type BondAdInfo struct {
|
||||
AggregatorId int
|
||||
NumPorts int
|
||||
@@ -525,7 +526,7 @@ func (bond *Bond) Type() string {
|
||||
return "bond"
|
||||
}
|
||||
|
||||
// GreTap devices must specify LocalIP and RemoteIP on create
|
||||
// Gretap devices must specify LocalIP and RemoteIP on create
|
||||
type Gretap struct {
|
||||
LinkAttrs
|
||||
IKey uint32
|
||||
|
||||
@@ -142,6 +142,54 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetVfHardwareAddr sets the hardware address of a vf for the link.
|
||||
// Equivalent to: `ip link set $link vf $vf mac $hwaddr`
|
||||
func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Index = int32(base.Index)
|
||||
req.AddData(msg)
|
||||
|
||||
data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
|
||||
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
|
||||
vfmsg := nl.VfMac{
|
||||
Vf: uint32(vf),
|
||||
}
|
||||
copy(vfmsg.Mac[:], []byte(hwaddr))
|
||||
nl.NewRtAttrChild(info, nl.IFLA_VF_MAC, vfmsg.Serialize())
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetVfVlan sets the vlan of a vf for the link.
|
||||
// Equivalent to: `ip link set $link vf $vf vlan $vlan`
|
||||
func LinkSetVfVlan(link Link, vf, vlan int) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Index = int32(base.Index)
|
||||
req.AddData(msg)
|
||||
|
||||
data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
|
||||
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
|
||||
vfmsg := nl.VfVlan{
|
||||
Vf: uint32(vf),
|
||||
Vlan: uint32(vlan),
|
||||
}
|
||||
nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize())
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetMaster sets the master of the link device.
|
||||
// Equivalent to: `ip link set $link master $master`
|
||||
func LinkSetMaster(link Link, master *Bridge) error {
|
||||
@@ -277,10 +325,12 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
|
||||
|
||||
if vxlan.UDPCSum {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum))
|
||||
}
|
||||
if vxlan.GBP {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GBP, boolAttr(vxlan.GBP))
|
||||
}
|
||||
|
||||
if vxlan.NoAge {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
|
||||
} else if vxlan.Age > 0 {
|
||||
@@ -815,6 +865,7 @@ func LinkList() ([]Link, error) {
|
||||
// LinkUpdate is used to pass information back from LinkSubscribe()
|
||||
type LinkUpdate struct {
|
||||
nl.IfInfomsg
|
||||
Header syscall.NlMsghdr
|
||||
Link
|
||||
}
|
||||
|
||||
@@ -844,7 +895,7 @@ func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ch <- LinkUpdate{IfInfomsg: *ifmsg, Link: link}
|
||||
ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: m.Header, Link: link}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -935,6 +986,8 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
vxlan.L2miss = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_L3MISS:
|
||||
vxlan.L3miss = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_UDP_CSUM:
|
||||
vxlan.UDPCSum = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_GBP:
|
||||
vxlan.GBP = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_AGEING:
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
// Family type definitions
|
||||
const (
|
||||
// Family type definitions
|
||||
FAMILY_ALL = nl.FAMILY_ALL
|
||||
FAMILY_V4 = nl.FAMILY_V4
|
||||
FAMILY_V6 = nl.FAMILY_V6
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package nl
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
DEFAULT_CHANGE = 0xFFFFFFFF
|
||||
// doesn't exist in syscall
|
||||
IFLA_VFINFO_LIST = 0x16
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -182,3 +188,209 @@ const (
|
||||
GRE_FLAGS = 0x00F8
|
||||
GRE_VERSION = 0x0007
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VF_INFO_UNSPEC = iota
|
||||
IFLA_VF_INFO
|
||||
IFLA_VF_INFO_MAX = IFLA_VF_INFO
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VF_UNSPEC = iota
|
||||
IFLA_VF_MAC /* Hardware queue specific attributes */
|
||||
IFLA_VF_VLAN
|
||||
IFLA_VF_TX_RATE /* Max TX Bandwidth Allocation */
|
||||
IFLA_VF_SPOOFCHK /* Spoof Checking on/off switch */
|
||||
IFLA_VF_LINK_STATE /* link state enable/disable/auto switch */
|
||||
IFLA_VF_RATE /* Min and Max TX Bandwidth Allocation */
|
||||
IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query
|
||||
* on/off switch
|
||||
*/
|
||||
IFLA_VF_STATS /* network device statistics */
|
||||
IFLA_VF_MAX = IFLA_VF_STATS
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VF_LINK_STATE_AUTO = iota /* link state of the uplink */
|
||||
IFLA_VF_LINK_STATE_ENABLE /* link always up */
|
||||
IFLA_VF_LINK_STATE_DISABLE /* link always down */
|
||||
IFLA_VF_LINK_STATE_MAX = IFLA_VF_LINK_STATE_DISABLE
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VF_STATS_RX_PACKETS = iota
|
||||
IFLA_VF_STATS_TX_PACKETS
|
||||
IFLA_VF_STATS_RX_BYTES
|
||||
IFLA_VF_STATS_TX_BYTES
|
||||
IFLA_VF_STATS_BROADCAST
|
||||
IFLA_VF_STATS_MULTICAST
|
||||
IFLA_VF_STATS_MAX = IFLA_VF_STATS_MULTICAST
|
||||
)
|
||||
|
||||
const (
|
||||
SizeofVfMac = 0x24
|
||||
SizeofVfVlan = 0x0c
|
||||
SizeofVfTxRate = 0x08
|
||||
SizeofVfRate = 0x0c
|
||||
SizeofVfSpoofchk = 0x08
|
||||
SizeofVfLinkState = 0x08
|
||||
SizeofVfRssQueryEn = 0x08
|
||||
)
|
||||
|
||||
// struct ifla_vf_mac {
|
||||
// __u32 vf;
|
||||
// __u8 mac[32]; /* MAX_ADDR_LEN */
|
||||
// };
|
||||
|
||||
type VfMac struct {
|
||||
Vf uint32
|
||||
Mac [32]byte
|
||||
}
|
||||
|
||||
func (msg *VfMac) Len() int {
|
||||
return SizeofVfMac
|
||||
}
|
||||
|
||||
func DeserializeVfMac(b []byte) *VfMac {
|
||||
return (*VfMac)(unsafe.Pointer(&b[0:SizeofVfMac][0]))
|
||||
}
|
||||
|
||||
func (msg *VfMac) Serialize() []byte {
|
||||
return (*(*[SizeofVfMac]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct ifla_vf_vlan {
|
||||
// __u32 vf;
|
||||
// __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
|
||||
// __u32 qos;
|
||||
// };
|
||||
|
||||
type VfVlan struct {
|
||||
Vf uint32
|
||||
Vlan uint32
|
||||
Qos uint32
|
||||
}
|
||||
|
||||
func (msg *VfVlan) Len() int {
|
||||
return SizeofVfVlan
|
||||
}
|
||||
|
||||
func DeserializeVfVlan(b []byte) *VfVlan {
|
||||
return (*VfVlan)(unsafe.Pointer(&b[0:SizeofVfVlan][0]))
|
||||
}
|
||||
|
||||
func (msg *VfVlan) Serialize() []byte {
|
||||
return (*(*[SizeofVfVlan]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct ifla_vf_tx_rate {
|
||||
// __u32 vf;
|
||||
// __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
|
||||
// };
|
||||
|
||||
type VfTxRate struct {
|
||||
Vf uint32
|
||||
Rate uint32
|
||||
}
|
||||
|
||||
func (msg *VfTxRate) Len() int {
|
||||
return SizeofVfTxRate
|
||||
}
|
||||
|
||||
func DeserializeVfTxRate(b []byte) *VfTxRate {
|
||||
return (*VfTxRate)(unsafe.Pointer(&b[0:SizeofVfTxRate][0]))
|
||||
}
|
||||
|
||||
func (msg *VfTxRate) Serialize() []byte {
|
||||
return (*(*[SizeofVfTxRate]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct ifla_vf_rate {
|
||||
// __u32 vf;
|
||||
// __u32 min_tx_rate; /* Min Bandwidth in Mbps */
|
||||
// __u32 max_tx_rate; /* Max Bandwidth in Mbps */
|
||||
// };
|
||||
|
||||
type VfRate struct {
|
||||
Vf uint32
|
||||
MinTxRate uint32
|
||||
MaxTxRate uint32
|
||||
}
|
||||
|
||||
func (msg *VfRate) Len() int {
|
||||
return SizeofVfRate
|
||||
}
|
||||
|
||||
func DeserializeVfRate(b []byte) *VfRate {
|
||||
return (*VfRate)(unsafe.Pointer(&b[0:SizeofVfRate][0]))
|
||||
}
|
||||
|
||||
func (msg *VfRate) Serialize() []byte {
|
||||
return (*(*[SizeofVfRate]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct ifla_vf_spoofchk {
|
||||
// __u32 vf;
|
||||
// __u32 setting;
|
||||
// };
|
||||
|
||||
type VfSpoofchk struct {
|
||||
Vf uint32
|
||||
Setting uint32
|
||||
}
|
||||
|
||||
func (msg *VfSpoofchk) Len() int {
|
||||
return SizeofVfSpoofchk
|
||||
}
|
||||
|
||||
func DeserializeVfSpoofchk(b []byte) *VfSpoofchk {
|
||||
return (*VfSpoofchk)(unsafe.Pointer(&b[0:SizeofVfSpoofchk][0]))
|
||||
}
|
||||
|
||||
func (msg *VfSpoofchk) Serialize() []byte {
|
||||
return (*(*[SizeofVfSpoofchk]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct ifla_vf_link_state {
|
||||
// __u32 vf;
|
||||
// __u32 link_state;
|
||||
// };
|
||||
|
||||
type VfLinkState struct {
|
||||
Vf uint32
|
||||
LinkState uint32
|
||||
}
|
||||
|
||||
func (msg *VfLinkState) Len() int {
|
||||
return SizeofVfLinkState
|
||||
}
|
||||
|
||||
func DeserializeVfLinkState(b []byte) *VfLinkState {
|
||||
return (*VfLinkState)(unsafe.Pointer(&b[0:SizeofVfLinkState][0]))
|
||||
}
|
||||
|
||||
func (msg *VfLinkState) Serialize() []byte {
|
||||
return (*(*[SizeofVfLinkState]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct ifla_vf_rss_query_en {
|
||||
// __u32 vf;
|
||||
// __u32 setting;
|
||||
// };
|
||||
|
||||
type VfRssQueryEn struct {
|
||||
Vf uint32
|
||||
Setting uint32
|
||||
}
|
||||
|
||||
func (msg *VfRssQueryEn) Len() int {
|
||||
return SizeofVfRssQueryEn
|
||||
}
|
||||
|
||||
func DeserializeVfRssQueryEn(b []byte) *VfRssQueryEn {
|
||||
return (*VfRssQueryEn)(unsafe.Pointer(&b[0:SizeofVfRssQueryEn][0]))
|
||||
}
|
||||
|
||||
func (msg *VfRssQueryEn) Serialize() []byte {
|
||||
return (*(*[SizeofVfRssQueryEn]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
@@ -49,6 +49,15 @@ const (
|
||||
TCAA_MAX = 1
|
||||
)
|
||||
|
||||
const (
|
||||
TCA_ACT_UNSPEC = iota
|
||||
TCA_ACT_KIND
|
||||
TCA_ACT_OPTIONS
|
||||
TCA_ACT_INDEX
|
||||
TCA_ACT_STATS
|
||||
TCA_ACT_MAX
|
||||
)
|
||||
|
||||
const (
|
||||
TCA_PRIO_UNSPEC = iota
|
||||
TCA_PRIO_MQ
|
||||
@@ -69,6 +78,7 @@ const (
|
||||
SizeofTcHtbGlob = 0x14
|
||||
SizeofTcU32Key = 0x10
|
||||
SizeofTcU32Sel = 0x10 // without keys
|
||||
SizeofTcActBpf = 0x14
|
||||
SizeofTcMirred = 0x1c
|
||||
SizeofTcPolice = 2*SizeofTcRateSpec + 0x20
|
||||
)
|
||||
@@ -533,9 +543,34 @@ const (
|
||||
TC_ACT_STOLEN = 4
|
||||
TC_ACT_QUEUED = 5
|
||||
TC_ACT_REPEAT = 6
|
||||
TC_ACT_REDIRECT = 7
|
||||
TC_ACT_JUMP = 0x10000000
|
||||
)
|
||||
|
||||
type TcGen struct {
|
||||
Index uint32
|
||||
Capab uint32
|
||||
Action int32
|
||||
Refcnt int32
|
||||
Bindcnt int32
|
||||
}
|
||||
|
||||
type TcActBpf struct {
|
||||
TcGen
|
||||
}
|
||||
|
||||
func (msg *TcActBpf) Len() int {
|
||||
return SizeofTcActBpf
|
||||
}
|
||||
|
||||
func DeserializeTcActBpf(b []byte) *TcActBpf {
|
||||
return (*TcActBpf)(unsafe.Pointer(&b[0:SizeofTcActBpf][0]))
|
||||
}
|
||||
|
||||
func (x *TcActBpf) Serialize() []byte {
|
||||
return (*(*[SizeofTcActBpf]byte)(unsafe.Pointer(x)))[:]
|
||||
}
|
||||
|
||||
// #define tc_gen \
|
||||
// __u32 index; \
|
||||
// __u32 capab; \
|
||||
@@ -549,11 +584,7 @@ const (
|
||||
// };
|
||||
|
||||
type TcMirred struct {
|
||||
Index uint32
|
||||
Capab uint32
|
||||
Action int32
|
||||
Refcnt int32
|
||||
Bindcnt int32
|
||||
TcGen
|
||||
Eaction int32
|
||||
Ifindex uint32
|
||||
}
|
||||
@@ -625,3 +656,31 @@ const (
|
||||
TCA_FW_MASK
|
||||
TCA_FW_MAX = TCA_FW_MASK
|
||||
)
|
||||
|
||||
const (
|
||||
TCA_BPF_FLAG_ACT_DIRECT uint32 = 1 << iota
|
||||
)
|
||||
|
||||
const (
|
||||
TCA_BPF_UNSPEC = iota
|
||||
TCA_BPF_ACT
|
||||
TCA_BPF_POLICE
|
||||
TCA_BPF_CLASSID
|
||||
TCA_BPF_OPS_LEN
|
||||
TCA_BPF_OPS
|
||||
TCA_BPF_FD
|
||||
TCA_BPF_NAME
|
||||
TCA_BPF_FLAGS
|
||||
TCA_BPF_MAX = TCA_BPF_FLAGS
|
||||
)
|
||||
|
||||
const (
|
||||
TCA_ACT_BPF_UNSPEC = iota
|
||||
TCA_ACT_BPF_TM
|
||||
TCA_ACT_BPF_PARMS
|
||||
TCA_ACT_BPF_OPS_LEN
|
||||
TCA_ACT_BPF_OPS
|
||||
TCA_ACT_BPF_FD
|
||||
TCA_ACT_BPF_NAME
|
||||
TCA_ACT_BPF_MAX = TCA_ACT_BPF_NAME
|
||||
)
|
||||
|
||||
@@ -8,16 +8,21 @@ import (
|
||||
const (
|
||||
HANDLE_NONE = 0
|
||||
HANDLE_INGRESS = 0xFFFFFFF1
|
||||
HANDLE_CLSACT = HANDLE_INGRESS
|
||||
HANDLE_ROOT = 0xFFFFFFFF
|
||||
PRIORITY_MAP_LEN = 16
|
||||
)
|
||||
const (
|
||||
HANDLE_MIN_INGRESS = 0xFFFFFFF2
|
||||
HANDLE_MIN_EGRESS = 0xFFFFFFF3
|
||||
)
|
||||
|
||||
type Qdisc interface {
|
||||
Attrs() *QdiscAttrs
|
||||
Type() string
|
||||
}
|
||||
|
||||
// Qdisc represents a netlink qdisc. A qdisc is associated with a link,
|
||||
// QdiscAttrs represents a netlink qdisc. A qdisc is associated with a link,
|
||||
// has a handle, a parent and a refcnt. The root qdisc of a device should
|
||||
// have parent == HANDLE_ROOT.
|
||||
type QdiscAttrs struct {
|
||||
@@ -28,7 +33,7 @@ type QdiscAttrs struct {
|
||||
}
|
||||
|
||||
func (q QdiscAttrs) String() string {
|
||||
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
|
||||
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
|
||||
}
|
||||
|
||||
func MakeHandle(major, minor uint16) uint32 {
|
||||
@@ -149,7 +154,7 @@ type NetemQdiscAttrs struct {
|
||||
|
||||
func (q NetemQdiscAttrs) String() string {
|
||||
return fmt.Sprintf(
|
||||
"{Latency: %d, Limit: %d, Loss: %d, Gap: %d, Duplicate: %d, Jitter: %d}",
|
||||
"{Latency: %d, Limit: %d, Loss: %f, Gap: %d, Duplicate: %f, Jitter: %d}",
|
||||
q.Latency, q.Limit, q.Loss, q.Gap, q.Duplicate, q.Jitter,
|
||||
)
|
||||
}
|
||||
@@ -173,9 +178,9 @@ type Netem struct {
|
||||
|
||||
func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
|
||||
var limit uint32 = 1000
|
||||
var loss_corr, delay_corr, duplicate_corr uint32
|
||||
var reorder_prob, reorder_corr uint32
|
||||
var corrupt_prob, corrupt_corr uint32
|
||||
var lossCorr, delayCorr, duplicateCorr uint32
|
||||
var reorderProb, reorderCorr uint32
|
||||
var corruptProb, corruptCorr uint32
|
||||
|
||||
latency := nattrs.Latency
|
||||
loss := Percentage2u32(nattrs.Loss)
|
||||
@@ -185,13 +190,13 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
|
||||
|
||||
// Correlation
|
||||
if latency > 0 && jitter > 0 {
|
||||
delay_corr = Percentage2u32(nattrs.DelayCorr)
|
||||
delayCorr = Percentage2u32(nattrs.DelayCorr)
|
||||
}
|
||||
if loss > 0 {
|
||||
loss_corr = Percentage2u32(nattrs.LossCorr)
|
||||
lossCorr = Percentage2u32(nattrs.LossCorr)
|
||||
}
|
||||
if duplicate > 0 {
|
||||
duplicate_corr = Percentage2u32(nattrs.DuplicateCorr)
|
||||
duplicateCorr = Percentage2u32(nattrs.DuplicateCorr)
|
||||
}
|
||||
// FIXME should validate values(like loss/duplicate are percentages...)
|
||||
latency = time2Tick(latency)
|
||||
@@ -204,34 +209,34 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
|
||||
jitter = time2Tick(jitter)
|
||||
}
|
||||
|
||||
reorder_prob = Percentage2u32(nattrs.ReorderProb)
|
||||
reorder_corr = Percentage2u32(nattrs.ReorderCorr)
|
||||
reorderProb = Percentage2u32(nattrs.ReorderProb)
|
||||
reorderCorr = Percentage2u32(nattrs.ReorderCorr)
|
||||
|
||||
if reorder_prob > 0 {
|
||||
if reorderProb > 0 {
|
||||
// ERROR if lantency == 0
|
||||
if gap == 0 {
|
||||
gap = 1
|
||||
}
|
||||
}
|
||||
|
||||
corrupt_prob = Percentage2u32(nattrs.CorruptProb)
|
||||
corrupt_corr = Percentage2u32(nattrs.CorruptCorr)
|
||||
corruptProb = Percentage2u32(nattrs.CorruptProb)
|
||||
corruptCorr = Percentage2u32(nattrs.CorruptCorr)
|
||||
|
||||
return &Netem{
|
||||
QdiscAttrs: attrs,
|
||||
Latency: latency,
|
||||
DelayCorr: delay_corr,
|
||||
DelayCorr: delayCorr,
|
||||
Limit: limit,
|
||||
Loss: loss,
|
||||
LossCorr: loss_corr,
|
||||
LossCorr: lossCorr,
|
||||
Gap: gap,
|
||||
Duplicate: duplicate,
|
||||
DuplicateCorr: duplicate_corr,
|
||||
DuplicateCorr: duplicateCorr,
|
||||
Jitter: jitter,
|
||||
ReorderProb: reorder_prob,
|
||||
ReorderCorr: reorder_corr,
|
||||
CorruptProb: corrupt_prob,
|
||||
CorruptCorr: corrupt_corr,
|
||||
ReorderProb: reorderProb,
|
||||
ReorderCorr: reorderCorr,
|
||||
CorruptProb: corruptProb,
|
||||
CorruptCorr: corruptCorr,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -334,9 +334,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
tickInUsec float64 = 0.0
|
||||
clockFactor float64 = 0.0
|
||||
hz float64 = 0.0
|
||||
tickInUsec float64
|
||||
clockFactor float64
|
||||
hz float64
|
||||
)
|
||||
|
||||
func initClock() {
|
||||
|
||||
@@ -59,8 +59,8 @@ type flagString struct {
|
||||
}
|
||||
|
||||
var testFlags = []flagString{
|
||||
flagString{f: FLAG_ONLINK, s: "onlink"},
|
||||
flagString{f: FLAG_PERVASIVE, s: "pervasive"},
|
||||
{f: FLAG_ONLINK, s: "onlink"},
|
||||
{f: FLAG_PERVASIVE, s: "pervasive"},
|
||||
}
|
||||
|
||||
func (r *Route) ListFlags() []string {
|
||||
|
||||
@@ -116,6 +116,7 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
|
||||
msg.Type = uint8(route.Type)
|
||||
}
|
||||
|
||||
msg.Flags = uint32(route.Flags)
|
||||
msg.Scope = uint8(route.Scope)
|
||||
msg.Family = uint8(family)
|
||||
req.AddData(msg)
|
||||
|
||||
@@ -29,7 +29,7 @@ func (e EncapType) String() string {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// XfrmEncap represents the encapsulation to use for the ipsec encryption.
|
||||
// XfrmStateEncap represents the encapsulation to use for the ipsec encryption.
|
||||
type XfrmStateEncap struct {
|
||||
Type EncapType
|
||||
SrcPort int
|
||||
|
||||
@@ -110,9 +110,6 @@ func XfrmStateDel(state *XfrmState) error {
|
||||
func XfrmStateList(family int) ([]XfrmState, error) {
|
||||
req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
|
||||
|
||||
msg := nl.NewIfInfomsg(family)
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user