add vendor

This commit is contained in:
Kevin Schoon 2018-01-21 18:41:29 +08:00
parent 70291554e1
commit 499d829860
450 changed files with 397592 additions and 0 deletions

51
Gopkg.lock generated Normal file
View File

@ -0,0 +1,51 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/fatih/color"
packages = ["."]
revision = "570b54cabe6b8eb0bc2dfce68d964677d63b5260"
version = "v1.5.0"
[[projects]]
branch = "master"
name = "github.com/gosuri/uilive"
packages = ["."]
revision = "ac356e6e42cd31fcef8e6aec13ae9ed6fe87713e"
[[projects]]
name = "github.com/jawher/mow.cli"
packages = ["."]
revision = "0e80ee9f63156ea1954dc2375c33a1c7e752c25c"
version = "v1.0.3"
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
name = "github.com/mattn/go-sqlite3"
packages = ["."]
revision = "6c771bb9887719704b210e87e934f08be014bdb1"
version = "v1.6.0"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "2c42eef0765b9837fbdab12011af7830f55f88f0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "1a1f721ab61fd1976d54ba03bad816beaefd926604a77b24c318305d4082f779"
solver-name = "gps-cdcl"
solver-version = 1

37
Gopkg.toml Normal file
View File

@ -0,0 +1,37 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/fatih/color"
version = "1.5.0"
[[constraint]]
branch = "master"
name = "github.com/gosuri/uilive"
[[constraint]]
name = "github.com/jawher/mow.cli"
version = "1.0.3"
[[constraint]]
name = "github.com/mattn/go-sqlite3"
version = "1.6.0"

5
vendor/github.com/fatih/color/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,5 @@
language: go
go:
- 1.6
- tip

20
vendor/github.com/fatih/color/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Fatih Arslan
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

177
vendor/github.com/fatih/color/README.md generated vendored Normal file
View File

@ -0,0 +1,177 @@
# Color [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/color) [![Build Status](http://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color)
Color lets you use colorized outputs in terms of [ANSI Escape
Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
has support for Windows too! The API can be used in several ways, pick one that
suits you.
![Color](http://i.imgur.com/c1JI0lA.png)
## Install
```bash
go get github.com/fatih/color
```
Note that the `vendor` folder is here for stability. Remove the folder if you
already have the dependencies in your GOPATH.
## Examples
### Standard colors
```go
// Print with default helper functions
color.Cyan("Prints text in cyan.")
// A newline will be appended automatically
color.Blue("Prints %s in blue.", "text")
// These are using the default foreground colors
color.Red("We have red")
color.Magenta("And many others ..")
```
### Mix and reuse colors
```go
// Create a new color object
c := color.New(color.FgCyan).Add(color.Underline)
c.Println("Prints cyan text with an underline.")
// Or just add them to New()
d := color.New(color.FgCyan, color.Bold)
d.Printf("This prints bold cyan %s\n", "too!.")
// Mix up foreground and background colors, create new mixes!
red := color.New(color.FgRed)
boldRed := red.Add(color.Bold)
boldRed.Println("This will print text in bold red.")
whiteBackground := red.Add(color.BgWhite)
whiteBackground.Println("Red text with white background.")
```
### Use your own output (io.Writer)
```go
// Use your own io.Writer output
color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
blue := color.New(color.FgBlue)
blue.Fprint(writer, "This will print text in blue.")
```
### Custom print functions (PrintFunc)
```go
// Create a custom print function for convenience
red := color.New(color.FgRed).PrintfFunc()
red("Warning")
red("Error: %s", err)
// Mix up multiple attributes
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
notice("Don't forget this...")
```
### Custom fprint functions (FprintFunc)
```go
blue := color.New(FgBlue).FprintfFunc()
blue(myWriter, "important notice: %s", stars)
// Mix up with multiple attributes
success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
success(myWriter, "Don't forget this...")
```
### Insert into noncolor strings (SprintFunc)
```go
// Create SprintXxx functions to mix strings with other non-colorized strings:
yellow := color.New(color.FgYellow).SprintFunc()
red := color.New(color.FgRed).SprintFunc()
fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
fmt.Printf("This %s rocks!\n", info("package"))
// Use helper functions
fmt.Println("This", color.RedString("warning"), "should be not neglected.")
fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.")
// Windows supported too! Just don't forget to change the output to color.Output
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
```
### Plug into existing code
```go
// Use handy standard colors
color.Set(color.FgYellow)
fmt.Println("Existing text will now be in yellow")
fmt.Printf("This one %s\n", "too")
color.Unset() // Don't forget to unset
// You can mix up parameters
color.Set(color.FgMagenta, color.Bold)
defer color.Unset() // Use it in your function
fmt.Println("All text will now be bold magenta.")
```
### Disable color
There might be a case where you want to disable color output (for example to
pipe the standard output of your app to somewhere else). `Color` has support to
disable colors both globally and for single color definition. For example
suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
the color output with:
```go
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
if *flagNoColor {
color.NoColor = true // disables colorized output
}
```
It also has support for single color definitions (local). You can
disable/enable color output on the fly:
```go
c := color.New(color.FgCyan)
c.Println("Prints cyan text")
c.DisableColor()
c.Println("This is printed without any color")
c.EnableColor()
c.Println("This prints again cyan...")
```
## Todo
* Save/Return previous values
* Evaluate fmt.Formatter interface
## Credits
* [Fatih Arslan](https://github.com/fatih)
* Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
## License
The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details

600
vendor/github.com/fatih/color/color.go generated vendored Normal file
View File

@ -0,0 +1,600 @@
package color
import (
"fmt"
"io"
"os"
"strconv"
"strings"
"sync"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
)
var (
// NoColor defines if the output is colorized or not. It's dynamically set to
// false or true based on the stdout's file descriptor referring to a terminal
// or not. This is a global option and affects all colors. For more control
// over each color block use the methods DisableColor() individually.
NoColor = os.Getenv("TERM") == "dumb" ||
(!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))
// Output defines the standard output of the print functions. By default
// os.Stdout is used.
Output = colorable.NewColorableStdout()
// colorsCache is used to reduce the count of created Color objects and
// allows to reuse already created objects with required Attribute.
colorsCache = make(map[Attribute]*Color)
colorsCacheMu sync.Mutex // protects colorsCache
)
// Color defines a custom color object which is defined by SGR parameters.
type Color struct {
params []Attribute
noColor *bool
}
// Attribute defines a single SGR Code
type Attribute int
const escape = "\x1b"
// Base attributes
const (
Reset Attribute = iota
Bold
Faint
Italic
Underline
BlinkSlow
BlinkRapid
ReverseVideo
Concealed
CrossedOut
)
// Foreground text colors
const (
FgBlack Attribute = iota + 30
FgRed
FgGreen
FgYellow
FgBlue
FgMagenta
FgCyan
FgWhite
)
// Foreground Hi-Intensity text colors
const (
FgHiBlack Attribute = iota + 90
FgHiRed
FgHiGreen
FgHiYellow
FgHiBlue
FgHiMagenta
FgHiCyan
FgHiWhite
)
// Background text colors
const (
BgBlack Attribute = iota + 40
BgRed
BgGreen
BgYellow
BgBlue
BgMagenta
BgCyan
BgWhite
)
// Background Hi-Intensity text colors
const (
BgHiBlack Attribute = iota + 100
BgHiRed
BgHiGreen
BgHiYellow
BgHiBlue
BgHiMagenta
BgHiCyan
BgHiWhite
)
// New returns a newly created color object.
func New(value ...Attribute) *Color {
c := &Color{params: make([]Attribute, 0)}
c.Add(value...)
return c
}
// Set sets the given parameters immediately. It will change the color of
// output with the given SGR parameters until color.Unset() is called.
func Set(p ...Attribute) *Color {
c := New(p...)
c.Set()
return c
}
// Unset resets all escape attributes and clears the output. Usually should
// be called after Set().
func Unset() {
if NoColor {
return
}
fmt.Fprintf(Output, "%s[%dm", escape, Reset)
}
// Set sets the SGR sequence.
func (c *Color) Set() *Color {
if c.isNoColorSet() {
return c
}
fmt.Fprintf(Output, c.format())
return c
}
func (c *Color) unset() {
if c.isNoColorSet() {
return
}
Unset()
}
func (c *Color) setWriter(w io.Writer) *Color {
if c.isNoColorSet() {
return c
}
fmt.Fprintf(w, c.format())
return c
}
func (c *Color) unsetWriter(w io.Writer) {
if c.isNoColorSet() {
return
}
if NoColor {
return
}
fmt.Fprintf(w, "%s[%dm", escape, Reset)
}
// Add is used to chain SGR parameters. Use as many as parameters to combine
// and create custom color objects. Example: Add(color.FgRed, color.Underline).
func (c *Color) Add(value ...Attribute) *Color {
c.params = append(c.params, value...)
return c
}
func (c *Color) prepend(value Attribute) {
c.params = append(c.params, 0)
copy(c.params[1:], c.params[0:])
c.params[0] = value
}
// Fprint formats using the default formats for its operands and writes to w.
// Spaces are added between operands when neither is a string.
// It returns the number of bytes written and any write error encountered.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprint(w, a...)
}
// Print formats using the default formats for its operands and writes to
// standard output. Spaces are added between operands when neither is a
// string. It returns the number of bytes written and any write error
// encountered. This is the standard fmt.Print() method wrapped with the given
// color.
func (c *Color) Print(a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprint(Output, a...)
}
// Fprintf formats according to a format specifier and writes to w.
// It returns the number of bytes written and any write error encountered.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprintf(w, format, a...)
}
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
// This is the standard fmt.Printf() method wrapped with the given color.
func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprintf(Output, format, a...)
}
// Fprintln formats using the default formats for its operands and writes to w.
// Spaces are always added between operands and a newline is appended.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprintln(w, a...)
}
// Println formats using the default formats for its operands and writes to
// standard output. Spaces are always added between operands and a newline is
// appended. It returns the number of bytes written and any write error
// encountered. This is the standard fmt.Print() method wrapped with the given
// color.
func (c *Color) Println(a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprintln(Output, a...)
}
// Sprint is just like Print, but returns a string instead of printing it.
func (c *Color) Sprint(a ...interface{}) string {
return c.wrap(fmt.Sprint(a...))
}
// Sprintln is just like Println, but returns a string instead of printing it.
func (c *Color) Sprintln(a ...interface{}) string {
return c.wrap(fmt.Sprintln(a...))
}
// Sprintf is just like Printf, but returns a string instead of printing it.
func (c *Color) Sprintf(format string, a ...interface{}) string {
return c.wrap(fmt.Sprintf(format, a...))
}
// FprintFunc returns a new function that prints the passed arguments as
// colorized with color.Fprint().
func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
return func(w io.Writer, a ...interface{}) {
c.Fprint(w, a...)
}
}
// PrintFunc returns a new function that prints the passed arguments as
// colorized with color.Print().
func (c *Color) PrintFunc() func(a ...interface{}) {
return func(a ...interface{}) {
c.Print(a...)
}
}
// FprintfFunc returns a new function that prints the passed arguments as
// colorized with color.Fprintf().
func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) {
return func(w io.Writer, format string, a ...interface{}) {
c.Fprintf(w, format, a...)
}
}
// PrintfFunc returns a new function that prints the passed arguments as
// colorized with color.Printf().
func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
return func(format string, a ...interface{}) {
c.Printf(format, a...)
}
}
// FprintlnFunc returns a new function that prints the passed arguments as
// colorized with color.Fprintln().
func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) {
return func(w io.Writer, a ...interface{}) {
c.Fprintln(w, a...)
}
}
// PrintlnFunc returns a new function that prints the passed arguments as
// colorized with color.Println().
func (c *Color) PrintlnFunc() func(a ...interface{}) {
return func(a ...interface{}) {
c.Println(a...)
}
}
// SprintFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprint(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output, example:
//
// put := New(FgYellow).SprintFunc()
// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
func (c *Color) SprintFunc() func(a ...interface{}) string {
return func(a ...interface{}) string {
return c.wrap(fmt.Sprint(a...))
}
}
// SprintfFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprintf(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output.
func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
return func(format string, a ...interface{}) string {
return c.wrap(fmt.Sprintf(format, a...))
}
}
// SprintlnFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprintln(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output.
func (c *Color) SprintlnFunc() func(a ...interface{}) string {
return func(a ...interface{}) string {
return c.wrap(fmt.Sprintln(a...))
}
}
// sequence returns a formated SGR sequence to be plugged into a "\x1b[...m"
// an example output might be: "1;36" -> bold cyan
func (c *Color) sequence() string {
format := make([]string, len(c.params))
for i, v := range c.params {
format[i] = strconv.Itoa(int(v))
}
return strings.Join(format, ";")
}
// wrap wraps the s string with the colors attributes. The string is ready to
// be printed.
func (c *Color) wrap(s string) string {
if c.isNoColorSet() {
return s
}
return c.format() + s + c.unformat()
}
func (c *Color) format() string {
return fmt.Sprintf("%s[%sm", escape, c.sequence())
}
func (c *Color) unformat() string {
return fmt.Sprintf("%s[%dm", escape, Reset)
}
// DisableColor disables the color output. Useful to not change any existing
// code and still being able to output. Can be used for flags like
// "--no-color". To enable back use EnableColor() method.
func (c *Color) DisableColor() {
c.noColor = boolPtr(true)
}
// EnableColor enables the color output. Use it in conjunction with
// DisableColor(). Otherwise this method has no side effects.
func (c *Color) EnableColor() {
c.noColor = boolPtr(false)
}
func (c *Color) isNoColorSet() bool {
// check first if we have user setted action
if c.noColor != nil {
return *c.noColor
}
// if not return the global option, which is disabled by default
return NoColor
}
// Equals returns a boolean value indicating whether two colors are equal.
func (c *Color) Equals(c2 *Color) bool {
if len(c.params) != len(c2.params) {
return false
}
for _, attr := range c.params {
if !c2.attrExists(attr) {
return false
}
}
return true
}
func (c *Color) attrExists(a Attribute) bool {
for _, attr := range c.params {
if attr == a {
return true
}
}
return false
}
func boolPtr(v bool) *bool {
return &v
}
func getCachedColor(p Attribute) *Color {
colorsCacheMu.Lock()
defer colorsCacheMu.Unlock()
c, ok := colorsCache[p]
if !ok {
c = New(p)
colorsCache[p] = c
}
return c
}
func colorPrint(format string, p Attribute, a ...interface{}) {
c := getCachedColor(p)
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
if len(a) == 0 {
c.Print(format)
} else {
c.Printf(format, a...)
}
}
func colorString(format string, p Attribute, a ...interface{}) string {
c := getCachedColor(p)
if len(a) == 0 {
return c.SprintFunc()(format)
}
return c.SprintfFunc()(format, a...)
}
// Black is a convenient helper function to print with black foreground. A
// newline is appended to format by default.
func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) }
// Red is a convenient helper function to print with red foreground. A
// newline is appended to format by default.
func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) }
// Green is a convenient helper function to print with green foreground. A
// newline is appended to format by default.
func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) }
// Yellow is a convenient helper function to print with yellow foreground.
// A newline is appended to format by default.
func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) }
// Blue is a convenient helper function to print with blue foreground. A
// newline is appended to format by default.
func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) }
// Magenta is a convenient helper function to print with magenta foreground.
// A newline is appended to format by default.
func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) }
// Cyan is a convenient helper function to print with cyan foreground. A
// newline is appended to format by default.
func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) }
// White is a convenient helper function to print with white foreground. A
// newline is appended to format by default.
func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) }
// BlackString is a convenient helper function to return a string with black
// foreground.
func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
// RedString is a convenient helper function to return a string with red
// foreground.
func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
// GreenString is a convenient helper function to return a string with green
// foreground.
func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
// YellowString is a convenient helper function to return a string with yellow
// foreground.
func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
// BlueString is a convenient helper function to return a string with blue
// foreground.
func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
// MagentaString is a convenient helper function to return a string with magenta
// foreground.
func MagentaString(format string, a ...interface{}) string {
return colorString(format, FgMagenta, a...)
}
// CyanString is a convenient helper function to return a string with cyan
// foreground.
func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
// WhiteString is a convenient helper function to return a string with white
// foreground.
func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }
// HiBlack is a convenient helper function to print with hi-intensity black foreground. A
// newline is appended to format by default.
func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) }
// HiRed is a convenient helper function to print with hi-intensity red foreground. A
// newline is appended to format by default.
func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) }
// HiGreen is a convenient helper function to print with hi-intensity green foreground. A
// newline is appended to format by default.
func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) }
// HiYellow is a convenient helper function to print with hi-intensity yellow foreground.
// A newline is appended to format by default.
func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) }
// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A
// newline is appended to format by default.
func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) }
// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground.
// A newline is appended to format by default.
func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) }
// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A
// newline is appended to format by default.
func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) }
// HiWhite is a convenient helper function to print with hi-intensity white foreground. A
// newline is appended to format by default.
func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) }
// HiBlackString is a convenient helper function to return a string with hi-intensity black
// foreground.
func HiBlackString(format string, a ...interface{}) string {
return colorString(format, FgHiBlack, a...)
}
// HiRedString is a convenient helper function to return a string with hi-intensity red
// foreground.
func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) }
// HiGreenString is a convenient helper function to return a string with hi-intensity green
// foreground.
func HiGreenString(format string, a ...interface{}) string {
return colorString(format, FgHiGreen, a...)
}
// HiYellowString is a convenient helper function to return a string with hi-intensity yellow
// foreground.
func HiYellowString(format string, a ...interface{}) string {
return colorString(format, FgHiYellow, a...)
}
// HiBlueString is a convenient helper function to return a string with hi-intensity blue
// foreground.
func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) }
// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta
// foreground.
func HiMagentaString(format string, a ...interface{}) string {
return colorString(format, FgHiMagenta, a...)
}
// HiCyanString is a convenient helper function to return a string with hi-intensity cyan
// foreground.
func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) }
// HiWhiteString is a convenient helper function to return a string with hi-intensity white
// foreground.
func HiWhiteString(format string, a ...interface{}) string {
return colorString(format, FgHiWhite, a...)
}

342
vendor/github.com/fatih/color/color_test.go generated vendored Normal file
View File

@ -0,0 +1,342 @@
package color
import (
"bytes"
"fmt"
"os"
"testing"
"github.com/mattn/go-colorable"
)
// Testing colors is kinda different. First we test for given colors and their
// escaped formatted results. Next we create some visual tests to be tested.
// Each visual test includes the color name to be compared.
func TestColor(t *testing.T) {
rb := new(bytes.Buffer)
Output = rb
NoColor = false
testColors := []struct {
text string
code Attribute
}{
{text: "black", code: FgBlack},
{text: "red", code: FgRed},
{text: "green", code: FgGreen},
{text: "yellow", code: FgYellow},
{text: "blue", code: FgBlue},
{text: "magent", code: FgMagenta},
{text: "cyan", code: FgCyan},
{text: "white", code: FgWhite},
{text: "hblack", code: FgHiBlack},
{text: "hred", code: FgHiRed},
{text: "hgreen", code: FgHiGreen},
{text: "hyellow", code: FgHiYellow},
{text: "hblue", code: FgHiBlue},
{text: "hmagent", code: FgHiMagenta},
{text: "hcyan", code: FgHiCyan},
{text: "hwhite", code: FgHiWhite},
}
for _, c := range testColors {
New(c.code).Print(c.text)
line, _ := rb.ReadString('\n')
scannedLine := fmt.Sprintf("%q", line)
colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
escapedForm := fmt.Sprintf("%q", colored)
fmt.Printf("%s\t: %s\n", c.text, line)
if scannedLine != escapedForm {
t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
}
}
for _, c := range testColors {
line := New(c.code).Sprintf("%s", c.text)
scannedLine := fmt.Sprintf("%q", line)
colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
escapedForm := fmt.Sprintf("%q", colored)
fmt.Printf("%s\t: %s\n", c.text, line)
if scannedLine != escapedForm {
t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
}
}
}
func TestColorEquals(t *testing.T) {
fgblack1 := New(FgBlack)
fgblack2 := New(FgBlack)
bgblack := New(BgBlack)
fgbgblack := New(FgBlack, BgBlack)
fgblackbgred := New(FgBlack, BgRed)
fgred := New(FgRed)
bgred := New(BgRed)
if !fgblack1.Equals(fgblack2) {
t.Error("Two black colors are not equal")
}
if fgblack1.Equals(bgblack) {
t.Error("Fg and bg black colors are equal")
}
if fgblack1.Equals(fgbgblack) {
t.Error("Fg black equals fg/bg black color")
}
if fgblack1.Equals(fgred) {
t.Error("Fg black equals Fg red")
}
if fgblack1.Equals(bgred) {
t.Error("Fg black equals Bg red")
}
if fgblack1.Equals(fgblackbgred) {
t.Error("Fg black equals fg black bg red")
}
}
func TestNoColor(t *testing.T) {
rb := new(bytes.Buffer)
Output = rb
testColors := []struct {
text string
code Attribute
}{
{text: "black", code: FgBlack},
{text: "red", code: FgRed},
{text: "green", code: FgGreen},
{text: "yellow", code: FgYellow},
{text: "blue", code: FgBlue},
{text: "magent", code: FgMagenta},
{text: "cyan", code: FgCyan},
{text: "white", code: FgWhite},
{text: "hblack", code: FgHiBlack},
{text: "hred", code: FgHiRed},
{text: "hgreen", code: FgHiGreen},
{text: "hyellow", code: FgHiYellow},
{text: "hblue", code: FgHiBlue},
{text: "hmagent", code: FgHiMagenta},
{text: "hcyan", code: FgHiCyan},
{text: "hwhite", code: FgHiWhite},
}
for _, c := range testColors {
p := New(c.code)
p.DisableColor()
p.Print(c.text)
line, _ := rb.ReadString('\n')
if line != c.text {
t.Errorf("Expecting %s, got '%s'\n", c.text, line)
}
}
// global check
NoColor = true
defer func() {
NoColor = false
}()
for _, c := range testColors {
p := New(c.code)
p.Print(c.text)
line, _ := rb.ReadString('\n')
if line != c.text {
t.Errorf("Expecting %s, got '%s'\n", c.text, line)
}
}
}
func TestColorVisual(t *testing.T) {
// First Visual Test
Output = colorable.NewColorableStdout()
New(FgRed).Printf("red\t")
New(BgRed).Print(" ")
New(FgRed, Bold).Println(" red")
New(FgGreen).Printf("green\t")
New(BgGreen).Print(" ")
New(FgGreen, Bold).Println(" green")
New(FgYellow).Printf("yellow\t")
New(BgYellow).Print(" ")
New(FgYellow, Bold).Println(" yellow")
New(FgBlue).Printf("blue\t")
New(BgBlue).Print(" ")
New(FgBlue, Bold).Println(" blue")
New(FgMagenta).Printf("magenta\t")
New(BgMagenta).Print(" ")
New(FgMagenta, Bold).Println(" magenta")
New(FgCyan).Printf("cyan\t")
New(BgCyan).Print(" ")
New(FgCyan, Bold).Println(" cyan")
New(FgWhite).Printf("white\t")
New(BgWhite).Print(" ")
New(FgWhite, Bold).Println(" white")
fmt.Println("")
// Second Visual test
Black("black")
Red("red")
Green("green")
Yellow("yellow")
Blue("blue")
Magenta("magenta")
Cyan("cyan")
White("white")
HiBlack("hblack")
HiRed("hred")
HiGreen("hgreen")
HiYellow("hyellow")
HiBlue("hblue")
HiMagenta("hmagenta")
HiCyan("hcyan")
HiWhite("hwhite")
// Third visual test
fmt.Println()
Set(FgBlue)
fmt.Println("is this blue?")
Unset()
Set(FgMagenta)
fmt.Println("and this magenta?")
Unset()
// Fourth Visual test
fmt.Println()
blue := New(FgBlue).PrintlnFunc()
blue("blue text with custom print func")
red := New(FgRed).PrintfFunc()
red("red text with a printf func: %d\n", 123)
put := New(FgYellow).SprintFunc()
warn := New(FgRed).SprintFunc()
fmt.Fprintf(Output, "this is a %s and this is %s.\n", put("warning"), warn("error"))
info := New(FgWhite, BgGreen).SprintFunc()
fmt.Fprintf(Output, "this %s rocks!\n", info("package"))
notice := New(FgBlue).FprintFunc()
notice(os.Stderr, "just a blue notice to stderr")
// Fifth Visual Test
fmt.Println()
fmt.Fprintln(Output, BlackString("black"))
fmt.Fprintln(Output, RedString("red"))
fmt.Fprintln(Output, GreenString("green"))
fmt.Fprintln(Output, YellowString("yellow"))
fmt.Fprintln(Output, BlueString("blue"))
fmt.Fprintln(Output, MagentaString("magenta"))
fmt.Fprintln(Output, CyanString("cyan"))
fmt.Fprintln(Output, WhiteString("white"))
fmt.Fprintln(Output, HiBlackString("hblack"))
fmt.Fprintln(Output, HiRedString("hred"))
fmt.Fprintln(Output, HiGreenString("hgreen"))
fmt.Fprintln(Output, HiYellowString("hyellow"))
fmt.Fprintln(Output, HiBlueString("hblue"))
fmt.Fprintln(Output, HiMagentaString("hmagenta"))
fmt.Fprintln(Output, HiCyanString("hcyan"))
fmt.Fprintln(Output, HiWhiteString("hwhite"))
}
func TestNoFormat(t *testing.T) {
fmt.Printf("%s %%s = ", BlackString("Black"))
Black("%s")
fmt.Printf("%s %%s = ", RedString("Red"))
Red("%s")
fmt.Printf("%s %%s = ", GreenString("Green"))
Green("%s")
fmt.Printf("%s %%s = ", YellowString("Yellow"))
Yellow("%s")
fmt.Printf("%s %%s = ", BlueString("Blue"))
Blue("%s")
fmt.Printf("%s %%s = ", MagentaString("Magenta"))
Magenta("%s")
fmt.Printf("%s %%s = ", CyanString("Cyan"))
Cyan("%s")
fmt.Printf("%s %%s = ", WhiteString("White"))
White("%s")
fmt.Printf("%s %%s = ", HiBlackString("HiBlack"))
HiBlack("%s")
fmt.Printf("%s %%s = ", HiRedString("HiRed"))
HiRed("%s")
fmt.Printf("%s %%s = ", HiGreenString("HiGreen"))
HiGreen("%s")
fmt.Printf("%s %%s = ", HiYellowString("HiYellow"))
HiYellow("%s")
fmt.Printf("%s %%s = ", HiBlueString("HiBlue"))
HiBlue("%s")
fmt.Printf("%s %%s = ", HiMagentaString("HiMagenta"))
HiMagenta("%s")
fmt.Printf("%s %%s = ", HiCyanString("HiCyan"))
HiCyan("%s")
fmt.Printf("%s %%s = ", HiWhiteString("HiWhite"))
HiWhite("%s")
}
func TestNoFormatString(t *testing.T) {
tests := []struct {
f func(string, ...interface{}) string
format string
args []interface{}
want string
}{
{BlackString, "%s", nil, "\x1b[30m%s\x1b[0m"},
{RedString, "%s", nil, "\x1b[31m%s\x1b[0m"},
{GreenString, "%s", nil, "\x1b[32m%s\x1b[0m"},
{YellowString, "%s", nil, "\x1b[33m%s\x1b[0m"},
{BlueString, "%s", nil, "\x1b[34m%s\x1b[0m"},
{MagentaString, "%s", nil, "\x1b[35m%s\x1b[0m"},
{CyanString, "%s", nil, "\x1b[36m%s\x1b[0m"},
{WhiteString, "%s", nil, "\x1b[37m%s\x1b[0m"},
{HiBlackString, "%s", nil, "\x1b[90m%s\x1b[0m"},
{HiRedString, "%s", nil, "\x1b[91m%s\x1b[0m"},
{HiGreenString, "%s", nil, "\x1b[92m%s\x1b[0m"},
{HiYellowString, "%s", nil, "\x1b[93m%s\x1b[0m"},
{HiBlueString, "%s", nil, "\x1b[94m%s\x1b[0m"},
{HiMagentaString, "%s", nil, "\x1b[95m%s\x1b[0m"},
{HiCyanString, "%s", nil, "\x1b[96m%s\x1b[0m"},
{HiWhiteString, "%s", nil, "\x1b[97m%s\x1b[0m"},
}
for i, test := range tests {
s := fmt.Sprintf("%s", test.f(test.format, test.args...))
if s != test.want {
t.Errorf("[%d] want: %q, got: %q", i, test.want, s)
}
}
}

133
vendor/github.com/fatih/color/doc.go generated vendored Normal file
View File

@ -0,0 +1,133 @@
/*
Package color is an ANSI color package to output colorized or SGR defined
output to the standard output. The API can be used in several way, pick one
that suits you.
Use simple and default helper functions with predefined foreground colors:
color.Cyan("Prints text in cyan.")
// a newline will be appended automatically
color.Blue("Prints %s in blue.", "text")
// More default foreground colors..
color.Red("We have red")
color.Yellow("Yellow color too!")
color.Magenta("And many others ..")
// Hi-intensity colors
color.HiGreen("Bright green color.")
color.HiBlack("Bright black means gray..")
color.HiWhite("Shiny white color!")
However there are times where custom color mixes are required. Below are some
examples to create custom color objects and use the print functions of each
separate color object.
// Create a new color object
c := color.New(color.FgCyan).Add(color.Underline)
c.Println("Prints cyan text with an underline.")
// Or just add them to New()
d := color.New(color.FgCyan, color.Bold)
d.Printf("This prints bold cyan %s\n", "too!.")
// Mix up foreground and background colors, create new mixes!
red := color.New(color.FgRed)
boldRed := red.Add(color.Bold)
boldRed.Println("This will print text in bold red.")
whiteBackground := red.Add(color.BgWhite)
whiteBackground.Println("Red text with White background.")
// Use your own io.Writer output
color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
blue := color.New(color.FgBlue)
blue.Fprint(myWriter, "This will print text in blue.")
You can create PrintXxx functions to simplify even more:
// Create a custom print function for convenient
red := color.New(color.FgRed).PrintfFunc()
red("warning")
red("error: %s", err)
// Mix up multiple attributes
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
notice("don't forget this...")
You can also FprintXxx functions to pass your own io.Writer:
blue := color.New(FgBlue).FprintfFunc()
blue(myWriter, "important notice: %s", stars)
// Mix up with multiple attributes
success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
success(myWriter, don't forget this...")
Or create SprintXxx functions to mix strings with other non-colorized strings:
yellow := New(FgYellow).SprintFunc()
red := New(FgRed).SprintFunc()
fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error"))
info := New(FgWhite, BgGreen).SprintFunc()
fmt.Printf("this %s rocks!\n", info("package"))
Windows support is enabled by default. All Print functions work as intended.
However only for color.SprintXXX functions, user should use fmt.FprintXXX and
set the output to color.Output:
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
info := New(FgWhite, BgGreen).SprintFunc()
fmt.Fprintf(color.Output, "this %s rocks!\n", info("package"))
Using with existing code is possible. Just use the Set() method to set the
standard output to the given parameters. That way a rewrite of an existing
code is not required.
// Use handy standard colors.
color.Set(color.FgYellow)
fmt.Println("Existing text will be now in Yellow")
fmt.Printf("This one %s\n", "too")
color.Unset() // don't forget to unset
// You can mix up parameters
color.Set(color.FgMagenta, color.Bold)
defer color.Unset() // use it in your function
fmt.Println("All text will be now bold magenta.")
There might be a case where you want to disable color output (for example to
pipe the standard output of your app to somewhere else). `Color` has support to
disable colors both globally and for single color definition. For example
suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
the color output with:
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
if *flagNoColor {
color.NoColor = true // disables colorized output
}
It also has support for single color definitions (local). You can
disable/enable color output on the fly:
c := color.New(color.FgCyan)
c.Println("Prints cyan text")
c.DisableColor()
c.Println("This is printed without any color")
c.EnableColor()
c.Println("This prints again cyan...")
*/
package color

7
vendor/github.com/gosuri/uilive/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,7 @@
language: go
sudo: false
install:
- go get ./...
go:
- 1.4
- tip

10
vendor/github.com/gosuri/uilive/LICENSE generated vendored Normal file
View File

@ -0,0 +1,10 @@
MIT License
===========
Copyright (c) 2015, Greg Osuri
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

31
vendor/github.com/gosuri/uilive/README.md generated vendored Normal file
View File

