diff --git a/controller-main.go b/controller-main.go index 98794b6f6..40d3165d6 100644 --- a/controller-main.go +++ b/controller-main.go @@ -18,7 +18,6 @@ package main import ( "crypto/tls" - "fmt" "net" "net/http" "os" @@ -37,12 +36,14 @@ var controllerCmd = cli.Command{ minio {{.Name}} - {{.Description}} USAGE: - minio {{.Name}} + minio {{.Name}} [OPTION] EXAMPLES: 1. Start minio controller $ minio {{.Name}} + 2. Colored output of generated keys + $ minio {{.Name}} keys `, } @@ -63,12 +64,10 @@ func configureControllerRPC(conf minioConfig, rpcHandler http.Handler) (*http.Se return nil, probe.NewError(err) } } - host, port, err := net.SplitHostPort(conf.ControllerAddress) if err != nil { return nil, probe.NewError(err) } - var hosts []string switch { case host != "": @@ -87,12 +86,11 @@ func configureControllerRPC(conf minioConfig, rpcHandler http.Handler) (*http.Se } } } - for _, host := range hosts { if conf.TLS { - fmt.Printf("Starting minio controller on: https://%s:%s, PID: %d\n", host, port, os.Getpid()) + Printf("Starting minio controller on: https://%s:%s, PID: %d\n", host, port, os.Getpid()) } else { - fmt.Printf("Starting minio controller on: http://%s:%s, PID: %d\n", host, port, os.Getpid()) + Printf("Starting minio controller on: http://%s:%s, PID: %d\n", host, port, os.Getpid()) } } return rpcServer, nil @@ -111,6 +109,57 @@ func startController(conf minioConfig) *probe.Error { return nil } +func genAuthFirstTime() (*AuthConfig, *probe.Error) { + if isAuthConfigFileExists() { + return nil, nil + } + // Initialize new config, since config file doesn't exist yet + config := &AuthConfig{} + config.Version = "0.0.1" + config.Users = make(map[string]*AuthUser) + accessKeyID, err := GenerateAccessKeyID() + if err != nil { + return nil, err.Trace() + } + secretAccessKey, err := GenerateSecretAccessKey() + if err != nil { + return nil, err.Trace() + } + config.Users["admin"] = &AuthUser{ + Name: "admin", + AccessKeyID: string(accessKeyID), + SecretAccessKey: string(secretAccessKey), + } + if err := SaveConfig(config); err != nil { + return nil, err.Trace() + } + return config, nil +} + +func getAuth() (*AuthConfig, *probe.Error) { + config, err := LoadConfig() + if err != nil { + return nil, err.Trace() + } + return config, nil +} + +// firstTimeAuth first time authorization +func firstTimeAuth() *probe.Error { + conf, err := genAuthFirstTime() + if err != nil { + return err.Trace() + } + if conf != nil { + for _, user := range conf.Users { + Println(colorizeMessage("AccessKey: " + user.AccessKeyID)) + Println(colorizeMessage("SecretKey: " + user.SecretAccessKey)) + Println(colorizeMessage("$ minio controller keys")) + } + } + return nil +} + func getControllerConfig(c *cli.Context) minioConfig { certFile := c.GlobalString("cert") keyFile := c.GlobalString("key") @@ -128,10 +177,25 @@ func getControllerConfig(c *cli.Context) minioConfig { } func controllerMain(c *cli.Context) { - if c.Args().Present() { + if c.Args().Present() && c.Args().First() != "keys" { cli.ShowCommandHelpAndExit(c, "controller", 1) } - err := startController(getControllerConfig(c)) - errorIf(err.Trace(), "Failed to start minio controller.", nil) + if c.Args().First() == "keys" { + conf, err := getAuth() + fatalIf(err.Trace(), "Failed to fetch keys for minio controller.", nil) + if conf != nil { + for _, user := range conf.Users { + Println(colorizeMessage("AccessKey: " + user.AccessKeyID)) + Println(colorizeMessage("SecretKey: " + user.SecretAccessKey)) + } + } + return + } + + err := firstTimeAuth() + fatalIf(err.Trace(), "Failed to generate keys for minio.", nil) + + err = startController(getControllerConfig(c)) + fatalIf(err.Trace(), "Failed to start minio controller.", nil) } diff --git a/controller-rpc.go b/controller-rpc.go index d8c2ebd06..72931440d 100644 --- a/controller-rpc.go +++ b/controller-rpc.go @@ -26,7 +26,6 @@ import ( "strings" "github.com/gorilla/rpc/v2/json" - "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/probe" ) @@ -36,13 +35,13 @@ type controllerRPCService struct { // generateAuth generate new auth keys for a user func generateAuth(args *AuthArgs, reply *AuthRep) *probe.Error { - config, err := auth.LoadConfig() + config, err := LoadConfig() if err != nil { if os.IsNotExist(err.ToGoError()) { // Initialize new config, since config file doesn't exist yet - config = &auth.Config{} + config = &AuthConfig{} config.Version = "0.0.1" - config.Users = make(map[string]*auth.User) + config.Users = make(map[string]*AuthUser) } else { return err.Trace() } @@ -50,25 +49,25 @@ func generateAuth(args *AuthArgs, reply *AuthRep) *probe.Error { if _, ok := config.Users[args.User]; ok { return probe.NewError(errors.New("Credentials already set, if you wish to change this invoke Reset() method")) } - accessKeyID, err := auth.GenerateAccessKeyID() + accessKeyID, err := GenerateAccessKeyID() if err != nil { return err.Trace() } reply.AccessKeyID = string(accessKeyID) - secretAccessKey, err := auth.GenerateSecretAccessKey() + secretAccessKey, err := GenerateSecretAccessKey() if err != nil { return err.Trace() } reply.SecretAccessKey = string(secretAccessKey) reply.Name = args.User - config.Users[args.User] = &auth.User{ + config.Users[args.User] = &AuthUser{ Name: args.User, AccessKeyID: string(accessKeyID), SecretAccessKey: string(secretAccessKey), } - if err := auth.SaveConfig(config); err != nil { + if err := SaveConfig(config); err != nil { return err.Trace() } return nil @@ -76,7 +75,7 @@ func generateAuth(args *AuthArgs, reply *AuthRep) *probe.Error { // fetchAuth fetch auth keys for a user func fetchAuth(args *AuthArgs, reply *AuthRep) *probe.Error { - config, err := auth.LoadConfig() + config, err := LoadConfig() if err != nil { return err.Trace() } @@ -91,31 +90,31 @@ func fetchAuth(args *AuthArgs, reply *AuthRep) *probe.Error { // resetAuth reset auth keys for a user func resetAuth(args *AuthArgs, reply *AuthRep) *probe.Error { - config, err := auth.LoadConfig() + config, err := LoadConfig() if err != nil { return err.Trace() } if _, ok := config.Users[args.User]; !ok { return probe.NewError(errors.New("User not found")) } - accessKeyID, err := auth.GenerateAccessKeyID() + accessKeyID, err := GenerateAccessKeyID() if err != nil { return err.Trace() } reply.AccessKeyID = string(accessKeyID) - secretAccessKey, err := auth.GenerateSecretAccessKey() + secretAccessKey, err := GenerateSecretAccessKey() if err != nil { return err.Trace() } reply.SecretAccessKey = string(secretAccessKey) reply.Name = args.User - config.Users[args.User] = &auth.User{ + config.Users[args.User] = &AuthUser{ Name: args.User, AccessKeyID: string(accessKeyID), SecretAccessKey: string(secretAccessKey), } - return auth.SaveConfig(config).Trace() + return SaveConfig(config).Trace() } // Generate auth keys diff --git a/controller_rpc_test.go b/controller_rpc_test.go index 30a736d97..9ebde48b0 100644 --- a/controller_rpc_test.go +++ b/controller_rpc_test.go @@ -24,7 +24,6 @@ import ( "os" "github.com/gorilla/rpc/v2/json" - "github.com/minio/minio/pkg/auth" . "gopkg.in/check.v1" ) @@ -44,7 +43,7 @@ func (s *ControllerRPCSuite) SetUpSuite(c *C) { root, err := ioutil.TempDir(os.TempDir(), "api-") c.Assert(err, IsNil) s.root = root - auth.SetAuthConfigPath(root) + SetAuthConfigPath(root) testControllerRPC = httptest.NewServer(getControllerRPCHandler()) testServerRPC = httptest.NewUnstartedServer(getServerRPCHandler()) diff --git a/globals.go b/globals.go new file mode 100644 index 000000000..1063e7df7 --- /dev/null +++ b/globals.go @@ -0,0 +1,22 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +var ( + globalJSONFlag = false // Json flag set via command line + globalDebugFlag = false // Debug flag set via command line +) diff --git a/notifier.go b/notifier.go new file mode 100644 index 000000000..dd41a1cfe --- /dev/null +++ b/notifier.go @@ -0,0 +1,72 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "fmt" + "runtime" + "strings" + + "github.com/fatih/color" + "github.com/olekukonko/ts" +) + +// colorizeMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier +func colorizeMessage(message string) string { + // initialize coloring + cyan := color.New(color.FgCyan, color.Bold).SprintFunc() + yellow := color.New(color.FgYellow, color.Bold).SprintfFunc() + + // calculate length without color coding, due to ANSI color characters padded to actual + // string the final length is wrong than the original string length + lineStr := fmt.Sprintf(" \"%s\" . ", message) + lineLength := len(lineStr) + + // populate lines with color coding + lineInColor := fmt.Sprintf(" \"%s\" . ", cyan(message)) + maxContentWidth := lineLength + + terminal, err := ts.GetSize() + if err != nil { + globalJSONFlag = true + return "" + } + var msg string + switch { + case len(lineStr) > terminal.Col(): + msg = lineInColor + default: + // on windows terminal turn off unicode characters + var top, bottom, sideBar string + if runtime.GOOS == "windows" { + top = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") + bottom = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") + sideBar = yellow("|") + } else { + // color the rectangular box, use unicode characters here + top = yellow("┏" + strings.Repeat("━", maxContentWidth) + "┓") + bottom = yellow("┗" + strings.Repeat("━", maxContentWidth) + "┛") + sideBar = yellow("┃") + } + + // construct the final message + msg = top + "\n" + + sideBar + lineInColor + sideBar + "\n" + + bottom + } + return msg +} diff --git a/pkg/signature/errors.go b/pkg/signature/errors.go index 5660f4793..0801e5190 100644 --- a/pkg/signature/errors.go +++ b/pkg/signature/errors.go @@ -1,3 +1,19 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package signature // MissingDateHeader date header missing diff --git a/pkg/signature/postpolicyform.go b/pkg/signature/postpolicyform.go index a88925547..3f33af661 100644 --- a/pkg/signature/postpolicyform.go +++ b/pkg/signature/postpolicyform.go @@ -1,3 +1,19 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package signature import ( diff --git a/server-api-signature-handler.go b/server-api-signature-handler.go index b90943203..a4a3500f5 100644 --- a/server-api-signature-handler.go +++ b/server-api-signature-handler.go @@ -1,3 +1,19 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package main import ( diff --git a/server-api-signature.go b/server-api-signature.go index 743ca89e5..cd4a51f47 100644 --- a/server-api-signature.go +++ b/server-api-signature.go @@ -26,7 +26,6 @@ import ( "strings" "time" - "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/probe" signv4 "github.com/minio/minio/pkg/signature" ) @@ -93,7 +92,7 @@ func stripAccessKeyID(authHeaderValue string) (string, *probe.Error) { return "", err.Trace() } accessKeyID := credentialElements[0] - if !auth.IsValidAccessKey(accessKeyID) { + if !IsValidAccessKey(accessKeyID) { return "", probe.NewError(errAccessKeyIDInvalid) } return accessKeyID, nil @@ -107,7 +106,7 @@ func initSignatureV4(req *http.Request) (*signv4.Signature, *probe.Error) { if err != nil { return nil, err.Trace() } - authConfig, err := auth.LoadConfig() + authConfig, err := LoadConfig() if err != nil { return nil, err.Trace() } @@ -212,10 +211,10 @@ func initPostPresignedPolicyV4(formValues map[string]string) (*signv4.Signature, return nil, probe.NewError(errCredentialTagMalformed) } accessKeyID := credentialElements[0] - if !auth.IsValidAccessKey(accessKeyID) { + if !IsValidAccessKey(accessKeyID) { return nil, probe.NewError(errAccessKeyIDInvalid) } - authConfig, perr := auth.LoadConfig() + authConfig, perr := LoadConfig() if perr != nil { return nil, perr.Trace() } @@ -240,10 +239,10 @@ func initPresignedSignatureV4(req *http.Request) (*signv4.Signature, *probe.Erro return nil, probe.NewError(errCredentialTagMalformed) } accessKeyID := credentialElements[0] - if !auth.IsValidAccessKey(accessKeyID) { + if !IsValidAccessKey(accessKeyID) { return nil, probe.NewError(errAccessKeyIDInvalid) } - authConfig, err := auth.LoadConfig() + authConfig, err := LoadConfig() if err != nil { return nil, err.Trace() } diff --git a/pkg/auth/common.go b/server-auth-common.go similarity index 98% rename from pkg/auth/common.go rename to server-auth-common.go index 78864cc5f..abf07e0e1 100644 --- a/pkg/auth/common.go +++ b/server-auth-common.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package auth +package main import "regexp" diff --git a/pkg/auth/config.go b/server-auth-config.go similarity index 90% rename from pkg/auth/config.go rename to server-auth-config.go index 0d37aa46b..1af01a6d7 100644 --- a/pkg/auth/config.go +++ b/server-auth-config.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package auth +package main import ( "os" @@ -25,17 +25,17 @@ import ( "github.com/minio/minio/pkg/quick" ) -// User container -type User struct { +// AuthUser container +type AuthUser struct { Name string AccessKeyID string SecretAccessKey string } -// Config auth keys -type Config struct { +// AuthConfig auth keys +type AuthConfig struct { Version string - Users map[string]*User + Users map[string]*AuthUser } // getAuthConfigPath get users config path @@ -101,7 +101,7 @@ func SetAuthConfigPath(configPath string) { } // SaveConfig save auth config -func SaveConfig(a *Config) *probe.Error { +func SaveConfig(a *AuthConfig) *probe.Error { authConfigFile, err := getAuthConfigFile() if err != nil { return err.Trace() @@ -117,7 +117,7 @@ func SaveConfig(a *Config) *probe.Error { } // LoadConfig load auth config -func LoadConfig() (*Config, *probe.Error) { +func LoadConfig() (*AuthConfig, *probe.Error) { authConfigFile, err := getAuthConfigFile() if err != nil { return nil, err.Trace() @@ -125,9 +125,9 @@ func LoadConfig() (*Config, *probe.Error) { if _, err := os.Stat(authConfigFile); err != nil { return nil, probe.NewError(err) } - a := &Config{} + a := &AuthConfig{} a.Version = "0.0.1" - a.Users = make(map[string]*User) + a.Users = make(map[string]*AuthUser) qc, err := quick.New(a) if err != nil { return nil, err.Trace() @@ -135,5 +135,5 @@ func LoadConfig() (*Config, *probe.Error) { if err := qc.Load(authConfigFile); err != nil { return nil, err.Trace() } - return qc.Data().(*Config), nil + return qc.Data().(*AuthConfig), nil } diff --git a/pkg/auth/auth.go b/server-auth.go similarity index 90% rename from pkg/auth/auth.go rename to server-auth.go index ceb070747..5d41b7ae3 100644 --- a/pkg/auth/auth.go +++ b/server-auth.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package auth +package main import ( "crypto/rand" @@ -23,9 +23,6 @@ import ( "github.com/minio/minio/pkg/probe" ) -// Static alphaNumeric table used for generating unique keys -var alphaNumericTable = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") - // GenerateAccessKeyID - generate random alpha numeric value using only uppercase characters // takes input as size in integer func GenerateAccessKeyID() ([]byte, *probe.Error) { diff --git a/server-main.go b/server-main.go index 5ef4aecaf..8ef8d2dc9 100644 --- a/server-main.go +++ b/server-main.go @@ -18,7 +18,6 @@ package main import ( "crypto/tls" - "fmt" "net" "net/http" "os" @@ -91,9 +90,9 @@ func configureAPIServer(conf minioConfig, apiHandler http.Handler) (*http.Server for _, host := range hosts { if conf.TLS { - fmt.Printf("Starting minio server on: https://%s:%s, PID: %d\n", host, port, os.Getpid()) + Printf("Starting minio server on: https://%s:%s, PID: %d\n", host, port, os.Getpid()) } else { - fmt.Printf("Starting minio server on: http://%s:%s, PID: %d\n", host, port, os.Getpid()) + Printf("Starting minio server on: http://%s:%s, PID: %d\n", host, port, os.Getpid()) } } return apiServer, nil diff --git a/pkg/auth/auth_test.go b/server_auth_test.go similarity index 70% rename from pkg/auth/auth_test.go rename to server_auth_test.go index 3950f91cf..19b74652a 100644 --- a/pkg/auth/auth_test.go +++ b/server_auth_test.go @@ -14,30 +14,23 @@ * limitations under the License. */ -package auth_test +package main -import ( - "testing" - - "github.com/minio/minio/pkg/auth" - . "gopkg.in/check.v1" -) - -func Test(t *testing.T) { TestingT(t) } +import . "gopkg.in/check.v1" type MySuite struct{} var _ = Suite(&MySuite{}) func (s *MySuite) TestAuth(c *C) { - secretID, err := auth.GenerateSecretAccessKey() + secretID, err := GenerateSecretAccessKey() c.Assert(err, IsNil) - accessID, err := auth.GenerateAccessKeyID() + accessID, err := GenerateAccessKeyID() c.Assert(err, IsNil) - c.Assert(len(secretID), Equals, auth.MinioSecretID) - c.Assert(len(accessID), Equals, auth.MinioAccessID) + c.Assert(len(secretID), Equals, MinioSecretID) + c.Assert(len(accessID), Equals, MinioAccessID) c.Log(string(secretID)) c.Log(string(accessID)) diff --git a/server_signature_v4_test.go b/server_signature_v4_test.go index 5e91d60a0..fb550347b 100644 --- a/server_signature_v4_test.go +++ b/server_signature_v4_test.go @@ -36,7 +36,6 @@ import ( "net/http" "net/http/httptest" - "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/donut" . "gopkg.in/check.v1" ) @@ -67,14 +66,14 @@ func (s *MyAPISignatureV4Suite) SetUpSuite(c *C) { perr := donut.SaveConfig(conf) c.Assert(perr, IsNil) - accessKeyID, perr := auth.GenerateAccessKeyID() + accessKeyID, perr := GenerateAccessKeyID() c.Assert(perr, IsNil) - secretAccessKey, perr := auth.GenerateSecretAccessKey() + secretAccessKey, perr := GenerateSecretAccessKey() c.Assert(perr, IsNil) - authConf := &auth.Config{} - authConf.Users = make(map[string]*auth.User) - authConf.Users[string(accessKeyID)] = &auth.User{ + authConf := &AuthConfig{} + authConf.Users = make(map[string]*AuthUser) + authConf.Users[string(accessKeyID)] = &AuthUser{ Name: "testuser", AccessKeyID: string(accessKeyID), SecretAccessKey: string(secretAccessKey), @@ -82,8 +81,8 @@ func (s *MyAPISignatureV4Suite) SetUpSuite(c *C) { s.accessKeyID = string(accessKeyID) s.secretAccessKey = string(secretAccessKey) - auth.SetAuthConfigPath(root) - perr = auth.SaveConfig(authConf) + SetAuthConfigPath(root) + perr = SaveConfig(authConf) c.Assert(perr, IsNil) minioAPI := getNewAPI() diff --git a/vendor.json b/vendor.json index 25da922ee..22027724c 100755 --- a/vendor.json +++ b/vendor.json @@ -44,6 +44,13 @@ "revision": "31fb71caf5a4f04c9f8bb3fa8e7c2597ba6eb50a", "revisionTime": "2015-06-12T18:29:15Z" }, + { + "canonical": "github.com/fatih/color", + "comment": "", + "local": "vendor/github.com/fatih/color", + "revision": "76d423163af754ff6423d2d9be0057fbf03c57c2", + "revisionTime": "2015-08-24T00:44:34+03:00" + }, { "canonical": "github.com/fatih/structs", "comment": "", @@ -79,6 +86,13 @@ "revision": "74aa4b5cceca1188df2c7128f7ede4c92893701e", "revisionTime": "2015-08-09T21:43:58-07:00" }, + { + "canonical": "github.com/mattn/go-isatty", + "comment": "", + "local": "vendor/github.com/mattn/go-isatty", + "revision": "7fcbc72f853b92b5720db4a6b8482be612daef24", + "revisionTime": "2015-08-14T09:26:29+09:00" + }, { "canonical": "github.com/minio/cli", "comment": "", @@ -100,6 +114,13 @@ "revision": "eb527c8097e0f19a3ff7b253a3fe70545070f420", "revisionTime": "2015-08-29T22:34:20-07:00" }, + { + "canonical": "github.com/shiena/ansicolor", + "comment": "", + "local": "vendor/github.com/shiena/ansicolor", + "revision": "a5e2b567a4dd6cc74545b8a4f27c9d63b9e7735b", + "revisionTime": "2015-07-19T16:15:31+09:00" + }, { "canonical": "github.com/weekface/mgorus", "comment": "", diff --git a/vendor/github.com/fatih/color/LICENSE.md b/vendor/github.com/fatih/color/LICENSE.md new file mode 100644 index 000000000..25fdaf639 --- /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 000000000..d6fb06a3e --- /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 000000000..f715d62b8 --- /dev/null +++ b/vendor/github.com/fatih/color/color.go @@ -0,0 +1,378 @@ +package color + +import ( + "fmt" + "os" + "strconv" + "strings" + + "github.com/mattn/go-isatty" + "github.com/shiena/ansicolor" +) + +// NoColor defines if the output is colorized or not. It's dynamically set to +// false or true based on the stdout's file descriptor referring to a terminal +// or not. This is a global option and affects all colors. For more control +// over each color block use the methods DisableColor() individually. +var NoColor = !isatty.IsTerminal(os.Stdout.Fd()) + +// 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.Fprintf(color.Output, "This is a %s", put("warning")) +func (c *Color) SprintFunc() func(a ...interface{}) string { + return func(a ...interface{}) string { + return c.wrap(fmt.Sprint(a...)) + } +} + +// SprintfFunc returns a new function that returns colorized strings for the +// given arguments with fmt.Sprintf(). Useful to put into or mix into other +// string. Windows users should use this in 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 +} + +// Equals returns a boolean value indicating whether two colors are equal. +func (c *Color) Equals(c2 *Color) bool { + if len(c.params) != len(c2.params) { + return false + } + + for _, attr := range c.params { + if !c2.attrExists(attr) { + return false + } + } + + return true +} + +func (c *Color) attrExists(a Attribute) bool { + for _, attr := range c.params { + if attr == a { + return true + } + } + + return false +} + +func boolPtr(v bool) *bool { + return &v +} + +// 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 000000000..053b561d6 --- /dev/null +++ b/vendor/github.com/fatih/color/color_test.go @@ -0,0 +1,212 @@ +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 + + NoColor = false + + testColors := []struct { + text string + code Attribute + }{ + {text: "black", code: FgBlack}, + {text: "red", code: FgRed}, + {text: "green", code: FgGreen}, + {text: "yellow", code: FgYellow}, + {text: "blue", code: FgBlue}, + {text: "magent", code: FgMagenta}, + {text: "cyan", code: FgCyan}, + {text: "white", code: FgWhite}, + } + + 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 TestColorEquals(t *testing.T) { + fgblack1 := New(FgBlack) + fgblack2 := New(FgBlack) + bgblack := New(BgBlack) + fgbgblack := New(FgBlack, BgBlack) + fgblackbgred := New(FgBlack, BgRed) + fgred := New(FgRed) + bgred := New(BgRed) + + if !fgblack1.Equals(fgblack2) { + t.Error("Two black colors are not equal") + } + + if fgblack1.Equals(bgblack) { + t.Error("Fg and bg black colors are equal") + } + + if fgblack1.Equals(fgbgblack) { + t.Error("Fg black equals fg/bg black color") + } + + if fgblack1.Equals(fgred) { + t.Error("Fg black equals Fg red") + } + + if fgblack1.Equals(bgred) { + t.Error("Fg black equals Bg red") + } + + if fgblack1.Equals(fgblackbgred) { + t.Error("Fg black equals fg black bg red") + } +} + +func TestNoColor(t *testing.T) { + rb := new(bytes.Buffer) + Output = rb + + testColors := []struct { + text string + code Attribute + }{ + {text: "black", code: FgBlack}, + {text: "red", code: FgRed}, + {text: "green", code: FgGreen}, + {text: "yellow", code: FgYellow}, + {text: "blue", code: FgBlue}, + {text: "magent", code: FgMagenta}, + {text: "cyan", code: FgCyan}, + {text: "white", code: FgWhite}, + } + + 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 000000000..17908787c --- /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/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE new file mode 100644 index 000000000..65dc692b6 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) Yasuhiro MATSUMOTO + +MIT License (Expat) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md new file mode 100644 index 000000000..74845de4a --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/README.md @@ -0,0 +1,37 @@ +# go-isatty + +isatty for golang + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/mattn/go-isatty" + "os" +) + +func main() { + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Println("Is Terminal") + } else { + fmt.Println("Is Not Terminal") + } +} +``` + +## Installation + +``` +$ go get github.com/mattn/go-isatty +``` + +# License + +MIT + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go new file mode 100644 index 000000000..17d4f90eb --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/doc.go @@ -0,0 +1,2 @@ +// Package isatty implements interface to isatty +package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go new file mode 100644 index 000000000..e6282b529 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -0,0 +1,17 @@ +// +build darwin freebsd openbsd netbsd + +package isatty + +import ( + "syscall" + "unsafe" +) + +const ioctlReadTermios = syscall.TIOCGETA + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_linux.go b/vendor/github.com/mattn/go-isatty/isatty_linux.go new file mode 100644 index 000000000..8b361d7fb --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_linux.go @@ -0,0 +1,17 @@ +// +build linux + +package isatty + +import ( + "syscall" + "unsafe" +) + +const ioctlReadTermios = syscall.TCGETS + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go new file mode 100644 index 000000000..562ee39ca --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go @@ -0,0 +1,18 @@ +// +build windows + +package isatty + +import ( + "syscall" + "unsafe" +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") +var procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + +// IsTerminal return true if the file descriptor is terminal. +func IsTerminal(fd uintptr) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} diff --git a/vendor/github.com/shiena/ansicolor/LICENSE b/vendor/github.com/shiena/ansicolor/LICENSE new file mode 100644 index 000000000..e58473ed9 --- /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 000000000..7797a4f18 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/README.md @@ -0,0 +1,100 @@ +[![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 + +## 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 000000000..d3ece8fc0 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor.go @@ -0,0 +1,20 @@ +// 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" + +// 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 { + if _, ok := w.(*ansiColorWriter); !ok { + return &ansiColorWriter{w: w} + } + return w +} 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 000000000..57b4633a7 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor_ansi.go @@ -0,0 +1,17 @@ +// 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 +} + +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 000000000..4feeb1de6 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor_test.go @@ -0,0 +1,25 @@ +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 000000000..d918ffe91 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor_windows.go @@ -0,0 +1,351 @@ +// 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 ansiColorWriter struct { + w io.Writer + state csiState + 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 = 0 + winAttr |= textAttr.foregroundColor + winAttr |= textAttr.backgroundColor + winAttr |= textAttr.foregroundIntensity + winAttr |= textAttr.backgroundIntensity + winAttr |= textAttr.underscore + winAttr |= textAttr.otherAttributes + return winAttr +} + +func changeColor(param []byte) { + if defaultAttr == nil { + return + } + + screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout)) + if screenInfo == nil { + return + } + + 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) +} + +func parseEscapeSequence(command byte, param []byte) { + switch command { + case sgrCode: + changeColor(param) + } +} + +func isParameterChar(b byte) bool { + return ('0' <= b && b <= '9') || b == separatorChar +} + +func (cw *ansiColorWriter) Write(p []byte) (int, error) { + r, nw, nc, first, last := 0, 0, 0, 0, 0 + var err error + for i, ch := range p { + switch cw.state { + case outsideCsiCode: + if ch == firstCsiChar { + nc++ + cw.state = firstCsiCode + } + case firstCsiCode: + switch ch { + case firstCsiChar: + nc++ + break + case secondeCsiChar: + nc++ + cw.state = secondCsiCode + last = i - 1 + default: + cw.state = outsideCsiCode + } + case secondCsiCode: + nc++ + 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 + param := cw.paramBuf.Bytes() + cw.paramBuf.Reset() + parseEscapeSequence(ch, param) + cw.state = outsideCsiCode + } + default: + cw.state = outsideCsiCode + } + } + + if cw.state == outsideCsiCode { + nw, err = cw.w.Write(p[first:len(p)]) + } + + return r + nw + nc, 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 000000000..6c126d517 --- /dev/null +++ b/vendor/github.com/shiena/ansicolor/ansicolor_windows_test.go @@ -0,0 +1,236 @@ +// 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 %s, want %s", 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 %s, want %s", 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 %s, want %s", 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 %s, want %s", 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 %s, want %s", 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 %s, want %s", 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 %s, want %s", actualText, expectedText) + } + if err != nil { + t.Fatal("Could not get ConsoleScreenBufferInfo") + } + if actualAttributes != expectedAttributes { + t.Errorf("Text: %s, 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) + } +} 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 000000000..f2ac67c17 --- /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 000000000..6d2f7c074 --- /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)) +}