diff --git a/vendor/github.com/fatih/color b/vendor/github.com/fatih/color deleted file mode 160000 index 1b35f289..00000000 --- a/vendor/github.com/fatih/color +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1b35f289c47d5c73c398cea8e006b7bcb6234a96 diff --git a/vendor/github.com/fatih/color/.travis.yml b/vendor/github.com/fatih/color/.travis.yml new file mode 100644 index 00000000..2405aef3 --- /dev/null +++ b/vendor/github.com/fatih/color/.travis.yml @@ -0,0 +1,3 @@ +language: go +go: 1.3 + diff --git a/vendor/github.com/fatih/color/LICENSE.md b/vendor/github.com/fatih/color/LICENSE.md new file mode 100644 index 00000000..25fdaf63 --- /dev/null +++ b/vendor/github.com/fatih/color/LICENSE.md @@ -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. diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md new file mode 100644 index 00000000..d6fb06a3 --- /dev/null +++ b/vendor/github.com/fatih/color/README.md @@ -0,0 +1,151 @@ +# 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 +``` + +## 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.") +``` + +### 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...") +``` + +### 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.Printf("This", color.RedString("warning"), "should be not neglected.") +fmt.Printf(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 @shiena: [ansicolor](https://github.com/shiena/ansicolor) + +## License + +The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details + diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go new file mode 100644 index 00000000..6a8ee935 --- /dev/null +++ b/vendor/github.com/fatih/color/color.go @@ -0,0 +1,351 @@ +package color + +import ( + "fmt" + "os" + "strconv" + "strings" + + "github.com/shiena/ansicolor" +) + +// NoColor defines if the output is colorized or not. By default it's set to +// false. This is a global option and affects all colors. For more control over +// each color block use the methods DisableColor() individually. +var NoColor = false + +// 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 +) + +// Background text colors +const ( + BgBlack Attribute = iota + 40 + BgRed + BgGreen + BgYellow + BgBlue + BgMagenta + BgCyan + BgWhite +) + +// 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() +} + +// 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 +} + +// Output defines the standard output of the print functions. By default +// os.Stdout is used. +var Output = ansicolor.NewAnsiColorWriter(os.Stdout) + +// 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...) +} + +// 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...) +} + +// 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...) +} + +// 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...) } +} + +// 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...) } +} + +// 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 conjuction with color.Output, example: +// +// put := New(FgYellow).SprintFunc() +// fmt.Ffprintf(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 conjuction 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 conjuction 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 conjuction 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 +} + +func boolPtr(v bool) *bool { + return &v +} + +// Black is an convenient helper function to print with black foreground. A +// newline is appended to format by default. +func Black(format string, a ...interface{}) { printColor(format, FgBlack, a...) } + +// Red is an convenient helper function to print with red foreground. A +// newline is appended to format by default. +func Red(format string, a ...interface{}) { printColor(format, FgRed, a...) } + +// Green is an convenient helper function to print with green foreground. A +// newline is appended to format by default. +func Green(format string, a ...interface{}) { printColor(format, FgGreen, a...) } + +// Yellow is an convenient helper function to print with yellow foreground. +// A newline is appended to format by default. +func Yellow(format string, a ...interface{}) { printColor(format, FgYellow, a...) } + +// Blue is an convenient helper function to print with blue foreground. A +// newline is appended to format by default. +func Blue(format string, a ...interface{}) { printColor(format, FgBlue, a...) } + +// Magenta is an convenient helper function to print with magenta foreground. +// A newline is appended to format by default. +func Magenta(format string, a ...interface{}) { printColor(format, FgMagenta, a...) } + +// Cyan is an convenient helper function to print with cyan foreground. A +// newline is appended to format by default. +func Cyan(format string, a ...interface{}) { printColor(format, FgCyan, a...) } + +// White is an convenient helper function to print with white foreground. A +// newline is appended to format by default. +func White(format string, a ...interface{}) { printColor(format, FgWhite, a...) } + +func printColor(format string, p Attribute, a ...interface{}) { + if !strings.HasSuffix(format, "\n") { + format += "\n" + } + + c := &Color{params: []Attribute{p}} + c.Printf(format, a...) +} + +// BlackString is an convenient helper function to return a string with black +// foreground. +func BlackString(format string, a ...interface{}) string { + return New(FgBlack).SprintfFunc()(format, a...) +} + +// RedString is an convenient helper function to return a string with red +// foreground. +func RedString(format string, a ...interface{}) string { + return New(FgRed).SprintfFunc()(format, a...) +} + +// GreenString is an convenient helper function to return a string with green +// foreground. +func GreenString(format string, a ...interface{}) string { + return New(FgGreen).SprintfFunc()(format, a...) +} + +// YellowString is an convenient helper function to return a string with yellow +// foreground. +func YellowString(format string, a ...interface{}) string { + return New(FgYellow).SprintfFunc()(format, a...) +} + +// BlueString is an convenient helper function to return a string with blue +// foreground. +func BlueString(format string, a ...interface{}) string { + return New(FgBlue).SprintfFunc()(format, a...) +} + +// MagentaString is an convenient helper function to return a string with magenta +// foreground. +func MagentaString(format string, a ...interface{}) string { + return New(FgMagenta).SprintfFunc()(format, a...) +} + +// CyanString is an convenient helper function to return a string with cyan +// foreground. +func CyanString(format string, a ...interface{}) string { + return New(FgCyan).SprintfFunc()(format, a...) +} + +// WhiteString is an convenient helper function to return a string with white +// foreground. +func WhiteString(format string, a ...interface{}) string { + return New(FgWhite).SprintfFunc()(format, a...) +} diff --git a/vendor/github.com/fatih/color/color_test.go b/vendor/github.com/fatih/color/color_test.go new file mode 100644 index 00000000..a1192b55 --- /dev/null +++ b/vendor/github.com/fatih/color/color_test.go @@ -0,0 +1,176 @@ +package color + +import ( + "bytes" + "fmt" + "os" + "testing" + + "github.com/shiena/ansicolor" +) + +// 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 + + 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}, + } + + 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) + } + } +} + +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}, + } + + 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 + fmt.Println("") + Output = ansicolor.NewAnsiColorWriter(os.Stdout) + + 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") + + // 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")) + + // 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")) +} diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go new file mode 100644 index 00000000..17908787 --- /dev/null +++ b/vendor/github.com/fatih/color/doc.go @@ -0,0 +1,114 @@ +/* +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 ..") + +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.") + + +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...") + + +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 works 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 diff --git a/vendor/github.com/kr/text b/vendor/github.com/kr/text deleted file mode 160000 index 7cafcd83..00000000 --- a/vendor/github.com/kr/text +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7cafcd837844e784b526369c9bce262804aebc60 diff --git a/vendor/github.com/kr/text/License b/vendor/github.com/kr/text/License new file mode 100644 index 00000000..480a3280 --- /dev/null +++ b/vendor/github.com/kr/text/License @@ -0,0 +1,19 @@ +Copyright 2012 Keith Rarick + +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. diff --git a/vendor/github.com/kr/text/Readme b/vendor/github.com/kr/text/Readme new file mode 100644 index 00000000..7e6e7c06 --- /dev/null +++ b/vendor/github.com/kr/text/Readme @@ -0,0 +1,3 @@ +This is a Go package for manipulating paragraphs of text. + +See http://go.pkgdoc.org/github.com/kr/text for full documentation. diff --git a/vendor/github.com/kr/text/cmd/agg/doc.go b/vendor/github.com/kr/text/cmd/agg/doc.go new file mode 100644 index 00000000..3a9ec2db --- /dev/null +++ b/vendor/github.com/kr/text/cmd/agg/doc.go @@ -0,0 +1,73 @@ +/* + +Agg computes aggregate values over tabular text. +It behaves somewhat like the SQL “GROUP BY” clause. + +Usage: + + agg [function...] + +It reads input from stdin as a sequence of records, one per line. +It treats each line as a set of fields separated by white space. +One field (the first, by default) is designated as the key. +Successive lines with equal keys are grouped into a group, +and agg produces one line of output for each group. +(Note that only contiguous input lines can form a group. +If you need to make sure that all records for a given key +are grouped together, sort the input first.) + +For each remaining field, +agg applies a function to all the values in the group, +producing a single output value. +The command line arguments specify which functions to use, +one per field in the input table. + +Functions + +The available functions are: + + key group by this field (default for field 1) + first value from first line of group (default for rest) + last value from last line of group + sample value from any line of group, uniformly at random + prefix longest common string prefix + join:sep concatenate strings with given sep + smin lexically least string + smax lexically greatest string + min numerically least value + max numerically greatest value + sum numeric sum + mean arithmetic mean + count number of records (ignores input value) + const:val print val, ignoring input + drop omit the column entirely + +The numeric functions skip items that don't parse as numbers. + +Examples + +Using the following input: + + $ cat >input + -rwx alice 100 /home/alice/bin/crdt + -rw- alice 210002 /home/alice/thesis.tex + -rw- bob 10051 /home/bob/expenses.tab + -rwx kr 862060 /home/kr/bin/blog + -rwx kr 304608 /home/kr/bin/agg + +Disk usage for each user, plus where that disk usage occurs +(longest common prefix of filesystem paths): + + $ agg = 0 { + sym, argmap[i] = sym[:p], sym[p+1:] + } + if sym == "key" { + key, sym = i, "first" + } + f, ok := symtab[sym] + if !ok { + log.Fatalf("bad function: %q", sym) + } + funcmap[i] = f + } + + sc := bufio.NewScanner(os.Stdin) + var g *group + for sc.Scan() { + ss := strings.Fields(sc.Text()) + if !matches(g, ss) { + emit(g) + g = &group{key: ss[key]} + } + mergeLine(g, ss) + } + emit(g) +} + +type group struct { + key string + agg []agg +} + +func matches(g *group, ss []string) bool { + return g != nil && g.key == ss[key] +} + +func emit(g *group) { + if g == nil { + return + } + rest := false + for i, a := range g.agg { + if f, ok := funcmap[i]; ok && f == nil { + continue + } + if rest { + fmt.Print("\t") + } + rest = true + fmt.Print(a) + } + fmt.Println() +} + +func mergeLine(g *group, ss []string) { + for i, s := range ss { + if i >= len(g.agg) { + f := funcmap[i] + if f == nil { + f = first + } + g.agg = append(g.agg, f(s, argmap[i])) + } else { + g.agg[i].merge(s) + } + } +} diff --git a/vendor/github.com/kr/text/cmd/agg/num.go b/vendor/github.com/kr/text/cmd/agg/num.go new file mode 100644 index 00000000..93ac3fe1 --- /dev/null +++ b/vendor/github.com/kr/text/cmd/agg/num.go @@ -0,0 +1,99 @@ +package main + +import ( + "math/big" + "strconv" +) + +func min(s, arg string) agg { return newBinop(s, opmin) } +func max(s, arg string) agg { return newBinop(s, opmax) } +func sum(s, arg string) agg { return newBinop(s, opsum) } + +type binop struct { + v *big.Float + f func(a, b *big.Float) *big.Float +} + +func newBinop(s string, f func(a, b *big.Float) *big.Float) *binop { + v, _ := parseFloat(s) + return &binop{v, f} +} + +func (o *binop) String() string { + if o.v == nil { + return "NaN" + } + return o.v.Text('f', -1) +} + +func (o *binop) merge(s string) { + v, ok := parseFloat(s) + if !ok { + return + } + o.v = o.f(o.v, v) +} + +func opmin(a, b *big.Float) *big.Float { + if a != nil && (b == nil || a.Cmp(b) <= 0) { + return a + } + return b +} + +func opmax(a, b *big.Float) *big.Float { + if a != nil && (b == nil || a.Cmp(b) >= 0) { + return a + } + return b +} + +func opsum(a, b *big.Float) *big.Float { + if a == nil { + return b + } else if b == nil { + return a + } + return a.Add(a, b) +} + +type meanagg struct { + v *big.Float + d float64 // actually an integer +} + +func mean(s, arg string) agg { + v, ok := parseFloat(s) + if !ok { + return &meanagg{new(big.Float), 0} + } + return &meanagg{v, 1} +} + +func (m *meanagg) String() string { + if m.d == 0 { + return "NaN" + } + v := new(big.Float).Quo(m.v, big.NewFloat(m.d)) + return v.Text('f', -1) +} + +func (m *meanagg) merge(s string) { + v, ok := parseFloat(s) + if !ok { + return + } + m.v.Add(m.v, v) + m.d++ +} + +func parseFloat(s string) (*big.Float, bool) { + v, _, err := big.ParseFloat(s, 0, 1000, big.ToNearestEven) + return v, err == nil +} + +type counter int + +func count(init, arg string) agg { return new(counter) } +func (c *counter) String() string { return strconv.Itoa(int(*c) + 1) } +func (c *counter) merge(string) { *c++ } diff --git a/vendor/github.com/kr/text/cmd/agg/string.go b/vendor/github.com/kr/text/cmd/agg/string.go new file mode 100644 index 00000000..9a8cf78c --- /dev/null +++ b/vendor/github.com/kr/text/cmd/agg/string.go @@ -0,0 +1,74 @@ +package main + +import ( + "math/rand" + "strings" +) + +func first(s, arg string) agg { return &sbinop{s, opfirst} } +func last(s, arg string) agg { return &sbinop{s, oplast} } +func prefix(s, arg string) agg { return &sbinop{s, opprefix} } +func join(s, arg string) agg { return &sbinop{s, opjoin(arg)} } +func smin(s, arg string) agg { return &sbinop{s, opsmin} } +func smax(s, arg string) agg { return &sbinop{s, opsmax} } + +type sbinop struct { + s string + f func(a, b string) string +} + +func (o *sbinop) String() string { return o.s } + +func (o *sbinop) merge(s string) { o.s = o.f(o.s, s) } + +func opfirst(a, b string) string { return a } +func oplast(a, b string) string { return b } + +func opprefix(a, b string) string { + for i := range a { + if i >= len(b) || a[i] != b[i] { + return a[:i] + } + } + return a +} + +func opjoin(sep string) func(a, b string) string { + return func(a, b string) string { + return a + sep + b // TODO(kr): too slow? maybe strings.Join? + } +} + +func opsmin(a, b string) string { + if strings.Compare(a, b) <= 0 { + return a + } + return b +} + +func opsmax(a, b string) string { + if strings.Compare(a, b) >= 0 { + return a + } + return b +} + +type sampler struct { + n int + s string +} + +func sample(s, arg string) agg { return &sampler{1, s} } +func (p *sampler) String() string { return p.s } +func (p *sampler) merge(s string) { + p.n++ + if rand.Intn(p.n) == 0 { + p.s = s + } +} + +type constant string + +func constf(init, arg string) agg { return constant(arg) } +func (c constant) String() string { return string(c) } +func (c constant) merge(string) {} diff --git a/vendor/github.com/kr/text/colwriter/Readme b/vendor/github.com/kr/text/colwriter/Readme new file mode 100644 index 00000000..1c1f4e68 --- /dev/null +++ b/vendor/github.com/kr/text/colwriter/Readme @@ -0,0 +1,5 @@ +Package colwriter provides a write filter that formats +input lines in multiple columns. + +The package is a straightforward translation from +/src/cmd/draw/mc.c in Plan 9 from User Space. diff --git a/vendor/github.com/kr/text/colwriter/column.go b/vendor/github.com/kr/text/colwriter/column.go new file mode 100644 index 00000000..7302ce9f --- /dev/null +++ b/vendor/github.com/kr/text/colwriter/column.go @@ -0,0 +1,147 @@ +// Package colwriter provides a write filter that formats +// input lines in multiple columns. +// +// The package is a straightforward translation from +// /src/cmd/draw/mc.c in Plan 9 from User Space. +package colwriter + +import ( + "bytes" + "io" + "unicode/utf8" +) + +const ( + tab = 4 +) + +const ( + // Print each input line ending in a colon ':' separately. + BreakOnColon uint = 1 << iota +) + +// A Writer is a filter that arranges input lines in as many columns as will +// fit in its width. Tab '\t' chars in the input are translated to sequences +// of spaces ending at multiples of 4 positions. +// +// If BreakOnColon is set, each input line ending in a colon ':' is written +// separately. +// +// The Writer assumes that all Unicode code points have the same width; this +// may not be true in some fonts. +type Writer struct { + w io.Writer + buf []byte + width int + flag uint +} + +// NewWriter allocates and initializes a new Writer writing to w. +// Parameter width controls the total number of characters on each line +// across all columns. +func NewWriter(w io.Writer, width int, flag uint) *Writer { + return &Writer{ + w: w, + width: width, + flag: flag, + } +} + +// Write writes p to the writer w. The only errors returned are ones +// encountered while writing to the underlying output stream. +func (w *Writer) Write(p []byte) (n int, err error) { + var linelen int + var lastWasColon bool + for i, c := range p { + w.buf = append(w.buf, c) + linelen++ + if c == '\t' { + w.buf[len(w.buf)-1] = ' ' + for linelen%tab != 0 { + w.buf = append(w.buf, ' ') + linelen++ + } + } + if w.flag&BreakOnColon != 0 && c == ':' { + lastWasColon = true + } else if lastWasColon { + if c == '\n' { + pos := bytes.LastIndex(w.buf[:len(w.buf)-1], []byte{'\n'}) + if pos < 0 { + pos = 0 + } + line := w.buf[pos:] + w.buf = w.buf[:pos] + if err = w.columnate(); err != nil { + if len(line) < i { + return i - len(line), err + } + return 0, err + } + if n, err := w.w.Write(line); err != nil { + if r := len(line) - n; r < i { + return i - r, err + } + return 0, err + } + } + lastWasColon = false + } + if c == '\n' { + linelen = 0 + } + } + return len(p), nil +} + +// Flush should be called after the last call to Write to ensure that any data +// buffered in the Writer is written to output. +func (w *Writer) Flush() error { + return w.columnate() +} + +func (w *Writer) columnate() error { + words := bytes.Split(w.buf, []byte{'\n'}) + w.buf = nil + if len(words[len(words)-1]) == 0 { + words = words[:len(words)-1] + } + maxwidth := 0 + for _, wd := range words { + if n := utf8.RuneCount(wd); n > maxwidth { + maxwidth = n + } + } + maxwidth++ // space char + wordsPerLine := w.width / maxwidth + if wordsPerLine <= 0 { + wordsPerLine = 1 + } + nlines := (len(words) + wordsPerLine - 1) / wordsPerLine + for i := 0; i < nlines; i++ { + col := 0 + endcol := 0 + for j := i; j < len(words); j += nlines { + endcol += maxwidth + _, err := w.w.Write(words[j]) + if err != nil { + return err + } + col += utf8.RuneCount(words[j]) + if j+nlines < len(words) { + for col < endcol { + _, err := w.w.Write([]byte{' '}) + if err != nil { + return err + } + col++ + } + } + } + _, err := w.w.Write([]byte{'\n'}) + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/kr/text/colwriter/column_test.go b/vendor/github.com/kr/text/colwriter/column_test.go new file mode 100644 index 00000000..ce388f5a --- /dev/null +++ b/vendor/github.com/kr/text/colwriter/column_test.go @@ -0,0 +1,90 @@ +package colwriter + +import ( + "bytes" + "testing" +) + +var src = ` +.git +.gitignore +.godir +Procfile: +README.md +api.go +apps.go +auth.go +darwin.go +data.go +dyno.go: +env.go +git.go +help.go +hkdist +linux.go +ls.go +main.go +plugin.go +run.go +scale.go +ssh.go +tail.go +term +unix.go +update.go +version.go +windows.go +`[1:] + +var tests = []struct { + wid int + flag uint + src string + want string +}{ + {80, 0, "", ""}, + {80, 0, src, ` +.git README.md darwin.go git.go ls.go scale.go unix.go +.gitignore api.go data.go help.go main.go ssh.go update.go +.godir apps.go dyno.go: hkdist plugin.go tail.go version.go +Procfile: auth.go env.go linux.go run.go term windows.go +`[1:]}, + {80, BreakOnColon, src, ` +.git .gitignore .godir + +Procfile: +README.md api.go apps.go auth.go darwin.go data.go + +dyno.go: +env.go hkdist main.go scale.go term version.go +git.go linux.go plugin.go ssh.go unix.go windows.go +help.go ls.go run.go tail.go update.go +`[1:]}, + {20, 0, ` +Hello +Γειά σου +안녕 +今日は +`[1:], ` +Hello 안녕 +Γειά σου 今日は +`[1:]}, +} + +func TestWriter(t *testing.T) { + for _, test := range tests { + b := new(bytes.Buffer) + w := NewWriter(b, test.wid, test.flag) + if _, err := w.Write([]byte(test.src)); err != nil { + t.Error(err) + } + if err := w.Flush(); err != nil { + t.Error(err) + } + if g := b.String(); test.want != g { + t.Log("\n" + test.want) + t.Log("\n" + g) + t.Errorf("%q != %q", test.want, g) + } + } +} diff --git a/vendor/github.com/kr/text/doc.go b/vendor/github.com/kr/text/doc.go new file mode 100644 index 00000000..cf4c198f --- /dev/null +++ b/vendor/github.com/kr/text/doc.go @@ -0,0 +1,3 @@ +// Package text provides rudimentary functions for manipulating text in +// paragraphs. +package text diff --git a/vendor/github.com/kr/text/indent.go b/vendor/github.com/kr/text/indent.go new file mode 100644 index 00000000..4ebac45c --- /dev/null +++ b/vendor/github.com/kr/text/indent.go @@ -0,0 +1,74 @@ +package text + +import ( + "io" +) + +// Indent inserts prefix at the beginning of each non-empty line of s. The +// end-of-line marker is NL. +func Indent(s, prefix string) string { + return string(IndentBytes([]byte(s), []byte(prefix))) +} + +// IndentBytes inserts prefix at the beginning of each non-empty line of b. +// The end-of-line marker is NL. +func IndentBytes(b, prefix []byte) []byte { + var res []byte + bol := true + for _, c := range b { + if bol && c != '\n' { + res = append(res, prefix...) + } + res = append(res, c) + bol = c == '\n' + } + return res +} + +// Writer indents each line of its input. +type indentWriter struct { + w io.Writer + bol bool + pre [][]byte + sel int + off int +} + +// NewIndentWriter makes a new write filter that indents the input +// lines. Each line is prefixed in order with the corresponding +// element of pre. If there are more lines than elements, the last +// element of pre is repeated for each subsequent line. +func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer { + return &indentWriter{ + w: w, + pre: pre, + bol: true, + } +} + +// The only errors returned are from the underlying indentWriter. +func (w *indentWriter) Write(p []byte) (n int, err error) { + for _, c := range p { + if w.bol { + var i int + i, err = w.w.Write(w.pre[w.sel][w.off:]) + w.off += i + if err != nil { + return n, err + } + } + _, err = w.w.Write([]byte{c}) + if err != nil { + return n, err + } + n++ + w.bol = c == '\n' + if w.bol { + w.off = 0 + if w.sel < len(w.pre)-1 { + w.sel++ + } + } + } + return n, nil +} diff --git a/vendor/github.com/kr/text/indent_test.go b/vendor/github.com/kr/text/indent_test.go new file mode 100644 index 00000000..5c723eee --- /dev/null +++ b/vendor/github.com/kr/text/indent_test.go @@ -0,0 +1,119 @@ +package text + +import ( + "bytes" + "testing" +) + +type T struct { + inp, exp, pre string +} + +var tests = []T{ + { + "The quick brown fox\njumps over the lazy\ndog.\nBut not quickly.\n", + "xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\nxxxBut not quickly.\n", + "xxx", + }, + { + "The quick brown fox\njumps over the lazy\ndog.\n\nBut not quickly.", + "xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\n\nxxxBut not quickly.", + "xxx", + }, +} + +func TestIndent(t *testing.T) { + for _, test := range tests { + got := Indent(test.inp, test.pre) + if got != test.exp { + t.Errorf("mismatch %q != %q", got, test.exp) + } + } +} + +type IndentWriterTest struct { + inp, exp string + pre []string +} + +var ts = []IndentWriterTest{ + { + ` +The quick brown fox +jumps over the lazy +dog. +But not quickly. +`[1:], + ` +xxxThe quick brown fox +xxxjumps over the lazy +xxxdog. +xxxBut not quickly. +`[1:], + []string{"xxx"}, + }, + { + ` +The quick brown fox +jumps over the lazy +dog. +But not quickly. +`[1:], + ` +xxaThe quick brown fox +xxxjumps over the lazy +xxxdog. +xxxBut not quickly. +`[1:], + []string{"xxa", "xxx"}, + }, + { + ` +The quick brown fox +jumps over the lazy +dog. +But not quickly. +`[1:], + ` +xxaThe quick brown fox +xxbjumps over the lazy +xxcdog. +xxxBut not quickly. +`[1:], + []string{"xxa", "xxb", "xxc", "xxx"}, + }, + { + ` +The quick brown fox +jumps over the lazy +dog. + +But not quickly.`[1:], + ` +xxaThe quick brown fox +xxxjumps over the lazy +xxxdog. +xxx +xxxBut not quickly.`[1:], + []string{"xxa", "xxx"}, + }, +} + +func TestIndentWriter(t *testing.T) { + for _, test := range ts { + b := new(bytes.Buffer) + pre := make([][]byte, len(test.pre)) + for i := range test.pre { + pre[i] = []byte(test.pre[i]) + } + w := NewIndentWriter(b, pre...) + if _, err := w.Write([]byte(test.inp)); err != nil { + t.Error(err) + } + if got := b.String(); got != test.exp { + t.Errorf("mismatch %q != %q", got, test.exp) + t.Log(got) + t.Log(test.exp) + } + } +} diff --git a/vendor/github.com/kr/text/mc/Readme b/vendor/github.com/kr/text/mc/Readme new file mode 100644 index 00000000..519ddc00 --- /dev/null +++ b/vendor/github.com/kr/text/mc/Readme @@ -0,0 +1,9 @@ +Command mc prints in multiple columns. + + Usage: mc [-] [-N] [file...] + +Mc splits the input into as many columns as will fit in N +print positions. If the output is a tty, the default N is +the number of characters in a terminal line; otherwise the +default N is 80. Under option - each input line ending in +a colon ':' is printed separately. diff --git a/vendor/github.com/kr/text/mc/mc.go b/vendor/github.com/kr/text/mc/mc.go new file mode 100644 index 00000000..00169a30 --- /dev/null +++ b/vendor/github.com/kr/text/mc/mc.go @@ -0,0 +1,62 @@ +// Command mc prints in multiple columns. +// +// Usage: mc [-] [-N] [file...] +// +// Mc splits the input into as many columns as will fit in N +// print positions. If the output is a tty, the default N is +// the number of characters in a terminal line; otherwise the +// default N is 80. Under option - each input line ending in +// a colon ':' is printed separately. +package main + +import ( + "github.com/kr/pty" + "github.com/kr/text/colwriter" + "io" + "log" + "os" + "strconv" +) + +func main() { + var width int + var flag uint + args := os.Args[1:] + for len(args) > 0 && len(args[0]) > 0 && args[0][0] == '-' { + if len(args[0]) > 1 { + width, _ = strconv.Atoi(args[0][1:]) + } else { + flag |= colwriter.BreakOnColon + } + args = args[1:] + } + if width < 1 { + _, width, _ = pty.Getsize(os.Stdout) + } + if width < 1 { + width = 80 + } + + w := colwriter.NewWriter(os.Stdout, width, flag) + if len(args) > 0 { + for _, s := range args { + if f, err := os.Open(s); err == nil { + copyin(w, f) + f.Close() + } else { + log.Println(err) + } + } + } else { + copyin(w, os.Stdin) + } +} + +func copyin(w *colwriter.Writer, r io.Reader) { + if _, err := io.Copy(w, r); err != nil { + log.Println(err) + } + if err := w.Flush(); err != nil { + log.Println(err) + } +} diff --git a/vendor/github.com/kr/text/wrap.go b/vendor/github.com/kr/text/wrap.go new file mode 100644 index 00000000..b09bb037 --- /dev/null +++ b/vendor/github.com/kr/text/wrap.go @@ -0,0 +1,86 @@ +package text + +import ( + "bytes" + "math" +) + +var ( + nl = []byte{'\n'} + sp = []byte{' '} +) + +const defaultPenalty = 1e5 + +// Wrap wraps s into a paragraph of lines of length lim, with minimal +// raggedness. +func Wrap(s string, lim int) string { + return string(WrapBytes([]byte(s), lim)) +} + +// WrapBytes wraps b into a paragraph of lines of length lim, with minimal +// raggedness. +func WrapBytes(b []byte, lim int) []byte { + words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp) + var lines [][]byte + for _, line := range WrapWords(words, 1, lim, defaultPenalty) { + lines = append(lines, bytes.Join(line, sp)) + } + return bytes.Join(lines, nl) +} + +// WrapWords is the low-level line-breaking algorithm, useful if you need more +// control over the details of the text wrapping process. For most uses, either +// Wrap or WrapBytes will be sufficient and more convenient. +// +// WrapWords splits a list of words into lines with minimal "raggedness", +// treating each byte as one unit, accounting for spc units between adjacent +// words on each line, and attempting to limit lines to lim units. Raggedness +// is the total error over all lines, where error is the square of the +// difference of the length of the line and lim. Too-long lines (which only +// happen when a single word is longer than lim units) have pen penalty units +// added to the error. +func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte { + n := len(words) + + length := make([][]int, n) + for i := 0; i < n; i++ { + length[i] = make([]int, n) + length[i][i] = len(words[i]) + for j := i + 1; j < n; j++ { + length[i][j] = length[i][j-1] + spc + len(words[j]) + } + } + + nbrk := make([]int, n) + cost := make([]int, n) + for i := range cost { + cost[i] = math.MaxInt32 + } + for i := n - 1; i >= 0; i-- { + if length[i][n-1] <= lim || i == n-1 { + cost[i] = 0 + nbrk[i] = n + } else { + for j := i + 1; j < n; j++ { + d := lim - length[i][j-1] + c := d*d + cost[j] + if length[i][j-1] > lim { + c += pen // too-long lines get a worse penalty + } + if c < cost[i] { + cost[i] = c + nbrk[i] = j + } + } + } + } + + var lines [][][]byte + i := 0 + for i < n { + lines = append(lines, words[i:nbrk[i]]) + i = nbrk[i] + } + return lines +} diff --git a/vendor/github.com/kr/text/wrap_test.go b/vendor/github.com/kr/text/wrap_test.go new file mode 100644 index 00000000..634b6e8e --- /dev/null +++ b/vendor/github.com/kr/text/wrap_test.go @@ -0,0 +1,62 @@ +package text + +import ( + "bytes" + "testing" +) + +var text = "The quick brown fox jumps over the lazy dog." + +func TestWrap(t *testing.T) { + exp := [][]string{ + {"The", "quick", "brown", "fox"}, + {"jumps", "over", "the", "lazy", "dog."}, + } + words := bytes.Split([]byte(text), sp) + got := WrapWords(words, 1, 24, defaultPenalty) + if len(exp) != len(got) { + t.Fail() + } + for i := range exp { + if len(exp[i]) != len(got[i]) { + t.Fail() + } + for j := range exp[i] { + if exp[i][j] != string(got[i][j]) { + t.Fatal(i, exp[i][j], got[i][j]) + } + } + } +} + +func TestWrapNarrow(t *testing.T) { + exp := "The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog." + if Wrap(text, 5) != exp { + t.Fail() + } +} + +func TestWrapOneLine(t *testing.T) { + exp := "The quick brown fox jumps over the lazy dog." + if Wrap(text, 500) != exp { + t.Fail() + } +} + +func TestWrapBug1(t *testing.T) { + cases := []struct { + limit int + text string + want string + }{ + {4, "aaaaa", "aaaaa"}, + {4, "a aaaaa", "a\naaaaa"}, + } + + for _, test := range cases { + got := Wrap(test.text, test.limit) + if got != test.want { + t.Errorf("Wrap(%q, %d) = %q want %q", test.text, test.limit, got, test.want) + } + } +} diff --git a/vendor/github.com/shiena/ansicolor b/vendor/github.com/shiena/ansicolor deleted file mode 160000 index a422bbe9..00000000 --- a/vendor/github.com/shiena/ansicolor +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a422bbe96644373c5753384a59d678f7d261ff10 diff --git a/vendor/github.com/shiena/ansicolor/.gitignore b/vendor/github.com/shiena/ansicolor/.gitignore new file mode 100644 index 00000000..69cec52c --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/.gitignore @@ -0,0 +1,27 @@ +# Created by http://www.gitignore.io + +### Go ### +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test + diff --git a/vendor/github.com/shiena/ansicolor/LICENSE b/vendor/github.com/shiena/ansicolor/LICENSE new file mode 100644 index 00000000..e58473ed --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) [2014] [shiena] + +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. diff --git a/vendor/github.com/shiena/ansicolor/README.md b/vendor/github.com/shiena/ansicolor/README.md new file mode 100644 index 00000000..cf2ae405 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/README.md @@ -0,0 +1,101 @@ +[![GoDoc](https://godoc.org/github.com/shiena/ansicolor?status.svg)](https://godoc.org/github.com/shiena/ansicolor) + +# ansicolor + +Ansicolor library provides color console in Windows as ANSICON for Golang. + +## Features + +|Escape sequence|Text attributes| +|---------------|----| +|\x1b[0m|All attributes off(color at startup)| +|\x1b[1m|Bold on(enable foreground intensity)| +|\x1b[4m|Underline on| +|\x1b[5m|Blink on(enable background intensity)| +|\x1b[21m|Bold off(disable foreground intensity)| +|\x1b[24m|Underline off| +|\x1b[25m|Blink off(disable background intensity)| + +|Escape sequence|Foreground colors| +|---------------|----| +|\x1b[30m|Black| +|\x1b[31m|Red| +|\x1b[32m|Green| +|\x1b[33m|Yellow| +|\x1b[34m|Blue| +|\x1b[35m|Magenta| +|\x1b[36m|Cyan| +|\x1b[37m|White| +|\x1b[39m|Default(foreground color at startup)| +|\x1b[90m|Light Gray| +|\x1b[91m|Light Red| +|\x1b[92m|Light Green| +|\x1b[93m|Light Yellow| +|\x1b[94m|Light Blue| +|\x1b[95m|Light Magenta| +|\x1b[96m|Light Cyan| +|\x1b[97m|Light White| + +|Escape sequence|Background colors| +|---------------|----| +|\x1b[40m|Black| +|\x1b[41m|Red| +|\x1b[42m|Green| +|\x1b[43m|Yellow| +|\x1b[44m|Blue| +|\x1b[45m|Magenta| +|\x1b[46m|Cyan| +|\x1b[47m|White| +|\x1b[49m|Default(background color at startup)| +|\x1b[100m|Light Gray| +|\x1b[101m|Light Red| +|\x1b[102m|Light Green| +|\x1b[103m|Light Yellow| +|\x1b[104m|Light Blue| +|\x1b[105m|Light Magenta| +|\x1b[106m|Light Cyan| +|\x1b[107m|Light White| + +## Example + +```go +package main + +import ( + "fmt" + "os" + + "github.com/shiena/ansicolor" +) + +func main() { + w := ansicolor.NewAnsiColorWriter(os.Stdout) + text := "%sforeground %sbold%s %sbackground%s\n" + fmt.Fprintf(w, text, "\x1b[31m", "\x1b[1m", "\x1b[21m", "\x1b[41;32m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[32m", "\x1b[1m", "\x1b[21m", "\x1b[42;31m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[33m", "\x1b[1m", "\x1b[21m", "\x1b[43;34m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[34m", "\x1b[1m", "\x1b[21m", "\x1b[44;33m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[35m", "\x1b[1m", "\x1b[21m", "\x1b[45;36m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[36m", "\x1b[1m", "\x1b[21m", "\x1b[46;35m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[37m", "\x1b[1m", "\x1b[21m", "\x1b[47;30m", "\x1b[0m") +} +``` + +![screenshot](https://gist.githubusercontent.com/shiena/a1bada24b525314a7d5e/raw/c763aa7cda6e4fefaccf831e2617adc40b6151c7/main.png) + +## See also: + +- https://github.com/daviddengcn/go-colortext +- https://github.com/adoxa/ansicon +- https://github.com/aslakhellesoy/wac +- https://github.com/wsxiaoys/terminal +- https://github.com/mattn/go-colorable + +## Contributing + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request + diff --git a/vendor/github.com/shiena/ansicolor/ansicolor.go b/vendor/github.com/shiena/ansicolor/ansicolor.go new file mode 100644 index 00000000..8551345b --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor.go @@ -0,0 +1,42 @@ +// Copyright 2014 shiena Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// Package ansicolor provides color console in Windows as ANSICON. +package ansicolor + +import "io" + +type outputMode int + +// DiscardNonColorEscSeq supports the divided color escape sequence. +// But non-color escape sequence is not output. +// Please use the OutputNonColorEscSeq If you want to output a non-color +// escape sequences such as ncurses. However, it does not support the divided +// color escape sequence. +const ( + _ outputMode = iota + DiscardNonColorEscSeq + OutputNonColorEscSeq +) + +// NewAnsiColorWriter creates and initializes a new ansiColorWriter +// using io.Writer w as its initial contents. +// In the console of Windows, which change the foreground and background +// colors of the text by the escape sequence. +// In the console of other systems, which writes to w all text. +func NewAnsiColorWriter(w io.Writer) io.Writer { + return NewModeAnsiColorWriter(w, DiscardNonColorEscSeq) +} + +// NewModeAnsiColorWriter create and initializes a new ansiColorWriter +// by specifying the outputMode. +func NewModeAnsiColorWriter(w io.Writer, mode outputMode) io.Writer { + if _, ok := w.(*ansiColorWriter); !ok { + return &ansiColorWriter{ + w: w, + mode: mode, + } + } + return w +} diff --git a/vendor/github.com/shiena/ansicolor/ansicolor/main.go b/vendor/github.com/shiena/ansicolor/ansicolor/main.go new file mode 100644 index 00000000..d86cfc0f --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor/main.go @@ -0,0 +1,27 @@ +// Copyright 2014 shiena Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +/* + +The ansicolor command colors a console text by ANSI escape sequence like wac. + + $ go get github.com/shiena/ansicolor/ansicolor + +See also: + https://github.com/aslakhellesoy/wac + +*/ +package main + +import ( + "io" + "os" + + "github.com/shiena/ansicolor" +) + +func main() { + w := ansicolor.NewAnsiColorWriter(os.Stdout) + io.Copy(w, os.Stdin) +} diff --git a/vendor/github.com/shiena/ansicolor/ansicolor_ansi.go b/vendor/github.com/shiena/ansicolor/ansicolor_ansi.go new file mode 100644 index 00000000..f4803bbb --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor_ansi.go @@ -0,0 +1,18 @@ +// Copyright 2014 shiena Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// +build !windows + +package ansicolor + +import "io" + +type ansiColorWriter struct { + w io.Writer + mode outputMode +} + +func (cw *ansiColorWriter) Write(p []byte) (int, error) { + return cw.w.Write(p) +} diff --git a/vendor/github.com/shiena/ansicolor/ansicolor_test.go b/vendor/github.com/shiena/ansicolor/ansicolor_test.go new file mode 100644 index 00000000..fc76ed12 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor_test.go @@ -0,0 +1,29 @@ +// Copyright 2015 shiena Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package ansicolor_test + +import ( + "bytes" + "testing" + + "github.com/shiena/ansicolor" +) + +func TestNewAnsiColor1(t *testing.T) { + inner := bytes.NewBufferString("") + w := ansicolor.NewAnsiColorWriter(inner) + if w == inner { + t.Errorf("Get %#v, want %#v", w, inner) + } +} + +func TestNewAnsiColor2(t *testing.T) { + inner := bytes.NewBufferString("") + w1 := ansicolor.NewAnsiColorWriter(inner) + w2 := ansicolor.NewAnsiColorWriter(w1) + if w1 != w2 { + t.Errorf("Get %#v, want %#v", w1, w2) + } +} diff --git a/vendor/github.com/shiena/ansicolor/ansicolor_windows.go b/vendor/github.com/shiena/ansicolor/ansicolor_windows.go new file mode 100644 index 00000000..ff2ae0ef --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor_windows.go @@ -0,0 +1,417 @@ +// Copyright 2014 shiena Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// +build windows + +package ansicolor + +import ( + "bytes" + "io" + "strings" + "syscall" + "unsafe" +) + +type csiState int + +const ( + outsideCsiCode csiState = iota + firstCsiCode + secondCsiCode +) + +type parseResult int + +const ( + noConsole parseResult = iota + changedColor + unknown +) + +type ansiColorWriter struct { + w io.Writer + mode outputMode + state csiState + paramStartBuf bytes.Buffer + paramBuf bytes.Buffer +} + +const ( + firstCsiChar byte = '\x1b' + secondeCsiChar byte = '[' + separatorChar byte = ';' + sgrCode byte = 'm' +) + +const ( + foregroundBlue = uint16(0x0001) + foregroundGreen = uint16(0x0002) + foregroundRed = uint16(0x0004) + foregroundIntensity = uint16(0x0008) + backgroundBlue = uint16(0x0010) + backgroundGreen = uint16(0x0020) + backgroundRed = uint16(0x0040) + backgroundIntensity = uint16(0x0080) + underscore = uint16(0x8000) + + foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity + backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity +) + +const ( + ansiReset = "0" + ansiIntensityOn = "1" + ansiIntensityOff = "21" + ansiUnderlineOn = "4" + ansiUnderlineOff = "24" + ansiBlinkOn = "5" + ansiBlinkOff = "25" + + ansiForegroundBlack = "30" + ansiForegroundRed = "31" + ansiForegroundGreen = "32" + ansiForegroundYellow = "33" + ansiForegroundBlue = "34" + ansiForegroundMagenta = "35" + ansiForegroundCyan = "36" + ansiForegroundWhite = "37" + ansiForegroundDefault = "39" + + ansiBackgroundBlack = "40" + ansiBackgroundRed = "41" + ansiBackgroundGreen = "42" + ansiBackgroundYellow = "43" + ansiBackgroundBlue = "44" + ansiBackgroundMagenta = "45" + ansiBackgroundCyan = "46" + ansiBackgroundWhite = "47" + ansiBackgroundDefault = "49" + + ansiLightForegroundGray = "90" + ansiLightForegroundRed = "91" + ansiLightForegroundGreen = "92" + ansiLightForegroundYellow = "93" + ansiLightForegroundBlue = "94" + ansiLightForegroundMagenta = "95" + ansiLightForegroundCyan = "96" + ansiLightForegroundWhite = "97" + + ansiLightBackgroundGray = "100" + ansiLightBackgroundRed = "101" + ansiLightBackgroundGreen = "102" + ansiLightBackgroundYellow = "103" + ansiLightBackgroundBlue = "104" + ansiLightBackgroundMagenta = "105" + ansiLightBackgroundCyan = "106" + ansiLightBackgroundWhite = "107" +) + +type drawType int + +const ( + foreground drawType = iota + background +) + +type winColor struct { + code uint16 + drawType drawType +} + +var colorMap = map[string]winColor{ + ansiForegroundBlack: {0, foreground}, + ansiForegroundRed: {foregroundRed, foreground}, + ansiForegroundGreen: {foregroundGreen, foreground}, + ansiForegroundYellow: {foregroundRed | foregroundGreen, foreground}, + ansiForegroundBlue: {foregroundBlue, foreground}, + ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground}, + ansiForegroundCyan: {foregroundGreen | foregroundBlue, foreground}, + ansiForegroundWhite: {foregroundRed | foregroundGreen | foregroundBlue, foreground}, + ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground}, + + ansiBackgroundBlack: {0, background}, + ansiBackgroundRed: {backgroundRed, background}, + ansiBackgroundGreen: {backgroundGreen, background}, + ansiBackgroundYellow: {backgroundRed | backgroundGreen, background}, + ansiBackgroundBlue: {backgroundBlue, background}, + ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background}, + ansiBackgroundCyan: {backgroundGreen | backgroundBlue, background}, + ansiBackgroundWhite: {backgroundRed | backgroundGreen | backgroundBlue, background}, + ansiBackgroundDefault: {0, background}, + + ansiLightForegroundGray: {foregroundIntensity, foreground}, + ansiLightForegroundRed: {foregroundIntensity | foregroundRed, foreground}, + ansiLightForegroundGreen: {foregroundIntensity | foregroundGreen, foreground}, + ansiLightForegroundYellow: {foregroundIntensity | foregroundRed | foregroundGreen, foreground}, + ansiLightForegroundBlue: {foregroundIntensity | foregroundBlue, foreground}, + ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground}, + ansiLightForegroundCyan: {foregroundIntensity | foregroundGreen | foregroundBlue, foreground}, + ansiLightForegroundWhite: {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground}, + + ansiLightBackgroundGray: {backgroundIntensity, background}, + ansiLightBackgroundRed: {backgroundIntensity | backgroundRed, background}, + ansiLightBackgroundGreen: {backgroundIntensity | backgroundGreen, background}, + ansiLightBackgroundYellow: {backgroundIntensity | backgroundRed | backgroundGreen, background}, + ansiLightBackgroundBlue: {backgroundIntensity | backgroundBlue, background}, + ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background}, + ansiLightBackgroundCyan: {backgroundIntensity | backgroundGreen | backgroundBlue, background}, + ansiLightBackgroundWhite: {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background}, +} + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + defaultAttr *textAttributes +) + +func init() { + screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout)) + if screenInfo != nil { + colorMap[ansiForegroundDefault] = winColor{ + screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue), + foreground, + } + colorMap[ansiBackgroundDefault] = winColor{ + screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue), + background, + } + defaultAttr = convertTextAttr(screenInfo.WAttributes) + } +} + +type coord struct { + X, Y int16 +} + +type smallRect struct { + Left, Top, Right, Bottom int16 +} + +type consoleScreenBufferInfo struct { + DwSize coord + DwCursorPosition coord + WAttributes uint16 + SrWindow smallRect + DwMaximumWindowSize coord +} + +func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo { + var csbi consoleScreenBufferInfo + ret, _, _ := procGetConsoleScreenBufferInfo.Call( + hConsoleOutput, + uintptr(unsafe.Pointer(&csbi))) + if ret == 0 { + return nil + } + return &csbi +} + +func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool { + ret, _, _ := procSetConsoleTextAttribute.Call( + hConsoleOutput, + uintptr(wAttributes)) + return ret != 0 +} + +type textAttributes struct { + foregroundColor uint16 + backgroundColor uint16 + foregroundIntensity uint16 + backgroundIntensity uint16 + underscore uint16 + otherAttributes uint16 +} + +func convertTextAttr(winAttr uint16) *textAttributes { + fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue) + bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue) + fgIntensity := winAttr & foregroundIntensity + bgIntensity := winAttr & backgroundIntensity + underline := winAttr & underscore + otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore) + return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes} +} + +func convertWinAttr(textAttr *textAttributes) uint16 { + var winAttr uint16 + winAttr |= textAttr.foregroundColor + winAttr |= textAttr.backgroundColor + winAttr |= textAttr.foregroundIntensity + winAttr |= textAttr.backgroundIntensity + winAttr |= textAttr.underscore + winAttr |= textAttr.otherAttributes + return winAttr +} + +func changeColor(param []byte) parseResult { + screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout)) + if screenInfo == nil { + return noConsole + } + + winAttr := convertTextAttr(screenInfo.WAttributes) + strParam := string(param) + if len(strParam) <= 0 { + strParam = "0" + } + csiParam := strings.Split(strParam, string(separatorChar)) + for _, p := range csiParam { + c, ok := colorMap[p] + switch { + case !ok: + switch p { + case ansiReset: + winAttr.foregroundColor = defaultAttr.foregroundColor + winAttr.backgroundColor = defaultAttr.backgroundColor + winAttr.foregroundIntensity = defaultAttr.foregroundIntensity + winAttr.backgroundIntensity = defaultAttr.backgroundIntensity + winAttr.underscore = 0 + winAttr.otherAttributes = 0 + case ansiIntensityOn: + winAttr.foregroundIntensity = foregroundIntensity + case ansiIntensityOff: + winAttr.foregroundIntensity = 0 + case ansiUnderlineOn: + winAttr.underscore = underscore + case ansiUnderlineOff: + winAttr.underscore = 0 + case ansiBlinkOn: + winAttr.backgroundIntensity = backgroundIntensity + case ansiBlinkOff: + winAttr.backgroundIntensity = 0 + default: + // unknown code + } + case c.drawType == foreground: + winAttr.foregroundColor = c.code + case c.drawType == background: + winAttr.backgroundColor = c.code + } + } + winTextAttribute := convertWinAttr(winAttr) + setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute) + + return changedColor +} + +func parseEscapeSequence(command byte, param []byte) parseResult { + if defaultAttr == nil { + return noConsole + } + + switch command { + case sgrCode: + return changeColor(param) + default: + return unknown + } +} + +func (cw *ansiColorWriter) flushBuffer() (int, error) { + return cw.flushTo(cw.w) +} + +func (cw *ansiColorWriter) resetBuffer() (int, error) { + return cw.flushTo(nil) +} + +func (cw *ansiColorWriter) flushTo(w io.Writer) (int, error) { + var n1, n2 int + var err error + + startBytes := cw.paramStartBuf.Bytes() + cw.paramStartBuf.Reset() + if w != nil { + n1, err = cw.w.Write(startBytes) + if err != nil { + return n1, err + } + } else { + n1 = len(startBytes) + } + paramBytes := cw.paramBuf.Bytes() + cw.paramBuf.Reset() + if w != nil { + n2, err = cw.w.Write(paramBytes) + if err != nil { + return n1 + n2, err + } + } else { + n2 = len(paramBytes) + } + return n1 + n2, nil +} + +func isParameterChar(b byte) bool { + return ('0' <= b && b <= '9') || b == separatorChar +} + +func (cw *ansiColorWriter) Write(p []byte) (int, error) { + r, nw, first, last := 0, 0, 0, 0 + if cw.mode != DiscardNonColorEscSeq { + cw.state = outsideCsiCode + cw.resetBuffer() + } + + var err error + for i, ch := range p { + switch cw.state { + case outsideCsiCode: + if ch == firstCsiChar { + cw.paramStartBuf.WriteByte(ch) + cw.state = firstCsiCode + } + case firstCsiCode: + switch ch { + case firstCsiChar: + cw.paramStartBuf.WriteByte(ch) + break + case secondeCsiChar: + cw.paramStartBuf.WriteByte(ch) + cw.state = secondCsiCode + last = i - 1 + default: + cw.resetBuffer() + cw.state = outsideCsiCode + } + case secondCsiCode: + if isParameterChar(ch) { + cw.paramBuf.WriteByte(ch) + } else { + nw, err = cw.w.Write(p[first:last]) + r += nw + if err != nil { + return r, err + } + first = i + 1 + result := parseEscapeSequence(ch, cw.paramBuf.Bytes()) + if result == noConsole || (cw.mode == OutputNonColorEscSeq && result == unknown) { + cw.paramBuf.WriteByte(ch) + nw, err := cw.flushBuffer() + if err != nil { + return r, err + } + r += nw + } else { + n, _ := cw.resetBuffer() + // Add one more to the size of the buffer for the last ch + r += n + 1 + } + + cw.state = outsideCsiCode + } + default: + cw.state = outsideCsiCode + } + } + + if cw.mode != DiscardNonColorEscSeq || cw.state == outsideCsiCode { + nw, err = cw.w.Write(p[first:len(p)]) + r += nw + } + + return r, err +} diff --git a/vendor/github.com/shiena/ansicolor/ansicolor_windows_test.go b/vendor/github.com/shiena/ansicolor/ansicolor_windows_test.go new file mode 100644 index 00000000..3d8c53b9 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor_windows_test.go @@ -0,0 +1,277 @@ +// Copyright 2014 shiena Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// +build windows + +package ansicolor_test + +import ( + "bytes" + "fmt" + "syscall" + "testing" + + "github.com/shiena/ansicolor" + . "github.com/shiena/ansicolor" +) + +func TestWritePlanText(t *testing.T) { + inner := bytes.NewBufferString("") + w := ansicolor.NewAnsiColorWriter(inner) + expected := "plain text" + fmt.Fprintf(w, expected) + actual := inner.String() + if actual != expected { + t.Errorf("Get %q, want %q", actual, expected) + } +} + +func TestWriteParseText(t *testing.T) { + inner := bytes.NewBufferString("") + w := ansicolor.NewAnsiColorWriter(inner) + + inputTail := "\x1b[0mtail text" + expectedTail := "tail text" + fmt.Fprintf(w, inputTail) + actualTail := inner.String() + inner.Reset() + if actualTail != expectedTail { + t.Errorf("Get %q, want %q", actualTail, expectedTail) + } + + inputHead := "head text\x1b[0m" + expectedHead := "head text" + fmt.Fprintf(w, inputHead) + actualHead := inner.String() + inner.Reset() + if actualHead != expectedHead { + t.Errorf("Get %q, want %q", actualHead, expectedHead) + } + + inputBothEnds := "both ends \x1b[0m text" + expectedBothEnds := "both ends text" + fmt.Fprintf(w, inputBothEnds) + actualBothEnds := inner.String() + inner.Reset() + if actualBothEnds != expectedBothEnds { + t.Errorf("Get %q, want %q", actualBothEnds, expectedBothEnds) + } + + inputManyEsc := "\x1b\x1b\x1b\x1b[0m many esc" + expectedManyEsc := "\x1b\x1b\x1b many esc" + fmt.Fprintf(w, inputManyEsc) + actualManyEsc := inner.String() + inner.Reset() + if actualManyEsc != expectedManyEsc { + t.Errorf("Get %q, want %q", actualManyEsc, expectedManyEsc) + } + + expectedSplit := "split text" + for _, ch := range "split \x1b[0m text" { + fmt.Fprintf(w, string(ch)) + } + actualSplit := inner.String() + inner.Reset() + if actualSplit != expectedSplit { + t.Errorf("Get %q, want %q", actualSplit, expectedSplit) + } +} + +type screenNotFoundError struct { + error +} + +func writeAnsiColor(expectedText, colorCode string) (actualText string, actualAttributes uint16, err error) { + inner := bytes.NewBufferString("") + w := ansicolor.NewAnsiColorWriter(inner) + fmt.Fprintf(w, "\x1b[%sm%s", colorCode, expectedText) + + actualText = inner.String() + screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout)) + if screenInfo != nil { + actualAttributes = screenInfo.WAttributes + } else { + err = &screenNotFoundError{} + } + return +} + +type testParam struct { + text string + attributes uint16 + ansiColor string +} + +func TestWriteAnsiColorText(t *testing.T) { + screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout)) + if screenInfo == nil { + t.Fatal("Could not get ConsoleScreenBufferInfo") + } + defer ChangeColor(screenInfo.WAttributes) + defaultFgColor := screenInfo.WAttributes & uint16(0x0007) + defaultBgColor := screenInfo.WAttributes & uint16(0x0070) + defaultFgIntensity := screenInfo.WAttributes & uint16(0x0008) + defaultBgIntensity := screenInfo.WAttributes & uint16(0x0080) + + fgParam := []testParam{ + {"foreground black ", uint16(0x0000 | 0x0000), "30"}, + {"foreground red ", uint16(0x0004 | 0x0000), "31"}, + {"foreground green ", uint16(0x0002 | 0x0000), "32"}, + {"foreground yellow ", uint16(0x0006 | 0x0000), "33"}, + {"foreground blue ", uint16(0x0001 | 0x0000), "34"}, + {"foreground magenta", uint16(0x0005 | 0x0000), "35"}, + {"foreground cyan ", uint16(0x0003 | 0x0000), "36"}, + {"foreground white ", uint16(0x0007 | 0x0000), "37"}, + {"foreground default", defaultFgColor | 0x0000, "39"}, + {"foreground light gray ", uint16(0x0000 | 0x0008 | 0x0000), "90"}, + {"foreground light red ", uint16(0x0004 | 0x0008 | 0x0000), "91"}, + {"foreground light green ", uint16(0x0002 | 0x0008 | 0x0000), "92"}, + {"foreground light yellow ", uint16(0x0006 | 0x0008 | 0x0000), "93"}, + {"foreground light blue ", uint16(0x0001 | 0x0008 | 0x0000), "94"}, + {"foreground light magenta", uint16(0x0005 | 0x0008 | 0x0000), "95"}, + {"foreground light cyan ", uint16(0x0003 | 0x0008 | 0x0000), "96"}, + {"foreground light white ", uint16(0x0007 | 0x0008 | 0x0000), "97"}, + } + + bgParam := []testParam{ + {"background black ", uint16(0x0007 | 0x0000), "40"}, + {"background red ", uint16(0x0007 | 0x0040), "41"}, + {"background green ", uint16(0x0007 | 0x0020), "42"}, + {"background yellow ", uint16(0x0007 | 0x0060), "43"}, + {"background blue ", uint16(0x0007 | 0x0010), "44"}, + {"background magenta", uint16(0x0007 | 0x0050), "45"}, + {"background cyan ", uint16(0x0007 | 0x0030), "46"}, + {"background white ", uint16(0x0007 | 0x0070), "47"}, + {"background default", uint16(0x0007) | defaultBgColor, "49"}, + {"background light gray ", uint16(0x0007 | 0x0000 | 0x0080), "100"}, + {"background light red ", uint16(0x0007 | 0x0040 | 0x0080), "101"}, + {"background light green ", uint16(0x0007 | 0x0020 | 0x0080), "102"}, + {"background light yellow ", uint16(0x0007 | 0x0060 | 0x0080), "103"}, + {"background light blue ", uint16(0x0007 | 0x0010 | 0x0080), "104"}, + {"background light magenta", uint16(0x0007 | 0x0050 | 0x0080), "105"}, + {"background light cyan ", uint16(0x0007 | 0x0030 | 0x0080), "106"}, + {"background light white ", uint16(0x0007 | 0x0070 | 0x0080), "107"}, + } + + resetParam := []testParam{ + {"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, "0"}, + {"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, ""}, + } + + boldParam := []testParam{ + {"bold on", uint16(0x0007 | 0x0008), "1"}, + {"bold off", uint16(0x0007), "21"}, + } + + underscoreParam := []testParam{ + {"underscore on", uint16(0x0007 | 0x8000), "4"}, + {"underscore off", uint16(0x0007), "24"}, + } + + blinkParam := []testParam{ + {"blink on", uint16(0x0007 | 0x0080), "5"}, + {"blink off", uint16(0x0007), "25"}, + } + + mixedParam := []testParam{ + {"both black, bold, underline, blink", uint16(0x0000 | 0x0000 | 0x0008 | 0x8000 | 0x0080), "30;40;1;4;5"}, + {"both red, bold, underline, blink", uint16(0x0004 | 0x0040 | 0x0008 | 0x8000 | 0x0080), "31;41;1;4;5"}, + {"both green, bold, underline, blink", uint16(0x0002 | 0x0020 | 0x0008 | 0x8000 | 0x0080), "32;42;1;4;5"}, + {"both yellow, bold, underline, blink", uint16(0x0006 | 0x0060 | 0x0008 | 0x8000 | 0x0080), "33;43;1;4;5"}, + {"both blue, bold, underline, blink", uint16(0x0001 | 0x0010 | 0x0008 | 0x8000 | 0x0080), "34;44;1;4;5"}, + {"both magenta, bold, underline, blink", uint16(0x0005 | 0x0050 | 0x0008 | 0x8000 | 0x0080), "35;45;1;4;5"}, + {"both cyan, bold, underline, blink", uint16(0x0003 | 0x0030 | 0x0008 | 0x8000 | 0x0080), "36;46;1;4;5"}, + {"both white, bold, underline, blink", uint16(0x0007 | 0x0070 | 0x0008 | 0x8000 | 0x0080), "37;47;1;4;5"}, + {"both default, bold, underline, blink", uint16(defaultFgColor | defaultBgColor | 0x0008 | 0x8000 | 0x0080), "39;49;1;4;5"}, + } + + assertTextAttribute := func(expectedText string, expectedAttributes uint16, ansiColor string) { + actualText, actualAttributes, err := writeAnsiColor(expectedText, ansiColor) + if actualText != expectedText { + t.Errorf("Get %q, want %q", actualText, expectedText) + } + if err != nil { + t.Fatal("Could not get ConsoleScreenBufferInfo") + } + if actualAttributes != expectedAttributes { + t.Errorf("Text: %q, Get 0x%04x, want 0x%04x", expectedText, actualAttributes, expectedAttributes) + } + } + + for _, v := range fgParam { + ResetColor() + assertTextAttribute(v.text, v.attributes, v.ansiColor) + } + + for _, v := range bgParam { + ChangeColor(uint16(0x0070 | 0x0007)) + assertTextAttribute(v.text, v.attributes, v.ansiColor) + } + + for _, v := range resetParam { + ChangeColor(uint16(0x0000 | 0x0070 | 0x0008)) + assertTextAttribute(v.text, v.attributes, v.ansiColor) + } + + ResetColor() + for _, v := range boldParam { + assertTextAttribute(v.text, v.attributes, v.ansiColor) + } + + ResetColor() + for _, v := range underscoreParam { + assertTextAttribute(v.text, v.attributes, v.ansiColor) + } + + ResetColor() + for _, v := range blinkParam { + assertTextAttribute(v.text, v.attributes, v.ansiColor) + } + + for _, v := range mixedParam { + ResetColor() + assertTextAttribute(v.text, v.attributes, v.ansiColor) + } +} + +func TestIgnoreUnknownSequences(t *testing.T) { + inner := bytes.NewBufferString("") + w := ansicolor.NewModeAnsiColorWriter(inner, ansicolor.OutputNonColorEscSeq) + + inputText := "\x1b[=decpath mode" + expectedTail := inputText + fmt.Fprintf(w, inputText) + actualTail := inner.String() + inner.Reset() + if actualTail != expectedTail { + t.Errorf("Get %q, want %q", actualTail, expectedTail) + } + + inputText = "\x1b[=tailing esc and bracket\x1b[" + expectedTail = inputText + fmt.Fprintf(w, inputText) + actualTail = inner.String() + inner.Reset() + if actualTail != expectedTail { + t.Errorf("Get %q, want %q", actualTail, expectedTail) + } + + inputText = "\x1b[?tailing esc\x1b" + expectedTail = inputText + fmt.Fprintf(w, inputText) + actualTail = inner.String() + inner.Reset() + if actualTail != expectedTail { + t.Errorf("Get %q, want %q", actualTail, expectedTail) + } + + inputText = "\x1b[1h;3punended color code invalid\x1b3" + expectedTail = inputText + fmt.Fprintf(w, inputText) + actualTail = inner.String() + inner.Reset() + if actualTail != expectedTail { + t.Errorf("Get %q, want %q", actualTail, expectedTail) + } +} diff --git a/vendor/github.com/shiena/ansicolor/example_test.go b/vendor/github.com/shiena/ansicolor/example_test.go new file mode 100644 index 00000000..f2ac67c1 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/example_test.go @@ -0,0 +1,24 @@ +// Copyright 2014 shiena Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package ansicolor_test + +import ( + "fmt" + "os" + + "github.com/shiena/ansicolor" +) + +func ExampleNewAnsiColorWriter() { + w := ansicolor.NewAnsiColorWriter(os.Stdout) + text := "%sforeground %sbold%s %sbackground%s\n" + fmt.Fprintf(w, text, "\x1b[31m", "\x1b[1m", "\x1b[21m", "\x1b[41;32m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[32m", "\x1b[1m", "\x1b[21m", "\x1b[42;31m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[33m", "\x1b[1m", "\x1b[21m", "\x1b[43;34m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[34m", "\x1b[1m", "\x1b[21m", "\x1b[44;33m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[35m", "\x1b[1m", "\x1b[21m", "\x1b[45;36m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[36m", "\x1b[1m", "\x1b[21m", "\x1b[46;35m", "\x1b[0m") + fmt.Fprintf(w, text, "\x1b[37m", "\x1b[1m", "\x1b[21m", "\x1b[47;30m", "\x1b[0m") +} diff --git a/vendor/github.com/shiena/ansicolor/export_test.go b/vendor/github.com/shiena/ansicolor/export_test.go new file mode 100644 index 00000000..6d2f7c07 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/export_test.go @@ -0,0 +1,19 @@ +// Copyright 2014 shiena Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// +build windows + +package ansicolor + +import "syscall" + +var GetConsoleScreenBufferInfo = getConsoleScreenBufferInfo + +func ChangeColor(color uint16) { + setConsoleTextAttribute(uintptr(syscall.Stdout), color) +} + +func ResetColor() { + ChangeColor(uint16(0x0007)) +} diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go b/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go new file mode 100644 index 00000000..c9670de5 --- /dev/null +++ b/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go @@ -0,0 +1,676 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package cache provides interface and implementation of a cache algorithms. +package cache + +import ( + "sync" + "sync/atomic" + "unsafe" + + "github.com/syndtr/goleveldb/leveldb/util" +) + +// Cacher provides interface to implements a caching functionality. +// An implementation must be goroutine-safe. +type Cacher interface { + // Capacity returns cache capacity. + Capacity() int + + // SetCapacity sets cache capacity. + SetCapacity(capacity int) + + // Promote promotes the 'cache node'. + Promote(n *Node) + + // Ban evicts the 'cache node' and prevent subsequent 'promote'. + Ban(n *Node) + + // Evict evicts the 'cache node'. + Evict(n *Node) + + // EvictNS evicts 'cache node' with the given namespace. + EvictNS(ns uint64) + + // EvictAll evicts all 'cache node'. + EvictAll() + + // Close closes the 'cache tree' + Close() error +} + +// Value is a 'cacheable object'. It may implements util.Releaser, if +// so the the Release method will be called once object is released. +type Value interface{} + +type CacheGetter struct { + Cache *Cache + NS uint64 +} + +func (g *CacheGetter) Get(key uint64, setFunc func() (size int, value Value)) *Handle { + return g.Cache.Get(g.NS, key, setFunc) +} + +// The hash tables implementation is based on: +// "Dynamic-Sized Nonblocking Hash Tables", by Yujie Liu, Kunlong Zhang, and Michael Spear. ACM Symposium on Principles of Distributed Computing, Jul 2014. + +const ( + mInitialSize = 1 << 4 + mOverflowThreshold = 1 << 5 + mOverflowGrowThreshold = 1 << 7 +) + +type mBucket struct { + mu sync.Mutex + node []*Node + frozen bool +} + +func (b *mBucket) freeze() []*Node { + b.mu.Lock() + defer b.mu.Unlock() + if !b.frozen { + b.frozen = true + } + return b.node +} + +func (b *mBucket) get(r *Cache, h *mNode, hash uint32, ns, key uint64, noset bool) (done, added bool, n *Node) { + b.mu.Lock() + + if b.frozen { + b.mu.Unlock() + return + } + + // Scan the node. + for _, n := range b.node { + if n.hash == hash && n.ns == ns && n.key == key { + atomic.AddInt32(&n.ref, 1) + b.mu.Unlock() + return true, false, n + } + } + + // Get only. + if noset { + b.mu.Unlock() + return true, false, nil + } + + // Create node. + n = &Node{ + r: r, + hash: hash, + ns: ns, + key: key, + ref: 1, + } + // Add node to bucket. + b.node = append(b.node, n) + bLen := len(b.node) + b.mu.Unlock() + + // Update counter. + grow := atomic.AddInt32(&r.nodes, 1) >= h.growThreshold + if bLen > mOverflowThreshold { + grow = grow || atomic.AddInt32(&h.overflow, 1) >= mOverflowGrowThreshold + } + + // Grow. + if grow && atomic.CompareAndSwapInt32(&h.resizeInProgess, 0, 1) { + nhLen := len(h.buckets) << 1 + nh := &mNode{ + buckets: make([]unsafe.Pointer, nhLen), + mask: uint32(nhLen) - 1, + pred: unsafe.Pointer(h), + growThreshold: int32(nhLen * mOverflowThreshold), + shrinkThreshold: int32(nhLen >> 1), + } + ok := atomic.CompareAndSwapPointer(&r.mHead, unsafe.Pointer(h), unsafe.Pointer(nh)) + if !ok { + panic("BUG: failed swapping head") + } + go nh.initBuckets() + } + + return true, true, n +} + +func (b *mBucket) delete(r *Cache, h *mNode, hash uint32, ns, key uint64) (done, deleted bool) { + b.mu.Lock() + + if b.frozen { + b.mu.Unlock() + return + } + + // Scan the node. + var ( + n *Node + bLen int + ) + for i := range b.node { + n = b.node[i] + if n.ns == ns && n.key == key { + if atomic.LoadInt32(&n.ref) == 0 { + deleted = true + + // Call releaser. + if n.value != nil { + if r, ok := n.value.(util.Releaser); ok { + r.Release() + } + n.value = nil + } + + // Remove node from bucket. + b.node = append(b.node[:i], b.node[i+1:]...) + bLen = len(b.node) + } + break + } + } + b.mu.Unlock() + + if deleted { + // Call OnDel. + for _, f := range n.onDel { + f() + } + + // Update counter. + atomic.AddInt32(&r.size, int32(n.size)*-1) + shrink := atomic.AddInt32(&r.nodes, -1) < h.shrinkThreshold + if bLen >= mOverflowThreshold { + atomic.AddInt32(&h.overflow, -1) + } + + // Shrink. + if shrink && len(h.buckets) > mInitialSize && atomic.CompareAndSwapInt32(&h.resizeInProgess, 0, 1) { + nhLen := len(h.buckets) >> 1 + nh := &mNode{ + buckets: make([]unsafe.Pointer, nhLen), + mask: uint32(nhLen) - 1, + pred: unsafe.Pointer(h), + growThreshold: int32(nhLen * mOverflowThreshold), + shrinkThreshold: int32(nhLen >> 1), + } + ok := atomic.CompareAndSwapPointer(&r.mHead, unsafe.Pointer(h), unsafe.Pointer(nh)) + if !ok { + panic("BUG: failed swapping head") + } + go nh.initBuckets() + } + } + + return true, deleted +} + +type mNode struct { + buckets []unsafe.Pointer // []*mBucket + mask uint32 + pred unsafe.Pointer // *mNode + resizeInProgess int32 + + overflow int32 + growThreshold int32 + shrinkThreshold int32 +} + +func (n *mNode) initBucket(i uint32) *mBucket { + if b := (*mBucket)(atomic.LoadPointer(&n.buckets[i])); b != nil { + return b + } + + p := (*mNode)(atomic.LoadPointer(&n.pred)) + if p != nil { + var node []*Node + if n.mask > p.mask { + // Grow. + pb := (*mBucket)(atomic.LoadPointer(&p.buckets[i&p.mask])) + if pb == nil { + pb = p.initBucket(i & p.mask) + } + m := pb.freeze() + // Split nodes. + for _, x := range m { + if x.hash&n.mask == i { + node = append(node, x) + } + } + } else { + // Shrink. + pb0 := (*mBucket)(atomic.LoadPointer(&p.buckets[i])) + if pb0 == nil { + pb0 = p.initBucket(i) + } + pb1 := (*mBucket)(atomic.LoadPointer(&p.buckets[i+uint32(len(n.buckets))])) + if pb1 == nil { + pb1 = p.initBucket(i + uint32(len(n.buckets))) + } + m0 := pb0.freeze() + m1 := pb1.freeze() + // Merge nodes. + node = make([]*Node, 0, len(m0)+len(m1)) + node = append(node, m0...) + node = append(node, m1...) + } + b := &mBucket{node: node} + if atomic.CompareAndSwapPointer(&n.buckets[i], nil, unsafe.Pointer(b)) { + if len(node) > mOverflowThreshold { + atomic.AddInt32(&n.overflow, int32(len(node)-mOverflowThreshold)) + } + return b + } + } + + return (*mBucket)(atomic.LoadPointer(&n.buckets[i])) +} + +func (n *mNode) initBuckets() { + for i := range n.buckets { + n.initBucket(uint32(i)) + } + atomic.StorePointer(&n.pred, nil) +} + +// Cache is a 'cache map'. +type Cache struct { + mu sync.RWMutex + mHead unsafe.Pointer // *mNode + nodes int32 + size int32 + cacher Cacher + closed bool +} + +// NewCache creates a new 'cache map'. The cacher is optional and +// may be nil. +func NewCache(cacher Cacher) *Cache { + h := &mNode{ + buckets: make([]unsafe.Pointer, mInitialSize), + mask: mInitialSize - 1, + growThreshold: int32(mInitialSize * mOverflowThreshold), + shrinkThreshold: 0, + } + for i := range h.buckets { + h.buckets[i] = unsafe.Pointer(&mBucket{}) + } + r := &Cache{ + mHead: unsafe.Pointer(h), + cacher: cacher, + } + return r +} + +func (r *Cache) getBucket(hash uint32) (*mNode, *mBucket) { + h := (*mNode)(atomic.LoadPointer(&r.mHead)) + i := hash & h.mask + b := (*mBucket)(atomic.LoadPointer(&h.buckets[i])) + if b == nil { + b = h.initBucket(i) + } + return h, b +} + +func (r *Cache) delete(n *Node) bool { + for { + h, b := r.getBucket(n.hash) + done, deleted := b.delete(r, h, n.hash, n.ns, n.key) + if done { + return deleted + } + } + return false +} + +// Nodes returns number of 'cache node' in the map. +func (r *Cache) Nodes() int { + return int(atomic.LoadInt32(&r.nodes)) +} + +// Size returns sums of 'cache node' size in the map. +func (r *Cache) Size() int { + return int(atomic.LoadInt32(&r.size)) +} + +// Capacity returns cache capacity. +func (r *Cache) Capacity() int { + if r.cacher == nil { + return 0 + } + return r.cacher.Capacity() +} + +// SetCapacity sets cache capacity. +func (r *Cache) SetCapacity(capacity int) { + if r.cacher != nil { + r.cacher.SetCapacity(capacity) + } +} + +// Get gets 'cache node' with the given namespace and key. +// If cache node is not found and setFunc is not nil, Get will atomically creates +// the 'cache node' by calling setFunc. Otherwise Get will returns nil. +// +// The returned 'cache handle' should be released after use by calling Release +// method. +func (r *Cache) Get(ns, key uint64, setFunc func() (size int, value Value)) *Handle { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return nil + } + + hash := murmur32(ns, key, 0xf00) + for { + h, b := r.getBucket(hash) + done, _, n := b.get(r, h, hash, ns, key, setFunc == nil) + if done { + if n != nil { + n.mu.Lock() + if n.value == nil { + if setFunc == nil { + n.mu.Unlock() + n.unref() + return nil + } + + n.size, n.value = setFunc() + if n.value == nil { + n.size = 0 + n.mu.Unlock() + n.unref() + return nil + } + atomic.AddInt32(&r.size, int32(n.size)) + } + n.mu.Unlock() + if r.cacher != nil { + r.cacher.Promote(n) + } + return &Handle{unsafe.Pointer(n)} + } + + break + } + } + return nil +} + +// Delete removes and ban 'cache node' with the given namespace and key. +// A banned 'cache node' will never inserted into the 'cache tree'. Ban +// only attributed to the particular 'cache node', so when a 'cache node' +// is recreated it will not be banned. +// +// If onDel is not nil, then it will be executed if such 'cache node' +// doesn't exist or once the 'cache node' is released. +// +// Delete return true is such 'cache node' exist. +func (r *Cache) Delete(ns, key uint64, onDel func()) bool { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return false + } + + hash := murmur32(ns, key, 0xf00) + for { + h, b := r.getBucket(hash) + done, _, n := b.get(r, h, hash, ns, key, true) + if done { + if n != nil { + if onDel != nil { + n.mu.Lock() + n.onDel = append(n.onDel, onDel) + n.mu.Unlock() + } + if r.cacher != nil { + r.cacher.Ban(n) + } + n.unref() + return true + } + + break + } + } + + if onDel != nil { + onDel() + } + + return false +} + +// Evict evicts 'cache node' with the given namespace and key. This will +// simply call Cacher.Evict. +// +// Evict return true is such 'cache node' exist. +func (r *Cache) Evict(ns, key uint64) bool { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return false + } + + hash := murmur32(ns, key, 0xf00) + for { + h, b := r.getBucket(hash) + done, _, n := b.get(r, h, hash, ns, key, true) + if done { + if n != nil { + if r.cacher != nil { + r.cacher.Evict(n) + } + n.unref() + return true + } + + break + } + } + + return false +} + +// EvictNS evicts 'cache node' with the given namespace. This will +// simply call Cacher.EvictNS. +func (r *Cache) EvictNS(ns uint64) { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return + } + + if r.cacher != nil { + r.cacher.EvictNS(ns) + } +} + +// EvictAll evicts all 'cache node'. This will simply call Cacher.EvictAll. +func (r *Cache) EvictAll() { + r.mu.RLock() + defer r.mu.RUnlock() + if r.closed { + return + } + + if r.cacher != nil { + r.cacher.EvictAll() + } +} + +// Close closes the 'cache map' and releases all 'cache node'. +func (r *Cache) Close() error { + r.mu.Lock() + if !r.closed { + r.closed = true + + if r.cacher != nil { + if err := r.cacher.Close(); err != nil { + return err + } + } + + h := (*mNode)(r.mHead) + h.initBuckets() + + for i := range h.buckets { + b := (*mBucket)(h.buckets[i]) + for _, n := range b.node { + // Call releaser. + if n.value != nil { + if r, ok := n.value.(util.Releaser); ok { + r.Release() + } + n.value = nil + } + + // Call OnDel. + for _, f := range n.onDel { + f() + } + } + } + } + r.mu.Unlock() + return nil +} + +// Node is a 'cache node'. +type Node struct { + r *Cache + + hash uint32 + ns, key uint64 + + mu sync.Mutex + size int + value Value + + ref int32 + onDel []func() + + CacheData unsafe.Pointer +} + +// NS returns this 'cache node' namespace. +func (n *Node) NS() uint64 { + return n.ns +} + +// Key returns this 'cache node' key. +func (n *Node) Key() uint64 { + return n.key +} + +// Size returns this 'cache node' size. +func (n *Node) Size() int { + return n.size +} + +// Value returns this 'cache node' value. +func (n *Node) Value() Value { + return n.value +} + +// Ref returns this 'cache node' ref counter. +func (n *Node) Ref() int32 { + return atomic.LoadInt32(&n.ref) +} + +// GetHandle returns an handle for this 'cache node'. +func (n *Node) GetHandle() *Handle { + if atomic.AddInt32(&n.ref, 1) <= 1 { + panic("BUG: Node.GetHandle on zero ref") + } + return &Handle{unsafe.Pointer(n)} +} + +func (n *Node) unref() { + if atomic.AddInt32(&n.ref, -1) == 0 { + n.r.delete(n) + } +} + +func (n *Node) unrefLocked() { + if atomic.AddInt32(&n.ref, -1) == 0 { + n.r.mu.RLock() + if !n.r.closed { + n.r.delete(n) + } + n.r.mu.RUnlock() + } +} + +type Handle struct { + n unsafe.Pointer // *Node +} + +func (h *Handle) Value() Value { + n := (*Node)(atomic.LoadPointer(&h.n)) + if n != nil { + return n.value + } + return nil +} + +func (h *Handle) Release() { + nPtr := atomic.LoadPointer(&h.n) + if nPtr != nil && atomic.CompareAndSwapPointer(&h.n, nPtr, nil) { + n := (*Node)(nPtr) + n.unrefLocked() + } +} + +func murmur32(ns, key uint64, seed uint32) uint32 { + const ( + m = uint32(0x5bd1e995) + r = 24 + ) + + k1 := uint32(ns >> 32) + k2 := uint32(ns) + k3 := uint32(key >> 32) + k4 := uint32(key) + + k1 *= m + k1 ^= k1 >> r + k1 *= m + + k2 *= m + k2 ^= k2 >> r + k2 *= m + + k3 *= m + k3 ^= k3 >> r + k3 *= m + + k4 *= m + k4 ^= k4 >> r + k4 *= m + + h := seed + + h *= m + h ^= k1 + h *= m + h ^= k2 + h *= m + h ^= k3 + h *= m + h ^= k4 + + h ^= h >> 13 + h *= m + h ^= h >> 15 + + return h +} diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/cache/lru.go b/vendor/github.com/syndtr/goleveldb/leveldb/cache/lru.go new file mode 100644 index 00000000..d9a84cde --- /dev/null +++ b/vendor/github.com/syndtr/goleveldb/leveldb/cache/lru.go @@ -0,0 +1,195 @@ +// Copyright (c) 2012, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package cache + +import ( + "sync" + "unsafe" +) + +type lruNode struct { + n *Node + h *Handle + ban bool + + next, prev *lruNode +} + +func (n *lruNode) insert(at *lruNode) { + x := at.next + at.next = n + n.prev = at + n.next = x + x.prev = n +} + +func (n *lruNode) remove() { + if n.prev != nil { + n.prev.next = n.next + n.next.prev = n.prev + n.prev = nil + n.next = nil + } else { + panic("BUG: removing removed node") + } +} + +type lru struct { + mu sync.Mutex + capacity int + used int + recent lruNode +} + +func (r *lru) reset() { + r.recent.next = &r.recent + r.recent.prev = &r.recent + r.used = 0 +} + +func (r *lru) Capacity() int { + r.mu.Lock() + defer r.mu.Unlock() + return r.capacity +} + +func (r *lru) SetCapacity(capacity int) { + var evicted []*lruNode + + r.mu.Lock() + r.capacity = capacity + for r.used > r.capacity { + rn := r.recent.prev + if rn == nil { + panic("BUG: invalid LRU used or capacity counter") + } + rn.remove() + rn.n.CacheData = nil + r.used -= rn.n.Size() + evicted = append(evicted, rn) + } + r.mu.Unlock() + + for _, rn := range evicted { + rn.h.Release() + } +} + +func (r *lru) Promote(n *Node) { + var evicted []*lruNode + + r.mu.Lock() + if n.CacheData == nil { + if n.Size() <= r.capacity { + rn := &lruNode{n: n, h: n.GetHandle()} + rn.insert(&r.recent) + n.CacheData = unsafe.Pointer(rn) + r.used += n.Size() + + for r.used > r.capacity { + rn := r.recent.prev + if rn == nil { + panic("BUG: invalid LRU used or capacity counter") + } + rn.remove() + rn.n.CacheData = nil + r.used -= rn.n.Size() + evicted = append(evicted, rn) + } + } + } else { + rn := (*lruNode)(n.CacheData) + if !rn.ban { + rn.remove() + rn.insert(&r.recent) + } + } + r.mu.Unlock() + + for _, rn := range evicted { + rn.h.Release() + } +} + +func (r *lru) Ban(n *Node) { + r.mu.Lock() + if n.CacheData == nil { + n.CacheData = unsafe.Pointer(&lruNode{n: n, ban: true}) + } else { + rn := (*lruNode)(n.CacheData) + if !rn.ban { + rn.remove() + rn.ban = true + r.used -= rn.n.Size() + r.mu.Unlock() + + rn.h.Release() + rn.h = nil + return + } + } + r.mu.Unlock() +} + +func (r *lru) Evict(n *Node) { + r.mu.Lock() + rn := (*lruNode)(n.CacheData) + if rn == nil || rn.ban { + r.mu.Unlock() + return + } + n.CacheData = nil + r.mu.Unlock() + + rn.h.Release() +} + +func (r *lru) EvictNS(ns uint64) { + var evicted []*lruNode + + r.mu.Lock() + for e := r.recent.prev; e != &r.recent; { + rn := e + e = e.prev + if rn.n.NS() == ns { + rn.remove() + rn.n.CacheData = nil + r.used -= rn.n.Size() + evicted = append(evicted, rn) + } + } + r.mu.Unlock() + + for _, rn := range evicted { + rn.h.Release() + } +} + +func (r *lru) EvictAll() { + r.mu.Lock() + back := r.recent.prev + for rn := back; rn != &r.recent; rn = rn.prev { + rn.n.CacheData = nil + } + r.reset() + r.mu.Unlock() + + for rn := back; rn != &r.recent; rn = rn.prev { + rn.h.Release() + } +} + +func (r *lru) Close() error { + return nil +} + +// NewLRU create a new LRU-cache. +func NewLRU(capacity int) Cacher { + r := &lru{capacity: capacity} + r.reset() + return r +}