@ -0,0 +1,31 @@
# uilive [![GoDoc](https://godoc.org/github.com/gosuri/uilive?status.svg)](https://godoc.org/github.com/gosuri/uilive) [![Build Status](https://travis-ci.org/gosuri/uilive.svg?branch=master)](https://travis-ci.org/gosuri/uilive)
uilive is a go library for updating terminal output in realtime. It provides a buffered [io.Writer](https://golang.org/pkg/io/#Writer) that is flushed at a timed interval. uilive powers [uiprogress](https://github.com/gosuri/uiprogress).
## Usage Example
Calling `uilive.New()` will create a new writer. To start rendering, simply call `writer.Start()` and update the ui by writing to the `writer`. Full source for the below example is in [example/main.go](example/main.go).
```go
writer := uilive.New()
// start listening for updates and render
writer.Start()
for i := 0; i <= 100; i++ {
fmt.Fprintf(writer, "Downloading.. (%d/%d) GB\n", i, 100)
time.Sleep(time.Millisecond * 5)
}
fmt.Fprintln(writer, "Finished: Downloaded 100GB")
writer.Stop() // flush and stop rendering
```
The above will render
![example](doc/example.gif)
## Installation
```sh
$ go get -v github.com/gosuri/uilive
```

2
vendor/github.com/gosuri/uilive/doc.go generated vendored Normal file
View File

@ -0,0 +1,2 @@
// Package uilive provides a writer that live updates the terminal. It provides a buffered io.Writer that is flushed at a timed interval.
package uilive

BIN
vendor/github.com/gosuri/uilive/doc/example.gif generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

26
vendor/github.com/gosuri/uilive/example/main.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
package main
import (
"fmt"
"time"
"github.com/gosuri/uilive"
)
func main() {
writer := uilive.New()
// start listening for updates and render
writer.Start()
for _, f := range []string{"Foo.zip", "Bar.iso"} {
for i := 0; i <= 50; i++ {
fmt.Fprintf(writer, "Downloading %s.. (%d/%d) GB\n", f, i, 50)
time.Sleep(time.Millisecond * 25)
}
fmt.Fprintf(writer.Bypass(), "Downloaded %s\n", f)
}
fmt.Fprintln(writer, "Finished: Downloaded 100GB")
writer.Stop() // flush and stop rendering
}

23
vendor/github.com/gosuri/uilive/example_test.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
package uilive_test
import (
"fmt"
"time"
"github.com/gosuri/uilive"
)
func Example() {
writer := uilive.New()
// start listening to updates and render
writer.Start()
for i := 0; i <= 100; i++ {
fmt.Fprintf(writer, "Downloading.. (%d/%d) GB\n", i, 100)
time.Sleep(time.Millisecond * 5)
}
fmt.Fprintln(writer, "Finished: Downloaded 100GB")
writer.Stop() // flush and stop rendering
}

138
vendor/github.com/gosuri/uilive/writer.go generated vendored Normal file
View File

@ -0,0 +1,138 @@
package uilive
import (
"bytes"
"errors"
"io"
"os"
"sync"
"time"
)
// ESC is the ASCII code for escape character
const ESC = 27
// RefreshInterval is the default refresh interval to update the ui
var RefreshInterval = time.Millisecond
// Out is the default output writer for the Writer
var Out = os.Stdout
// ErrClosedPipe is the error returned when trying to writer is not listening
var ErrClosedPipe = errors.New("uilive: read/write on closed pipe")
// FdWriter is a writer with a file descriptor.
type FdWriter interface {
io.Writer
Fd() uintptr
}
// Writer is a buffered the writer that updates the terminal. The contents of writer will be flushed on a timed interval or when Flush is called.
type Writer struct {
// Out is the writer to write to
Out io.Writer
// RefreshInterval is the time the UI sould refresh
RefreshInterval time.Duration
ticker *time.Ticker
tdone chan bool
buf bytes.Buffer
mtx *sync.Mutex
lineCount int
}
type bypass struct {
writer *Writer
}
// New returns a new Writer with defaults
func New() *Writer {
return &Writer{
Out: Out,
RefreshInterval: RefreshInterval,
mtx: &sync.Mutex{},
}
}
// Flush writes to the out and resets the buffer. It should be called after the last call to Write to ensure that any data buffered in the Writer is written to output.
// Any incomplete escape sequence at the end is considered complete for formatting purposes.
// An error is returned if the contents of the buffer cannot be written to the underlying output stream
func (w *Writer) Flush() error {
w.mtx.Lock()
defer w.mtx.Unlock()
// do nothing is buffer is empty
if len(w.buf.Bytes()) == 0 {
return nil
}
w.clearLines()
lines := 0
for _, b := range w.buf.Bytes() {
if b == '\n' {
lines++
}
}
w.lineCount = lines
_, err := w.Out.Write(w.buf.Bytes())
w.buf.Reset()
return err
}
// Start starts the listener in a non-blocking manner
func (w *Writer) Start() {
if w.ticker == nil {
w.ticker = time.NewTicker(w.RefreshInterval)
w.tdone = make(chan bool, 1)
}
go w.Listen()
}
// Stop stops the listener that updates the terminal
func (w *Writer) Stop() {
w.Flush()
close(w.tdone)
}
// Listen listens for updates to the writer's buffer and flushes to the out provided. It blocks the runtime.
func (w *Writer) Listen() {
for {
select {
case <-w.ticker.C:
if w.ticker != nil {
w.Flush()
}
case <-w.tdone:
w.mtx.Lock()
w.ticker.Stop()
w.ticker = nil
w.mtx.Unlock()
return
}
}
}
// Write save the contents of b to its buffers. The only errors returned are ones encountered while writing to the underlying buffer.
func (w *Writer) Write(b []byte) (n int, err error) {
w.mtx.Lock()
defer w.mtx.Unlock()
return w.buf.Write(b)
}
// Bypass creates an io.Writer which allows non-buffered output to be written to the underlying output
func (w *Writer) Bypass() io.Writer {
return &bypass{writer: w}
}
func (b *bypass) Write(p []byte) (n int, err error) {
b.writer.mtx.Lock()
defer b.writer.mtx.Unlock()
b.writer.clearLines()
b.writer.lineCount = 0
return b.writer.Out.Write(p)
}

14
vendor/github.com/gosuri/uilive/writer_posix.go generated vendored Normal file
View File

@ -0,0 +1,14 @@
// +build !windows
package uilive
import (
"fmt"
)
func (w *Writer) clearLines() {
for i := 0; i < w.lineCount; i++ {
fmt.Fprintf(w.Out, "%c[2K", ESC) // clear the line
fmt.Fprintf(w.Out, "%c[%dA", ESC, 1) // move the cursor up
}
}

24
vendor/github.com/gosuri/uilive/writer_test.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
package uilive
import (
"bytes"
"fmt"
"testing"
)
func TestWriter(t *testing.T) {
w := New()
b := &bytes.Buffer{}
w.Out = b
w.Start()
for i := 0; i < 2; i++ {
fmt.Fprintln(w, "foo")
}
w.Stop()
fmt.Fprintln(b, "bar")
want := "foo\nfoo\nbar\n"
if b.String() != want {
t.Fatalf("want %q, got %q", want, b.String())
}
}

74
vendor/github.com/gosuri/uilive/writer_windows.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
// +build windows
package uilive
import (
"fmt"
"github.com/mattn/go-isatty"
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
)
type short int16
type dword uint32
type word uint16
type coord struct {
x short
y short
}
type smallRect struct {
left short
top short
right short
bottom short
}
type consoleScreenBufferInfo struct {
size coord
cursorPosition coord
attributes word
window smallRect
maximumWindowSize coord
}
func (w *Writer) clearLines() {
f, ok := w.Out.(FdWriter)
if ok && !isatty.IsTerminal(f.Fd()) {
ok = false
}
if !ok {
for i := 0; i < w.lineCount; i++ {
fmt.Fprintf(w.Out, "%c[%dA", ESC, 0) // move the cursor up
fmt.Fprintf(w.Out, "%c[2K\r", ESC) // clear the line
}
return
}
fd := f.Fd()
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(fd, uintptr(unsafe.Pointer(&csbi)))
for i := 0; i < w.lineCount; i++ {
// move the cursor up
csbi.cursorPosition.y--
procSetConsoleCursorPosition.Call(fd, uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition))))
// clear the line
cursor := coord{
x: csbi.window.left,
y: csbi.window.top + csbi.cursorPosition.y,
}
var count, w dword
count = dword(csbi.size.x)
procFillConsoleOutputCharacter.Call(fd, uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&w)))
}
}

2
vendor/github.com/jawher/mow.cli/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
testdata/*.golden
coverage.out

19
vendor/github.com/jawher/mow.cli/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,19 @@
language: go
go:
- 1.8
- 1.7
- tip
sudo: false
install: make setup
script: make check test
deploy:
provider: releases
api_key:
secure: D2fwuS7n54ZkjfRmLMEAnwR2lQLa5xd+4s0l65pI6UN4ljVfQwQiFdZXaZWFr8PYSTKTm0UPj6Iqqw7VOl8I6iDzcaOqN3hoh5mDaJ7kyo7GZRPodwK9MKdOp5dPw459L2Atll8kxb4iYmfnjmcl0lDCUuWvMxXx+zgiFTB7BO0=
skip_cleanup: true
on:
tags: true
go: 1.8

22
vendor/github.com/jawher/mow.cli/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2014, Jawher Moussa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

25
vendor/github.com/jawher/mow.cli/Makefile generated vendored Normal file
View File

@ -0,0 +1,25 @@
test:
go test -v ./...
check: lint vet fmtcheck ineffassign
lint:
golint -set_exit_status .
vet:
go vet
fmtcheck:
@ export output="$$(gofmt -s -d .)"; \
[ -n "$${output}" ] && echo "$${output}" && export status=1; \
exit $${status:-0}
ineffassign:
ineffassign .
setup:
go get github.com/gordonklaus/ineffassign
go get github.com/golang/lint/golint
go get -t -u ./...
.PHONY: test check lint vet fmtcheck ineffassign

771
vendor/github.com/jawher/mow.cli/README.md generated vendored Normal file
View File

@ -0,0 +1,771 @@
# mow.cli
[![Build Status](https://travis-ci.org/jawher/mow.cli.svg?branch=master)](https://travis-ci.org/jawher/mow.cli)
[![GoDoc](https://godoc.org/github.com/jawher/mow.cli?status.svg)](https://godoc.org/github.com/jawher/mow.cli)
A framework to build command line applications in Go with most of the burden of arguments parsing and validation placed on the framework instead of the developer.
## First app
### A simple app
```go
package main
import (
"fmt"
"os"
"github.com/jawher/mow.cli"
)
func main() {
app := cli.App("cp", "Copy files around")
app.Spec = "[-r] SRC... DST"
var (
recursive = app.BoolOpt("r recursive", false, "Copy files recursively")
src = app.StringsArg("SRC", nil, "Source files to copy")
dst = app.StringArg("DST", "", "Destination where to copy files to")
)
app.Action = func() {
fmt.Printf("Copying %v to %s [recursively: %v]\n", *src, *dst, *recursive)
}
app.Run(os.Args)
}
```
### An app with multiple commands:
```go
package main
import (
"fmt"
"os"
"github.com/jawher/mow.cli"
)
func main() {
app := cli.App("uman", "User Manager")
app.Spec = "[-v]"
var (
verbose = app.BoolOpt("v verbose", false, "Verbose debug mode")
)
app.Before = func() {
if *verbose {
// Here you can enable debug output in your logger for example
fmt.Println("Verbose mode enabled")
}
}
// Declare a first command, invocable with "uman list"
app.Command("list", "list the users", func(cmd *cli.Cmd) {
// These are the command specific options and args, nicely scoped inside a func
var (
all = cmd.BoolOpt("all", false, "Display all users, including disabled ones")
)
// What to run when this command is called
cmd.Action = func() {
// Inside the action, and only inside, you can safely access the values of the options and arguments
fmt.Printf("user list (including disabled ones: %v)\n", *all)
}
})
// The second command, invocable with "uman get"
app.Command("get", "get a user details", func(cmd *cli.Cmd) {
var (
detailed = cmd.BoolOpt("detailed", false, "Disaply detailed information")
id = cmd.StringArg("ID", "", "The user id to display")
)
cmd.Action = func() {
fmt.Printf("user %q details (detailed mode: %v)\n", *id, *detailed)
}
})
// Now that the app is configured, execute it passing in the os.Args array
app.Run(os.Args)
}
```
## Motivation
| | mow.cli | codegangsta/cli | flag |
|----------------------------------------------------------------------|---------|-----------------|------|
| Contextual help | ✓ | ✓ | |
| Commands | ✓ | ✓ | |
| Option folding `-xyz` | ✓ | | |
| Option Value folding `-fValue` | ✓ | | |
| Option exclusion: `--start ❘ --stop` | ✓ | | |
| Option dependency : `[-a -b]` or `[-a [-b]]` | ✓ | | |
| Arguments validation : `SRC DST` | ✓ | | |
| Argument optionality : `SRC [DST]` | ✓ | | |
| Argument repetition : `SRC... DST` | ✓ | | |
| Option/Argument dependency : `SRC [-f DST]` | ✓ | | |
| Any combination of the above: `[-d ❘ --rm] IMAGE [COMMAND [ARG...]]` | ✓ | | |
In the goland, docopt is another library with rich flags and arguments validation.
However, it falls short for many use cases:
| | mow.cli | docopt |
|-----------------------------|---------|--------|
| Contextual help | ✓ | |
| Backtracking: `SRC... DST` | ✓ | |
| Backtracking: `[SRC] DST` | ✓ | |
| Branching: `(SRC ❘ -f DST)` | ✓ | |
## Installation
To install this library, simply run:
```
$ go get github.com/jawher/mow.cli
```
## Basics
You start by creating an application by passing a name and a description:
```go
cp := cli.App("cp", "Copy files around")
```
To attach the code to execute when the app is launched, assign a function to the Action field:
```go
cp.Action = func() {
fmt.Printf("Hello world\n")
}
```
If you want you can add support for printing the app version (invoked by ```-v, --version```) like so:
```go
cp.Version("v version", "cp 1.2.3")
```
Finally, in your main func, call Run on the app:
```go
cp.Run(os.Args)
```
## Options
To add a (global) option, call one of the (String[s]|Int[s]|Bool)Opt methods on the app:
```go
recursive := cp.BoolOpt("R recursive", false, "recursively copy the src to dst")
```
* The first argument is a space separated list of names (short and long) for the option without the dashes, e.g `"f force"`. While you can specify multiple short or long names, e.g. `"f x force force-push"`, only the first short name and the first long name will be displayed in the help messages
* The second parameter is the default value for the option
* The third and last parameter is the option description, as will be shown in the help messages
There is also a second set of methods Bool, String, Int, Strings and Ints, which accepts a struct describing the option:
```go
recursive = cp.Bool(cli.BoolOpt{
Name: "R recursive",
Value: false,
Desc: "copy src files recursively",
EnvVar: "VAR_RECURSIVE",
SetByUser: &recursiveSetByUser,
})
```
`EnvVar` accepts a space separated list of environment variables names to be used to initialize the option.
If `SetByUser` is specified (by passing a pointer to a bool variable), it will be set to `true` if the user explicitly set the option.
The result is a pointer to a value which will be populated after parsing the command line arguments.
You can access the values in the Action func.
In the command line, mow.cli accepts the following syntaxes
### For boolean options:
* `-f` : a single dash for the one letter names
* `-f=false` : a single dash for the one letter names, equal sign followed by true or false
* `--force` : double dash for longer option names
* `-it` : mow.cli supports option folding, this is equivalent to: -i -t
### For string, int options:
* `-e=value` : single dash for one letter names, equal sign followed by the value
* `-e value` : single dash for one letter names, space followed by the value
* `-Ivalue` : single dash for one letter names immediately followed by the value
* `--extra=value` : double dash for longer option names, equal sign followed by the value
* `--extra value` : double dash for longer option names, space followed by the value
### For slice options (StringsOpt, IntsOpt):
repeat the option to accumulate the values in the resulting slice:
* `-e PATH:/bin -e PATH:/usr/bin` : resulting slice contains `["/bin", "/usr/bin"]`
* `-ePATH:/bin -ePATH:/usr/bin` : resulting slice contains `["/bin", "/usr/bin"]`
* `-e=PATH:/bin -e=PATH:/usr/bin` : resulting slice contains `["/bin", "/usr/bin"]`
* `--env PATH:/bin --env PATH:/usr/bin` : resulting slice contains `["/bin", "/usr/bin"]`
* `--env=PATH:/bin --env=PATH:/usr/bin` : resulting slice contains `["/bin", "/usr/bin"]`
## Arguments
To accept arguments, you need to explicitly declare them by calling one of the (String[s]|Int[s]|Bool)Arg methods on the app:
```go
src := cp.StringArg("SRC", "", "the file to copy")
dst := cp.StringArg("DST", "", "the destination")
```
* The first argument is the argument name as will be shown in the help messages
* The second parameter is the default value for the argument
* The third parameter is the argument description, as will be shown in the help messages
There is also a second set of methods Bool, String, Int, Strings and Ints, which accepts structs describing the argument:
```go
src = cp.Strings(cli.StringsArg{
Name: "SRC",
Desc: "The source files to copy",
Value: "default value",
EnvVar: "VAR1 VAR2",
SetByUser: &srcSetByUser,
})
```
The Value field is where you can set the initial value for the argument.
`EnvVar` accepts a space separated list of environment variables names to be used to initialize the argument.
If `SetByUser` is specified (by passing a pointer to a bool variable), it will be set to `true` only if the user explicitly sets the argument.
The result is a pointer to a value that will be populated after parsing the command line arguments.
You can access the values in the Action func.
## Operators
The `--` operator marks the end of options.
Everything that follow will be treated as an argument,
even if starts with a dash.
For example, given the `touch` command which takes a filename as an argument (and possibly other options):
```go
file := cp.StringArg("FILE", "", "the file to create")
```
If we try to create a file named `-f` this way:
```
touch -f
```
Would fail, because `-f` will be parsed as an option not as an argument.
The fix is to prefix the filename with the `--` operator:
```
touch -- -f
```
## Commands
mow.cli supports nesting commands and sub commands.
Declare a top level command by calling the Command func on the app struct, and a sub command by calling
the Command func on the command struct:
```go
docker := cli.App("docker", "A self-sufficient runtime for linux containers")
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
// initialize the run command here
})
```
* The first argument is the command name, as will be shown in the help messages and as will need to be input by the user in the command line to call the command
* The second argument is the command description as will be shown in the help messages
* The third argument is a CmdInitializer, a function that receives a pointer to a Cmd struct representing the command.
In this function, you can add options and arguments by calling the same methods as you would with an app struct (BoolOpt, StringArg, ...).
You would also assign a function to the Action field of the Cmd struct for it to be executed when the command is invoked.
```go
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
var (
detached = cmd.BoolOpt("d detach", false, "Detached mode: run the container in the background and print the new container ID")
memory = cmd.StringOpt("m memory", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
image = cmd.StringArg("IMAGE", "", "")
)
cmd.Action = func() {
if *detached {
//do something
}
runContainer(*image, *detached, *memory)
}
})
```
You can also add sub commands by calling Command on the Cmd struct:
```go
bzk.Command("job", "actions on jobs", func(cmd *cli.Cmd) {
cmd.Command("list", "list jobs", listJobs)
cmd.Command("start", "start a new job", startJob)
cmd.Command("log", "show a job log", nil)
})
```
When you just want to set Action to cmd, you can use ActionCommand function for this:
```go
app.Command("list", "list all configs", cli.ActionCommand(func() { list() }))
```
is the same as:
```go
app.Command("list", "list all configs", func(cmd *cli.Cmd)) {
cmd.Action = func() {
list()
}
}
```
This could go on to any depth if need be.
mow.cli also supports command aliases. For example:
```go
app.Command("start run r", "start doing things", cli.ActionCommand(func() { start() }))
```
will alias `start`, `run`, and `r` to the same action. Aliases also work for
subcommands:
```go
app.Command("job j", "actions on jobs", func(cmd *cli.Cmd) {
cmd.Command("list ls", "list jobs", func(cmd *cli.Cmd) {
cmd.Action = func() {
list()
}
})
})
```
which then allows you to invoke the subcommand as `app job list`, `app job ls`,
`app j ls`, or `app j list`.
As a side-note: it may seem a bit weird the way mow.cli uses a function to initialize a command instead of just returning the command struct.
The motivation behind this choice is scoping: as with the standard flag package, adding an option or an argument returns a pointer to a value which will be populated when the app is run.
Since you'll want to store these pointers in variables, and to avoid having dozens of them in the same scope (the main func for example or as global variables),
mow.cli's API was specifically tailored to take a func parameter (called CmdInitializer) which accepts the command struct.
This way, the command specific variables scope is limited to this function.
## Custom types
Out of the box, mow.cli supports the following types for options and arguments:
* bool
* string
* int
* strings (slice of strings)
* ints (slice of ints)
You can however extend mow.cli to handle other types, e.g. `time.Duration`, `float64`, or even your own struct types for example.
To do so, you'll need to:
* implement the `flag.Value` interface for the custom type
* declare the option or the flag using `VarOpt`, `VarArg` for the short hands, and `Var` for the full form.
Here's an example:
```go
// Declare your type
type Duration time.Duration
// Make it implement flag.Value
func (d *Duration) Set(v string) error {
parsed, err := time.ParseDuration(v)
if err != nil {
return err
}
*d = Duration(parsed)
return nil
}
func (d *Duration) String() string {
duration := time.Duration(*d)
return duration.String()
}
func main() {
duration := Duration(0)
app := App("var", "")
app.VarArg("DURATION", &duration, "")
app.Run([]string{"cp", "1h31m42s"})
}
```
### Boolean custom types
To make your custom type behave as a boolean option, i.e. doesn't take a value, it has to implement a `IsBoolFlag` method that returns true:
```go
type BoolLike int
func (d *BoolLike) IsBoolFlag() bool {
return true
}
```
### Multi-valued custom type
To make your custom type behave as a multi-valued option or argument, i.e. takes multiple values,
it has to implement a `Clear` method which will be called whenever the value list needs to be cleared,
e.g. when the value was initially populated from an environment variable, and then explicitly set from the CLI:
```go
type Durations []time.Duration
// Make it implement flag.Value
func (d *Durations) Set(v string) error {
parsed, err := time.ParseDuration(v)
if err != nil {
return err
}
*d = append(*d, Duration(parsed))
return nil
}
func (d *Durations) String() string {
return fmt.Sprintf("%v", *d)
}
// Make it multi-valued
func (d *Durations) Clear() {
*d = []Duration{}
}
```
### Hide default value of custom type
If your custom type implements a `IsDefault` method (returning a boolean), the help message generation will make use of it to decide whether or not to display the default value.
```go
type Action string
// Make it implement flag.Value
:
:
// Make it multi-valued
func (a *Action) IsDefault() bool {
return (*a) == "nop"
}
```
## Interceptors
It is possible to define snippets of code to be executed before and after a command or any of its sub commands is executed.
For example, given an app with multiple commands but with a global flag which toggles a verbose mode:
```go
app := cli.App("app", "bla bla")
verbose := app.Bool(cli.BoolOpt{
Name: "verbose",
Value: false,
Desc: "Enable debug logs",
})
app.Command("command1", "...", func(cmd *cli.Cmd) {
})
app.Command("command2", "...", func(cmd *cli.Cmd) {
})
```
Instead of repeating yourself by checking if the verbose flag is set or not, and setting the debug level in every command (and its sub-commands),
a before interceptor can be set on the `app` instead:
```go
app.Before = func() {
if (*verbose) {
logrus.SetLevel(logrus.DebugLevel)
}
}
```
Whenever a valid command is called by the user, all the before interceptors defined on the app and the intermediate commands
will be called, in order from the root to the leaf.
Similarly, if you need to execute a code snippet after a command has been called, e.g. to cleanup resources allocated in before interceptors,
simply set the `After` field of the app struct or any other command.
`After` interceptors will be called, in order from the leaf up to the root (the opposite order of the `Before` interceptors).
Here's a diagram which shows in when and in which order multiple `Before` and `After` interceptors get executed:
![flow](http://i.imgur.com/oUEa8Sh.png)
## Spec
An app or command's call syntax can be customized using spec strings.
This can be useful to indicate that an argument is optional for example, or that 2 options are mutually exclusive.
You can set a spec string on:
* The app: to configure the syntax for global options and arguments
* A command: to configure the syntax for that command's options and arguments
In both cases, a spec string is assigned to the Spec field:
```go
cp := cli.App("cp", "Copy files around")
cp.Spec = "[-R [-H | -L | -P]]"
```
And:
```go
docker := cli.App("docker", "A self-sufficient runtime for linux containers")
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
cmd.Spec = "[-d|--rm] IMAGE [COMMAND [ARG...]]"
:
:
}
```
The spec syntax is mostly based on the conventions used in POSIX command line apps help messages and man pages:
### Options
You can use both short and long option names in spec strings:
```go
x.Spec="-f"
```
And:
```go
x.Spec="--force"
```
In both cases, we required that the f or force flag be set
Any option you reference in a spec string MUST be explicitly declared, otherwise mow.cli will panic:
```go
x.BoolOpt("f force", ...)
```
### Arguments
Arguments are all-uppercased words:
```go
x.Spec="SRC DST"
```
This spec string will force the user to pass exactly 2 arguments, SRC and DST
Any argument you reference in a spec string MUST be explicitly declared, otherwise mow.cli will panic:
```go
x.StringArg("SRC", ...)
x.StringArg("DST", ...)
```
### Ordering
Except for options, The order of the elements in a spec string is respected and enforced when parsing the command line arguments:
```go
x.Spec = "-f -g SRC -h DST"
```
Consecutive options (`-f` and `-g` for example) get parsed regardless of the order they are specified in (both `-f=5 -g=6` and `-g=6 -f=5` are valid).
Order between options and arguments is significant (`-f` and `-g` must appear before the `SRC` argument).
Same goes for arguments, where `SRC` must appear before `DST`.
### Optionality
You can mark items as optional in a spec string by enclosing them in square brackets :`[...]`
```go
x.Spec = "[-x]"
```
### Choice
You can use the `|` operator to indicate a choice between two or more items
```go
x.Spec = "--rm | --daemon"
x.Spec = "-H | -L | -P"
x.Spec = "-t | DST"
```
### Repetition
You can use the `...` postfix operator to mark an element as repeatable:
```go
x.Spec="SRC..."
x.Spec="-e..."
```
### Grouping
You can group items using parenthesis. This is useful in combination with the choice and repetition operators (`|` and `...`):
```go
x.Spec = "(-e COMMAND)... | (-x|-y)"
```
The parenthesis in the example above serve to mark that it is the sequence of a -e flag followed by an argument that is repeatable, and that
all that is mutually exclusive to a choice between -x and -y options.
### Option group
This is a shortcut to declare a choice between multiple options:
```go
x.Spec = "-abcd"
```
Is equivalent to:
```go
x.Spec = "(-a | -b | -c | -d)..."
```
I.e. any combination of the listed options in any order, with at least one option.
### All options
Another shortcut:
```go
x.Spec = "[OPTIONS]"
```
This is a special syntax (the square brackets are not for marking an optional item, and the uppercased word is not for an argument).
This is equivalent to a repeatable choice between all the available options.
For example, if an app or a command declares 4 options a, b, c and d, `[OPTIONS]` is equivalent to:
```go
x.Spec = "[-a | -b | -c | -d]..."
```
### Inline option values
You can use the `=<some-text>` notation right after an option (long or short form) to give an inline description or value.
An example:
```go
x.Spec = "[ -a=<absolute-path> | --timeout=<in seconds> ] ARG"
```
The inline values are ignored by the spec parser and are just there for the final user as a contextual hint.
### Operators
The `--` operator can be used in a spec string to automatically treat everything following it as an options.
In other words, placing a `--` in the spec string automatically inserts a `--` in the same position in the program call arguments.
This lets you write programs like the `time` utility for example:
```go
x.Spec = "time -lp [-- CMD [ARG...]]"
```
## Grammar
Here's the (simplified) EBNF grammar for the Specs language:
```
spec -> sequence
sequence -> choice*
req_sequence -> choice+
choice -> atom ('|' atom)*
atom -> (shortOpt | longOpt | optSeq | allOpts | group | optional) rep? | optEnd
shortOp -> '-' [A-Za-z]
longOpt -> '--' [A-Za-z][A-Za-z0-9]*
optSeq -> '-' [A-Za-z]+
allOpts -> '[OPTIONS]'
group -> '(' req_sequence ')'
optional -> '[' req_sequence ']'
rep -> '...'
optEnd -> '--'
```
And that's it for the spec language.
You can combine these few building blocks in any way you want (while respecting the grammar above) to construct sophisticated validation constraints
(don't go too wild though).
Behind the scenes, mow.cli parses the spec string and constructs a finite state machine to be used to parse the command line arguments.
mow.cli also handles backtracking, and so it can handle tricky cases, or what I like to call "the cp test"
```
cp SRC... DST
```
Without backtracking, this deceptively simple spec string cannot be parsed correctly.
For instance, docopt can't handle this case, whereas mow.cli does.
## Default spec
By default, and unless a spec string is set by the user, mow.cli auto-generates one for the app and every command using this logic:
* Start with an empty spec string
* If at least one option was declared, append `[OPTIONS]` to the spec string
* For every declared argument, append it, in the order of declaration, to the spec string
For example, given this command declaration:
```go
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
var (
detached = cmd.BoolOpt("d detach", false, "Detached mode: run the container in the background and print the new container ID", nil)
memory = cmd.StringOpt("m memory", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)", nil)
image = cmd.StringArg("IMAGE", "", "", nil)
args = cmd.StringsArg("ARG", "", "", nil)
)
})
```
The auto-generated spec string would be:
```go
[OPTIONS] IMAGE ARG
```
Which should suffice for simple cases. If not, the spec string has to be set explicitly.
## Exiting
`mow.cli` provides the `Exit` function which accepts an exit code and exits the app with the provided code.
You are highly encouraged to call `cli.Exit` instead of `os.Exit` for the `After` interceptors to be executed.
## License
This work is published under the MIT license.
Please see the `LICENSE` file for details.

224
vendor/github.com/jawher/mow.cli/args.go generated vendored Normal file
View File

@ -0,0 +1,224 @@
package cli
import (
"flag"
"fmt"
)
// BoolArg describes a boolean argument
type BoolArg struct {
// The argument name as will be shown in help messages
Name string
// The argument description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this argument
EnvVar string
// The argument's inital value
Value bool
// A boolean to display or not the current value of the argument in the help message
HideValue bool
// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (a BoolArg) value() bool {
return a.Value
}
// StringArg describes a string argument
type StringArg struct {
// The argument name as will be shown in help messages
Name string
// The argument description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this argument
EnvVar string
// The argument's initial value
Value string
// A boolean to display or not the current value of the argument in the help message
HideValue bool
// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (a StringArg) value() string {
return a.Value
}
// IntArg describes an int argument
type IntArg struct {
// The argument name as will be shown in help messages
Name string
// The argument description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this argument
EnvVar string
// The argument's initial value
Value int
// A boolean to display or not the current value of the argument in the help message
HideValue bool
// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (a IntArg) value() int {
return a.Value
}
// StringsArg describes a string slice argument
type StringsArg struct {
// The argument name as will be shown in help messages
Name string
// The argument description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this argument.
// The env variable should contain a comma separated list of values
EnvVar string
// The argument's initial value
Value []string
// A boolean to display or not the current value of the argument in the help message
HideValue bool
// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (a StringsArg) value() []string {
return a.Value
}
// IntsArg describes an int slice argument
type IntsArg struct {
// The argument name as will be shown in help messages
Name string
// The argument description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this argument.
// The env variable should contain a comma separated list of values
EnvVar string
// The argument's initial value
Value []int
// A boolean to display or not the current value of the argument in the help message
HideValue bool
// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (a IntsArg) value() []int {
return a.Value
}
// VarArg describes an argument where the type and format of the value is controlled by the developer
type VarArg struct {
// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
// The one letter names will then be called with a single dash (short option), the others with two (long options).
Name string
// The option description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this option
EnvVar string
// A value implementing the flag.Value type (will hold the final value)
Value flag.Value
// A boolean to display or not the current value of the option in the help message
HideValue bool
// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (a VarArg) value() flag.Value {
return a.Value
}
/*
BoolArg defines a boolean argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The result should be stored in a variable (a pointer to a bool) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) BoolArg(name string, value bool, desc string) *bool {
return c.Bool(BoolArg{
Name: name,
Value: value,
Desc: desc,
})
}
/*
StringArg defines a string argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The result should be stored in a variable (a pointer to a string) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) StringArg(name string, value string, desc string) *string {
return c.String(StringArg{
Name: name,
Value: value,
Desc: desc,
})
}
/*
IntArg defines an int argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The result should be stored in a variable (a pointer to an int) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) IntArg(name string, value int, desc string) *int {
return c.Int(IntArg{
Name: name,
Value: value,
Desc: desc,
})
}
/*
StringsArg defines a string slice argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The result should be stored in a variable (a pointer to a string slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) StringsArg(name string, value []string, desc string) *[]string {
return c.Strings(StringsArg{
Name: name,
Value: value,
Desc: desc,
})
}
/*
IntsArg defines an int slice argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The result should be stored in a variable (a pointer to an int slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) IntsArg(name string, value []int, desc string) *[]int {
return c.Ints(IntsArg{
Name: name,
Value: value,
Desc: desc,
})
}
/*
VarArg defines an argument where the type and format is controlled by the developer on the command c named `name` and a description of `desc` which will be used in help messages.
The result will be stored in the value parameter (a value implementing the flag.Value interface) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) VarArg(name string, value flag.Value, desc string) {
c.mkArg(arg{name: name, desc: desc, value: value})
}
type arg struct {
name string
desc string
envVar string
hideValue bool
valueSetFromEnv bool
valueSetByUser *bool
value flag.Value
}
func (a *arg) String() string {
return fmt.Sprintf("ARG(%s)", a.name)
}
func (c *Cmd) mkArg(arg arg) {
arg.valueSetFromEnv = setFromEnv(arg.value, arg.envVar)
c.args = append(c.args, &arg)
c.argsIdx[arg.name] = &arg
}

142
vendor/github.com/jawher/mow.cli/args_test.go generated vendored Normal file
View File

@ -0,0 +1,142 @@
package cli
import (
"os"
"strconv"
"testing"
"github.com/stretchr/testify/require"
)
func TestStringArg(t *testing.T) {
cmd := &Cmd{argsIdx: map[string]*arg{}}
a := cmd.String(StringArg{Name: "a", Value: "test"})
require.Equal(t, "test", *a)
os.Setenv("B", "")
b := cmd.String(StringArg{Name: "b", Value: "test", EnvVar: "B"})
require.Equal(t, "test", *b)
os.Setenv("B", "mow")
b = cmd.String(StringArg{Name: "b", Value: "test", EnvVar: "B"})
require.Equal(t, "mow", *b)
os.Setenv("B", "")
os.Setenv("C", "cli")
os.Setenv("D", "mow")
b = cmd.String(StringArg{Name: "b", Value: "test", EnvVar: "B C D"})
require.Equal(t, "cli", *b)
}
func TestBoolArg(t *testing.T) {
cmd := &Cmd{argsIdx: map[string]*arg{}}
a := cmd.Bool(BoolArg{Name: "a", Value: true, Desc: ""})
require.True(t, *a)
os.Setenv("B", "")
b := cmd.Bool(BoolArg{Name: "b", Value: false, EnvVar: "B", Desc: ""})
require.False(t, *b)
trueValues := []string{"1", "true", "TRUE"}
for _, tv := range trueValues {
os.Setenv("B", tv)
b = cmd.Bool(BoolArg{Name: "b", Value: false, EnvVar: "B", Desc: ""})
require.True(t, *b, "env=%s", tv)
}
falseValues := []string{"0", "false", "FALSE", "xyz"}
for _, tv := range falseValues {
os.Setenv("B", tv)
b = cmd.Bool(BoolArg{Name: "b", Value: false, EnvVar: "B", Desc: ""})
require.False(t, *b, "env=%s", tv)
}
os.Setenv("B", "")
os.Setenv("C", "false")
os.Setenv("D", "true")
b = cmd.Bool(BoolArg{Name: "b", Value: true, EnvVar: "B C D", Desc: ""})
require.False(t, *b)
}
func TestIntArg(t *testing.T) {
cmd := &Cmd{argsIdx: map[string]*arg{}}
a := cmd.Int(IntArg{Name: "a", Value: -1, Desc: ""})
require.Equal(t, -1, *a)
os.Setenv("B", "")
b := cmd.Int(IntArg{Name: "b", Value: -1, EnvVar: "B", Desc: ""})
require.Equal(t, -1, *b)
goodValues := []int{1, 0, 33}
for _, tv := range goodValues {
os.Setenv("B", strconv.Itoa(tv))
b := cmd.Int(IntArg{Name: "b", Value: -1, EnvVar: "B", Desc: ""})
require.Equal(t, tv, *b, "env=%s", tv)
}
badValues := []string{"", "b", "q1", "_"}
for _, tv := range badValues {
os.Setenv("B", tv)
b := cmd.Int(IntArg{Name: "b", Value: -1, EnvVar: "B", Desc: ""})
require.Equal(t, -1, *b, "env=%s", tv)
}
os.Setenv("B", "")
os.Setenv("C", "42")
os.Setenv("D", "666")
b = cmd.Int(IntArg{Name: "b", Value: -1, EnvVar: "B C D", Desc: ""})
require.Equal(t, 42, *b)
}
func TestStringsArg(t *testing.T) {
cmd := &Cmd{argsIdx: map[string]*arg{}}
v := []string{"test"}
a := cmd.Strings(StringsArg{Name: "a", Value: v, Desc: ""})
require.Equal(t, v, *a)
os.Setenv("B", "")
b := cmd.Strings(StringsArg{Name: "b", Value: v, EnvVar: "B", Desc: ""})
require.Equal(t, v, *b)
os.Setenv("B", "mow")
b = cmd.Strings(StringsArg{Name: "b", Value: nil, EnvVar: "B", Desc: ""})
require.Equal(t, []string{"mow"}, *b)
os.Setenv("B", "mow, cli")
b = cmd.Strings(StringsArg{Name: "b", Value: nil, EnvVar: "B", Desc: ""})
require.Equal(t, []string{"mow", "cli"}, *b)
os.Setenv("B", "")
os.Setenv("C", "test")
os.Setenv("D", "xxx")
b = cmd.Strings(StringsArg{Name: "b", Value: nil, EnvVar: "B C D", Desc: ""})
require.Equal(t, v, *b)
}
func TestIntsArg(t *testing.T) {
cmd := &Cmd{argsIdx: map[string]*arg{}}
vi := []int{42}
a := cmd.Ints(IntsArg{Name: "a", Value: vi, Desc: ""})
require.Equal(t, vi, *a)
os.Setenv("B", "")
b := cmd.Ints(IntsArg{Name: "b", Value: vi, EnvVar: "B", Desc: ""})
require.Equal(t, vi, *b)
os.Setenv("B", "666")
b = cmd.Ints(IntsArg{Name: "b", Value: nil, EnvVar: "B", Desc: ""})
require.Equal(t, []int{666}, *b)
os.Setenv("B", "1, 2 , 3")
b = cmd.Ints(IntsArg{Name: "b", Value: nil, EnvVar: "B", Desc: ""})
require.Equal(t, []int{1, 2, 3}, *b)
os.Setenv("B", "")
os.Setenv("C", "abc")
os.Setenv("D", "1, abc")
os.Setenv("E", "42")
os.Setenv("F", "666")
b = cmd.Ints(IntsArg{Name: "b", Value: nil, EnvVar: "B C D E F", Desc: ""})
require.Equal(t, vi, *b)
}

133
vendor/github.com/jawher/mow.cli/cli.go generated vendored Normal file
View File

@ -0,0 +1,133 @@
package cli
import (
"flag"
"fmt"
"io"
"os"
)
/*
Cli represents the structure of a CLI app. It should be constructed using the App() function
*/
type Cli struct {
*Cmd
version *cliVersion
}
type cliVersion struct {
version string
option *opt
}
/*
App creates a new and empty CLI app configured with the passed name and description.
name and description will be used to construct the help message for the app:
Usage: $name [OPTIONS] COMMAND [arg...]
$desc
*/
func App(name, desc string) *Cli {
return &Cli{
Cmd: &Cmd{
name: name,
desc: desc,
optionsIdx: map[string]*opt{},
argsIdx: map[string]*arg{},
ErrorHandling: flag.ExitOnError,
},
}
}
/*
Version sets the version string of the CLI app together with the options that can be used to trigger
printing the version string via the CLI.
Usage: appName --$name
$version
*/
func (cli *Cli) Version(name, version string) {
cli.Bool(BoolOpt{
Name: name,
Value: false,
Desc: "Show the version and exit",
HideValue: true,
})
names := mkOptStrs(name)
option := cli.optionsIdx[names[0]]
cli.version = &cliVersion{version, option}
}
func (cli *Cli) parse(args []string, entry, inFlow, outFlow *step) error {
// We overload Cmd.parse() and handle cases that only apply to the CLI command, like versioning
// After that, we just call Cmd.parse() for the default behavior
if cli.versionSetAndRequested(args) {
cli.PrintVersion()
cli.onError(errVersionRequested)
return nil
}
return cli.Cmd.parse(args, entry, inFlow, outFlow)
}
func (cli *Cli) versionSetAndRequested(args []string) bool {
return cli.version != nil && cli.isFlagSet(args, cli.version.option.names)
}
/*
PrintVersion prints the CLI app's version.
In most cases the library users won't need to call this method, unless
a more complex validation is needed.
*/
func (cli *Cli) PrintVersion() {
fmt.Fprintln(stdErr, cli.version.version)
}
/*
Run uses the app configuration (specs, commands, ...) to parse the args slice
and to execute the matching command.
In case of an incorrect usage, and depending on the configured ErrorHandling policy,
it may return an error, panic or exit
*/
func (cli *Cli) Run(args []string) error {
if err := cli.doInit(); err != nil {
panic(err)
}
inFlow := &step{desc: "RootIn"}
outFlow := &step{desc: "RootOut"}
return cli.parse(args[1:], inFlow, inFlow, outFlow)
}
/*
ActionCommand is a convenience function to configure a command with an action.
cmd.ActionCommand(_, _, myFun } is equivalent to cmd.Command(_, _, func(cmd *cli.Cmd) { cmd.Action = myFun })
*/
func ActionCommand(action func()) CmdInitializer {
return func(cmd *Cmd) {
cmd.Action = action
}
}
/*
Exit causes the app the exit with the specified exit code while giving the After interceptors a chance to run.
This should be used instead of os.Exit.
*/
func Exit(code int) {
panic(exit(code))
}
type exit int
var exiter = func(code int) {
os.Exit(code)
}
var (
stdOut io.Writer = os.Stdout
stdErr io.Writer = os.Stderr
)

1106
vendor/github.com/jawher/mow.cli/cli_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

545
vendor/github.com/jawher/mow.cli/commands.go generated vendored Normal file
View File

@ -0,0 +1,545 @@
package cli
import (
"flag"
"fmt"
"strings"
"text/tabwriter"
)
/*
Cmd represents a command (or sub command) in a CLI application. It should be constructed
by calling Command() on an app to create a top level command or by calling Command() on another
command to create a sub command
*/
type Cmd struct {
// The code to execute when this command is matched
Action func()
// The code to execute before this command or any of its children is matched
Before func()
// The code to execute after this command or any of its children is matched
After func()
// The command options and arguments
Spec string
// The command long description to be shown when help is requested
LongDesc string
// The command error handling strategy
ErrorHandling flag.ErrorHandling
init CmdInitializer
name string
aliases []string
desc string
commands []*Cmd
options []*opt
optionsIdx map[string]*opt
args []*arg
argsIdx map[string]*arg
parents []string
fsm *state
}
/*
BoolParam represents a Bool option or argument
*/
type BoolParam interface {
value() bool
}
/*
StringParam represents a String option or argument
*/
type StringParam interface {
value() string
}
/*
IntParam represents an Int option or argument
*/
type IntParam interface {
value() int
}
/*
StringsParam represents a string slice option or argument
*/
type StringsParam interface {
value() []string
}
/*
IntsParam represents an int slice option or argument
*/
type IntsParam interface {
value() []int
}
/*
VarParam represents an custom option or argument where the type and format are controlled by the developer
*/
type VarParam interface {
value() flag.Value
}
/*
CmdInitializer is a function that configures a command by adding options, arguments, a spec, sub commands and the code
to execute when the command is called
*/
type CmdInitializer func(*Cmd)
/*
Command adds a new (sub) command to c where name is the command name (what you type in the console),
description is what would be shown in the help messages, e.g.:
Usage: git [OPTIONS] COMMAND [arg...]
Commands:
$name $desc
the last argument, init, is a function that will be called by mow.cli to further configure the created
(sub) command, e.g. to add options, arguments and the code to execute
*/
func (c *Cmd) Command(name, desc string, init CmdInitializer) {
aliases := strings.Fields(name)
c.commands = append(c.commands, &Cmd{
ErrorHandling: c.ErrorHandling,
name: aliases[0],
aliases: aliases,
desc: desc,
init: init,
commands: []*Cmd{},
options: []*opt{},
optionsIdx: map[string]*opt{},
args: []*arg{},
argsIdx: map[string]*arg{},
})
}
/*
Bool can be used to add a bool option or argument to a command.
It accepts either a BoolOpt or a BoolArg struct.
The result should be stored in a variable (a pointer to a bool) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Bool(p BoolParam) *bool {
into := new(bool)
value := newBoolValue(into, p.value())
switch x := p.(type) {
case BoolOpt:
c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
case BoolArg:
c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
default:
panic(fmt.Sprintf("Unhandled param %v", p))
}
return into
}
/*
String can be used to add a string option or argument to a command.
It accepts either a StringOpt or a StringArg struct.
The result should be stored in a variable (a pointer to a string) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) String(p StringParam) *string {
into := new(string)
value := newStringValue(into, p.value())
switch x := p.(type) {
case StringOpt:
c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
case StringArg:
c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
default:
panic(fmt.Sprintf("Unhandled param %v", p))
}
return into
}
/*
Int can be used to add an int option or argument to a command.
It accepts either a IntOpt or a IntArg struct.
The result should be stored in a variable (a pointer to an int) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Int(p IntParam) *int {
into := new(int)
value := newIntValue(into, p.value())
switch x := p.(type) {
case IntOpt:
c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
case IntArg:
c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
default:
panic(fmt.Sprintf("Unhandled param %v", p))
}
return into
}
/*
Strings can be used to add a string slice option or argument to a command.
It accepts either a StringsOpt or a StringsArg struct.
The result should be stored in a variable (a pointer to a string slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Strings(p StringsParam) *[]string {
into := new([]string)
value := newStringsValue(into, p.value())
switch x := p.(type) {
case StringsOpt:
c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
case StringsArg:
c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
default:
panic(fmt.Sprintf("Unhandled param %v", p))
}
return into
}
/*
Ints can be used to add an int slice option or argument to a command.
It accepts either a IntsOpt or a IntsArg struct.
The result should be stored in a variable (a pointer to an int slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) Ints(p IntsParam) *[]int {
into := new([]int)
value := newIntsValue(into, p.value())
switch x := p.(type) {
case IntsOpt:
c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
case IntsArg:
c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: value, valueSetByUser: x.SetByUser})
default:
panic(fmt.Sprintf("Unhandled param %v", p))
}
return into
}
/*
Var can be used to add a custom option or argument to a command.
It accepts either a VarOpt or a VarArg struct.
As opposed to the other built-in types, this function does not return a pointer the the value.
Instead, the VarOpt or VarOptArg structs hold the said value.
*/
func (c *Cmd) Var(p VarParam) {
switch x := p.(type) {
case VarOpt:
c.mkOpt(opt{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: p.value(), valueSetByUser: x.SetByUser})
case VarArg:
c.mkArg(arg{name: x.Name, desc: x.Desc, envVar: x.EnvVar, hideValue: x.HideValue, value: p.value(), valueSetByUser: x.SetByUser})
default:
panic(fmt.Sprintf("Unhandled param %v", p))
}
}
func (c *Cmd) doInit() error {
if c.init != nil {
c.init(c)
}
parents := append(c.parents, c.name)
for _, sub := range c.commands {
sub.parents = parents
}
if len(c.Spec) == 0 {
if len(c.options) > 0 {
c.Spec = "[OPTIONS] "
}
for _, arg := range c.args {
c.Spec += arg.name + " "
}
}
fsm, err := uParse(c)
if err != nil {
return err
}
c.fsm = fsm
return nil
}
func (c *Cmd) onError(err error) {
if err == errHelpRequested || err == errVersionRequested {
if c.ErrorHandling == flag.ExitOnError {
exiter(0)
}
return
}
switch c.ErrorHandling {
case flag.ExitOnError:
exiter(2)
case flag.PanicOnError:
panic(err)
}
}
/*
PrintHelp prints the command's help message.
In most cases the library users won't need to call this method, unless
a more complex validation is needed
*/
func (c *Cmd) PrintHelp() {
c.printHelp(false)
}
/*
PrintLongHelp prints the command's help message using the command long description if specified.
In most cases the library users won't need to call this method, unless
a more complex validation is needed
*/
func (c *Cmd) PrintLongHelp() {
c.printHelp(true)
}
func (c *Cmd) printHelp(longDesc bool) {
full := append(c.parents, c.name)
path := strings.Join(full, " ")
fmt.Fprintf(stdErr, "\nUsage: %s", path)
spec := strings.TrimSpace(c.Spec)
if len(spec) > 0 {
fmt.Fprintf(stdErr, " %s", spec)
}
if len(c.commands) > 0 {
fmt.Fprint(stdErr, " COMMAND [arg...]")
}
fmt.Fprint(stdErr, "\n\n")
desc := c.desc
if longDesc && len(c.LongDesc) > 0 {
desc = c.LongDesc
}
if len(desc) > 0 {
fmt.Fprintf(stdErr, "%s\n", desc)
}
w := tabwriter.NewWriter(stdErr, 15, 1, 3, ' ', 0)
if len(c.args) > 0 {
fmt.Fprint(w, "\t\nArguments:\t\n")
for _, arg := range c.args {
var (
env = formatEnvVarsForHelp(arg.envVar)
value = formatValueForHelp(arg.hideValue, arg.value)
)
fmt.Fprintf(w, " %s\t%s\n", arg.name, joinStrings(arg.desc, env, value))
}
}
if len(c.options) > 0 {
fmt.Fprint(w, "\t\nOptions:\t\n")
for _, opt := range c.options {
var (
optNames = formatOptNamesForHelp(opt)
env = formatEnvVarsForHelp(opt.envVar)
value = formatValueForHelp(opt.hideValue, opt.value)
)
fmt.Fprintf(w, " %s\t%s\n", optNames, joinStrings(opt.desc, env, value))
}
}
if len(c.commands) > 0 {
fmt.Fprint(w, "\t\nCommands:\t\n")
for _, c := range c.commands {
fmt.Fprintf(w, " %s\t%s\n", strings.Join(c.aliases, ", "), c.desc)
}
}
if len(c.commands) > 0 {
fmt.Fprintf(w, "\t\nRun '%s COMMAND --help' for more information on a command.\n", path)
}
w.Flush()
}
func formatOptNamesForHelp(o *opt) string {
short, long := "", ""
for _, n := range o.names {
if len(n) == 2 && short == "" {
short = n
}
if len(n) > 2 && long == "" {
long = n
}
}
switch {
case short != "" && long != "":
return fmt.Sprintf("%s, %s", short, long)
case short != "":
return fmt.Sprintf("%s", short)
case long != "":
// 2 spaces instead of the short option (-x), one space for the comma (,) and one space for the after comma blank
return fmt.Sprintf(" %s", long)
default:
return ""
}
}
func formatValueForHelp(hide bool, v flag.Value) string {
if hide {
return ""
}
if dv, ok := v.(defaultValued); ok {
if dv.IsDefault() {
return ""
}
}
return fmt.Sprintf("(default %s)", v.String())
}
func formatEnvVarsForHelp(envVars string) string {
if strings.TrimSpace(envVars) == "" {
return ""
}
vars := strings.Fields(envVars)
res := "(env"
sep := " "
for i, v := range vars {
if i > 0 {
sep = ", "
}
res += fmt.Sprintf("%s$%s", sep, v)
}
res += ")"
return res
}
func (c *Cmd) parse(args []string, entry, inFlow, outFlow *step) error {
if c.helpRequested(args) {
c.PrintLongHelp()
c.onError(errHelpRequested)
return nil
}
nargsLen := c.getOptsAndArgs(args)
if err := c.fsm.parse(args[:nargsLen]); err != nil {
fmt.Fprintf(stdErr, "Error: %s\n", err.Error())
c.PrintHelp()
c.onError(err)
return err
}
newInFlow := &step{
do: c.Before,
error: outFlow,
desc: fmt.Sprintf("%s.Before", c.name),
}
inFlow.success = newInFlow
newOutFlow := &step{
do: c.After,
success: outFlow,
error: outFlow,
desc: fmt.Sprintf("%s.After", c.name),
}
args = args[nargsLen:]
if len(args) == 0 {
if c.Action != nil {
newInFlow.success = &step{
do: c.Action,
success: newOutFlow,
error: newOutFlow,
desc: fmt.Sprintf("%s.Action", c.name),
}
entry.run(nil)
return nil
}
c.PrintHelp()
c.onError(nil)
return nil
}
arg := args[0]
for _, sub := range c.commands {
if sub.isAlias(arg) {
if err := sub.doInit(); err != nil {
panic(err)
}
return sub.parse(args[1:], entry, newInFlow, newOutFlow)
}
}
var err error
switch {
case strings.HasPrefix(arg, "-"):
err = fmt.Errorf("Error: illegal option %s", arg)
fmt.Fprintln(stdErr, err.Error())
default:
err = fmt.Errorf("Error: illegal input %s", arg)
fmt.Fprintln(stdErr, err.Error())
}
c.PrintHelp()
c.onError(err)
return err
}
func (c *Cmd) helpRequested(args []string) bool {
return c.isFlagSet(args, []string{"-h", "--help"})
}
func (c *Cmd) isFlagSet(args []string, searchArgs []string) bool {
if len(args) == 0 {
return false
}
arg := args[0]
for _, searchArg := range searchArgs {
if arg == searchArg {
return true
}
}
return false
}
func (c *Cmd) getOptsAndArgs(args []string) int {
consumed := 0
for _, arg := range args {
for _, sub := range c.commands {
if sub.isAlias(arg) {
return consumed
}
}
consumed++
}
return consumed
}
func (c *Cmd) isAlias(arg string) bool {
for _, alias := range c.aliases {
if arg == alias {
return true
}
}
return false
}

518
vendor/github.com/jawher/mow.cli/doc.go generated vendored Normal file
View File

@ -0,0 +1,518 @@
/*
Package cli provides a framework to build command line applications in Go with most of the burden of arguments parsing and validation
placed on the framework instead of the user.
Basics
You start by creating an application by passing a name and a description:
cp = cli.App("cp", "Copy files around")
To attach the code to execute when the app is launched, assign a function to the Action field:
cp.Action = func() {
fmt.Printf("Hello world\n")
}
Finally, in your main func, call Run on the app:
cp.Run(os.Args)
Options
To add a (global) option, call one of the (String[s]|Int[s]|Bool)Opt methods on the app:
recursive := cp.BoolOpt("R recursive", false, "recursively copy the src to dst")
* The first argument is a space separated list of names for the option without the dashes
* The second parameter is the default value for the option
* The third parameter is the option description, as will be shown in the help messages
There is also a second set of methods Bool, String, Int, Strings and Ints, which accepts a struct describing the option:
recursive = cp.Bool(BoolOpt{
Name: "R",
Value: false,
Desc: "copy src files recursively",
EnvVar: "",
})
There EnvVar field is a space separated list of environment variables names to be used to initialize the option.
The result is a pointer to a value which will be populated after parsing the command line arguments.
You can access the values in the Action func.
In the command line, mow.cli accepts the following syntaxes
* For boolean options:
-f : a single dash for the one letter names
-f=false : a single dash for the one letter names, equal sign followed by true or false
--force : double dash for longer option names
-it : mow.cli supports option folding, this is equivalent to: -i -t
* For string, int options:
-e=value : single dash for one letter names, equal sign followed by the value
-e value : single dash for one letter names, space followed by the value
-Ivalue : single dash for one letter names immediately followed by the value
--extra=value : double dash for longer option names, equal sign followed by the value
--extra value : double dash for longer option names, space followed by the value
* For slice options (StringsOpt, IntsOpt): repeat the option to accumulate the values in the resulting slice:
-e PATH:/bin -e PATH:/usr/bin : resulting slice contains ["/bin", "/usr/bin"]
Arguments
To accept arguments, you need to explicitly declare them by calling one of the (String[s]|Int[s]|Bool)Arg methods on the app:
src := cp.StringArg("SRC", "", "the file to copy")
dst := cp.StringArg("DST", "", "the destination")
* The first argument is the argument name as will be shown in the help messages
* The second parameter is the default value for the argument
* The third parameter is the argument description, as will be shown in the help messages
There is also a second set of methods Bool, String, Int, Strings and Ints, which accepts structs describing the argument:
src = cp.Strings(StringsArg{
Name: "SRC",
Desc: "The source files to copy",
Value: "",
EnvVar: "",
SetByUser: &srcSetByUser,
})
The Value field is where you can set the initial value for the argument.
EnvVar accepts a space separated list of environment variables names to be used to initialize the argument.
If SetByUser is specified (by passing a pointer to a bool variable), it will be set to true only if the user explicitly sets the argument.
The result is a pointer to a value that will be populated after parsing the command line arguments.
You can access the values in the Action func.
Operators
The -- operator marks the end of options.
Everything that follow will be treated as an argument,
even if starts with a dash.
For example, given the touch command which takes a filename as an argument (and possibly other options):
file := cp.StringArg("FILE", "", "the file to create")
If we try to create a file named -f this way:
touch -f
Would fail, because -f will be parsed as an option not as an argument.
The fix is to prefix the filename with the -- operator:
touch -- -f
Commands
mow.cli supports nesting commands and sub commands.
Declare a top level command by calling the Command func on the app struct, and a sub command by calling
the Command func on the command struct:
docker := cli.App("docker", "A self-sufficient runtime for linux containers")
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
// initialize the run command here
})
* The first argument is the command name, as will be shown in the help messages and as will need to be input by the user in the command line to call the command
* The second argument is the command description as will be shown in the help messages
* The third argument is a CmdInitializer, a function that receives a pointer to a Cmd struct representing the command.
In this function, you can add options and arguments by calling the same methods as you would with an app struct (BoolOpt, StringArg, ...).
You would also assign a function to the Action field of the Cmd struct for it to be executed when the command is invoked.
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
detached := cmd.BoolOpt("d detach", false, "Detached mode: run the container in the background and print the new container ID")
memory := cmd.StringOpt("m memory", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
image := cmd.StringArg("IMAGE", "", "The image to run")
cmd.Action = func() {
if *detached {
//do something
}
runContainer(*image, *detached, *memory)
}
})
You can also add sub commands by calling Command on the Cmd struct:
bzk.Command("job", "actions on jobs", func(cmd *cli.Cmd) {
cmd.Command("list", "list jobs", listJobs)
cmd.Command("start", "start a new job", startJob)
cmd.Command("log", "show a job log", nil)
})
This could go on to any depth if need be.
mow.cli also supports command aliases. For example:
app.Command("start run r", "start doing things", cli.ActionCommand(func() { start() }))
will alias `start`, `run`, and `r` to the same action. Aliases also work for
subcommands:
app.Command("job j", "actions on jobs", func(cmd *cli.Cmd) {
cmd.Command("list ls", "list jobs", func(cmd *cli.Cmd) {
cmd.Action = func() {
list()
}
})
})
which then allows you to invoke the subcommand as `app job list`, `app job ls`,
`app j ls`, or `app j list`.
As a side-note: it may seem a bit weird the way mow.cli uses a function to initialize a command
instead of just returning the command struct.
The motivation behind this choice is scoping: as with the standard flag package, adding an option or an argument
returns a pointer to a value which will be populated when the app is run.
Since you'll want to store these pointers in variables, and to avoid having dozens of them in the same scope (the main func for example or as global variables),
mow.cli's API was specifically tailored to take a func parameter (called CmdInitializer) which accepts the command struct.
This way, the command specific variables scope is limited to this function.
Custom types
Out of the box, mow.cli supports the following types for options and arguments: bool, string, int, strings (slice of strings) and ints (slice of ints)
You can however extend mow.cli to handle other types, e.g. `time.Duration`, `float64`, or even your own struct types for example.
To do so, you'll need to:
* implement the `flag.Value` interface for the custom type
* declare the option or the flag using `VarOpt`, `VarArg` for the short hands, and `Var` for the full form.
Here's an example:
// Declare your type
type Duration time.Duration
// Make it implement flag.Value
func (d *Duration) Set(v string) error {
parsed, err := time.ParseDuration(v)
if err != nil {
return err
}
*d = Duration(parsed)
return nil
}
func (d *Duration) String() string {
duration := time.Duration(*d)
return duration.String()
}
func main() {
duration := Duration(0)
app := App("var", "")
app.VarArg("DURATION", &duration, "")
app.Run([]string{"cp", "1h31m42s"})
}
Boolean custom types
To make your custom type behave as a boolean option, i.e. doesn't take a value, it has to implement a IsBoolFlag method that returns true:
type BoolLike int
func (d *BoolLike) IsBoolFlag() bool {
return true
}
Multi-valued custom type
To make your custom type behave as a multi-valued option or argument, i.e. takes multiple values,
it has to implement a `Clear` method which will be called whenever the values list needs to be cleared,
e.g. when the value was initially populated from an environment variable, and then explicitly set from the CLI:
type Durations []time.Duration
// Make it implement flag.Value
func (d *Durations) Set(v string) error {
parsed, err := time.ParseDuration(v)
if err != nil {
return err
}
*d = append(*d, Duration(parsed))
return nil
}
func (d *Durations) String() string {
return fmt.Sprintf("%v", *d)
}
// Make it multi-valued
func (d *Durations) Clear() {
*d = []Duration{}
}
Interceptors
It is possible to define snippets of code to be executed before and after a command or any of its sub commands is executed.
For example, given an app with multiple commands but with a global flag which toggles a verbose mode:
app := cli.App("app", "bla bla")
verbose := app.Bool(cli.BoolOpt{
Name: "verbose",
Value: false,
Desc: "Enable debug logs",
})
app.Command("command1", "...", func(cmd *cli.Cmd) {
})
app.Command("command2", "...", func(cmd *cli.Cmd) {
})
Instead of repeating yourself by checking if the verbose flag is set or not, and setting the debug level in every command (and its sub-commands),
a before interceptor can be set on the `app` instead:
app.Before = func() {
if (*verbose) {
logrus.SetLevel(logrus.DebugLevel)
}
}
Whenever a valid command is called by the user, all the before interceptors defined on the app and the intermediate commands
will be called, in order from the root to the leaf.
Similarly, if you need to execute a code snippet after a command has been called, e.g. to cleanup resources allocated in before interceptors,
simply set the After field of the app struct or any other command.
After interceptors will be called, in order from the leaf up to the root (the opposite order of the Before interceptors).
Here's a diagram which shows in when and in which order multiple Before and After interceptors get executed:
+------------+ success +------------+ success +----------------+ success
| app.Before +---------------> cmd.Before +-------------> sub_cmd.Before +---------+
+------------+ +-+----------+ +--+-------------+ |
| | +-v-------+
error | error | | sub_cmd |
+-----------------------+ +-----------------------+ | Action |
| | +-+-------+
+------v-----+ +-----v------+ +----------------+ |
| app.After <---------------+ cmd.After <-------------+ sub_cmd.After <---------+
+------------+ always +------------+ always +----------------+ always
Spec
An app or command's call syntax can be customized using spec strings.
This can be useful to indicate that an argument is optional for example, or that 2 options are mutually exclusive.
You can set a spec string on:
* The app: to configure the syntax for global options and arguments
* A command: to configure the syntax for that command's options and arguments
In both cases, a spec string is assigned to the Spec field:
cp := cli.App("cp", "Copy files around")
cp.Spec = "[-R [-H | -L | -P]]"
And:
docker := cli.App("docker", "A self-sufficient runtime for linux containers")
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
cmd.Spec = "[-d|--rm] IMAGE [COMMAND [ARG...]]"
:
:
}
The spec syntax is mostly based on the conventions used in POSIX command line apps help messages and man pages:
Options
You can use both short and long option names in spec strings:
x.Spec="-f"
And:
x.Spec="--force"
In both cases, we required that the f or force flag be set
Any option you reference in a spec string MUST be explicitly declared, otherwise mow.cli will panic:
x.BoolOpt("f force", ...)
Arguments
Arguments are all-uppercased words:
x.Spec="SRC DST"
This spec string will force the user to pass exactly 2 arguments, SRC and DST
Any argument you reference in a spec string MUST be explicitly declared, otherwise mow.cli will panic:
x.StringArg("SRC", ...)
x.StringArg("DST", ...)
Ordering
Except for options, The order of the elements in a spec string is respected and enforced when parsing the command line arguments:
x.Spec = "-f -g SRC -h DST"
Consecutive options (-f and -g for example) get parsed regardless of the order they are specified in (both "-f=5 -g=6" and "-g=6 -f=5" are valid).
Order between options and arguments is significant (-f and -g must appear before the SRC argument).
Same goes for arguments, where SRC must appear before DST.
Optionality
You can mark items as optional in a spec string by enclosing them in square brackets :[...]
x.Spec = "[-x]"
Choice
You can use the | operator to indicate a choice between two or more items
x.Spec = "--rm | --daemon"
x.Spec = "-H | -L | -P"
x.Spec = "-t | DST"
Repetition
You can use the ... postfix operator to mark an element as repeatable:
x.Spec="SRC..."
x.Spec="-e..."
Grouping
You can group items using parenthesis. This is useful in combination with the choice and repetition operators (| and ...):
x.Spec = "(-e COMMAND)... | (-x|-y)"
The parenthesis in the example above serve to mark that it is the sequence of a -e flag followed by an argument that is repeatable, and that
all that is mutually exclusive to a choice between -x and -y options.
Option group
This is a shortcut to declare a choice between multiple options:
x.Spec = "-abcd"
Is equivalent to:
x.Spec = "(-a | -b | -c | -d)..."
I.e. any combination of the listed options in any order, with at least one option.
All options
Another shortcut:
x.Spec = "[OPTIONS]"
This is a special syntax (the square brackets are not for marking an optional item, and the uppercased word is not for an argument).
This is equivalent to a repeatable choice between all the available options.
For example, if an app or a command declares 4 options a, b, c and d, [OPTIONS] is equivalent to
x.Spec = "[-a | -b | -c | -d]..."
Inline option values
You can use the =<some-text> notation right after an option (long or short form) to give an inline description or value.
An example:
x.Spec = "[ -a=<absolute-path> | --timeout=<in seconds> ] ARG"
The inline values are ignored by the spec parser and are just there for the final user as a contextual hint.
Operators
The `--` operator can be used in a spec string to automatically treat everything following it as an options.
In other words, placing a `--` in the spec string automatically inserts a `--` in the same position in the program call arguments.
This lets you write programs like the `time` utility for example:
x.Spec = "time -lp [-- CMD [ARG...]]"
Spec Grammar
Here's the EBNF grammar for the Specs language:
spec -> sequence
sequence -> choice*
req_sequence -> choice+
choice -> atom ('|' atom)*
atom -> (shortOpt | longOpt | optSeq | allOpts | group | optional) rep?
shortOp -> '-' [A-Za-z]
longOpt -> '--' [A-Za-z][A-Za-z0-9]*
optSeq -> '-' [A-Za-z]+
allOpts -> '[OPTIONS]'
group -> '(' req_sequence ')'
optional -> '[' req_sequence ']'
rep -> '...'
And that's it for the spec language.
You can combine these few building blocks in any way you want (while respecting the grammar above) to construct sophisticated validation constraints
(don't go too wild though).
Behind the scenes, mow.cli parses the spec string and constructs a finite state machine to be used to parse the command line arguments.
mow.cli also handles backtracking, and so it can handle tricky cases, or what I like to call "the cp test"
cp SRC... DST
Without backtracking, this deceptively simple spec string cannot be parsed correctly.
For instance, docopt can't handle this case, whereas mow.cli does.
Default spec
By default, and unless a spec string is set by the user, mow.cli auto-generates one for the app and every command using this logic:
* Start with an empty spec string
* If at least one option was declared, append "[OPTIONS]" to the spec string
* For every declared argument, append it, in the order of declaration, to the spec string
For example, given this command declaration:
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
detached := cmd.BoolOpt("d detach", false, "Detached mode: run the container in the background and print the new container ID")
memory := cmd.StringOpt("m memory", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")
image := cmd.StringArg("IMAGE", "", "")
args := cmd.StringsArg("ARG", "", "")
})
The auto-generated spec string would be:
[OPTIONS] IMAGE ARG
Which should suffice for simple cases. If not, the spec string has to be set explicitly.
Exiting
mow.cli provides the Exit function which accepts an exit code and exits the app with the provided code.
You are highly encouraged to call cli.Exit instead of os.Exit for the After interceptors to be executed.
*/
package cli

10
vendor/github.com/jawher/mow.cli/errors.go generated vendored Normal file
View File

@ -0,0 +1,10 @@
package cli
import (
"errors"
)
var (
errHelpRequested = errors.New("Help requested")
errVersionRequested = errors.New("Version requested")
)

149
vendor/github.com/jawher/mow.cli/examples_test.go generated vendored Normal file
View File

@ -0,0 +1,149 @@
package cli
import (
"fmt"
"os"
"time"
)
func Example_greet() {
app := App("greet", "Greet")
app.Spec = "[NAME]"
name := app.String(StringArg{Name: "NAME", Value: "stranger", Desc: "Your name", EnvVar: "USER"})
app.Action = func() {
fmt.Printf("Hello %s\n", *name)
}
app.Run(os.Args)
}
func Example_cp() {
cp := App("cp", "Copy files around")
cp.Spec = "[-R [-H | -L | -P]] [-fi | -n] SRC... DST"
var (
recursive = cp.Bool(BoolOpt{
Name: "R",
Value: false,
Desc: "copy src files recursively",
})
followSymbolicCL = cp.Bool(BoolOpt{Name: "H", Value: false, Desc: "If the -R option is specified, symbolic links on the command line are followed. (Symbolic links encountered in the tree traversal are not followed.)"})
followSymbolicTree = cp.Bool(BoolOpt{Name: "L", Value: false, Desc: "If the -R option is specified, all symbolic links are followed."})
followSymbolicNo = cp.Bool(BoolOpt{Name: "P", Value: true, Desc: "If the -R option is specified, no symbolic links are followed. This is the default."})
force = cp.Bool(BoolOpt{Name: "f", Value: false, Desc: "If the destination file cannot be opened, remove it and create a new file, without prompting for confirmation regardless of its permissions. (The -f option overrides any previous -n option.)"})
interactive = cp.Bool(BoolOpt{Name: "i", Value: false, Desc: "Cause cp to write a prompt to the standard error output before copying a file that would overwrite an existing file. If the response from the standard input begins with the character `y' or `Y', the file copy is attempted. (The -i option overrides any previous -n option.)"})
noOverwrite = cp.Bool(BoolOpt{Name: "f", Value: false, Desc: "Do not overwrite an existing file. (The -n option overrides any previous -f or -i options.)"})
)
var (
src = cp.Strings(StringsArg{
Name: "SRC",
Desc: "The source files to copy",
})
dst = cp.Strings(StringsArg{Name: "DST", Value: nil, Desc: "The destination directory"})
)
cp.Action = func() {
fmt.Printf(`copy:
SRC: %v
DST: %v
recursive: %v
follow links (CL, Tree, No): %v %v %v
force: %v
interactive: %v
no overwrite: %v`,
*src, *dst, *recursive,
*followSymbolicCL, *followSymbolicTree, *followSymbolicNo,
*force,
*interactive,
*noOverwrite)
}
cp.Run(os.Args)
}
func Example_docker() {
docker := App("docker", "A self-sufficient runtime for linux containers")
docker.Command("run", "Run a command in a new container", func(cmd *Cmd) {
cmd.Spec = "[-d|--rm] IMAGE [COMMAND [ARG...]]"
var (
detached = cmd.Bool(BoolOpt{Name: "d detach", Value: false, Desc: "Detached mode: run the container in the background and print the new container ID"})
rm = cmd.Bool(BoolOpt{Name: "rm", Value: false, Desc: "Automatically remove the container when it exits (incompatible with -d)"})
memory = cmd.String(StringOpt{Name: "m memory", Value: "", Desc: "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)"})
)
var (
image = cmd.String(StringArg{Name: "IMAGE", Value: "", Desc: ""})
command = cmd.String(StringArg{Name: "COMMAND", Value: "", Desc: "The command to run"})
args = cmd.Strings(StringsArg{Name: "ARG", Value: nil, Desc: "The command arguments"})
)
cmd.Action = func() {
var how string
switch {
case *detached:
how = "detached"
case *rm:
how = "rm after"
default:
how = "--"
}
fmt.Printf("Run image %s, command %s, args %v, how? %v, mem %s", *image, *command, *args, how, *memory)
}
})
docker.Command("pull", "Pull an image or a repository from the registry", func(cmd *Cmd) {
cmd.Spec = "[-a] NAME"
all := cmd.Bool(BoolOpt{Name: "a all-tags", Value: false, Desc: "Download all tagged images in the repository"})
name := cmd.String(StringArg{Name: "NAME", Value: "", Desc: "Image name (optionally NAME:TAG)"})
cmd.Action = func() {
if *all {
fmt.Printf("Download all tags for image %s", *name)
return
}
fmt.Printf("Download image %s", *name)
}
})
docker.Run(os.Args)
}
func Example_beforeAfter() {
app := App("app", "App")
bench := app.BoolOpt("b bench", false, "Measure execution time")
var t0 time.Time
app.Before = func() {
if *bench {
t0 = time.Now()
}
}
app.After = func() {
if *bench {
d := time.Since(t0)
fmt.Printf("Command execution took: %vs", d.Seconds())
}
}
app.Command("cmd1", "first command", func(cmd *Cmd) {
cmd.Action = func() {
fmt.Print("Running command 1")
}
})
app.Command("cmd2", "second command", func(cmd *Cmd) {
cmd.Action = func() {
fmt.Print("Running command 2")
}
})
app.Run(os.Args)
}

View File

@ -0,0 +1,43 @@
package cli_test
import (
"fmt"
cli "github.com/jawher/mow.cli"
)
// Declare your type
type Counter int
// Make it implement flag.Value
func (c *Counter) Set(v string) error {
*c++
return nil
}
func (c *Counter) String() string {
return fmt.Sprintf("%d", *c)
}
// Make it a bool option
func (c *Counter) IsBoolFlag() bool {
return true
}
func ExampleVarOpt() {
app := cli.App("var", "Var opt example")
// Declare a variable of your type
verbosity := Counter(0)
// Call one of the Var methods (arg, opt, ...) to declare your custom type
app.VarOpt("v", &verbosity, "verbosity level")
app.Action = func() {
// The variable will be populated after the app is ran
fmt.Print(verbosity)
}
app.Run([]string{"app", "-vvvvv"})
// Output: 5
}

View File

@ -0,0 +1,44 @@
package cli_test
import (
"fmt"
"time"
cli "github.com/jawher/mow.cli"
)
// Declare your type
type Duration time.Duration
// Make it implement flag.Value
func (d *Duration) Set(v string) error {
parsed, err := time.ParseDuration(v)
if err != nil {
return err
}
*d = Duration(parsed)
return nil
}
func (d *Duration) String() string {
duration := time.Duration(*d)
return duration.String()
}
func ExampleVarArg() {
app := cli.App("var", "Var arg example")
// Declare a variable of your type
duration := Duration(0)
// Call one of the Var methods (arg, opt, ...) to declare your custom type
app.VarArg("DURATION", &duration, "")
app.Action = func() {
// The variable will be populated after the app is ran
fmt.Print(time.Duration(duration))
}
app.Run([]string{"cp", "1h31m42s"})
// Output: 1h31m42s
}

68
vendor/github.com/jawher/mow.cli/flow.go generated vendored Normal file
View File

@ -0,0 +1,68 @@
package cli
import (
"fmt"
"strings"
)
type step struct {
do func()
success *step
error *step
desc string
}
func (s *step) run(p interface{}) {
s.callDo(p)
switch {
case s.success != nil:
s.success.run(p)
case p == nil:
return
default:
if code, ok := p.(exit); ok {
exiter(int(code))
return
}
panic(p)
}
}
func (s *step) callDo(p interface{}) {
if s.do == nil {
return
}
defer func() {
if e := recover(); e != nil {
if s.error == nil {
panic(p)
}
s.error.run(e)
}
}()
s.do()
}
func (s *step) dot() string {
trs := flowDot(s, map[*step]bool{})
return fmt.Sprintf("digraph G {\n\trankdir=LR\n%s\n}\n", strings.Join(trs, "\n"))
}
func flowDot(s *step, visited map[*step]bool) []string {
res := []string{}
if visited[s] {
return res
}
visited[s] = true
if s.success != nil {
res = append(res, fmt.Sprintf("\t\"%s\" -> \"%s\" [label=\"ok\"]", s.desc, s.success.desc))
res = append(res, flowDot(s.success, visited)...)
}
if s.error != nil {
res = append(res, fmt.Sprintf("\t\"%s\" -> \"%s\" [label=\"ko\"]", s.desc, s.error.desc))
res = append(res, flowDot(s.error, visited)...)
}
return res
}

236
vendor/github.com/jawher/mow.cli/flow_test.go generated vendored Normal file
View File

@ -0,0 +1,236 @@
package cli
import (
"github.com/stretchr/testify/require"
"testing"
)
func TestStepCallsDo(t *testing.T) {
called := false
step := &step{
do: func() {
called = true
},
}
step.run(nil)
require.True(t, called, "Step's do wasn't called")
}
func TestStepCallsSuccessAfterDo(t *testing.T) {
calls := 0
step := &step{
do: func() {
require.Equal(t, 0, calls, "Do should be called first")
calls++
},
success: &step{
do: func() {
require.Equal(t, 1, calls, "Success should be called second")
calls++
},
},
error: &step{
do: func() {
t.Fatalf("Error should not have been called")
},
},
}
step.run(nil)
require.Equal(t, 2, calls, "Both do and success should be called")
}
func TestStepCallsErrorIfDoPanics(t *testing.T) {
defer func() { recover() }()
calls := 0
step := &step{
do: func() {
require.Equal(t, 0, calls, "Do should be called first")
calls++
panic(42)
},
success: &step{
do: func() {
t.Fatalf("Success should not have been called")
},
},
error: &step{
do: func() {
require.Equal(t, 1, calls, "Error should be called second")
calls++
},
},
}
step.run(nil)
require.Equal(t, 2, calls, "Both do and error should be called")
}
func TestStepCallsOsExitIfAskedTo(t *testing.T) {
exitCalled := false
defer exitShouldBeCalledWith(t, 42, &exitCalled)()
step := &step{}
step.run(exit(42))
require.True(t, exitCalled, "should have called exit")
}
func TestStepRethrowsPanic(t *testing.T) {
defer func() {
require.Equal(t, 42, recover(), "should panicked with the same value")
}()
step := &step{}
step.run(42)
t.Fatalf("Should have panicked")
}
func TestStepShouldNopIfNoSuccessNorPanic(t *testing.T) {
defer exitShouldNotCalled(t)()
step := &step{}
step.run(nil)
}
func TestBeforeAndAfterFlowOrder(t *testing.T) {
counter := 0
app := App("app", "")
app.Before = callChecker(t, 0, &counter)
app.Command("c", "", func(c *Cmd) {
c.Before = callChecker(t, 1, &counter)
c.Command("cc", "", func(cc *Cmd) {
cc.Before = callChecker(t, 2, &counter)
cc.Action = callChecker(t, 3, &counter)
cc.After = callChecker(t, 4, &counter)
})
c.After = callChecker(t, 5, &counter)
})
app.After = callChecker(t, 6, &counter)
app.Run([]string{"app", "c", "cc"})
require.Equal(t, 7, counter)
}
func TestBeforeAndAfterFlowOrderWhenOneBeforePanics(t *testing.T) {
defer func() {
recover()
}()
counter := 0
app := App("app", "")
app.Before = callChecker(t, 0, &counter)
app.Command("c", "", func(c *Cmd) {
c.Before = callChecker(t, 1, &counter)
c.Command("cc", "", func(cc *Cmd) {
cc.Before = callCheckerAndPanic(t, 42, 2, &counter)
cc.Action = func() {
t.Fatalf("should not have been called")
}
cc.After = func() {
t.Fatalf("should not have been called")
}
})
c.After = callChecker(t, 3, &counter)
})
app.After = callChecker(t, 4, &counter)
app.Run([]string{"app", "c", "cc"})
require.Equal(t, 5, counter)
}
func TestBeforeAndAfterFlowOrderWhenOneAfterPanics(t *testing.T) {
defer func() {
e := recover()
require.Equal(t, 42, e)
}()
counter := 0
app := App("app", "")
app.Before = callChecker(t, 0, &counter)
app.Command("c", "", func(c *Cmd) {
c.Before = callChecker(t, 1, &counter)
c.Command("cc", "", func(cc *Cmd) {
cc.Before = callChecker(t, 2, &counter)
cc.Action = callChecker(t, 3, &counter)
cc.After = callCheckerAndPanic(t, 42, 4, &counter)
})
c.After = callChecker(t, 5, &counter)
})
app.After = callChecker(t, 6, &counter)
app.Run([]string{"app", "c", "cc"})
require.Equal(t, 7, counter)
}
func TestBeforeAndAfterFlowOrderWhenMultipleAftersPanic(t *testing.T) {
defer func() {
e := recover()
require.Equal(t, 666, e)
}()
counter := 0
app := App("app", "")
app.Before = callChecker(t, 0, &counter)
app.Command("c", "", func(c *Cmd) {
c.Before = callChecker(t, 1, &counter)
c.Command("cc", "", func(cc *Cmd) {
cc.Before = callChecker(t, 2, &counter)
cc.Action = callChecker(t, 3, &counter)
cc.After = callCheckerAndPanic(t, 42, 4, &counter)
})
c.After = callChecker(t, 5, &counter)
})
app.After = callCheckerAndPanic(t, 666, 6, &counter)
app.Run([]string{"app", "c", "cc"})
require.Equal(t, 7, counter)
}
func TestCommandAction(t *testing.T) {
called := false
app := App("app", "")
app.Command("a", "", ActionCommand(func() { called = true }))
app.Run([]string{"app", "a"})
require.True(t, called, "commandAction should be called")
}
func callChecker(t *testing.T, wanted int, counter *int) func() {
return func() {
t.Logf("checker: wanted: %d, got %d", wanted, *counter)
require.Equal(t, wanted, *counter)
*counter++
}
}
func callCheckerAndPanic(t *testing.T, panicValue interface{}, wanted int, counter *int) func() {
return func() {
t.Logf("checker: wanted: %d, got %d", wanted, *counter)
require.Equal(t, wanted, *counter)
*counter++
panic(panicValue)
}
}

254
vendor/github.com/jawher/mow.cli/fsm.go generated vendored Normal file
View File

@ -0,0 +1,254 @@
package cli
import (
"sort"
"strings"
"fmt"
)
type state struct {
id int
terminal bool
transitions transitions
cmd *Cmd
}
type transition struct {
matcher upMatcher
next *state
}
type transitions []*transition
func (t transitions) Len() int { return len(t) }
func (t transitions) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t transitions) Less(i, j int) bool {
a, _ := t[i].matcher, t[j].matcher
switch a.(type) {
case upShortcut:
return false
case upOptsEnd:
return false
case *arg:
return false
default:
return true
}
}
var _id = 0
func newState(cmd *Cmd) *state {
_id++
return &state{_id, false, []*transition{}, cmd}
}
func (s *state) t(matcher upMatcher, next *state) *state {
s.transitions = append(s.transitions, &transition{matcher, next})
return next
}
func (s *state) has(tr *transition) bool {
for _, t := range s.transitions {
if t.next == tr.next && t.matcher == tr.matcher {
return true
}
}
return false
}
func incoming(s, into *state, visited map[*state]bool) []*transition {
res := []*transition{}
if visited[s] {
return res
}
visited[s] = true
for _, tr := range s.transitions {
if tr.next == into {
res = append(res, tr)
}
res = append(res, incoming(tr.next, into, visited)...)
}
return res
}
func removeTransitionAt(idx int, arr transitions) transitions {
res := make([]*transition, len(arr)-1)
copy(res, arr[:idx])
copy(res[idx:], arr[idx+1:])
return res
}
func (s *state) simplify() {
simplify(s, s, map[*state]bool{})
}
func simplify(start, s *state, visited map[*state]bool) {
if visited[s] {
return
}
visited[s] = true
for _, tr := range s.transitions {
simplify(start, tr.next, visited)
}
for s.simplifySelf(start) {
}
}
func (s *state) simplifySelf(start *state) bool {
for idx, tr := range s.transitions {
if _, ok := tr.matcher.(upShortcut); ok {
next := tr.next
s.transitions = removeTransitionAt(idx, s.transitions)
for _, tr := range next.transitions {
if !s.has(tr) {
s.transitions = append(s.transitions, tr)
}
}
if next.terminal {
s.terminal = true
}
return true
}
}
return false
}
func (s *state) dot() string {
trs := dot(s, map[*state]bool{})
return fmt.Sprintf("digraph G {\n\trankdir=LR\n%s\n}\n", strings.Join(trs, "\n"))
}
func dot(s *state, visited map[*state]bool) []string {
res := []string{}
if visited[s] {
return res
}
visited[s] = true
for _, tr := range s.transitions {
res = append(res, fmt.Sprintf("\tS%d -> S%d [label=\"%v\"]", s.id, tr.next.id, tr.matcher))
res = append(res, dot(tr.next, visited)...)
}
if s.terminal {
res = append(res, fmt.Sprintf("\tS%d [peripheries=2]", s.id))
}
return res
}
type parseContext struct {
args map[*arg][]string
opts map[*opt][]string
excludedOpts map[*opt]struct{}
rejectOptions bool
}
func newParseContext() parseContext {
return parseContext{
args: map[*arg][]string{},
opts: map[*opt][]string{},
excludedOpts: map[*opt]struct{}{},
rejectOptions: false,
}
}
func (pc parseContext) merge(o parseContext) {
for k, vs := range o.args {
pc.args[k] = append(pc.args[k], vs...)
}
for k, vs := range o.opts {
pc.opts[k] = append(pc.opts[k], vs...)
}
}
func (s *state) parse(args []string) error {
pc := newParseContext()
ok, err := s.apply(args, pc)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("incorrect usage")
}
for opt, vs := range pc.opts {
if multiValued, ok := opt.value.(multiValued); ok {
multiValued.Clear()
opt.valueSetFromEnv = false
}
for _, v := range vs {
if err := opt.value.Set(v); err != nil {
return err
}
}
if opt.valueSetByUser != nil {
*opt.valueSetByUser = true
}
}
for arg, vs := range pc.args {
if multiValued, ok := arg.value.(multiValued); ok {
multiValued.Clear()
arg.valueSetFromEnv = false
}
for _, v := range vs {
if err := arg.value.Set(v); err != nil {
return err
}
}
if arg.valueSetByUser != nil {
*arg.valueSetByUser = true
}
}
return nil
}
func (s *state) apply(args []string, pc parseContext) (bool, error) {
if s.terminal && len(args) == 0 {
return true, nil
}
sort.Sort(s.transitions)
if len(args) > 0 {
arg := args[0]
if !pc.rejectOptions && arg == "--" {
pc.rejectOptions = true
args = args[1:]
}
}
type match struct {
tr *transition
rem []string
pc parseContext
}
matches := []*match{}
for _, tr := range s.transitions {
fresh := newParseContext()
fresh.rejectOptions = pc.rejectOptions
if ok, rem := tr.matcher.match(args, &fresh); ok {
matches = append(matches, &match{tr, rem, fresh})
}
}
for _, m := range matches {
ok, err := m.tr.next.apply(m.rem, m.pc)
if err != nil {
return false, err
}
if ok {
pc.merge(m.pc)
return true, nil
}
}
return false, nil
}

73
vendor/github.com/jawher/mow.cli/helper_test.go generated vendored Normal file
View File

@ -0,0 +1,73 @@
package cli
import (
"testing"
"bytes"
"io/ioutil"
"github.com/stretchr/testify/require"
)
func exitShouldBeCalledWith(t *testing.T, wantedExitCode int, called *bool) func() {
oldExiter := exiter
exiter = func(code int) {
require.Equal(t, wantedExitCode, code, "unwanted exit code")
*called = true
}
return func() { exiter = oldExiter }
}
func exitShouldNotCalled(t *testing.T) func() {
oldExiter := exiter
exiter = func(code int) {
t.Errorf("exit should not have been called")
}
return func() { exiter = oldExiter }
}
func suppressOutput() func() {
return captureAndRestoreOutput(nil, nil)
}
func captureAndRestoreOutput(out, err *string) func() {
oldStdOut := stdOut
oldStdErr := stdErr
if out == nil {
stdOut = ioutil.Discard
} else {
stdOut = trapWriter(out)
}
if err == nil {
stdErr = ioutil.Discard
} else {
stdErr = trapWriter(err)
}
return func() {
stdOut = oldStdOut
stdErr = oldStdErr
}
}
func trapWriter(writeTo *string) *writerTrap {
return &writerTrap{
buffer: bytes.NewBuffer(nil),
writeTo: writeTo,
}
}
type writerTrap struct {
buffer *bytes.Buffer
writeTo *string
}
func (w *writerTrap) Write(p []byte) (n int, err error) {
n, err = w.buffer.Write(p)
if err == nil {
*(w.writeTo) = w.buffer.String()
}
return
}

282
vendor/github.com/jawher/mow.cli/matchers.go generated vendored Normal file
View File

@ -0,0 +1,282 @@
package cli
import (
"fmt"
"strings"
)
type upMatcher interface {
match(args []string, c *parseContext) (bool, []string)
}
type upShortcut bool
func (u upShortcut) match(args []string, c *parseContext) (bool, []string) {
return true, args
}
func (u upShortcut) String() string {
return "*"
}
type upOptsEnd bool
func (u upOptsEnd) match(args []string, c *parseContext) (bool, []string) {
c.rejectOptions = true
return true, args
}
func (u upOptsEnd) String() string {
return "--"
}
const (
shortcut = upShortcut(true)
optsEnd = upOptsEnd(true)
)
func (arg *arg) match(args []string, c *parseContext) (bool, []string) {
if len(args) == 0 {
return false, args
}
if !c.rejectOptions && strings.HasPrefix(args[0], "-") && args[0] != "-" {
return false, args
}
c.args[arg] = append(c.args[arg], args[0])
return true, args[1:]
}
type optMatcher struct {
theOne *opt
optionsIdx map[string]*opt
}
func (o *optMatcher) match(args []string, c *parseContext) (bool, []string) {
if len(args) == 0 || c.rejectOptions {
return o.theOne.valueSetFromEnv, args
}
idx := 0
for idx < len(args) {
arg := args[idx]
switch {
case arg == "-":
idx++
case arg == "--":
return o.theOne.valueSetFromEnv, nil
case strings.HasPrefix(arg, "--"):
matched, consumed, nargs := o.matchLongOpt(args, idx, c)
if matched {
return true, nargs
}
if consumed == 0 {
return o.theOne.valueSetFromEnv, args
}
idx += consumed
case strings.HasPrefix(arg, "-"):
matched, consumed, nargs := o.matchShortOpt(args, idx, c)
if matched {
return true, nargs
}
if consumed == 0 {
return o.theOne.valueSetFromEnv, args
}
idx += consumed
default:
return o.theOne.valueSetFromEnv, args
}
}
return o.theOne.valueSetFromEnv, args
}
func (o *optMatcher) matchLongOpt(args []string, idx int, c *parseContext) (bool, int, []string) {
arg := args[idx]
kv := strings.Split(arg, "=")
name := kv[0]
opt, found := o.optionsIdx[name]
if !found {
return false, 0, args
}
switch {
case len(kv) == 2:
if opt != o.theOne {
return false, 1, args
}
value := kv[1]
c.opts[o.theOne] = append(c.opts[o.theOne], value)
return true, 1, removeStringAt(idx, args)
case opt.isBool():
if opt != o.theOne {
return false, 1, args
}
c.opts[o.theOne] = append(c.opts[o.theOne], "true")
return true, 1, removeStringAt(idx, args)
default:
if len(args[idx:]) < 2 {
return false, 0, args
}
if opt != o.theOne {
return false, 2, args
}
value := args[idx+1]
if strings.HasPrefix(value, "-") {
return false, 0, args
}
c.opts[o.theOne] = append(c.opts[o.theOne], value)
return true, 2, removeStringsBetween(idx, idx+1, args)
}
}
func (o *optMatcher) matchShortOpt(args []string, idx int, c *parseContext) (bool, int, []string) {
arg := args[idx]
if len(arg) < 2 {
return false, 0, args
}
if strings.HasPrefix(arg[2:], "=") {
name := arg[0:2]
opt, _ := o.optionsIdx[name]
if opt == o.theOne {
value := arg[3:]
if value == "" {
return false, 0, args
}
c.opts[o.theOne] = append(c.opts[o.theOne], value)
return true, 1, removeStringAt(idx, args)
}
return false, 1, args
}
rem := arg[1:]
remIdx := 0
for len(rem[remIdx:]) > 0 {
name := "-" + rem[remIdx:remIdx+1]
opt, found := o.optionsIdx[name]
if !found {
return false, 0, args
}
if opt.isBool() {
if opt != o.theOne {
remIdx++
continue
}
c.opts[o.theOne] = append(c.opts[o.theOne], "true")
newRem := rem[:remIdx] + rem[remIdx+1:]
if newRem == "" {
return true, 1, removeStringAt(idx, args)
}
return true, 0, replaceStringAt(idx, "-"+newRem, args)
}
value := rem[remIdx+1:]
if value == "" {
if len(args[idx+1:]) == 0 {
return false, 0, args
}
if opt != o.theOne {
return false, 2, args
}
value = args[idx+1]
if strings.HasPrefix(value, "-") {
return false, 0, args
}
c.opts[o.theOne] = append(c.opts[o.theOne], value)
newRem := rem[:remIdx]
if newRem == "" {
return true, 2, removeStringsBetween(idx, idx+1, args)
}
nargs := replaceStringAt(idx, "-"+newRem, args)
return true, 1, removeStringAt(idx+1, nargs)
}
if opt != o.theOne {
return false, 1, args
}
c.opts[o.theOne] = append(c.opts[o.theOne], value)
newRem := rem[:remIdx]
if newRem == "" {
return true, 1, removeStringAt(idx, args)
}
return true, 0, replaceStringAt(idx, "-"+newRem, args)
}
return false, 1, args
}
type optsMatcher struct {
options []*opt
optionsIndex map[string]*opt
}
func (om optsMatcher) try(args []string, c *parseContext) (bool, []string) {
if len(args) == 0 || c.rejectOptions {
return false, args
}
for _, o := range om.options {
if _, exclude := c.excludedOpts[o]; exclude {
continue
}
if ok, nargs := (&optMatcher{theOne: o, optionsIdx: om.optionsIndex}).match(args, c); ok {
if o.valueSetFromEnv {
c.excludedOpts[o] = struct{}{}
}
return true, nargs
}
}
return false, args
}
func (om optsMatcher) match(args []string, c *parseContext) (bool, []string) {
ok, nargs := om.try(args, c)
if !ok {
return false, args
}
for {
ok, nnargs := om.try(nargs, c)
if !ok {
return true, nargs
}
nargs = nnargs
}
}
func (om optsMatcher) String() string {
return fmt.Sprintf("Opts(%v)", om.options)
}
func removeStringAt(idx int, arr []string) []string {
res := make([]string, len(arr)-1)
copy(res, arr[:idx])
copy(res[idx:], arr[idx+1:])
return res
}
func removeStringsBetween(from, to int, arr []string) []string {
res := make([]string, len(arr)-(to-from+1))
copy(res, arr[:from])
copy(res[from:], arr[to+1:])
return res
}
func replaceStringAt(idx int, with string, arr []string) []string {
res := make([]string, len(arr))
copy(res, arr[:idx])
res[idx] = with
copy(res[idx+1:], arr[idx+1:])
return res
}

227
vendor/github.com/jawher/mow.cli/matchers_test.go generated vendored Normal file
View File

@ -0,0 +1,227 @@
package cli
import (
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestShortcut(t *testing.T) {
pc := &parseContext{}
args := []string{"a", "b"}
ok, nargs := shortcut.match(args, pc)
require.True(t, ok, "shortcut always matches")
require.Equal(t, args, nargs, "shortcut doesn't touch the passed args")
}
func TestOptsEnd(t *testing.T) {
pc := &parseContext{}
args := []string{"a", "b"}
ok, nargs := optsEnd.match(args, pc)
require.True(t, ok, "optsEnd always matches")
require.Equal(t, args, nargs, "optsEnd doesn't touch the passed args")
require.True(t, pc.rejectOptions, "optsEnd sets the rejectOptions flag")
}
func TestArgMatcher(t *testing.T) {
arg := &arg{name: "X"}
{
pc := newParseContext()
args := []string{"a", "b"}
ok, nargs := arg.match(args, &pc)
require.True(t, ok, "arg should match")
require.Equal(t, []string{"b"}, nargs, "arg should consume the matched value")
require.Equal(t, []string{"a"}, pc.args[arg], "arg should stored the matched value")
}
{
pc := newParseContext()
ok, _ := arg.match([]string{"-v"}, &pc)
require.False(t, ok, "arg should not match options")
}
{
pc := newParseContext()
pc.rejectOptions = true
ok, _ := arg.match([]string{"-v"}, &pc)
require.True(t, ok, "arg should match options when the reject flag is set")
}
}
func TestBoolOptMatcher(t *testing.T) {
forceOpt := &opt{names: []string{"-f", "--force"}, value: newBoolValue(new(bool), false)}
optMatcher := &optMatcher{
theOne: forceOpt,
optionsIdx: map[string]*opt{
"-f": forceOpt,
"--force": forceOpt,
"-g": {names: []string{"-g"}, value: newBoolValue(new(bool), false)},
"-x": {names: []string{"-x"}, value: newBoolValue(new(bool), false)},
"-y": {names: []string{"-y"}, value: newBoolValue(new(bool), false)},
},
}
cases := []struct {
args []string
nargs []string
val []string
}{
{[]string{"-f", "x"}, []string{"x"}, []string{"true"}},
{[]string{"-f=true", "x"}, []string{"x"}, []string{"true"}},
{[]string{"-f=false", "x"}, []string{"x"}, []string{"false"}},
{[]string{"--force", "x"}, []string{"x"}, []string{"true"}},
{[]string{"--force=true", "x"}, []string{"x"}, []string{"true"}},
{[]string{"--force=false", "x"}, []string{"x"}, []string{"false"}},
{[]string{"-fgxy", "x"}, []string{"-gxy", "x"}, []string{"true"}},
{[]string{"-gfxy", "x"}, []string{"-gxy", "x"}, []string{"true"}},
{[]string{"-gxfy", "x"}, []string{"-gxy", "x"}, []string{"true"}},
{[]string{"-gxyf", "x"}, []string{"-gxy", "x"}, []string{"true"}},
}
for _, cas := range cases {
t.Logf("Testing case: %#v", cas)
pc := newParseContext()
ok, nargs := optMatcher.match(cas.args, &pc)
require.True(t, ok, "opt should match")
require.Equal(t, cas.nargs, nargs, "opt should consume the option name")
require.Equal(t, cas.val, pc.opts[forceOpt], "true should stored as the option's value")
pc = newParseContext()
pc.rejectOptions = true
nok, _ := optMatcher.match(cas.args, &pc)
require.False(t, nok, "opt shouldn't match when rejectOptions flag is set")
}
}
func TestOptMatcher(t *testing.T) {
names := []string{"-f", "--force"}
opts := []*opt{
{names: names, value: newStringValue(new(string), "")},
{names: names, value: newIntValue(new(int), 0)},
{names: names, value: newStringsValue(new([]string), nil)},
{names: names, value: newIntsValue(new([]int), nil)},
}
cases := []struct {
args []string
nargs []string
val []string
}{
{[]string{"-f", "x"}, []string{}, []string{"x"}},
{[]string{"-f=x", "y"}, []string{"y"}, []string{"x"}},
{[]string{"-fx", "y"}, []string{"y"}, []string{"x"}},
{[]string{"-afx", "y"}, []string{"-a", "y"}, []string{"x"}},
{[]string{"-af", "x", "y"}, []string{"-a", "y"}, []string{"x"}},
{[]string{"--force", "x"}, []string{}, []string{"x"}},
{[]string{"--force=x", "y"}, []string{"y"}, []string{"x"}},
}
for _, cas := range cases {
for _, forceOpt := range opts {
t.Logf("Testing case: %#v with opt: %#v", cas, forceOpt)
optMatcher := &optMatcher{
theOne: forceOpt,
optionsIdx: map[string]*opt{
"-f": forceOpt,
"--force": forceOpt,
"-a": {names: []string{"-a"}, value: newBoolValue(new(bool), false)},
},
}
pc := newParseContext()
ok, nargs := optMatcher.match(cas.args, &pc)
require.True(t, ok, "opt %#v should match args %v, %v", forceOpt, cas.args, forceOpt.isBool())
require.Equal(t, cas.nargs, nargs, "opt should consume the option name")
require.Equal(t, cas.val, pc.opts[forceOpt], "true should stored as the option's value")
pc = newParseContext()
pc.rejectOptions = true
nok, _ := optMatcher.match(cas.args, &pc)
require.False(t, nok, "opt shouldn't match when rejectOptions flag is set")
}
}
}
func TestOptsMatcher(t *testing.T) {
opts := optsMatcher{
options: []*opt{
{names: []string{"-f", "--force"}, value: newBoolValue(new(bool), false)},
{names: []string{"-g", "--green"}, value: newStringValue(new(string), "")},
},
optionsIndex: map[string]*opt{},
}
for _, o := range opts.options {
for _, n := range o.names {
opts.optionsIndex[n] = o
}
}
cases := []struct {
args []string
nargs []string
val [][]string
}{
{[]string{"-f", "x"}, []string{"x"}, [][]string{{"true"}, nil}},
{[]string{"-f=false", "y"}, []string{"y"}, [][]string{{"false"}, nil}},
{[]string{"--force", "x"}, []string{"x"}, [][]string{{"true"}, nil}},
{[]string{"--force=false", "y"}, []string{"y"}, [][]string{{"false"}, nil}},
{[]string{"-g", "x"}, []string{}, [][]string{nil, {"x"}}},
{[]string{"-g=x", "y"}, []string{"y"}, [][]string{nil, {"x"}}},
{[]string{"-gx", "y"}, []string{"y"}, [][]string{nil, {"x"}}},
{[]string{"--green", "x"}, []string{}, [][]string{nil, {"x"}}},
{[]string{"--green=x", "y"}, []string{"y"}, [][]string{nil, {"x"}}},
{[]string{"-f", "-g", "x", "y"}, []string{"y"}, [][]string{{"true"}, {"x"}}},
{[]string{"-g", "x", "-f", "y"}, []string{"y"}, [][]string{{"true"}, {"x"}}},
{[]string{"-fg", "x", "y"}, []string{"y"}, [][]string{{"true"}, {"x"}}},
{[]string{"-fgxxx", "y"}, []string{"y"}, [][]string{{"true"}, {"xxx"}}},
}
for _, cas := range cases {
t.Logf("testing with args %v", cas.args)
pc := newParseContext()
ok, nargs := opts.match(cas.args, &pc)
require.True(t, ok, "opts should match")
require.Equal(t, cas.nargs, nargs, "opts should consume the option name")
for i, opt := range opts.options {
require.Equal(t, cas.val[i], pc.opts[opt], "the option value for %v should be stored", opt)
}
pc = newParseContext()
pc.rejectOptions = true
nok, _ := opts.match(cas.args, &pc)
require.False(t, nok, "opts shouldn't match when rejectOptions flag is set")
}
}
// Issue 55
func TestOptsMatcherInfiniteLoop(t *testing.T) {
opts := optsMatcher{
options: []*opt{
{names: []string{"-g"}, value: newStringValue(new(string), ""), valueSetFromEnv: true},
},
optionsIndex: map[string]*opt{},
}
for _, o := range opts.options {
for _, n := range o.names {
opts.optionsIndex[n] = o
}
}
done := make(chan struct{}, 1)
pc := newParseContext()
go func() {
opts.match([]string{"-x"}, &pc)
done <- struct{}{}
}()
select {
case <-done:
// nop, everything is good
case <-time.After(5 * time.Second):
t.Fatalf("Timed out after 5 seconds. Infinite loop in optsMatcher.")
}
}

279
vendor/github.com/jawher/mow.cli/options.go generated vendored Normal file
View File

@ -0,0 +1,279 @@
package cli
import (
"flag"
"fmt"
"strings"
)
// BoolOpt describes a boolean option
type BoolOpt struct {
// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
// The one letter names will then be called with a single dash (short option), the others with two (long options).
Name string
// The option description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this option
EnvVar string
// The option's initial value
Value bool
// A boolean to display or not the current value of the option in the help message
HideValue bool
// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (o BoolOpt) value() bool {
return o.Value
}
// StringOpt describes a string option
type StringOpt struct {
// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
// The one letter names will then be called with a single dash (short option), the others with two (long options).
Name string
// The option description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this option
EnvVar string
// The option's initial value
Value string
// A boolean to display or not the current value of the option in the help message
HideValue bool
// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (o StringOpt) value() string {
return o.Value
}
// IntOpt describes an int option
type IntOpt struct {
// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
// The one letter names will then be called with a single dash (short option), the others with two (long options).
Name string
// The option description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this option
EnvVar string
// The option's initial value
Value int
// A boolean to display or not the current value of the option in the help message
HideValue bool
// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (o IntOpt) value() int {
return o.Value
}
// StringsOpt describes a string slice option
type StringsOpt struct {
// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
// The one letter names will then be called with a single dash (short option), the others with two (long options).
Name string
// The option description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this option.
// The env variable should contain a comma separated list of values
EnvVar string
// The option's initial value
Value []string
// A boolean to display or not the current value of the option in the help message
HideValue bool
// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (o StringsOpt) value() []string {
return o.Value
}
// IntsOpt describes an int slice option
type IntsOpt struct {
// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
// The one letter names will then be called with a single dash (short option), the others with two (long options).
Name string
// The option description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this option.
// The env variable should contain a comma separated list of values
EnvVar string
// The option's initial value
Value []int
// A boolean to display or not the current value of the option in the help message
HideValue bool
// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (o IntsOpt) value() []int {
return o.Value
}
// VarOpt describes an option where the type and format of the value is controlled by the developer
type VarOpt struct {
// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
// The one letter names will then be called with a single dash (short option), the others with two (long options).
Name string
// The option description as will be shown in help messages
Desc string
// A space separated list of environment variables names to be used to initialize this option
EnvVar string
// A value implementing the flag.Value type (will hold the final value)
Value flag.Value
// A boolean to display or not the current value of the option in the help message
HideValue bool
// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
SetByUser *bool
}
func (o VarOpt) value() flag.Value {
return o.Value
}
/*
BoolOpt defines a boolean option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
The one letter names will then be called with a single dash (short option), the others with two (long options).
The result should be stored in a variable (a pointer to a bool) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) BoolOpt(name string, value bool, desc string) *bool {
return c.Bool(BoolOpt{
Name: name,
Value: value,
Desc: desc,
})
}
/*
StringOpt defines a string option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
The one letter names will then be called with a single dash (short option), the others with two (long options).
The result should be stored in a variable (a pointer to a string) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) StringOpt(name string, value string, desc string) *string {
return c.String(StringOpt{
Name: name,
Value: value,
Desc: desc,
})
}
/*
IntOpt defines an int option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
The one letter names will then be called with a single dash (short option), the others with two (long options).
The result should be stored in a variable (a pointer to an int) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) IntOpt(name string, value int, desc string) *int {
return c.Int(IntOpt{
Name: name,
Value: value,
Desc: desc,
})
}
/*
StringsOpt defines a string slice option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
The one letter names will then be called with a single dash (short option), the others with two (long options).
The result should be stored in a variable (a pointer to a string slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) StringsOpt(name string, value []string, desc string) *[]string {
return c.Strings(StringsOpt{
Name: name,
Value: value,
Desc: desc,
})
}
/*
IntsOpt defines an int slice option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.
The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
The one letter names will then be called with a single dash (short option), the others with two (long options).
The result should be stored in a variable (a pointer to an int slice) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) IntsOpt(name string, value []int, desc string) *[]int {
return c.Ints(IntsOpt{
Name: name,
Value: value,
Desc: desc,
})
}
/*
VarOpt defines an option where the type and format is controlled by the developer.
The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
The one letter names will then be called with a single dash (short option), the others with two (long options).
The result will be stored in the value parameter (a value implementing the flag.Value interface) which will be populated when the app is run and the call arguments get parsed
*/
func (c *Cmd) VarOpt(name string, value flag.Value, desc string) {
c.mkOpt(opt{name: name, desc: desc, value: value})
}
type opt struct {
name string
desc string
envVar string
names []string
hideValue bool
valueSetFromEnv bool
valueSetByUser *bool
value flag.Value
}
func (o *opt) isBool() bool {
if bf, ok := o.value.(boolValued); ok {
return bf.IsBoolFlag()
}
return false
}
func (o *opt) String() string {
return fmt.Sprintf("Opt(%v)", o.names)
}
func mkOptStrs(optName string) []string {
res := strings.Fields(optName)
for i, name := range res {
prefix := "-"
if len(name) > 1 {
prefix = "--"
}
res[i] = prefix + name
}
return res
}
func (c *Cmd) mkOpt(opt opt) {
opt.valueSetFromEnv = setFromEnv(opt.value, opt.envVar)
opt.names = mkOptStrs(opt.name)
c.options = append(c.options, &opt)
for _, name := range opt.names {
c.optionsIdx[name] = &opt
}
}

141
vendor/github.com/jawher/mow.cli/options_test.go generated vendored Normal file
View File

@ -0,0 +1,141 @@
package cli
import (
"os"
"strconv"
"testing"
"github.com/stretchr/testify/require"
)
func TestStringOpt(t *testing.T) {
cmd := &Cmd{optionsIdx: map[string]*opt{}}
a := cmd.String(StringOpt{Name: "a", Value: "test", Desc: ""})
require.Equal(t, "test", *a)
os.Setenv("B", "")
b := cmd.String(StringOpt{Name: "b", Value: "test", EnvVar: "B", Desc: ""})
require.Equal(t, "test", *b)
os.Setenv("B", "mow")
b = cmd.String(StringOpt{Name: "b", Value: "test", EnvVar: "B", Desc: ""})
require.Equal(t, "mow", *b)
os.Setenv("B", "")
os.Setenv("C", "cli")
os.Setenv("D", "mow")
b = cmd.String(StringOpt{Name: "b", Value: "test", EnvVar: "B C D", Desc: ""})
require.Equal(t, "cli", *b)
}
func TestBoolOpt(t *testing.T) {
cmd := &Cmd{optionsIdx: map[string]*opt{}}
a := cmd.Bool(BoolOpt{Name: "a", Value: true, Desc: ""})
require.True(t, *a)
os.Setenv("B", "")
b := cmd.Bool(BoolOpt{Name: "b", Value: false, EnvVar: "B", Desc: ""})
require.False(t, *b)
trueValues := []string{"1", "true", "TRUE"}
for _, tv := range trueValues {
os.Setenv("B", tv)
b = cmd.Bool(BoolOpt{Name: "b", Value: false, EnvVar: "B", Desc: ""})
require.True(t, *b, "env=%s", tv)
}
falseValues := []string{"0", "false", "FALSE", "xyz"}
for _, tv := range falseValues {
os.Setenv("B", tv)
b = cmd.Bool(BoolOpt{Name: "b", Value: false, EnvVar: "B", Desc: ""})
require.False(t, *b, "env=%s", tv)
}
os.Setenv("B", "")
os.Setenv("C", "false")
os.Setenv("D", "true")
b = cmd.Bool(BoolOpt{Name: "b", Value: true, EnvVar: "B C D", Desc: ""})
require.False(t, *b)
}
func TestIntOpt(t *testing.T) {
cmd := &Cmd{optionsIdx: map[string]*opt{}}
a := cmd.Int(IntOpt{Name: "a", Value: -1, Desc: ""})
require.Equal(t, -1, *a)
os.Setenv("B", "")
b := cmd.Int(IntOpt{Name: "b", Value: -1, EnvVar: "B", Desc: ""})
require.Equal(t, -1, *b)
goodValues := []int{1, 0, 33}
for _, tv := range goodValues {
os.Setenv("B", strconv.Itoa(tv))
b := cmd.Int(IntOpt{Name: "b", Value: -1, EnvVar: "B", Desc: ""})
require.Equal(t, tv, *b, "env=%s", tv)
}
badValues := []string{"", "b", "q1", "_"}
for _, tv := range badValues {
os.Setenv("B", tv)
b := cmd.Int(IntOpt{Name: "b", Value: -1, EnvVar: "B", Desc: ""})
require.Equal(t, -1, *b, "env=%s", tv)
}
os.Setenv("B", "")
os.Setenv("C", "42")
os.Setenv("D", "666")
b = cmd.Int(IntOpt{Name: "b", Value: -1, EnvVar: "B C D", Desc: ""})
require.Equal(t, 42, *b)
}
func TestStringsOpt(t *testing.T) {
cmd := &Cmd{optionsIdx: map[string]*opt{}}
v := []string{"test"}
a := cmd.Strings(StringsOpt{Name: "a", Value: v, Desc: ""})
require.Equal(t, v, *a)
os.Setenv("B", "")
b := cmd.Strings(StringsOpt{Name: "b", Value: v, EnvVar: "B", Desc: ""})
require.Equal(t, v, *b)
os.Setenv("B", "mow")
b = cmd.Strings(StringsOpt{Name: "b", Value: nil, EnvVar: "B", Desc: ""})
require.Equal(t, []string{"mow"}, *b)
os.Setenv("B", "mow, cli")
b = cmd.Strings(StringsOpt{Name: "b", Value: nil, EnvVar: "B", Desc: ""})
require.Equal(t, []string{"mow", "cli"}, *b)
os.Setenv("B", "")
os.Setenv("C", "test")
os.Setenv("D", "xxx")
b = cmd.Strings(StringsOpt{Name: "b", Value: nil, EnvVar: "B C D", Desc: ""})
require.Equal(t, v, *b)
}
func TestIntsOpt(t *testing.T) {
cmd := &Cmd{optionsIdx: map[string]*opt{}}
vi := []int{42}
a := cmd.Ints(IntsOpt{Name: "a", Value: vi, Desc: ""})
require.Equal(t, vi, *a)
os.Setenv("B", "")
b := cmd.Ints(IntsOpt{Name: "b", Value: vi, EnvVar: "B", Desc: ""})
require.Equal(t, vi, *b)
os.Setenv("B", "666")
b = cmd.Ints(IntsOpt{Name: "b", Value: nil, EnvVar: "B", Desc: ""})
require.Equal(t, []int{666}, *b)
os.Setenv("B", "1, 2 , 3")
b = cmd.Ints(IntsOpt{Name: "b", Value: nil, EnvVar: "B", Desc: ""})
require.Equal(t, []int{1, 2, 3}, *b)
os.Setenv("B", "")
os.Setenv("C", "abc")
os.Setenv("D", "1, abc")
os.Setenv("E", "42")
os.Setenv("F", "666")
b = cmd.Ints(IntsOpt{Name: "b", Value: nil, EnvVar: "B C D E F", Desc: ""})
require.Equal(t, vi, *b)
}

1315
vendor/github.com/jawher/mow.cli/spec_n_parse_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

243
vendor/github.com/jawher/mow.cli/spec_parser.go generated vendored Normal file
View File

@ -0,0 +1,243 @@
package cli
import "fmt"
func uParse(c *Cmd) (*state, error) {
tokens, err := uTokenize(c.Spec)
if err != nil {
return nil, err
}
p := &uParser{cmd: c, tokens: tokens}
return p.parse()
}
type uParser struct {
cmd *Cmd
tokens []*uToken
tkpos int
matchedToken *uToken
rejectOptions bool
}
func (p *uParser) parse() (s *state, err error) {
defer func() {
if v := recover(); v != nil {
pos := len(p.cmd.Spec)
if !p.eof() {
pos = p.token().pos
}
s = nil
switch t, ok := v.(string); ok {
case true:
err = &parseError{p.cmd.Spec, t, pos}
default:
panic(v)
}
}
}()
err = nil
var e *state
s, e = p.seq(false)
if !p.eof() {
s = nil
err = &parseError{p.cmd.Spec, "Unexpected input", p.token().pos}
return
}
e.terminal = true
s.simplify()
return
}
func (p *uParser) seq(required bool) (*state, *state) {
start := newState(p.cmd)
end := start
appendComp := func(s, e *state) {
for _, tr := range s.transitions {
end.t(tr.matcher, tr.next)
}
end = e
}
if required {
s, e := p.choice()
appendComp(s, e)
}
for p.canAtom() {
s, e := p.choice()
appendComp(s, e)
}
return start, end
}
func (p *uParser) choice() (*state, *state) {
start, end := newState(p.cmd), newState(p.cmd)
add := func(s, e *state) {
start.t(shortcut, s)
e.t(shortcut, end)
}
add(p.atom())
for p.found(utChoice) {
add(p.atom())
}
return start, end
}
func (p *uParser) atom() (*state, *state) {
start := newState(p.cmd)
var end *state
switch {
case p.eof():
panic("Unexpected end of input")
case p.found(utPos):
name := p.matchedToken.val
arg, declared := p.cmd.argsIdx[name]
if !declared {
p.back()
panic(fmt.Sprintf("Undeclared arg %s", name))
}
end = start.t(arg, newState(p.cmd))
case p.found(utOptions):
if p.rejectOptions {
p.back()
panic("No options after --")
}
end = newState(p.cmd)
start.t(optsMatcher{options: p.cmd.options, optionsIndex: p.cmd.optionsIdx}, end)
case p.found(utShortOpt):
if p.rejectOptions {
p.back()
panic("No options after --")
}
name := p.matchedToken.val
opt, declared := p.cmd.optionsIdx[name]
if !declared {
p.back()
panic(fmt.Sprintf("Undeclared option %s", name))
}
end = start.t(&optMatcher{
theOne: opt,
optionsIdx: p.cmd.optionsIdx,
}, newState(p.cmd))
p.found(utOptValue)
case p.found(utLongOpt):
if p.rejectOptions {
p.back()
panic("No options after --")
}
name := p.matchedToken.val
opt, declared := p.cmd.optionsIdx[name]
if !declared {
p.back()
panic(fmt.Sprintf("Undeclared option %s", name))
}
end = start.t(&optMatcher{
theOne: opt,
optionsIdx: p.cmd.optionsIdx,
}, newState(p.cmd))
p.found(utOptValue)
case p.found(utOptSeq):
if p.rejectOptions {
p.back()
panic("No options after --")
}
end = newState(p.cmd)
sq := p.matchedToken.val
opts := []*opt{}
for i := range sq {
sn := sq[i : i+1]
opt, declared := p.cmd.optionsIdx["-"+sn]
if !declared {
p.back()
panic(fmt.Sprintf("Undeclared option %s", sn))
}
opts = append(opts, opt)
}
start.t(optsMatcher{options: opts, optionsIndex: p.cmd.optionsIdx}, end)
case p.found(utOpenPar):
start, end = p.seq(true)
p.expect(utClosePar)
case p.found(utOpenSq):
start, end = p.seq(true)
start.t(shortcut, end)
p.expect(utCloseSq)
case p.found(utDoubleDash):
p.rejectOptions = true
end = start.t(optsEnd, newState(p.cmd))
return start, end
default:
panic("Unexpected input: was expecting a command or a positional argument or an option")
}
if p.found(utRep) {
end.t(shortcut, start)
}
return start, end
}
func (p *uParser) canAtom() bool {
switch {
case p.is(utPos):
return true
case p.is(utOptions):
return true
case p.is(utShortOpt):
return true
case p.is(utLongOpt):
return true
case p.is(utOptSeq):
return true
case p.is(utOpenPar):
return true
case p.is(utOpenSq):
return true
case p.is(utDoubleDash):
return true
default:
return false
}
}
func (p *uParser) found(t uTokenType) bool {
if p.is(t) {
p.matchedToken = p.token()
p.tkpos++
return true
}
return false
}
func (p *uParser) is(t uTokenType) bool {
if p.eof() {
return false
}
return p.token().typ == t
}
func (p *uParser) expect(t uTokenType) {
if !p.found(t) {
panic(fmt.Sprintf("Was expecting %v", t))
}
}
func (p *uParser) back() {
p.tkpos--
}
func (p *uParser) eof() bool {
return p.tkpos >= len(p.tokens)
}
func (p *uParser) token() *uToken {
if p.eof() {
return nil
}
return p.tokens[p.tkpos]
}

223
vendor/github.com/jawher/mow.cli/spec_tk.go generated vendored Normal file
View File

@ -0,0 +1,223 @@
package cli
import (
"strings"
"fmt"
)
type uTokenType string
const (
utPos uTokenType = "Pos"
utOpenPar uTokenType = "OpenPar"
utClosePar uTokenType = "ClosePar"
utOpenSq uTokenType = "OpenSq"
utCloseSq uTokenType = "CloseSq"
utChoice uTokenType = "Choice"
utOptions uTokenType = "Options"
utRep uTokenType = "Rep"
utShortOpt uTokenType = "ShortOpt"
utLongOpt uTokenType = "LongOpt"
utOptSeq uTokenType = "OptSeq"
utOptValue uTokenType = "OptValue"
utDoubleDash uTokenType = "DblDash"
)
type uToken struct {
typ uTokenType
val string
pos int
}
func (t *uToken) String() string {
return fmt.Sprintf("%s('%s')@%d", t.typ, t.val, t.pos)
}
type parseError struct {
input string
msg string
pos int
}
func (t *parseError) ident() string {
return strings.Map(func(c rune) rune {
switch c {
case '\t':
return c
default:
return ' '
}
}, t.input[:t.pos])
}
func (t *parseError) Error() string {
return fmt.Sprintf("Parse error at position %d:\n%s\n%s^ %s",
t.pos, t.input, t.ident(), t.msg)
}
func uTokenize(usage string) ([]*uToken, *parseError) {
pos := 0
res := []*uToken{}
var (
tk = func(t uTokenType, v string) {
res = append(res, &uToken{t, v, pos})
}
tkp = func(t uTokenType, v string, p int) {
res = append(res, &uToken{t, v, p})
}
err = func(msg string) *parseError {
return &parseError{usage, msg, pos}
}
)
eof := len(usage)
for pos < eof {
switch c := usage[pos]; c {
case ' ':
pos++
case '\t':
pos++
case '[':
tk(utOpenSq, "[")
pos++
case ']':
tk(utCloseSq, "]")
pos++
case '(':
tk(utOpenPar, "(")
pos++
case ')':
tk(utClosePar, ")")
pos++
case '|':
tk(utChoice, "|")
pos++
case '.':
start := pos
pos++
if pos >= eof || usage[pos] != '.' {
return nil, err("Unexpected end of usage, was expecting '..'")
}
pos++
if pos >= eof || usage[pos] != '.' {
return nil, err("Unexpected end of usage, was expecting '.'")
}
tkp(utRep, "...", start)
pos++
case '-':
start := pos
pos++
if pos >= eof {
return nil, err("Unexpected end of usage, was expecting an option name")
}
switch o := usage[pos]; {
case isLetter(o):
pos++
for ; pos < eof; pos++ {
ok := isLetter(usage[pos])
if !ok {
break
}
}
typ := utShortOpt
if pos-start > 2 {
typ = utOptSeq
start++
}
opt := usage[start:pos]
tkp(typ, opt, start)
if pos < eof && usage[pos] == '-' {
return nil, err("Invalid syntax")
}
case o == '-':
pos++
if pos == eof || usage[pos] == ' ' {
tkp(utDoubleDash, "--", start)
continue
}
for pos0 := pos; pos < eof; pos++ {
ok := isOkLongOpt(usage[pos], pos == pos0)
if !ok {
break
}
}
opt := usage[start:pos]
if len(opt) == 2 {
return nil, err("Was expecting a long option name")
}
tkp(utLongOpt, opt, start)
}
case '=':
start := pos
pos++
if pos >= eof || usage[pos] != '<' {
return nil, err("Unexpected end of usage, was expecting '=<'")
}
closed := false
for ; pos < eof; pos++ {
closed = usage[pos] == '>'
if closed {
break
}
}
if !closed {
return nil, err("Unclosed option value")
}
if pos-start == 2 {
return nil, err("Was expecting an option value")
}
pos++
value := usage[start:pos]
tkp(utOptValue, value, start)
default:
switch {
case isUppercase(c):
start := pos
for pos = pos + 1; pos < eof; pos++ {
if !isOkPos(usage[pos]) {
break
}
}
s := usage[start:pos]
typ := utPos
if s == "OPTIONS" {
typ = utOptions
}
tkp(typ, s, start)
default:
return nil, err("Unexpected input")
}
}
}
return res, nil
}
func isLowercase(c uint8) bool {
return c >= 'a' && c <= 'z'
}
func isUppercase(c uint8) bool {
return c >= 'A' && c <= 'Z'
}
func isOkPos(c uint8) bool {
return isUppercase(c) || isDigit(c) || c == '_'
}
func isLetter(c uint8) bool {
return isLowercase(c) || isUppercase(c)
}
func isDigit(c uint8) bool {
return c >= '0' && c <= '9'
}
func isOkLongOpt(c uint8, first bool) bool {
return isLetter(c) || isDigit(c) || c == '_' || (!first && c == '-')
}

111
vendor/github.com/jawher/mow.cli/spec_tk_test.go generated vendored Normal file
View File

@ -0,0 +1,111 @@
package cli
import (
"testing"
)
func TestUTokenize(t *testing.T) {
cases := []struct {
usage string
expected []*uToken
}{
{"OPTIONS", []*uToken{{utOptions, "OPTIONS", 0}}},
{"XOPTIONS", []*uToken{{utPos, "XOPTIONS", 0}}},
{"OPTIONSX", []*uToken{{utPos, "OPTIONSX", 0}}},
{"ARG", []*uToken{{utPos, "ARG", 0}}},
{"ARG42", []*uToken{{utPos, "ARG42", 0}}},
{"ARG_EXTRA", []*uToken{{utPos, "ARG_EXTRA", 0}}},
{"ARG1 ARG2", []*uToken{{utPos, "ARG1", 0}, {utPos, "ARG2", 5}}},
{"ARG1 ARG2", []*uToken{{utPos, "ARG1", 0}, {utPos, "ARG2", 6}}},
{"[ARG]", []*uToken{{utOpenSq, "[", 0}, {utPos, "ARG", 1}, {utCloseSq, "]", 4}}},
{"[ ARG ]", []*uToken{{utOpenSq, "[", 0}, {utPos, "ARG", 2}, {utCloseSq, "]", 6}}},
{"ARG [ARG2 ]", []*uToken{{utPos, "ARG", 0}, {utOpenSq, "[", 4}, {utPos, "ARG2", 5}, {utCloseSq, "]", 10}}},
{"ARG [ ARG2]", []*uToken{{utPos, "ARG", 0}, {utOpenSq, "[", 4}, {utPos, "ARG2", 6}, {utCloseSq, "]", 10}}},
{"...", []*uToken{{utRep, "...", 0}}},
{"ARG...", []*uToken{{utPos, "ARG", 0}, {utRep, "...", 3}}},
{"ARG ...", []*uToken{{utPos, "ARG", 0}, {utRep, "...", 4}}},
{"[ARG...]", []*uToken{{utOpenSq, "[", 0}, {utPos, "ARG", 1}, {utRep, "...", 4}, {utCloseSq, "]", 7}}},
{"|", []*uToken{{utChoice, "|", 0}}},
{"ARG|ARG2", []*uToken{{utPos, "ARG", 0}, {utChoice, "|", 3}, {utPos, "ARG2", 4}}},
{"ARG |ARG2", []*uToken{{utPos, "ARG", 0}, {utChoice, "|", 4}, {utPos, "ARG2", 5}}},
{"ARG| ARG2", []*uToken{{utPos, "ARG", 0}, {utChoice, "|", 3}, {utPos, "ARG2", 5}}},
{"[OPTIONS]", []*uToken{{utOpenSq, "[", 0}, {utOptions, "OPTIONS", 1}, {utCloseSq, "]", 8}}},
{"-p", []*uToken{{utShortOpt, "-p", 0}}},
{"-X", []*uToken{{utShortOpt, "-X", 0}}},
{"--force", []*uToken{{utLongOpt, "--force", 0}}},
{"--sig-proxy", []*uToken{{utLongOpt, "--sig-proxy", 0}}},
{"-aBc", []*uToken{{utOptSeq, "aBc", 1}}},
{"--", []*uToken{{utDoubleDash, "--", 0}}},
{"=<bla>", []*uToken{{utOptValue, "=<bla>", 0}}},
{"=<bla-bla>", []*uToken{{utOptValue, "=<bla-bla>", 0}}},
{"=<bla--bla>", []*uToken{{utOptValue, "=<bla--bla>", 0}}},
{"-p=<file-path>", []*uToken{{utShortOpt, "-p", 0}, {utOptValue, "=<file-path>", 2}}},
{"--path=<absolute-path>", []*uToken{{utLongOpt, "--path", 0}, {utOptValue, "=<absolute-path>", 6}}},
}
for _, c := range cases {
t.Logf("test %s", c.usage)
tks, err := uTokenize(c.usage)
if err != nil {
t.Errorf("[Tokenize '%s']: Unexpected error: %v", c.usage, err)
continue
}
t.Logf("actual: %v\n", tks)
if len(tks) != len(c.expected) {
t.Errorf("[Tokenize '%s']: token count mismatch:\n\tExpected: %v\n\tActual : %v", c.usage, c.expected, tks)
continue
}
for i, actual := range tks {
expected := c.expected[i]
switch {
case actual.typ != expected.typ:
t.Errorf("[Tokenize '%s']: token type mismatch:\n\tExpected: %v\n\tActual : %v", c.usage, expected, actual)
case actual.val != expected.val:
t.Errorf("[Tokenize '%s']: token text mismatch:\n\tExpected: %v\n\tActual : %v", c.usage, expected, actual)
case actual.pos != expected.pos:
t.Errorf("[Tokenize '%s']: token pos mismatch:\n\tExpected: %v\n\tActual : %v", c.usage, expected, actual)
}
}
}
}
func TestUTokenizeErrors(t *testing.T) {
cases := []struct {
usage string
pos int
}{
{"-", 1},
{"---x", 2},
{"-x-", 2},
{"=", 1},
{"=<", 2},
{"=<dsdf", 6},
{"=<>", 2},
}
for _, c := range cases {
t.Logf("test %s", c.usage)
tks, err := uTokenize(c.usage)
if err == nil {
t.Errorf("Tokenize('%s') should have failed, instead got %v", c.usage, tks)
continue
}
t.Logf("Got expected error %v", err)
if err.pos != c.pos {
t.Errorf("[Tokenize '%s']: error pos mismatch:\n\tExpected: %v\n\tActual : %v", c.usage, c.pos, err.pos)
}
}
}

View File

@ -0,0 +1,45 @@
Usage: app [-bdsuikqs] BOOL1 [STR1] INT3... COMMAND [arg...]
App Desc
Arguments:
BOOL1 Bool Argument 1 (env $BOOL1)
BOOL2 Bool Argument 2 (default true)
BOOL3 Bool Argument 3 (env $BOOL3)
STR1 String Argument 1 (env $STR1)
STR2 String Argument 2 (env $STR2) (default "a value")
STR3 String Argument 3 (env $STR3)
INT1 Int Argument 1 (env $INT1) (default 0)
INT2 Int Argument 2 (env $INT2) (default 1)
INT3 Int Argument 3 (env $INT3)
STRS1 Strings Argument 1 (env $STRS1)
STRS2 (env $STRS2) (default ["value1", "value2"])
STRS3 Strings Argument 3 (env $STRS3)
INTS1 Ints Argument 1 (env $INTS1)
INTS2 Ints Argument 2 (env $INTS2) (default [1, 2, 3])
INTS3 Ints Argument 3 (env $INTS3)
Options:
-b, --bool1 Bool Option 1 (env $BOOL1)
--bool2 Bool Option 2 (default true)
-d Bool Option 3 (env $BOOL3)
-s, --str1 String Option 1 (env $STR1)
--str2 String Option 2 (default "a value")
-u String Option 3 (env $STR3)
-i, --int1 (env $INT1, $ALIAS_INT1) (default 0)
--int2 Int Option 2 (env $INT2) (default 1)
-k Int Option 3 (env $INT3)
-x, --strs1 Strings Option 1 (env $STRS1)
--strs2 Strings Option 2 (env $STRS2) (default ["value1", "value2"])
-z Strings Option 3 (env $STRS3)
-q, --ints1 Ints Option 1 (env $INTS1)
--ints2 Ints Option 2 (env $INTS2) (default [1, 2, 3])
-s Ints Option 3 (env $INTS3)
Commands:
command1 command1 description
command2 command2 description
command3 command3 description
Run 'app COMMAND --help' for more information on a command.

View File

@ -0,0 +1,10 @@
Usage: app [-o] ARG
Longer App Desc
Arguments:
ARG Argument
Options:
-o, --opt Option

66
vendor/github.com/jawher/mow.cli/utils.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
package cli
import (
"flag"
"os"
"strings"
)
func setFromEnv(into flag.Value, envVars string) bool {
multiValued, isMulti := into.(multiValued)
if len(envVars) > 0 {
for _, rev := range strings.Split(envVars, " ") {
ev := strings.TrimSpace(rev)
if len(ev) == 0 {
continue
}
v := os.Getenv(ev)
if len(v) == 0 {
continue
}
if !isMulti {
if err := into.Set(v); err == nil {
return true
}
continue
}
vs := strings.Split(v, ",")
if err := setMultivalued(multiValued, vs); err == nil {
return true
}
}
}
return false
}
func setMultivalued(into multiValued, values []string) error {
into.Clear()
for _, v := range values {
v = strings.TrimSpace(v)
if err := into.Set(v); err != nil {
into.Clear()
return err
}
}
return nil
}
func joinStrings(parts ...string) string {
res := ""
for _, part := range parts {
s := strings.TrimSpace(part)
if s == "" {
continue
}
if res != "" {
res += " "
}
res += part
}
return res
}

30
vendor/github.com/jawher/mow.cli/utils_test.go generated vendored Normal file
View File

@ -0,0 +1,30 @@
package cli
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestJoinStrings(t *testing.T) {
cases := []struct {
input []string
expected string
}{
{nil, ""},
{[]string{""}, ""},
{[]string{" "}, ""},
{[]string{"\t"}, ""},
{[]string{"", " ", "\t"}, ""},
{[]string{"a"}, "a"},
{[]string{"a", "b c"}, "a b c"},
{[]string{"", "a", " ", "b", "\t"}, "a b"},
}
for _, cas := range cases {
t.Logf("Testing %#v", cas.input)
actual := joinStrings(cas.input...)
require.Equal(t, cas.expected, actual)
}
}

203
vendor/github.com/jawher/mow.cli/values.go generated vendored Normal file
View File

@ -0,0 +1,203 @@
package cli
import (
"flag"
"fmt"
"strconv"
)
type boolValued interface {
flag.Value
IsBoolFlag() bool
}
type multiValued interface {
flag.Value
Clear()
}
type defaultValued interface {
IsDefault() bool
}
/******************************************************************************/
/* BOOL */
/******************************************************************************/
type boolValue bool
var (
_ flag.Value = newBoolValue(new(bool), false)
_ boolValued = newBoolValue(new(bool), false)
_ defaultValued = newBoolValue(new(bool), false)
)
func newBoolValue(into *bool, v bool) *boolValue {
*into = v
return (*boolValue)(into)
}
func (bo *boolValue) Set(s string) error {
b, err := strconv.ParseBool(s)
if err != nil {
return err
}
*bo = boolValue(b)
return nil
}
func (bo *boolValue) IsBoolFlag() bool {
return true
}
func (bo *boolValue) String() string {
return fmt.Sprintf("%v", *bo)
}
func (bo *boolValue) IsDefault() bool {
return !bool(*bo)
}
/******************************************************************************/
/* STRING */
/******************************************************************************/
type stringValue string
var (
_ flag.Value = newStringValue(new(string), "")
_ defaultValued = newStringValue(new(string), "")
)
func newStringValue(into *string, v string) *stringValue {
*into = v
return (*stringValue)(into)
}
func (sa *stringValue) Set(s string) error {
*sa = stringValue(s)
return nil
}
func (sa *stringValue) String() string {
return fmt.Sprintf("%#v", *sa)
}
func (sa *stringValue) IsDefault() bool {
return string(*sa) == ""
}
/******************************************************************************/
/* INT */
/******************************************************************************/
type intValue int
var (
_ flag.Value = newIntValue(new(int), 0)
)
func newIntValue(into *int, v int) *intValue {
*into = v
return (*intValue)(into)
}
func (ia *intValue) Set(s string) error {
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
*ia = intValue(int(i))
return nil
}
func (ia *intValue) String() string {
return fmt.Sprintf("%v", *ia)
}
/******************************************************************************/
/* STRINGS */
/******************************************************************************/
// Strings describes a string slice argument
type stringsValue []string
var (
_ flag.Value = newStringsValue(new([]string), nil)
_ multiValued = newStringsValue(new([]string), nil)
_ defaultValued = newStringsValue(new([]string), nil)
)
func newStringsValue(into *[]string, v []string) *stringsValue {
*into = v
return (*stringsValue)(into)
}
func (sa *stringsValue) Set(s string) error {
*sa = append(*sa, s)
return nil
}
func (sa *stringsValue) String() string {
res := "["
for idx, s := range *sa {
if idx > 0 {
res += ", "
}
res += fmt.Sprintf("%#v", s)
}
return res + "]"
}
func (sa *stringsValue) Clear() {
*sa = nil
}
func (sa *stringsValue) IsDefault() bool {
return len(*sa) == 0
}
/******************************************************************************/
/* INTS */
/******************************************************************************/
type intsValue []int
var (
_ flag.Value = newIntsValue(new([]int), nil)
_ multiValued = newIntsValue(new([]int), nil)
_ defaultValued = newIntsValue(new([]int), nil)
)
func newIntsValue(into *[]int, v []int) *intsValue {
*into = v
return (*intsValue)(into)
}
func (ia *intsValue) Set(s string) error {
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
*ia = append(*ia, int(i))
return nil
}
func (ia *intsValue) String() string {
res := "["
for idx, s := range *ia {
if idx > 0 {
res += ", "
}
res += fmt.Sprintf("%v", s)
}
return res + "]"
}
func (ia *intsValue) Clear() {
*ia = nil
}
func (ia *intsValue) IsDefault() bool {
return len(*ia) == 0
}

137
vendor/github.com/jawher/mow.cli/values_test.go generated vendored Normal file
View File

@ -0,0 +1,137 @@
package cli
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestBoolParam(t *testing.T) {
var into bool
param := newBoolValue(&into, false)
require.True(t, param.IsBoolFlag())
cases := []struct {
input string
err bool
result bool
string string
}{
{"true", false, true, "true"},
{"false", false, false, "false"},
{"123", true, false, ""},
{"", true, false, ""},
}
for _, cas := range cases {
t.Logf("testing with %q", cas.input)
err := param.Set(cas.input)
if cas.err {
require.Errorf(t, err, "value %q should have returned an error", cas.input)
continue
}
require.Equal(t, cas.result, into)
require.Equal(t, cas.string, param.String())
}
}
func TestStringParam(t *testing.T) {
var into string
param := newStringValue(&into, "")
cases := []struct {
input string
string string
}{
{"a", `"a"`},
{"", `""`},
}
for _, cas := range cases {
t.Logf("testing with %q", cas.input)
err := param.Set(cas.input)
require.NoError(t, err)
require.Equal(t, cas.input, into)
require.Equal(t, cas.string, param.String())
}
}
func TestIntParam(t *testing.T) {
var into int
param := newIntValue(&into, 0)
cases := []struct {
input string
err bool
result int
string string
}{
{"12", false, 12, "12"},
{"0", false, 0, "0"},
{"01", false, 1, "1"},
{"", true, 0, ""},
{"abc", true, 0, ""},
}
for _, cas := range cases {
t.Logf("testing with %q", cas.input)
err := param.Set(cas.input)
if cas.err {
require.Errorf(t, err, "value %q should have returned an error", cas.input)
continue
}
require.Equal(t, cas.result, into)
require.Equal(t, cas.string, param.String())
}
}
func TestStringsParam(t *testing.T) {
into := []string{}
param := newStringsValue(&into, nil)
param.Set("a")
param.Set("b")
require.Equal(t, []string{"a", "b"}, into)
require.Equal(t, `["a", "b"]`, param.String())
param.Clear()
require.Empty(t, into)
}
func TestIntsParam(t *testing.T) {
into := []int{}
param := newIntsValue(&into, nil)
err := param.Set("1")
require.NoError(t, err)
err = param.Set("2")
require.NoError(t, err)
require.Equal(t, []int{1, 2}, into)
require.Equal(t, `[1, 2]`, param.String())
err = param.Set("c")
require.Error(t, err)
require.Equal(t, []int{1, 2}, into)
param.Clear()
require.Empty(t, into)
}

162
vendor/github.com/jawher/mow.cli/var_test.go generated vendored Normal file
View File

@ -0,0 +1,162 @@
package cli
import (
"fmt"
"testing"
"time"
"os"
"github.com/stretchr/testify/require"
)
// Counter
type Counter int
func (d *Counter) Set(v string) error {
*d++
return nil
}
func (d *Counter) String() string {
return fmt.Sprintf("%d", *d)
}
func (d *Counter) IsBoolFlag() bool {
return true
}
// Duration
type Duration time.Duration
func (d *Duration) Set(v string) error {
parsed, err := time.ParseDuration(v)
if err != nil {
return err
}
*d = Duration(parsed)
return nil
}
func (d *Duration) String() string {
duration := time.Duration(*d)
return duration.String()
}
type Percent []float64
func parsePercent(v string) (float64, error) {
var d int
_, err := fmt.Sscanf(v, "%d%%", &d)
if err != nil {
return 0, err
}
return float64(d) / 100, nil
}
func (p *Percent) Set(v string) error {
f, err := parsePercent(v)
if err != nil {
return err
}
*p = append(*p, f)
return nil
}
func (p *Percent) Clear() {
*p = nil
}
func (p *Percent) String() string {
res := "["
for idx, p := range *p {
if idx > 0 {
res += ", "
}
res += fmt.Sprintf("%.0f%%", p*100)
}
return res + "]"
}
func TestVar(t *testing.T) {
value := Counter(0)
duration := Duration(0)
percents := Percent{}
app := App("var", "")
app.Spec = "-v... DURATION PERCENT..."
app.VarOpt("v", &value, "")
app.VarArg("DURATION", &duration, "")
app.VarArg("PERCENT", &percents, "")
ex := false
app.Action = func() {
ex = true
}
app.Run([]string{"cp", "-vvv", "1h", "10%", "5%"})
require.Equal(t, Counter(3), value)
require.Equal(t, Duration(1*time.Hour), duration)
require.Equal(t, Percent([]float64{0.1, 0.05}), percents)
require.True(t, ex, "Exec wasn't called")
}
func TestVarFromEnv(t *testing.T) {
os.Setenv("MOWCLI_DURATION", "1h2m3s")
os.Setenv("MOWCLI_ARG_PERCENTS", "25%, 1%")
os.Setenv("MOWCLI_OPT_PERCENTS", "90%, 42%")
duration := Duration(0)
argPercents := Percent{}
optPercents := Percent{}
app := App("var", "")
app.Spec = "-p... DURATION PERCENT..."
app.Var(VarArg{
Name: "DURATION",
Value: &duration,
EnvVar: "MOWCLI_DURATION",
})
app.Var(VarArg{
Name: "PERCENT",
Value: &argPercents,
EnvVar: "MOWCLI_ARG_PERCENTS",
})
app.Var(VarOpt{
Name: "p",
Value: &optPercents,
EnvVar: "MOWCLI_OPT_PERCENTS",
})
require.Equal(t, Duration(1*time.Hour+2*time.Minute+3*time.Second), duration)
require.Equal(t, Percent([]float64{0.25, 0.01}), argPercents)
require.Equal(t, Percent([]float64{0.9, 0.42}), optPercents)
}
func TestVarOverrideEnv(t *testing.T) {
os.Setenv("MOWCLI_PERCENTS", "25%, 1%")
percents := Percent{}
app := App("var", "")
app.Spec = "PERCENT..."
app.Var(VarArg{
Name: "PERCENT",
Value: &percents,
EnvVar: "MOWCLI_PERCENTS",
})
ex := false
app.Action = func() {
ex = true
require.Equal(t, Percent([]float64{0, 0.99}), percents)
}
app.Run([]string{"var", "0%", "99%"})
require.True(t, ex, "Action should have been called")
}

9
vendor/github.com/mattn/go-colorable/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
language: go
go:
- tip
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw

21
vendor/github.com/mattn/go-colorable/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Yasuhiro Matsumoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

48
vendor/github.com/mattn/go-colorable/README.md generated vendored Normal file
View File

@ -0,0 +1,48 @@
# go-colorable
[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable)
[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master)
[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
Colorable writer for windows.
For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
This package is possible to handle escape sequence for ansi color on windows.
## Too Bad!
![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
## So Good!
![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
## Usage
```go
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
logrus.SetOutput(colorable.NewColorableStdout())
logrus.Info("succeeded")
logrus.Warn("not correct")
logrus.Error("something error")
logrus.Fatal("panic")
```
You can compile above code on non-windows OSs.
## Installation
```
$ go get github.com/mattn/go-colorable
```
# License
MIT
# Author
Yasuhiro Matsumoto (a.k.a mattn)

View File

@ -0,0 +1,16 @@
package main
import (
"bufio"
"fmt"
"github.com/mattn/go-colorable"
)
func main() {
stdOut := bufio.NewWriter(colorable.NewColorableStdout())
fmt.Fprint(stdOut, "\x1B[3GMove to 3rd Column\n")
fmt.Fprint(stdOut, "\x1B[1;2HMove to 2nd Column on 1st Line\n")
stdOut.Flush()
}

View File

@ -0,0 +1,16 @@
package main
import (
"github.com/mattn/go-colorable"
"github.com/sirupsen/logrus"
)
func main() {
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
logrus.SetOutput(colorable.NewColorableStdout())
logrus.Info("succeeded")
logrus.Warn("not correct")
logrus.Error("something error")
logrus.Fatal("panic")
}

View File

@ -0,0 +1,14 @@
package main
import (
"fmt"
"os"
. "github.com/mattn/go-colorable"
)
func main() {
out := NewColorableStdout()
fmt.Fprint(out, "\x1B]0;TITLE Changed\007(See title and hit any key)")
var c [1]byte
os.Stdin.Read(c[:])
}

View File

@ -0,0 +1,29 @@
// +build appengine
package colorable
import (
"io"
"os"
_ "github.com/mattn/go-isatty"
)
// NewColorable return new instance of Writer which handle escape sequence.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
return file
}
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
func NewColorableStdout() io.Writer {
return os.Stdout
}
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
func NewColorableStderr() io.Writer {
return os.Stderr
}

View File

@ -0,0 +1,30 @@
// +build !windows
// +build !appengine
package colorable
import (
"io"
"os"
_ "github.com/mattn/go-isatty"
)
// NewColorable return new instance of Writer which handle escape sequence.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
return file
}
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
func NewColorableStdout() io.Writer {
return os.Stdout
}
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
func NewColorableStderr() io.Writer {
return os.Stderr
}

83
vendor/github.com/mattn/go-colorable/colorable_test.go generated vendored Normal file
View File

@ -0,0 +1,83 @@
package colorable
import (
"bytes"
"os"
"runtime"
"testing"
)
// checkEncoding checks that colorable is output encoding agnostic as long as
// the encoding is a superset of ASCII. This implies that one byte not part of
// an ANSI sequence must give exactly one byte in output
func checkEncoding(t *testing.T, data []byte) {
// Send non-UTF8 data to colorable
b := bytes.NewBuffer(make([]byte, 0, 10))
if b.Len() != 0 {
t.FailNow()
}
// TODO move colorable wrapping outside the test
c := NewNonColorable(b)
c.Write(data)
if b.Len() != len(data) {
t.Fatalf("%d bytes expected, got %d", len(data), b.Len())
}
}
func TestEncoding(t *testing.T) {
checkEncoding(t, []byte{}) // Empty
checkEncoding(t, []byte(`abc`)) // "abc"
checkEncoding(t, []byte(`é`)) // "é" in UTF-8
checkEncoding(t, []byte{233}) // 'é' in Latin-1
}
func TestNonColorable(t *testing.T) {
var buf bytes.Buffer
want := "hello"
NewNonColorable(&buf).Write([]byte("\x1b[0m" + want + "\x1b[2J"))
got := buf.String()
if got != "hello" {
t.Fatalf("want %q but %q", want, got)
}
buf.Reset()
NewNonColorable(&buf).Write([]byte("\x1b["))
got = buf.String()
if got != "" {
t.Fatalf("want %q but %q", "", got)
}
}
func TestNonColorableNil(t *testing.T) {
paniced := false
func() {
defer func() {
recover()
paniced = true
}()
NewNonColorable(nil)
NewColorable(nil)
}()
if !paniced {
t.Fatalf("should panic")
}
}
func TestColorable(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skipf("skip this test on windows")
}
_, ok := NewColorableStdout().(*os.File)
if !ok {
t.Fatalf("should os.Stdout on UNIX")
}
_, ok = NewColorableStderr().(*os.File)
if !ok {
t.Fatalf("should os.Stdout on UNIX")
}
_, ok = NewColorable(os.Stdout).(*os.File)
if !ok {
t.Fatalf("should os.Stdout on UNIX")
}
}

View File

@ -0,0 +1,884 @@
// +build windows
// +build !appengine
package colorable
import (
"bytes"
"io"
"math"
"os"
"strconv"
"strings"
"syscall"
"unsafe"
"github.com/mattn/go-isatty"
)
const (
foregroundBlue = 0x1
foregroundGreen = 0x2
foregroundRed = 0x4
foregroundIntensity = 0x8
foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
backgroundBlue = 0x10
backgroundGreen = 0x20
backgroundRed = 0x40
backgroundIntensity = 0x80
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
)
type wchar uint16
type short int16
type dword uint32
type word uint16
type coord struct {
x short
y short
}
type smallRect struct {
left short
top short
right short
bottom short
}
type consoleScreenBufferInfo struct {
size coord
cursorPosition coord
attributes word
window smallRect
maximumWindowSize coord
}
type consoleCursorInfo struct {
size dword
visible int32
}
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
)
// Writer provide colorable Writer to the console
type Writer struct {
out io.Writer
handle syscall.Handle
oldattr word
oldpos coord
}
// NewColorable return new instance of Writer which handle escape sequence from File.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
if isatty.IsTerminal(file.Fd()) {
var csbi consoleScreenBufferInfo
handle := syscall.Handle(file.Fd())
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
}
return file
}
// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
func NewColorableStdout() io.Writer {
return NewColorable(os.Stdout)
}
// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
func NewColorableStderr() io.Writer {
return NewColorable(os.Stderr)
}
var color256 = map[int]int{
0: 0x000000,
1: 0x800000,
2: 0x008000,
3: 0x808000,
4: 0x000080,
5: 0x800080,
6: 0x008080,
7: 0xc0c0c0,
8: 0x808080,
9: 0xff0000,
10: 0x00ff00,
11: 0xffff00,
12: 0x0000ff,
13: 0xff00ff,
14: 0x00ffff,
15: 0xffffff,
16: 0x000000,
17: 0x00005f,
18: 0x000087,
19: 0x0000af,
20: 0x0000d7,
21: 0x0000ff,
22: 0x005f00,
23: 0x005f5f,
24: 0x005f87,
25: 0x005faf,
26: 0x005fd7,
27: 0x005fff,
28: 0x008700,
29: 0x00875f,
30: 0x008787,
31: 0x0087af,
32: 0x0087d7,
33: 0x0087ff,
34: 0x00af00,
35: 0x00af5f,
36: 0x00af87,
37: 0x00afaf,
38: 0x00afd7,
39: 0x00afff,
40: 0x00d700,
41: 0x00d75f,
42: 0x00d787,
43: 0x00d7af,
44: 0x00d7d7,
45: 0x00d7ff,
46: 0x00ff00,
47: 0x00ff5f,
48: 0x00ff87,
49: 0x00ffaf,
50: 0x00ffd7,
51: 0x00ffff,
52: 0x5f0000,
53: 0x5f005f,
54: 0x5f0087,
55: 0x5f00af,
56: 0x5f00d7,
57: 0x5f00ff,
58: 0x5f5f00,
59: 0x5f5f5f,
60: 0x5f5f87,
61: 0x5f5faf,
62: 0x5f5fd7,
63: 0x5f5fff,
64: 0x5f8700,
65: 0x5f875f,
66: 0x5f8787,
67: 0x5f87af,
68: 0x5f87d7,
69: 0x5f87ff,
70: 0x5faf00,
71: 0x5faf5f,
72: 0x5faf87,
73: 0x5fafaf,
74: 0x5fafd7,
75: 0x5fafff,
76: 0x5fd700,
77: 0x5fd75f,
78: 0x5fd787,
79: 0x5fd7af,
80: 0x5fd7d7,
81: 0x5fd7ff,
82: 0x5fff00,
83: 0x5fff5f,
84: 0x5fff87,
85: 0x5fffaf,
86: 0x5fffd7,
87: 0x5fffff,
88: 0x870000,
89: 0x87005f,
90: 0x870087,
91: 0x8700af,
92: 0x8700d7,
93: 0x8700ff,
94: 0x875f00,
95: 0x875f5f,
96: 0x875f87,
97: 0x875faf,
98: 0x875fd7,
99: 0x875fff,
100: 0x878700,
101: 0x87875f,
102: 0x878787,
103: 0x8787af,
104: 0x8787d7,
105: 0x8787ff,
106: 0x87af00,
107: 0x87af5f,
108: 0x87af87,
109: 0x87afaf,
110: 0x87afd7,
111: 0x87afff,
112: 0x87d700,
113: 0x87d75f,
114: 0x87d787,
115: 0x87d7af,
116: 0x87d7d7,
117: 0x87d7ff,
118: 0x87ff00,
119: 0x87ff5f,
120: 0x87ff87,
121: 0x87ffaf,
122: 0x87ffd7,
123: 0x87ffff,
124: 0xaf0000,
125: 0xaf005f,
126: 0xaf0087,
127: 0xaf00af,
128: 0xaf00d7,
129: 0xaf00ff,
130: 0xaf5f00,
131: 0xaf5f5f,
132: 0xaf5f87,
133: 0xaf5faf,
134: 0xaf5fd7,
135: 0xaf5fff,
136: 0xaf8700,
137: 0xaf875f,
138: 0xaf8787,
139: 0xaf87af,
140: 0xaf87d7,
141: 0xaf87ff,
142: 0xafaf00,
143: 0xafaf5f,
144: 0xafaf87,
145: 0xafafaf,
146: 0xafafd7,
147: 0xafafff,
148: 0xafd700,
149: 0xafd75f,
150: 0xafd787,
151: 0xafd7af,
152: 0xafd7d7,
153: 0xafd7ff,
154: 0xafff00,
155: 0xafff5f,
156: 0xafff87,
157: 0xafffaf,
158: 0xafffd7,
159: 0xafffff,
160: 0xd70000,
161: 0xd7005f,
162: 0xd70087,
163: 0xd700af,
164: 0xd700d7,
165: 0xd700ff,
166: 0xd75f00,
167: 0xd75f5f,
168: 0xd75f87,
169: 0xd75faf,
170: 0xd75fd7,
171: 0xd75fff,
172: 0xd78700,
173: 0xd7875f,
174: 0xd78787,
175: 0xd787af,
176: 0xd787d7,
177: 0xd787ff,
178: 0xd7af00,
179: 0xd7af5f,
180: 0xd7af87,
181: 0xd7afaf,
182: 0xd7afd7,
183: 0xd7afff,
184: 0xd7d700,
185: 0xd7d75f,
186: 0xd7d787,
187: 0xd7d7af,
188: 0xd7d7d7,
189: 0xd7d7ff,
190: 0xd7ff00,
191: 0xd7ff5f,
192: 0xd7ff87,
193: 0xd7ffaf,
194: 0xd7ffd7,
195: 0xd7ffff,
196: 0xff0000,
197: 0xff005f,
198: 0xff0087,
199: 0xff00af,
200: 0xff00d7,
201: 0xff00ff,
202: 0xff5f00,
203: 0xff5f5f,
204: 0xff5f87,
205: 0xff5faf,
206: 0xff5fd7,
207: 0xff5fff,
208: 0xff8700,
209: 0xff875f,
210: 0xff8787,
211: 0xff87af,
212: 0xff87d7,
213: 0xff87ff,
214: 0xffaf00,
215: 0xffaf5f,
216: 0xffaf87,
217: 0xffafaf,
218: 0xffafd7,
219: 0xffafff,
220: 0xffd700,
221: 0xffd75f,
222: 0xffd787,
223: 0xffd7af,
224: 0xffd7d7,
225: 0xffd7ff,
226: 0xffff00,
227: 0xffff5f,
228: 0xffff87,
229: 0xffffaf,
230: 0xffffd7,
231: 0xffffff,
232: 0x080808,
233: 0x121212,
234: 0x1c1c1c,
235: 0x262626,
236: 0x303030,
237: 0x3a3a3a,
238: 0x444444,
239: 0x4e4e4e,
240: 0x585858,
241: 0x626262,
242: 0x6c6c6c,
243: 0x767676,
244: 0x808080,
245: 0x8a8a8a,
246: 0x949494,
247: 0x9e9e9e,
248: 0xa8a8a8,
249: 0xb2b2b2,
250: 0xbcbcbc,
251: 0xc6c6c6,
252: 0xd0d0d0,
253: 0xdadada,
254: 0xe4e4e4,
255: 0xeeeeee,
}
// `\033]0;TITLESTR\007`
func doTitleSequence(er *bytes.Reader) error {
var c byte
var err error
c, err = er.ReadByte()
if err != nil {
return err
}
if c != '0' && c != '2' {
return nil
}
c, err = er.ReadByte()
if err != nil {
return err
}
if c != ';' {
return nil
}
title := make([]byte, 0, 80)
for {
c, err = er.ReadByte()
if err != nil {
return err
}
if c == 0x07 || c == '\n' {
break
}
title = append(title, c)
}
if len(title) > 0 {
title8, err := syscall.UTF16PtrFromString(string(title))
if err == nil {
procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
}
}
return nil
}
// Write write data on console
func (w *Writer) Write(data []byte) (n int, err error) {
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
er := bytes.NewReader(data)
var bw [1]byte
loop:
for {
c1, err := er.ReadByte()
if err != nil {
break loop
}
if c1 != 0x1b {
bw[0] = c1
w.out.Write(bw[:])
continue
}
c2, err := er.ReadByte()
if err != nil {
break loop
}
if c2 == ']' {
if err := doTitleSequence(er); err != nil {
break loop
}
continue
}
if c2 != 0x5b {
continue
}
var buf bytes.Buffer
var m byte
for {
c, err := er.ReadByte()
if err != nil {
break loop
}
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
m = c
break
}
buf.Write([]byte(string(c)))
}
switch m {
case 'A':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.y -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'B':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.y += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'C':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'D':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'E':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = 0
csbi.cursorPosition.y += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'F':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = 0
csbi.cursorPosition.y -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'G':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = short(n - 1)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'H', 'f':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
if buf.Len() > 0 {
token := strings.Split(buf.String(), ";")
switch len(token) {
case 1:
n1, err := strconv.Atoi(token[0])
if err != nil {
continue
}
csbi.cursorPosition.y = short(n1 - 1)
case 2:
n1, err := strconv.Atoi(token[0])
if err != nil {
continue
}
n2, err := strconv.Atoi(token[1])
if err != nil {
continue
}
csbi.cursorPosition.x = short(n2 - 1)
csbi.cursorPosition.y = short(n1 - 1)
}
} else {
csbi.cursorPosition.y = 0
}
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'J':
n := 0
if buf.Len() > 0 {
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
}
var count, written dword
var cursor coord
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
switch n {
case 0:
cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
case 1:
cursor = coord{x: csbi.window.left, y: csbi.window.top}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x)
case 2:
cursor = coord{x: csbi.window.left, y: csbi.window.top}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
}
procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'K':
n := 0
if buf.Len() > 0 {
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
var cursor coord
var count, written dword
switch n {
case 0:
cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x - 1)
case 1:
cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x)
case 2:
cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
count = dword(csbi.size.x)
}
procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'm':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
attr := csbi.attributes
cs := buf.String()
if cs == "" {
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
continue
}
token := strings.Split(cs, ";")
for i := 0; i < len(token); i++ {
ns := token[i]
if n, err = strconv.Atoi(ns); err == nil {
switch {
case n == 0 || n == 100:
attr = w.oldattr
case 1 <= n && n <= 5:
attr |= foregroundIntensity
case n == 7:
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
case n == 22 || n == 25:
attr |= foregroundIntensity
case n == 27:
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
case 30 <= n && n <= 37:
attr &= backgroundMask
if (n-30)&1 != 0 {
attr |= foregroundRed
}
if (n-30)&2 != 0 {
attr |= foregroundGreen
}
if (n-30)&4 != 0 {
attr |= foregroundBlue
}
case n == 38: // set foreground color.
if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
if n256, err := strconv.Atoi(token[i+2]); err == nil {
if n256foreAttr == nil {
n256setup()
}
attr &= backgroundMask
attr |= n256foreAttr[n256]
i += 2
}
} else {
attr = attr & (w.oldattr & backgroundMask)
}
case n == 39: // reset foreground color.
attr &= backgroundMask
attr |= w.oldattr & foregroundMask
case 40 <= n && n <= 47:
attr &= foregroundMask
if (n-40)&1 != 0 {
attr |= backgroundRed
}
if (n-40)&2 != 0 {
attr |= backgroundGreen
}
if (n-40)&4 != 0 {
attr |= backgroundBlue
}
case n == 48: // set background color.
if i < len(token)-2 && token[i+1] == "5" {
if n256, err := strconv.Atoi(token[i+2]); err == nil {
if n256backAttr == nil {
n256setup()
}
attr &= foregroundMask
attr |= n256backAttr[n256]
i += 2
}
} else {
attr = attr & (w.oldattr & foregroundMask)
}
case n == 49: // reset foreground color.
attr &= foregroundMask
attr |= w.oldattr & backgroundMask
case 90 <= n && n <= 97:
attr = (attr & backgroundMask)
attr |= foregroundIntensity
if (n-90)&1 != 0 {
attr |= foregroundRed
}
if (n-90)&2 != 0 {
attr |= foregroundGreen
}
if (n-90)&4 != 0 {
attr |= foregroundBlue
}
case 100 <= n && n <= 107:
attr = (attr & foregroundMask)
attr |= backgroundIntensity
if (n-100)&1 != 0 {
attr |= backgroundRed
}
if (n-100)&2 != 0 {
attr |= backgroundGreen
}
if (n-100)&4 != 0 {
attr |= backgroundBlue
}
}
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
}
}
case 'h':
var ci consoleCursorInfo
cs := buf.String()
if cs == "5>" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?25" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
}
case 'l':
var ci consoleCursorInfo
cs := buf.String()
if cs == "5>" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?25" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
}
case 's':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
w.oldpos = csbi.cursorPosition
case 'u':
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
}
}
return len(data), nil
}
type consoleColor struct {
rgb int
red bool
green bool
blue bool
intensity bool
}
func (c consoleColor) foregroundAttr() (attr word) {
if c.red {
attr |= foregroundRed
}
if c.green {
attr |= foregroundGreen
}
if c.blue {
attr |= foregroundBlue
}
if c.intensity {
attr |= foregroundIntensity
}
return
}
func (c consoleColor) backgroundAttr() (attr word) {
if c.red {
attr |= backgroundRed
}
if c.green {
attr |= backgroundGreen
}
if c.blue {
attr |= backgroundBlue
}
if c.intensity {
attr |= backgroundIntensity
}
return
}
var color16 = []consoleColor{
{0x000000, false, false, false, false},
{0x000080, false, false, true, false},
{0x008000, false, true, false, false},
{0x008080, false, true, true, false},
{0x800000, true, false, false, false},
{0x800080, true, false, true, false},
{0x808000, true, true, false, false},
{0xc0c0c0, true, true, true, false},
{0x808080, false, false, false, true},
{0x0000ff, false, false, true, true},
{0x00ff00, false, true, false, true},
{0x00ffff, false, true, true, true},
{0xff0000, true, false, false, true},
{0xff00ff, true, false, true, true},
{0xffff00, true, true, false, true},
{0xffffff, true, true, true, true},
}
type hsv struct {
h, s, v float32
}
func (a hsv) dist(b hsv) float32 {
dh := a.h - b.h
switch {
case dh > 0.5:
dh = 1 - dh
case dh < -0.5:
dh = -1 - dh
}
ds := a.s - b.s
dv := a.v - b.v
return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
}
func toHSV(rgb int) hsv {
r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
float32((rgb&0x00FF00)>>8)/256.0,
float32(rgb&0x0000FF)/256.0
min, max := minmax3f(r, g, b)
h := max - min
if h > 0 {
if max == r {
h = (g - b) / h
if h < 0 {
h += 6
}
} else if max == g {
h = 2 + (b-r)/h
} else {
h = 4 + (r-g)/h
}
}
h /= 6.0
s := max - min
if max != 0 {
s /= max
}
v := max
return hsv{h: h, s: s, v: v}
}
type hsvTable []hsv
func toHSVTable(rgbTable []consoleColor) hsvTable {
t := make(hsvTable, len(rgbTable))
for i, c := range rgbTable {
t[i] = toHSV(c.rgb)
}
return t
}
func (t hsvTable) find(rgb int) consoleColor {
hsv := toHSV(rgb)
n := 7
l := float32(5.0)
for i, p := range t {
d := hsv.dist(p)
if d < l {
l, n = d, i
}
}
return color16[n]
}
func minmax3f(a, b, c float32) (min, max float32) {
if a < b {
if b < c {
return a, c
} else if a < c {
return a, b
} else {
return c, b
}
} else {
if a < c {
return b, c
} else if b < c {
return b, a
} else {
return c, a
}
}
}
var n256foreAttr []word
var n256backAttr []word
func n256setup() {
n256foreAttr = make([]word, 256)
n256backAttr = make([]word, 256)
t := toHSVTable(color16)
for i, rgb := range color256 {
c := t.find(rgb)
n256foreAttr[i] = c.foregroundAttr()
n256backAttr[i] = c.backgroundAttr()
}
}

55
vendor/github.com/mattn/go-colorable/noncolorable.go generated vendored Normal file
View File

@ -0,0 +1,55 @@
package colorable
import (
"bytes"
"io"
)
// NonColorable hold writer but remove escape sequence.
type NonColorable struct {
out io.Writer
}
// NewNonColorable return new instance of Writer which remove escape sequence from Writer.
func NewNonColorable(w io.Writer) io.Writer {
return &NonColorable{out: w}
}
// Write write data on console
func (w *NonColorable) Write(data []byte) (n int, err error) {
er := bytes.NewReader(data)
var bw [1]byte
loop:
for {
c1, err := er.ReadByte()
if err != nil {
break loop
}
if c1 != 0x1b {
bw[0] = c1
w.out.Write(bw[:])
continue
}
c2, err := er.ReadByte()
if err != nil {
break loop
}
if c2 != 0x5b {
continue
}
var buf bytes.Buffer
for {
c, err := er.ReadByte()
if err != nil {
break loop
}
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
break
}
buf.Write([]byte(string(c)))
}
}
return len(data), nil
}

9
vendor/github.com/mattn/go-isatty/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
language: go
go:
- tip
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5

9
vendor/github.com/mattn/go-isatty/LICENSE generated vendored Normal file
View File

@ -0,0 +1,9 @@
Copyright (c) Yasuhiro MATSUMOTO <mattn.jp@gmail.com>
MIT License (Expat)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

50
vendor/github.com/mattn/go-isatty/README.md generated vendored Normal file
View File

@ -0,0 +1,50 @@
# go-isatty
[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty)
[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
isatty for golang
## Usage
```go
package main
import (
"fmt"
"github.com/mattn/go-isatty"
"os"
)
func main() {
if isatty.IsTerminal(os.Stdout.Fd()) {
fmt.Println("Is Terminal")
} else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
fmt.Println("Is Cygwin/MSYS2 Terminal")
} else {
fmt.Println("Is Not Terminal")
}
}
```
## Installation
```
$ go get github.com/mattn/go-isatty
```
## License
MIT
## Author
Yasuhiro Matsumoto (a.k.a mattn)
## Thanks
* k-takata: base idea for IsCygwinTerminal
https://github.com/k-takata/go-iscygpty

2
vendor/github.com/mattn/go-isatty/doc.go generated vendored Normal file
View File

@ -0,0 +1,2 @@
// Package isatty implements interface to isatty
package isatty

18
vendor/github.com/mattn/go-isatty/example_test.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
package isatty_test
import (
"fmt"
"os"
"github.com/mattn/go-isatty"
)
func Example() {
if isatty.IsTerminal(os.Stdout.Fd()) {
fmt.Println("Is Terminal")
} else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
fmt.Println("Is Cygwin/MSYS2 Terminal")
} else {
fmt.Println("Is Not Terminal")
}
}

15
vendor/github.com/mattn/go-isatty/isatty_appengine.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// +build appengine
package isatty
// IsTerminal returns true if the file descriptor is terminal which
// is always false on on appengine classic which is a sandboxed PaaS.
func IsTerminal(fd uintptr) bool {
return false
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

18
vendor/github.com/mattn/go-isatty/isatty_bsd.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package isatty
import (
"syscall"
"unsafe"
)
const ioctlReadTermios = syscall.TIOCGETA
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

18
vendor/github.com/mattn/go-isatty/isatty_linux.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// +build linux
// +build !appengine,!ppc64,!ppc64le
package isatty
import (
"syscall"
"unsafe"
)
const ioctlReadTermios = syscall.TCGETS
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

View File

@ -0,0 +1,19 @@
// +build linux
// +build ppc64 ppc64le
package isatty
import (
"unsafe"
syscall "golang.org/x/sys/unix"
)
const ioctlReadTermios = syscall.TCGETS
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

10
vendor/github.com/mattn/go-isatty/isatty_others.go generated vendored Normal file
View File

@ -0,0 +1,10 @@
// +build !windows
// +build !appengine
package isatty
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

View File

@ -0,0 +1,19 @@
// +build !windows
package isatty
import (
"os"
"testing"
)
func TestTerminal(t *testing.T) {
// test for non-panic
IsTerminal(os.Stdout.Fd())
}
func TestCygwinPipeName(t *testing.T) {
if IsCygwinTerminal(os.Stdout.Fd()) {
t.Fatal("should be false always")
}
}

16
vendor/github.com/mattn/go-isatty/isatty_solaris.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// +build solaris
// +build !appengine
package isatty
import (
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
func IsTerminal(fd uintptr) bool {
var termio unix.Termio
err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
return err == nil
}

94
vendor/github.com/mattn/go-isatty/isatty_windows.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
// +build windows
// +build !appengine
package isatty
import (
"strings"
"syscall"
"unicode/utf16"
"unsafe"
)
const (
fileNameInfo uintptr = 2
fileTypePipe = 3
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
procGetFileType = kernel32.NewProc("GetFileType")
)
func init() {
// Check if GetFileInformationByHandleEx is available.
if procGetFileInformationByHandleEx.Find() != nil {
procGetFileInformationByHandleEx = nil
}
}
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
// Check pipe name is used for cygwin/msys2 pty.
// Cygwin/MSYS2 PTY has a name like:
// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
func isCygwinPipeName(name string) bool {
token := strings.Split(name, "-")
if len(token) < 5 {
return false
}
if token[0] != `\msys` && token[0] != `\cygwin` {
return false
}
if token[1] == "" {
return false
}
if !strings.HasPrefix(token[2], "pty") {
return false
}
if token[3] != `from` && token[3] != `to` {
return false
}
if token[4] != "master" {
return false
}
return true
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal.
func IsCygwinTerminal(fd uintptr) bool {
if procGetFileInformationByHandleEx == nil {
return false
}
// Cygwin/msys's pty is a pipe.
ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
if ft != fileTypePipe || e != 0 {
return false
}
var buf [2 + syscall.MAX_PATH]uint16
r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
uintptr(len(buf)*2), 0, 0)
if r == 0 || e != 0 {
return false
}
l := *(*uint32)(unsafe.Pointer(&buf))
return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
}

View File

@ -0,0 +1,35 @@
// +build windows
package isatty
import (
"testing"
)
func TestCygwinPipeName(t *testing.T) {
tests := []struct {
name string
result bool
}{
{``, false},
{`\msys-`, false},
{`\cygwin-----`, false},
{`\msys-x-PTY5-pty1-from-master`, false},
{`\cygwin-x-PTY5-from-master`, false},
{`\cygwin-x-pty2-from-toaster`, false},
{`\cygwin--pty2-from-master`, false},
{`\\cygwin-x-pty2-from-master`, false},
{`\cygwin-x-pty2-from-master-`, true}, // for the feature
{`\cygwin-e022582115c10879-pty4-from-master`, true},
{`\msys-e022582115c10879-pty4-to-master`, true},
{`\cygwin-e022582115c10879-pty4-to-master`, true},
}
for _, test := range tests {
want := test.result
got := isCygwinPipeName(test.name)
if want != got {
t.Fatalf("isatty(%q): got %v, want %v:", test.name, got, want)
}
}
}

4
vendor/github.com/mattn/go-sqlite3/.gitignore generated vendored Normal file
View File

@ -0,0 +1,4 @@
*.db
*.exe
*.dll
*.o

19
vendor/github.com/mattn/go-sqlite3/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,19 @@
language: go
sudo: required
dist: trusty
env:
- GOTAGS=
- GOTAGS=libsqlite3
- GOTAGS=trace
- GOTAGS=vtable
go:
- 1.7.x
- 1.8.x
- 1.9.x
- master
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx
- go test -race -v . -tags "$GOTAGS"

21
vendor/github.com/mattn/go-sqlite3/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Yasuhiro Matsumoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

97
vendor/github.com/mattn/go-sqlite3/README.md generated vendored Normal file
View File

@ -0,0 +1,97 @@
go-sqlite3
==========
[![GoDoc Reference](https://godoc.org/github.com/mattn/go-sqlite3?status.svg)](http://godoc.org/github.com/mattn/go-sqlite3)
[![Build Status](https://travis-ci.org/mattn/go-sqlite3.svg?branch=master)](https://travis-ci.org/mattn/go-sqlite3)
[![Coverage Status](https://coveralls.io/repos/mattn/go-sqlite3/badge.svg?branch=master)](https://coveralls.io/r/mattn/go-sqlite3?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-sqlite3)](https://goreportcard.com/report/github.com/mattn/go-sqlite3)
Description
-----------
sqlite3 driver conforming to the built-in database/sql interface
Installation
------------
This package can be installed with the go get command:
go get github.com/mattn/go-sqlite3
_go-sqlite3_ is *cgo* package.
If you want to build your app using go-sqlite3, you need gcc.
However, if you install _go-sqlite3_ with `go install github.com/mattn/go-sqlite3`, you don't need gcc to build your app anymore.
Documentation
-------------
API documentation can be found here: http://godoc.org/github.com/mattn/go-sqlite3
Examples can be found under the `./_example` directory
FAQ
---
* Want to build go-sqlite3 with libsqlite3 on my linux.
Use `go build --tags "libsqlite3 linux"`
* Want to build go-sqlite3 with libsqlite3 on OS X.
Install sqlite3 from homebrew: `brew install sqlite3`
Use `go build --tags "libsqlite3 darwin"`
* Want to build go-sqlite3 with icu extension.
Use `go build --tags "icu"`
Available extensions: `json1`, `fts5`, `icu`
* Can't build go-sqlite3 on windows 64bit.
> Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit.
> See: [#27](https://github.com/mattn/go-sqlite3/issues/27)
* Getting insert error while query is opened.
> You can pass some arguments into the connection string, for example, a URI.
> See: [#39](https://github.com/mattn/go-sqlite3/issues/39)
* Do you want to cross compile? mingw on Linux or Mac?
> See: [#106](https://github.com/mattn/go-sqlite3/issues/106)
> See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html
* Want to get time.Time with current locale
Use `_loc=auto` in SQLite3 filename schema like `file:foo.db?_loc=auto`.
* Can I use this in multiple routines concurrently?
Yes for readonly. But, No for writable. See [#50](https://github.com/mattn/go-sqlite3/issues/50), [#51](https://github.com/mattn/go-sqlite3/issues/51), [#209](https://github.com/mattn/go-sqlite3/issues/209).
* Why is it racy if I use a `sql.Open("sqlite3", ":memory:")` database?
Each connection to :memory: opens a brand new in-memory sql database, so if
the stdlib's sql engine happens to open another connection and you've only
specified ":memory:", that connection will see a brand new database. A
workaround is to use "file::memory:?mode=memory&cache=shared". Every
connection to this string will point to the same in-memory database. See
[#204](https://github.com/mattn/go-sqlite3/issues/204) for more info.
License
-------
MIT: http://mattn.mit-license.org/2012
sqlite3-binding.c, sqlite3-binding.h, sqlite3ext.h
The -binding suffix was added to avoid build failures under gccgo.
In this repository, those files are an amalgamation of code that was copied from SQLite3. The license of that code is the same as the license of SQLite3.
Author
------
Yasuhiro Matsumoto (a.k.a mattn)

View File

@ -0,0 +1,133 @@
package main
import (
"database/sql"
"fmt"
"log"
"math"
"math/rand"
sqlite "github.com/mattn/go-sqlite3"
)
// Computes x^y
func pow(x, y int64) int64 {
return int64(math.Pow(float64(x), float64(y)))
}
// Computes the bitwise exclusive-or of all its arguments
func xor(xs ...int64) int64 {
var ret int64
for _, x := range xs {
ret ^= x
}
return ret
}
// Returns a random number. It's actually deterministic here because
// we don't seed the RNG, but it's an example of a non-pure function
// from SQLite's POV.
func getrand() int64 {
return rand.Int63()
}
// Computes the standard deviation of a GROUPed BY set of values
type stddev struct {
xs []int64
// Running average calculation
sum int64
n int64
}
func newStddev() *stddev { return &stddev{} }
func (s *stddev) Step(x int64) {
s.xs = append(s.xs, x)
s.sum += x
s.n++
}
func (s *stddev) Done() float64 {
mean := float64(s.sum) / float64(s.n)
var sqDiff []float64
for _, x := range s.xs {
sqDiff = append(sqDiff, math.Pow(float64(x)-mean, 2))
}
var dev float64
for _, x := range sqDiff {
dev += x
}
dev /= float64(len(sqDiff))
return math.Sqrt(dev)
}
func main() {
sql.Register("sqlite3_custom", &sqlite.SQLiteDriver{
ConnectHook: func(conn *sqlite.SQLiteConn) error {
if err := conn.RegisterFunc("pow", pow, true); err != nil {
return err
}
if err := conn.RegisterFunc("xor", xor, true); err != nil {
return err
}
if err := conn.RegisterFunc("rand", getrand, false); err != nil {
return err
}
if err := conn.RegisterAggregator("stddev", newStddev, true); err != nil {
return err
}
return nil
},
})
db, err := sql.Open("sqlite3_custom", ":memory:")
if err != nil {
log.Fatal("Failed to open database:", err)
}
defer db.Close()
var i int64
err = db.QueryRow("SELECT pow(2,3)").Scan(&i)
if err != nil {
log.Fatal("POW query error:", err)
}
fmt.Println("pow(2,3) =", i) // 8
err = db.QueryRow("SELECT xor(1,2,3,4,5,6)").Scan(&i)
if err != nil {
log.Fatal("XOR query error:", err)
}
fmt.Println("xor(1,2,3,4,5) =", i) // 7
err = db.QueryRow("SELECT rand()").Scan(&i)
if err != nil {
log.Fatal("RAND query error:", err)
}
fmt.Println("rand() =", i) // pseudorandom
_, err = db.Exec("create table foo (department integer, profits integer)")
if err != nil {
log.Fatal("Failed to create table:", err)
}
_, err = db.Exec("insert into foo values (1, 10), (1, 20), (1, 45), (2, 42), (2, 115)")
if err != nil {
log.Fatal("Failed to insert records:", err)
}
rows, err := db.Query("select department, stddev(profits) from foo group by department")
if err != nil {
log.Fatal("STDDEV query error:", err)
}
defer rows.Close()
for rows.Next() {
var dept int64
var dev float64
if err := rows.Scan(&dept, &dev); err != nil {
log.Fatal(err)
}
fmt.Printf("dept=%d stddev=%f\n", dept, dev)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
}

View File

@ -0,0 +1,78 @@
package main
import (
"database/sql"
"log"
"os"
"github.com/mattn/go-sqlite3"
)
func main() {
sqlite3conn := []*sqlite3.SQLiteConn{}
sql.Register("sqlite3_with_hook_example",
&sqlite3.SQLiteDriver{
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
sqlite3conn = append(sqlite3conn, conn)
conn.RegisterUpdateHook(func(op int, db string, table string, rowid int64) {
switch op {
case sqlite3.SQLITE_INSERT:
log.Println("Notified of insert on db", db, "table", table, "rowid", rowid)
}
})
return nil
},
})
os.Remove("./foo.db")
os.Remove("./bar.db")
srcDb, err := sql.Open("sqlite3_with_hook_example", "./foo.db")
if err != nil {
log.Fatal(err)
}
defer srcDb.Close()
srcDb.Ping()
_, err = srcDb.Exec("create table foo(id int, value text)")
if err != nil {
log.Fatal(err)
}
_, err = srcDb.Exec("insert into foo values(1, 'foo')")
if err != nil {
log.Fatal(err)
}
_, err = srcDb.Exec("insert into foo values(2, 'bar')")
if err != nil {
log.Fatal(err)
}
_, err = srcDb.Query("select * from foo")
if err != nil {
log.Fatal(err)
}
destDb, err := sql.Open("sqlite3_with_hook_example", "./bar.db")
if err != nil {
log.Fatal(err)
}
defer destDb.Close()
destDb.Ping()
bk, err := sqlite3conn[1].Backup("main", sqlite3conn[0], "main")
if err != nil {
log.Fatal(err)
}
_, err = bk.Step(-1)
if err != nil {
log.Fatal(err)
}
_, err = destDb.Query("select * from foo")
if err != nil {
log.Fatal(err)
}
_, err = destDb.Exec("insert into foo values(3, 'bar')")
if err != nil {
log.Fatal(err)
}
bk.Finish()
}

View File

@ -0,0 +1,113 @@
package main
import (
"database/sql"
"fmt"
"log"
"os"
"strings"
"github.com/mattn/go-sqlite3"
)
func createBulkInsertQuery(n int, start int) (query string, args []interface{}) {
values := make([]string, n)
args = make([]interface{}, n*2)
pos := 0
for i := 0; i < n; i++ {
values[i] = "(?, ?)"
args[pos] = start + i
args[pos+1] = fmt.Sprintf("こんにちわ世界%03d", i)
pos += 2
}
query = fmt.Sprintf(
"insert into foo(id, name) values %s",
strings.Join(values, ", "),
)
return
}
func bukInsert(db *sql.DB, query string, args []interface{}) (err error) {
stmt, err := db.Prepare(query)
if err != nil {
return
}
_, err = stmt.Exec(args...)
if err != nil {
return
}
return
}
func main() {
var sqlite3conn *sqlite3.SQLiteConn
sql.Register("sqlite3_with_limit", &sqlite3.SQLiteDriver{
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
sqlite3conn = conn
return nil
},
})
os.Remove("./foo.db")
db, err := sql.Open("sqlite3_with_limit", "./foo.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sqlStmt := `
create table foo (id integer not null primary key, name text);
delete from foo;
`
_, err = db.Exec(sqlStmt)
if err != nil {
log.Printf("%q: %s\n", err, sqlStmt)
return
}
if sqlite3conn == nil {
log.Fatal("not set sqlite3 connection")
}
limitVariableNumber := sqlite3conn.GetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER)
log.Printf("default SQLITE_LIMIT_VARIABLE_NUMBER: %d", limitVariableNumber)
num := 400
query, args := createBulkInsertQuery(num, 0)
err = bukInsert(db, query, args)
if err != nil {
log.Fatal(err)
}
smallLimitVariableNumber := 100
sqlite3conn.SetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER, smallLimitVariableNumber)
limitVariableNumber = sqlite3conn.GetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER)
log.Printf("updated SQLITE_LIMIT_VARIABLE_NUMBER: %d", limitVariableNumber)
query, args = createBulkInsertQuery(num, num)
err = bukInsert(db, query, args)
if err != nil {
if err != nil {
log.Printf("expect failed since SQLITE_LIMIT_VARIABLE_NUMBER is too small: %v", err)
}
}
bigLimitVariableNumber := 999999
sqlite3conn.SetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER, bigLimitVariableNumber)
limitVariableNumber = sqlite3conn.GetLimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER)
log.Printf("set SQLITE_LIMIT_VARIABLE_NUMBER: %d", bigLimitVariableNumber)
log.Printf("updated SQLITE_LIMIT_VARIABLE_NUMBER: %d", limitVariableNumber)
query, args = createBulkInsertQuery(500, num+num)
err = bukInsert(db, query, args)
if err != nil {
if err != nil {
log.Fatal(err)
}
}
log.Println("no error if SQLITE_LIMIT_VARIABLE_NUMBER > 999")
}

View File

@ -0,0 +1,22 @@
ifeq ($(OS),Windows_NT)
EXE=extension.exe
EXT=sqlite3_mod_regexp.dll
RM=cmd /c del
LDFLAG=
else
EXE=extension
EXT=sqlite3_mod_regexp.so
RM=rm
LDFLAG=-fPIC
endif
all : $(EXE) $(EXT)
$(EXE) : extension.go
go build $<
$(EXT) : sqlite3_mod_regexp.c
gcc $(LDFLAG) -shared -o $@ $< -lsqlite3 -lpcre
clean :
@-$(RM) $(EXE) $(EXT)

View File

@ -0,0 +1,43 @@
package main
import (
"database/sql"
"fmt"
"github.com/mattn/go-sqlite3"
"log"
)
func main() {
sql.Register("sqlite3_with_extensions",
&sqlite3.SQLiteDriver{
Extensions: []string{
"sqlite3_mod_regexp",
},
})
db, err := sql.Open("sqlite3_with_extensions", ":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Force db to make a new connection in pool
// by putting the original in a transaction
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
defer tx.Commit()
// New connection works (hopefully!)
rows, err := db.Query("select 'hello world' where 'hello world' regexp '^hello.*d$'")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var helloworld string
rows.Scan(&helloworld)
fmt.Println(helloworld)
}
}

View File

@ -0,0 +1,31 @@
#include <pcre.h>
#include <string.h>
#include <stdio.h>
#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
if (argc >= 2) {
const char *target = (const char *)sqlite3_value_text(argv[1]);
const char *pattern = (const char *)sqlite3_value_text(argv[0]);
const char* errstr = NULL;
int erroff = 0;
int vec[500];
int n, rc;
pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL);
rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
if (rc <= 0) {
sqlite3_result_error(context, errstr, 0);
return;
}
sqlite3_result_int(context, 1);
}
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
SQLITE_EXTENSION_INIT2(api);
return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, (void*)db, regexp_func, NULL, NULL);
}

View File

@ -0,0 +1,24 @@
ifeq ($(OS),Windows_NT)
EXE=extension.exe
EXT=sqlite3_mod_vtable.dll
RM=cmd /c del
LIBCURL=-lcurldll
LDFLAG=
else
EXE=extension
EXT=sqlite3_mod_vtable.so
RM=rm
LDFLAG=-fPIC
LIBCURL=-lcurl
endif
all : $(EXE) $(EXT)
$(EXE) : extension.go
go build $<
$(EXT) : sqlite3_mod_vtable.cc
g++ $(LDFLAG) -shared -o $@ $< -lsqlite3 $(LIBCURL)
clean :
@-$(RM) $(EXE) $(EXT)

View File

@ -0,0 +1,37 @@
package main
import (
"database/sql"
"fmt"
"log"
"github.com/mattn/go-sqlite3"
)
func main() {
sql.Register("sqlite3_with_extensions",
&sqlite3.SQLiteDriver{
Extensions: []string{
"sqlite3_mod_vtable",
},
})
db, err := sql.Open("sqlite3_with_extensions", ":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
db.Exec("create virtual table repo using github(id, full_name, description, html_url)")
rows, err := db.Query("select id, full_name, description, html_url from repo")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id, fullName, description, htmlURL string
rows.Scan(&id, &fullName, &description, &htmlURL)
fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, fullName, description, htmlURL)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,238 @@
#include <string>
#include <sstream>
#include <sqlite3-binding.h>
#include <sqlite3ext.h>
#include <curl/curl.h>
#include "picojson.h"
#ifdef _WIN32
# define EXPORT __declspec(dllexport)
#else
# define EXPORT
#endif
SQLITE_EXTENSION_INIT1;
typedef struct {
char* data; // response data from server
size_t size; // response size of data
} MEMFILE;
MEMFILE*
memfopen() {
MEMFILE* mf = (MEMFILE*) malloc(sizeof(MEMFILE));
if (mf) {
mf->data = NULL;
mf->size = 0;
}
return mf;
}
void
memfclose(MEMFILE* mf) {
if (mf->data) free(mf->data);
free(mf);
}
size_t
memfwrite(char* ptr, size_t size, size_t nmemb, void* stream) {
MEMFILE* mf = (MEMFILE*) stream;
int block = size * nmemb;
if (!mf) return block; // through
if (!mf->data)
mf->data = (char*) malloc(block);
else
mf->data = (char*) realloc(mf->data, mf->size + block);
if (mf->data) {
memcpy(mf->data + mf->size, ptr, block);
mf->size += block;
}
return block;
}
char*
memfstrdup(MEMFILE* mf) {
char* buf;
if (mf->size == 0) return NULL;
buf = (char*) malloc(mf->size + 1);
memcpy(buf, mf->data, mf->size);
buf[mf->size] = 0;
return buf;
}
static int
my_connect(sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **c) {
std::stringstream ss;
ss << "CREATE TABLE " << argv[0]
<< "(id int, full_name text, description text, html_url text)";
int rc = sqlite3_declare_vtab(db, ss.str().c_str());
*ppVTab = (sqlite3_vtab *) sqlite3_malloc(sizeof(sqlite3_vtab));
memset(*ppVTab, 0, sizeof(sqlite3_vtab));
return rc;
}
static int
my_create(sqlite3 *db, void *pAux, int argc, const char * const * argv, sqlite3_vtab **ppVTab, char **c) {
return my_connect(db, pAux, argc, argv, ppVTab, c);
}
static int my_disconnect(sqlite3_vtab *pVTab) {
sqlite3_free(pVTab);
return SQLITE_OK;
}
static int
my_destroy(sqlite3_vtab *pVTab) {
sqlite3_free(pVTab);
return SQLITE_OK;
}
typedef struct {
sqlite3_vtab_cursor base;
int index;
picojson::value* rows;
} cursor;
static int
my_open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
MEMFILE* mf;
CURL* curl;
char* json;
CURLcode res = CURLE_OK;
char error[CURL_ERROR_SIZE] = {0};
char* cert_file = getenv("SSL_CERT_FILE");
mf = memfopen();
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.29.0");
curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repositories");
if (cert_file)
curl_easy_setopt(curl, CURLOPT_CAINFO, cert_file);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
std::cerr << error << std::endl;
return SQLITE_FAIL;
}
picojson::value* v = new picojson::value;
std::string err;
picojson::parse(*v, mf->data, mf->data + mf->size, &err);
memfclose(mf);
if (!err.empty()) {
delete v;
std::cerr << err << std::endl;
return SQLITE_FAIL;
}
cursor *c = (cursor *)sqlite3_malloc(sizeof(cursor));
c->rows = v;
c->index = 0;
*ppCursor = &c->base;
return SQLITE_OK;
}
static int
my_close(cursor *c) {
delete c->rows;
sqlite3_free(c);
return SQLITE_OK;
}
static int
my_filter(cursor *c, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) {
c->index = 0;
return SQLITE_OK;
}
static int
my_next(cursor *c) {
c->index++;
return SQLITE_OK;
}
static int
my_eof(cursor *c) {
return c->index >= c->rows->get<picojson::array>().size() ? 1 : 0;
}
static int
my_column(cursor *c, sqlite3_context *ctxt, int i) {
picojson::value v = c->rows->get<picojson::array>()[c->index];
picojson::object row = v.get<picojson::object>();
const char* p = NULL;
switch (i) {
case 0:
p = row["id"].to_str().c_str();
break;
case 1:
p = row["full_name"].to_str().c_str();
break;
case 2:
p = row["description"].to_str().c_str();
break;
case 3:
p = row["html_url"].to_str().c_str();
break;
}
sqlite3_result_text(ctxt, strdup(p), strlen(p), free);
return SQLITE_OK;
}
static int
my_rowid(cursor *c, sqlite3_int64 *pRowid) {
*pRowid = c->index;
return SQLITE_OK;
}
static int
my_bestindex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) {
return SQLITE_OK;
}
static const sqlite3_module module = {
0,
my_create,
my_connect,
my_bestindex,
my_disconnect,
my_destroy,
my_open,
(int (*)(sqlite3_vtab_cursor *)) my_close,
(int (*)(sqlite3_vtab_cursor *, int, char const *, int, sqlite3_value **)) my_filter,
(int (*)(sqlite3_vtab_cursor *)) my_next,
(int (*)(sqlite3_vtab_cursor *)) my_eof,
(int (*)(sqlite3_vtab_cursor *, sqlite3_context *, int)) my_column,
(int (*)(sqlite3_vtab_cursor *, sqlite3_int64 *)) my_rowid,
NULL, // my_update
NULL, // my_begin
NULL, // my_sync
NULL, // my_commit
NULL, // my_rollback
NULL, // my_findfunction
NULL, // my_rename
};
static void
destructor(void *arg) {
return;
}
extern "C" {
EXPORT int
sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
SQLITE_EXTENSION_INIT2(api);
sqlite3_create_module_v2(db, "github", &module, NULL, destructor);
return 0;
}
}

View File

@ -0,0 +1,106 @@
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
"log"
"os"
)
func main() {
os.Remove("./foo.db")
db, err := sql.Open("sqlite3", "./foo.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sqlStmt := `
create table foo (id integer not null primary key, name text);
delete from foo;
`
_, err = db.Exec(sqlStmt)
if err != nil {
log.Printf("%q: %s\n", err, sqlStmt)
return
}
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
for i := 0; i < 100; i++ {
_, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i))
if err != nil {
log.Fatal(err)
}
}
tx.Commit()
rows, err := db.Query("select id, name from foo")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err = rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
stmt, err = db.Prepare("select name from foo where id = ?")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
var name string
err = stmt.QueryRow("3").Scan(&name)
if err != nil {
log.Fatal(err)
}
fmt.Println(name)
_, err = db.Exec("delete from foo")
if err != nil {
log.Fatal(err)
}
_, err = db.Exec("insert into foo(id, name) values(1, 'foo'), (2, 'bar'), (3, 'baz')")
if err != nil {
log.Fatal(err)
}
rows, err = db.Query("select id, name from foo")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err = rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}

View File

@ -0,0 +1,264 @@
package main
import (
"database/sql"
"fmt"
"log"
"os"
sqlite3 "github.com/mattn/go-sqlite3"
)
func traceCallback(info sqlite3.TraceInfo) int {
// Not very readable but may be useful; uncomment next line in case of doubt:
//fmt.Printf("Trace: %#v\n", info)
var dbErrText string
if info.DBError.Code != 0 || info.DBError.ExtendedCode != 0 {
dbErrText = fmt.Sprintf("; DB error: %#v", info.DBError)
} else {
dbErrText = "."
}
// Show the Statement-or-Trigger text in curly braces ('{', '}')
// since from the *paired* ASCII characters they are
// the least used in SQL syntax, therefore better visual delimiters.
// Maybe show 'ExpandedSQL' the same way as 'StmtOrTrigger'.
//
// A known use of curly braces (outside strings) is
// for ODBC escape sequences. Not likely to appear here.
//
// Template languages, etc. don't matter, we should see their *result*
// at *this* level.
// Strange curly braces in SQL code that reached the database driver
// suggest that there is a bug in the application.
// The braces are likely to be either template syntax or
// a programming language's string interpolation syntax.
var expandedText string
if info.ExpandedSQL != "" {
if info.ExpandedSQL == info.StmtOrTrigger {
expandedText = " = exp"
} else {
expandedText = fmt.Sprintf(" expanded {%q}", info.ExpandedSQL)
}
} else {
expandedText = ""
}
// SQLite docs as of September 6, 2016: Tracing and Profiling Functions
// https://www.sqlite.org/c3ref/profile.html
//
// The profile callback time is in units of nanoseconds, however
// the current implementation is only capable of millisecond resolution
// so the six least significant digits in the time are meaningless.
// Future versions of SQLite might provide greater resolution on the profiler callback.
var runTimeText string
if info.RunTimeNanosec == 0 {
if info.EventCode == sqlite3.TraceProfile {
//runTimeText = "; no time" // seems confusing
runTimeText = "; time 0" // no measurement unit
} else {
//runTimeText = "; no time" // seems useless and confusing
}
} else {
const nanosPerMillisec = 1000000
if info.RunTimeNanosec%nanosPerMillisec == 0 {
runTimeText = fmt.Sprintf("; time %d ms", info.RunTimeNanosec/nanosPerMillisec)
} else {
// unexpected: better than millisecond resolution
runTimeText = fmt.Sprintf("; time %d ns!!!", info.RunTimeNanosec)
}
}
var modeText string
if info.AutoCommit {
modeText = "-AC-"
} else {
modeText = "+Tx+"
}
fmt.Printf("Trace: ev %d %s conn 0x%x, stmt 0x%x {%q}%s%s%s\n",
info.EventCode, modeText, info.ConnHandle, info.StmtHandle,
info.StmtOrTrigger, expandedText,
runTimeText,
dbErrText)
return 0
}
func main() {
eventMask := sqlite3.TraceStmt | sqlite3.TraceProfile | sqlite3.TraceRow | sqlite3.TraceClose
sql.Register("sqlite3_tracing",
&sqlite3.SQLiteDriver{
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
err := conn.SetTrace(&sqlite3.TraceConfig{
Callback: traceCallback,
EventMask: uint(eventMask),
WantExpandedSQL: true,
})
return err
},
})
os.Exit(dbMain())
}
// Harder to do DB work in main().
// It's better with a separate function because
// 'defer' and 'os.Exit' don't go well together.
//
// DO NOT use 'log.Fatal...' below: remember that it's equivalent to
// Print() followed by a call to os.Exit(1) --- and
// we want to avoid Exit() so 'defer' can do cleanup.
// Use 'log.Panic...' instead.
func dbMain() int {
db, err := sql.Open("sqlite3_tracing", ":memory:")
if err != nil {
fmt.Printf("Failed to open database: %#+v\n", err)
return 1
}
defer db.Close()
err = db.Ping()
if err != nil {
log.Panic(err)
}
dbSetup(db)
dbDoInsert(db)
dbDoInsertPrepared(db)
dbDoSelect(db)
dbDoSelectPrepared(db)
return 0
}
// 'DDL' stands for "Data Definition Language":
// Note: "INTEGER PRIMARY KEY NOT NULL AUTOINCREMENT" causes the error
// 'near "AUTOINCREMENT": syntax error'; without "NOT NULL" it works.
const tableDDL = `CREATE TABLE t1 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
note VARCHAR NOT NULL
)`
// 'DML' stands for "Data Manipulation Language":
const insertDML = "INSERT INTO t1 (note) VALUES (?)"
const selectDML = "SELECT id, note FROM t1 WHERE note LIKE ?"
const textPrefix = "bla-1234567890-"
const noteTextPattern = "%Prep%"
const nGenRows = 4 // Number of Rows to Generate (for *each* approach tested)
func dbSetup(db *sql.DB) {
var err error
_, err = db.Exec("DROP TABLE IF EXISTS t1")
if err != nil {
log.Panic(err)
}
_, err = db.Exec(tableDDL)
if err != nil {
log.Panic(err)
}
}
func dbDoInsert(db *sql.DB) {
const Descr = "DB-Exec"
for i := 0; i < nGenRows; i++ {
result, err := db.Exec(insertDML, textPrefix+Descr)
if err != nil {
log.Panic(err)
}
resultDoCheck(result, Descr, i)
}
}
func dbDoInsertPrepared(db *sql.DB) {
const Descr = "DB-Prepare"
stmt, err := db.Prepare(insertDML)
if err != nil {
log.Panic(err)
}
defer stmt.Close()
for i := 0; i < nGenRows; i++ {
result, err := stmt.Exec(textPrefix + Descr)
if err != nil {
log.Panic(err)
}
resultDoCheck(result, Descr, i)
}
}
func resultDoCheck(result sql.Result, callerDescr string, callIndex int) {
lastID, err := result.LastInsertId()
if err != nil {
log.Panic(err)
}
nAffected, err := result.RowsAffected()
if err != nil {
log.Panic(err)
}
log.Printf("Exec result for %s (%d): ID = %d, affected = %d\n", callerDescr, callIndex, lastID, nAffected)
}
func dbDoSelect(db *sql.DB) {
const Descr = "DB-Query"
rows, err := db.Query(selectDML, noteTextPattern)
if err != nil {
log.Panic(err)
}
defer rows.Close()
rowsDoFetch(rows, Descr)
}
func dbDoSelectPrepared(db *sql.DB) {
const Descr = "DB-Prepare"
stmt, err := db.Prepare(selectDML)
if err != nil {
log.Panic(err)
}
defer stmt.Close()
rows, err := stmt.Query(noteTextPattern)
if err != nil {
log.Panic(err)
}
defer rows.Close()
rowsDoFetch(rows, Descr)
}
func rowsDoFetch(rows *sql.Rows, callerDescr string) {
var nRows int
var id int64
var note string
for rows.Next() {
err := rows.Scan(&id, &note)
if err != nil {
log.Panic(err)
}
log.Printf("Row for %s (%d): id=%d, note=%q\n",
callerDescr, nRows, id, note)
nRows++
}
if err := rows.Err(); err != nil {
log.Panic(err)
}
log.Printf("Total %d rows for %s.\n", nRows, callerDescr)
}

View File

@ -0,0 +1,38 @@
package main
import (
"database/sql"
"fmt"
"log"
"github.com/mattn/go-sqlite3"
)
func main() {
sql.Register("sqlite3_with_extensions", &sqlite3.SQLiteDriver{
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
return conn.CreateModule("github", &githubModule{})
},
})
db, err := sql.Open("sqlite3_with_extensions", ":memory:")
if err != nil {
log.Fatal(err)
}
defer db.Close()
_, err = db.Exec("create virtual table repo using github(id, full_name, description, html_url)")
if err != nil {
log.Fatal(err)
}
rows, err := db.Query("select id, full_name, description, html_url from repo")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id, fullName, description, htmlURL string
rows.Scan(&id, &fullName, &description, &htmlURL)
fmt.Printf("%s: %s\n\t%s\n\t%s\n\n", id, fullName, description, htmlURL)
}
}

View File

@ -0,0 +1,111 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/mattn/go-sqlite3"
)
type githubRepo struct {
ID int `json:"id"`
FullName string `json:"full_name"`
Description string `json:"description"`
HTMLURL string `json:"html_url"`
}
type githubModule struct {
}
func (m *githubModule) Create(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) {
err := c.DeclareVTab(fmt.Sprintf(`
CREATE TABLE %s (
id INT,
full_name TEXT,
description TEXT,
html_url TEXT
)`, args[0]))
if err != nil {
return nil, err
}
return &ghRepoTable{}, nil
}
func (m *githubModule) Connect(c *sqlite3.SQLiteConn, args []string) (sqlite3.VTab, error) {
return m.Create(c, args)
}
func (m *githubModule) DestroyModule() {}
type ghRepoTable struct {
repos []githubRepo
}
func (v *ghRepoTable) Open() (sqlite3.VTabCursor, error) {
resp, err := http.Get("https://api.github.com/repositories")
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var repos []githubRepo
if err := json.Unmarshal(body, &repos); err != nil {
return nil, err
}
return &ghRepoCursor{0, repos}, nil
}
func (v *ghRepoTable) BestIndex(cst []sqlite3.InfoConstraint, ob []sqlite3.InfoOrderBy) (*sqlite3.IndexResult, error) {
return &sqlite3.IndexResult{}, nil
}
func (v *ghRepoTable) Disconnect() error { return nil }
func (v *ghRepoTable) Destroy() error { return nil }
type ghRepoCursor struct {
index int
repos []githubRepo
}
func (vc *ghRepoCursor) Column(c *sqlite3.SQLiteContext, col int) error {
switch col {
case 0:
c.ResultInt(vc.repos[vc.index].ID)
case 1:
c.ResultText(vc.repos[vc.index].FullName)
case 2:
c.ResultText(vc.repos[vc.index].Description)
case 3:
c.ResultText(vc.repos[vc.index].HTMLURL)
}
return nil
}
func (vc *ghRepoCursor) Filter(idxNum int, idxStr string, vals []interface{}) error {
vc.index = 0
return nil
}
func (vc *ghRepoCursor) Next() error {
vc.index++
return nil
}
func (vc *ghRepoCursor) EOF() bool {
return vc.index >= len(vc.repos)
}
func (vc *ghRepoCursor) Rowid() (int64, error) {
return int64(vc.index), nil
}
func (vc *ghRepoCursor) Close() error {
return nil
}

85
vendor/github.com/mattn/go-sqlite3/backup.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package sqlite3
/*
#ifndef USE_LIBSQLITE3
#include <sqlite3-binding.h>
#else
#include <sqlite3.h>
#endif
#include <stdlib.h>
*/
import "C"
import (
"runtime"
"unsafe"
)
// SQLiteBackup implement interface of Backup.
type SQLiteBackup struct {
b *C.sqlite3_backup
}
// Backup make backup from src to dest.
func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*SQLiteBackup, error) {
destptr := C.CString(dest)
defer C.free(unsafe.Pointer(destptr))
srcptr := C.CString(src)
defer C.free(unsafe.Pointer(srcptr))
if b := C.sqlite3_backup_init(c.db, destptr, conn.db, srcptr); b != nil {
bb := &SQLiteBackup{b: b}
runtime.SetFinalizer(bb, (*SQLiteBackup).Finish)
return bb, nil
}
return nil, c.lastError()
}
// Step to backs up for one step. Calls the underlying `sqlite3_backup_step`
// function. This function returns a boolean indicating if the backup is done
// and an error signalling any other error. Done is returned if the underlying
// C function returns SQLITE_DONE (Code 101)
func (b *SQLiteBackup) Step(p int) (bool, error) {
ret := C.sqlite3_backup_step(b.b, C.int(p))
if ret == C.SQLITE_DONE {
return true, nil
} else if ret != 0 && ret != C.SQLITE_LOCKED && ret != C.SQLITE_BUSY {
return false, Error{Code: ErrNo(ret)}
}
return false, nil
}
// Remaining return whether have the rest for backup.
func (b *SQLiteBackup) Remaining() int {
return int(C.sqlite3_backup_remaining(b.b))
}
// PageCount return count of pages.
func (b *SQLiteBackup) PageCount() int {
return int(C.sqlite3_backup_pagecount(b.b))
}
// Finish close backup.
func (b *SQLiteBackup) Finish() error {
return b.Close()
}
// Close close backup.
func (b *SQLiteBackup) Close() error {
ret := C.sqlite3_backup_finish(b.b)
// sqlite3_backup_finish() never fails, it just returns the
// error code from previous operations, so clean up before
// checking and returning an error
b.b = nil
runtime.SetFinalizer(b, nil)
if ret != 0 {
return Error{Code: ErrNo(ret)}
}
return nil
}

290
vendor/github.com/mattn/go-sqlite3/backup_test.go generated vendored Normal file
View File

@ -0,0 +1,290 @@
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package sqlite3
import (
"database/sql"
"fmt"
"os"
"testing"
"time"
)
// The number of rows of test data to create in the source database.
// Can be used to control how many pages are available to be backed up.
const testRowCount = 100
// The maximum number of seconds after which the page-by-page backup is considered to have taken too long.
const usePagePerStepsTimeoutSeconds = 30
// Test the backup functionality.
func testBackup(t *testing.T, testRowCount int, usePerPageSteps bool) {
// This function will be called multiple times.
// It uses sql.Register(), which requires the name parameter value to be unique.
// There does not currently appear to be a way to unregister a registered driver, however.
// So generate a database driver name that will likely be unique.
var driverName = fmt.Sprintf("sqlite3_testBackup_%v_%v_%v", testRowCount, usePerPageSteps, time.Now().UnixNano())
// The driver's connection will be needed in order to perform the backup.
driverConns := []*SQLiteConn{}
sql.Register(driverName, &SQLiteDriver{
ConnectHook: func(conn *SQLiteConn) error {
driverConns = append(driverConns, conn)
return nil
},
})
// Connect to the source database.
srcTempFilename := TempFilename(t)
defer os.Remove(srcTempFilename)
srcDb, err := sql.Open(driverName, srcTempFilename)
if err != nil {
t.Fatal("Failed to open the source database:", err)
}
defer srcDb.Close()
err = srcDb.Ping()
if err != nil {
t.Fatal("Failed to connect to the source database:", err)
}
// Connect to the destination database.
destTempFilename := TempFilename(t)
defer os.Remove(destTempFilename)
destDb, err := sql.Open(driverName, destTempFilename)
if err != nil {
t.Fatal("Failed to open the destination database:", err)
}
defer destDb.Close()
err = destDb.Ping()
if err != nil {
t.Fatal("Failed to connect to the destination database:", err)
}
// Check the driver connections.
if len(driverConns) != 2 {
t.Fatalf("Expected 2 driver connections, but found %v.", len(driverConns))
}
srcDbDriverConn := driverConns[0]
if srcDbDriverConn == nil {
t.Fatal("The source database driver connection is nil.")
}
destDbDriverConn := driverConns[1]
if destDbDriverConn == nil {
t.Fatal("The destination database driver connection is nil.")
}
// Generate some test data for the given ID.
var generateTestData = func(id int) string {
return fmt.Sprintf("test-%v", id)
}
// Populate the source database with a test table containing some test data.
tx, err := srcDb.Begin()
if err != nil {
t.Fatal("Failed to begin a transaction when populating the source database:", err)
}
_, err = srcDb.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)")
if err != nil {
tx.Rollback()
t.Fatal("Failed to create the source database \"test\" table:", err)
}
for id := 0; id < testRowCount; id++ {
_, err = srcDb.Exec("INSERT INTO test (id, value) VALUES (?, ?)", id, generateTestData(id))
if err != nil {
tx.Rollback()
t.Fatal("Failed to insert a row into the source database \"test\" table:", err)
}
}
err = tx.Commit()
if err != nil {
t.Fatal("Failed to populate the source database:", err)
}
// Confirm that the destination database is initially empty.
var destTableCount int
err = destDb.QueryRow("SELECT COUNT(*) FROM sqlite_master WHERE type = 'table'").Scan(&destTableCount)
if err != nil {
t.Fatal("Failed to check the destination table count:", err)
}
if destTableCount != 0 {
t.Fatalf("The destination database is not empty; %v table(s) found.", destTableCount)
}
// Prepare to perform the backup.
backup, err := destDbDriverConn.Backup("main", srcDbDriverConn, "main")
if err != nil {
t.Fatal("Failed to initialize the backup:", err)
}
// Allow the initial page count and remaining values to be retrieved.
// According to <https://www.sqlite.org/c3ref/backup_finish.html>, the page count and remaining values are "... only updated by sqlite3_backup_step()."
isDone, err := backup.Step(0)
if err != nil {
t.Fatal("Unable to perform an initial 0-page backup step:", err)
}
if isDone {
t.Fatal("Backup is unexpectedly done.")
}
// Check that the page count and remaining values are reasonable.
initialPageCount := backup.PageCount()
if initialPageCount <= 0 {
t.Fatalf("Unexpected initial page count value: %v", initialPageCount)
}
initialRemaining := backup.Remaining()
if initialRemaining <= 0 {
t.Fatalf("Unexpected initial remaining value: %v", initialRemaining)
}
if initialRemaining != initialPageCount {
t.Fatalf("Initial remaining value differs from the initial page count value; remaining: %v; page count: %v", initialRemaining, initialPageCount)
}
// Perform the backup.
if usePerPageSteps {
var startTime = time.Now().Unix()
// Test backing-up using a page-by-page approach.
var latestRemaining = initialRemaining
for {
// Perform the backup step.
isDone, err = backup.Step(1)
if err != nil {
t.Fatal("Failed to perform a backup step:", err)
}
// The page count should remain unchanged from its initial value.
currentPageCount := backup.PageCount()
if currentPageCount != initialPageCount {
t.Fatalf("Current page count differs from the initial page count; initial page count: %v; current page count: %v", initialPageCount, currentPageCount)
}
// There should now be one less page remaining.
currentRemaining := backup.Remaining()
expectedRemaining := latestRemaining - 1
if currentRemaining != expectedRemaining {
t.Fatalf("Unexpected remaining value; expected remaining value: %v; actual remaining value: %v", expectedRemaining, currentRemaining)
}
latestRemaining = currentRemaining
if isDone {
break
}
// Limit the runtime of the backup attempt.
if (time.Now().Unix() - startTime) > usePagePerStepsTimeoutSeconds {
t.Fatal("Backup is taking longer than expected.")
}
}
} else {
// Test the copying of all remaining pages.
isDone, err = backup.Step(-1)
if err != nil {
t.Fatal("Failed to perform a backup step:", err)
}
if !isDone {
t.Fatal("Backup is unexpectedly not done.")
}
}
// Check that the page count and remaining values are reasonable.
finalPageCount := backup.PageCount()
if finalPageCount != initialPageCount {
t.Fatalf("Final page count differs from the initial page count; initial page count: %v; final page count: %v", initialPageCount, finalPageCount)
}
finalRemaining := backup.Remaining()
if finalRemaining != 0 {
t.Fatalf("Unexpected remaining value: %v", finalRemaining)
}
// Finish the backup.
err = backup.Finish()
if err != nil {
t.Fatal("Failed to finish backup:", err)
}
// Confirm that the "test" table now exists in the destination database.
var doesTestTableExist bool
err = destDb.QueryRow("SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'test' LIMIT 1) AS test_table_exists").Scan(&doesTestTableExist)
if err != nil {
t.Fatal("Failed to check if the \"test\" table exists in the destination database:", err)
}
if !doesTestTableExist {
t.Fatal("The \"test\" table could not be found in the destination database.")
}
// Confirm that the number of rows in the destination database's "test" table matches that of the source table.
var actualTestTableRowCount int
err = destDb.QueryRow("SELECT COUNT(*) FROM test").Scan(&actualTestTableRowCount)
if err != nil {
t.Fatal("Failed to determine the rowcount of the \"test\" table in the destination database:", err)
}
if testRowCount != actualTestTableRowCount {
t.Fatalf("Unexpected destination \"test\" table row count; expected: %v; found: %v", testRowCount, actualTestTableRowCount)
}
// Check each of the rows in the destination database.
for id := 0; id < testRowCount; id++ {
var checkedValue string
err = destDb.QueryRow("SELECT value FROM test WHERE id = ?", id).Scan(&checkedValue)
if err != nil {
t.Fatal("Failed to query the \"test\" table in the destination database:", err)
}
var expectedValue = generateTestData(id)
if checkedValue != expectedValue {
t.Fatalf("Unexpected value in the \"test\" table in the destination database; expected value: %v; actual value: %v", expectedValue, checkedValue)
}
}
}
func TestBackupStepByStep(t *testing.T) {
testBackup(t, testRowCount, true)
}
func TestBackupAllRemainingPages(t *testing.T) {
testBackup(t, testRowCount, false)
}
// Test the error reporting when preparing to perform a backup.
func TestBackupError(t *testing.T) {
const driverName = "sqlite3_TestBackupError"
// The driver's connection will be needed in order to perform the backup.
var dbDriverConn *SQLiteConn
sql.Register(driverName, &SQLiteDriver{
ConnectHook: func(conn *SQLiteConn) error {
dbDriverConn = conn
return nil
},
})
// Connect to the database.
dbTempFilename := TempFilename(t)
defer os.Remove(dbTempFilename)
db, err := sql.Open(driverName, dbTempFilename)
if err != nil {
t.Fatal("Failed to open the database:", err)
}
defer db.Close()
db.Ping()
// Need the driver connection in order to perform the backup.
if dbDriverConn == nil {
t.Fatal("Failed to get the driver connection.")
}
// Prepare to perform the backup.
// Intentionally using the same connection for both the source and destination databases, to trigger an error result.
backup, err := dbDriverConn.Backup("main", dbDriverConn, "main")
if err == nil {
t.Fatal("Failed to get the expected error result.")
}
const expectedError = "source and destination must be distinct"
if err.Error() != expectedError {
t.Fatalf("Unexpected error message; expected value: \"%v\"; actual value: \"%v\"", expectedError, err.Error())
}
if backup != nil {
t.Fatal("Failed to get the expected nil backup result.")
}
}

364
vendor/github.com/mattn/go-sqlite3/callback.go generated vendored Normal file
View File

@ -0,0 +1,364 @@
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package sqlite3
// You can't export a Go function to C and have definitions in the C
// preamble in the same file, so we have to have callbackTrampoline in
// its own file. Because we need a separate file anyway, the support
// code for SQLite custom functions is in here.
/*
#ifndef USE_LIBSQLITE3
#include <sqlite3-binding.h>
#else
#include <sqlite3.h>
#endif
#include <stdlib.h>
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
*/
import "C"
import (
"errors"
"fmt"
"math"
"reflect"
"sync"
"unsafe"
)
//export callbackTrampoline
func callbackTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) {
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
fi := lookupHandle(uintptr(C.sqlite3_user_data(ctx))).(*functionInfo)
fi.Call(ctx, args)
}
//export stepTrampoline
func stepTrampoline(ctx *C.sqlite3_context, argc C.int, argv **C.sqlite3_value) {
args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:int(argc):int(argc)]
ai := lookupHandle(uintptr(C.sqlite3_user_data(ctx))).(*aggInfo)
ai.Step(ctx, args)
}
//export doneTrampoline
func doneTrampoline(ctx *C.sqlite3_context) {
handle := uintptr(C.sqlite3_user_data(ctx))
ai := lookupHandle(handle).(*aggInfo)
ai.Done(ctx)
}
//export compareTrampoline
func compareTrampoline(handlePtr uintptr, la C.int, a *C.char, lb C.int, b *C.char) C.int {
cmp := lookupHandle(handlePtr).(func(string, string) int)
return C.int(cmp(C.GoStringN(a, la), C.GoStringN(b, lb)))
}
//export commitHookTrampoline
func commitHookTrampoline(handle uintptr) int {
callback := lookupHandle(handle).(func() int)
return callback()
}
//export rollbackHookTrampoline
func rollbackHookTrampoline(handle uintptr) {
callback := lookupHandle(handle).(func())
callback()
}
//export updateHookTrampoline
func updateHookTrampoline(handle uintptr, op int, db *C.char, table *C.char, rowid int64) {
callback := lookupHandle(handle).(func(int, string, string, int64))
callback(op, C.GoString(db), C.GoString(table), rowid)
}
// Use handles to avoid passing Go pointers to C.
type handleVal struct {
db *SQLiteConn
val interface{}
}
var handleLock sync.Mutex
var handleVals = make(map[uintptr]handleVal)
var handleIndex uintptr = 100
func newHandle(db *SQLiteConn, v interface{}) uintptr {
handleLock.Lock()
defer handleLock.Unlock()
i := handleIndex
handleIndex++
handleVals[i] = handleVal{db, v}
return i
}
func lookupHandle(handle uintptr) interface{} {
handleLock.Lock()
defer handleLock.Unlock()
r, ok := handleVals[handle]
if !ok {
if handle >= 100 && handle < handleIndex {
panic("deleted handle")
} else {
panic("invalid handle")
}
}
return r.val
}
func deleteHandles(db *SQLiteConn) {
handleLock.Lock()
defer handleLock.Unlock()
for handle, val := range handleVals {
if val.db == db {
delete(handleVals, handle)
}
}
}
// This is only here so that tests can refer to it.
type callbackArgRaw C.sqlite3_value
type callbackArgConverter func(*C.sqlite3_value) (reflect.Value, error)
type callbackArgCast struct {
f callbackArgConverter
typ reflect.Type
}
func (c callbackArgCast) Run(v *C.sqlite3_value) (reflect.Value, error) {
val, err := c.f(v)
if err != nil {
return reflect.Value{}, err
}
if !val.Type().ConvertibleTo(c.typ) {
return reflect.Value{}, fmt.Errorf("cannot convert %s to %s", val.Type(), c.typ)
}
return val.Convert(c.typ), nil
}
func callbackArgInt64(v *C.sqlite3_value) (reflect.Value, error) {
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
}
return reflect.ValueOf(int64(C.sqlite3_value_int64(v))), nil
}
func callbackArgBool(v *C.sqlite3_value) (reflect.Value, error) {
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
}
i := int64(C.sqlite3_value_int64(v))
val := false
if i != 0 {
val = true
}
return reflect.ValueOf(val), nil
}
func callbackArgFloat64(v *C.sqlite3_value) (reflect.Value, error) {
if C.sqlite3_value_type(v) != C.SQLITE_FLOAT {
return reflect.Value{}, fmt.Errorf("argument must be a FLOAT")
}
return reflect.ValueOf(float64(C.sqlite3_value_double(v))), nil
}
func callbackArgBytes(v *C.sqlite3_value) (reflect.Value, error) {
switch C.sqlite3_value_type(v) {
case C.SQLITE_BLOB:
l := C.sqlite3_value_bytes(v)
p := C.sqlite3_value_blob(v)
return reflect.ValueOf(C.GoBytes(p, l)), nil
case C.SQLITE_TEXT:
l := C.sqlite3_value_bytes(v)
c := unsafe.Pointer(C.sqlite3_value_text(v))
return reflect.ValueOf(C.GoBytes(c, l)), nil
default:
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
}
}
func callbackArgString(v *C.sqlite3_value) (reflect.Value, error) {
switch C.sqlite3_value_type(v) {
case C.SQLITE_BLOB:
l := C.sqlite3_value_bytes(v)
p := (*C.char)(C.sqlite3_value_blob(v))
return reflect.ValueOf(C.GoStringN(p, l)), nil
case C.SQLITE_TEXT:
c := (*C.char)(unsafe.Pointer(C.sqlite3_value_text(v)))
return reflect.ValueOf(C.GoString(c)), nil
default:
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
}
}
func callbackArgGeneric(v *C.sqlite3_value) (reflect.Value, error) {
switch C.sqlite3_value_type(v) {
case C.SQLITE_INTEGER:
return callbackArgInt64(v)
case C.SQLITE_FLOAT:
return callbackArgFloat64(v)
case C.SQLITE_TEXT:
return callbackArgString(v)
case C.SQLITE_BLOB:
return callbackArgBytes(v)
case C.SQLITE_NULL:
// Interpret NULL as a nil byte slice.
var ret []byte
return reflect.ValueOf(ret), nil
default:
panic("unreachable")
}
}
func callbackArg(typ reflect.Type) (callbackArgConverter, error) {
switch typ.Kind() {
case reflect.Interface:
if typ.NumMethod() != 0 {
return nil, errors.New("the only supported interface type is interface{}")
}
return callbackArgGeneric, nil
case reflect.Slice:
if typ.Elem().Kind() != reflect.Uint8 {
return nil, errors.New("the only supported slice type is []byte")
}
return callbackArgBytes, nil
case reflect.String:
return callbackArgString, nil
case reflect.Bool:
return callbackArgBool, nil
case reflect.Int64:
return callbackArgInt64, nil
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
c := callbackArgCast{callbackArgInt64, typ}
return c.Run, nil
case reflect.Float64:
return callbackArgFloat64, nil
case reflect.Float32:
c := callbackArgCast{callbackArgFloat64, typ}
return c.Run, nil
default:
return nil, fmt.Errorf("don't know how to convert to %s", typ)
}
}
func callbackConvertArgs(argv []*C.sqlite3_value, converters []callbackArgConverter, variadic callbackArgConverter) ([]reflect.Value, error) {
var args []reflect.Value
if len(argv) < len(converters) {
return nil, fmt.Errorf("function requires at least %d arguments", len(converters))
}
for i, arg := range argv[:len(converters)] {
v, err := converters[i](arg)
if err != nil {
return nil, err
}
args = append(args, v)
}
if variadic != nil {
for _, arg := range argv[len(converters):] {
v, err := variadic(arg)
if err != nil {
return nil, err
}
args = append(args, v)
}
}
return args, nil
}
type callbackRetConverter func(*C.sqlite3_context, reflect.Value) error
func callbackRetInteger(ctx *C.sqlite3_context, v reflect.Value) error {
switch v.Type().Kind() {
case reflect.Int64:
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
v = v.Convert(reflect.TypeOf(int64(0)))
case reflect.Bool:
b := v.Interface().(bool)
if b {
v = reflect.ValueOf(int64(1))
} else {
v = reflect.ValueOf(int64(0))
}
default:
return fmt.Errorf("cannot convert %s to INTEGER", v.Type())
}
C.sqlite3_result_int64(ctx, C.sqlite3_int64(v.Interface().(int64)))
return nil
}
func callbackRetFloat(ctx *C.sqlite3_context, v reflect.Value) error {
switch v.Type().Kind() {
case reflect.Float64:
case reflect.Float32:
v = v.Convert(reflect.TypeOf(float64(0)))
default:
return fmt.Errorf("cannot convert %s to FLOAT", v.Type())
}
C.sqlite3_result_double(ctx, C.double(v.Interface().(float64)))
return nil
}
func callbackRetBlob(ctx *C.sqlite3_context, v reflect.Value) error {
if v.Type().Kind() != reflect.Slice || v.Type().Elem().Kind() != reflect.Uint8 {
return fmt.Errorf("cannot convert %s to BLOB", v.Type())
}
i := v.Interface()
if i == nil || len(i.([]byte)) == 0 {
C.sqlite3_result_null(ctx)
} else {
bs := i.([]byte)
C._sqlite3_result_blob(ctx, unsafe.Pointer(&bs[0]), C.int(len(bs)))
}
return nil
}
func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error {
if v.Type().Kind() != reflect.String {
return fmt.Errorf("cannot convert %s to TEXT", v.Type())
}
C._sqlite3_result_text(ctx, C.CString(v.Interface().(string)))
return nil
}
func callbackRet(typ reflect.Type) (callbackRetConverter, error) {
switch typ.Kind() {
case reflect.Slice:
if typ.Elem().Kind() != reflect.Uint8 {
return nil, errors.New("the only supported slice type is []byte")
}
return callbackRetBlob, nil
case reflect.String:
return callbackRetText, nil
case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
return callbackRetInteger, nil
case reflect.Float32, reflect.Float64:
return callbackRetFloat, nil
default:
return nil, fmt.Errorf("don't know how to convert to %s", typ)
}
}
func callbackError(ctx *C.sqlite3_context, err error) {
cstr := C.CString(err.Error())
defer C.free(unsafe.Pointer(cstr))
C.sqlite3_result_error(ctx, cstr, -1)
}
// Test support code. Tests are not allowed to import "C", so we can't
// declare any functions that use C.sqlite3_value.
func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter {
return func(*C.sqlite3_value) (reflect.Value, error) {
return v, err
}
}

97
vendor/github.com/mattn/go-sqlite3/callback_test.go generated vendored Normal file
View File

@ -0,0 +1,97 @@
package sqlite3
import (
"errors"
"math"
"reflect"
"testing"
)
func TestCallbackArgCast(t *testing.T) {
intConv := callbackSyntheticForTests(reflect.ValueOf(int64(math.MaxInt64)), nil)
floatConv := callbackSyntheticForTests(reflect.ValueOf(float64(math.MaxFloat64)), nil)
errConv := callbackSyntheticForTests(reflect.Value{}, errors.New("test"))
tests := []struct {
f callbackArgConverter
o reflect.Value
}{
{intConv, reflect.ValueOf(int8(-1))},
{intConv, reflect.ValueOf(int16(-1))},
{intConv, reflect.ValueOf(int32(-1))},
{intConv, reflect.ValueOf(uint8(math.MaxUint8))},
{intConv, reflect.ValueOf(uint16(math.MaxUint16))},
{intConv, reflect.ValueOf(uint32(math.MaxUint32))},
// Special case, int64->uint64 is only 1<<63 - 1, not 1<<64 - 1
{intConv, reflect.ValueOf(uint64(math.MaxInt64))},
{floatConv, reflect.ValueOf(float32(math.Inf(1)))},
}
for _, test := range tests {
conv := callbackArgCast{test.f, test.o.Type()}
val, err := conv.Run(nil)
if err != nil {
t.Errorf("Couldn't convert to %s: %s", test.o.Type(), err)
} else if !reflect.DeepEqual(val.Interface(), test.o.Interface()) {
t.Errorf("Unexpected result from converting to %s: got %v, want %v", test.o.Type(), val.Interface(), test.o.Interface())
}
}
conv := callbackArgCast{errConv, reflect.TypeOf(int8(0))}
_, err := conv.Run(nil)
if err == nil {
t.Errorf("Expected error during callbackArgCast, but got none")
}
}
func TestCallbackConverters(t *testing.T) {
tests := []struct {
v interface{}
err bool
}{
// Unfortunately, we can't tell which converter was returned,
// but we can at least check which types can be converted.
{[]byte{0}, false},
{"text", false},
{true, false},
{int8(0), false},
{int16(0), false},
{int32(0), false},
{int64(0), false},
{uint8(0), false},
{uint16(0), false},
{uint32(0), false},
{uint64(0), false},
{int(0), false},
{uint(0), false},
{float64(0), false},
{float32(0), false},
{func() {}, true},
{complex64(complex(0, 0)), true},
{complex128(complex(0, 0)), true},
{struct{}{}, true},
{map[string]string{}, true},
{[]string{}, true},
{(*int8)(nil), true},
{make(chan int), true},
}
for _, test := range tests {
_, err := callbackArg(reflect.TypeOf(test.v))
if test.err && err == nil {
t.Errorf("Expected an error when converting %s, got no error", reflect.TypeOf(test.v))
} else if !test.err && err != nil {
t.Errorf("Expected converter when converting %s, got error: %s", reflect.TypeOf(test.v), err)
}
}
for _, test := range tests {
_, err := callbackRet(reflect.TypeOf(test.v))
if test.err && err == nil {
t.Errorf("Expected an error when converting %s, got no error", reflect.TypeOf(test.v))
} else if !test.err && err != nil {
t.Errorf("Expected converter when converting %s, got error: %s", reflect.TypeOf(test.v), err)
}
}
}

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