/* * Minio Client (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 console import ( "fmt" "os" "sync" "path/filepath" "github.com/minio/mc/internal/github.com/fatih/color" "github.com/minio/mc/internal/github.com/mattn/go-isatty" "github.com/minio/mc/internal/github.com/minio/minio/pkg/probe" "github.com/minio/mc/internal/github.com/shiena/ansicolor" ) // NoDebugPrint defines if the input should be printed in debug or not. By default it's set to true. var NoDebugPrint = true // IsTesting this flag indicates if IsExited should be set or not, false by default var IsTesting = false // IsExited sets this boolean value if Fatal is called when IsTestng is enabled var IsExited = false // IsError sets this boolean value if Error is called when IsTesting is enabled var IsError = false // Theme default map var Theme = map[string]*color.Color{ "Debug": color.New(color.FgWhite, color.Faint, color.Italic), "Fatal": color.New(color.FgRed, color.Italic, color.Bold), "Error": color.New(color.FgYellow, color.Italic), "Info": color.New(color.FgGreen, color.Bold), "File": color.New(color.FgWhite), "Dir": color.New(color.FgCyan, color.Bold), "Command": color.New(color.FgWhite, color.Bold), "SessionID": color.New(color.FgYellow, color.Bold), "Size": color.New(color.FgYellow), "Time": color.New(color.FgGreen), "Bar": color.New(color.FgGreen, color.Bold), "Print": color.New(), "PrintC": color.New(color.FgGreen, color.Bold), } var ( mutex = &sync.RWMutex{} stderrColoredOutput = ansicolor.NewAnsiColorWriter(os.Stderr) // Print prints a message Print = func(data ...interface{}) { consolePrint("Print", Theme["Print"], data...) return } // PrintC prints a message with color PrintC = func(data ...interface{}) { consolePrint("PrintC", Theme["PrintC"], data...) return } // Printf prints a formatted message Printf = func(format string, data ...interface{}) { consolePrintf("Print", Theme["Print"], format, data...) return } // Println prints a message with a newline Println = func(data ...interface{}) { consolePrintln("Print", Theme["Print"], data...) return } // Fatal print a error message and exit Fatal = func(data ...interface{}) { consolePrint("Fatal", Theme["Fatal"], data...) if !IsTesting { os.Exit(1) } defer func() { IsExited = true }() return } // Fatalf print a error message with a format specified and exit Fatalf = func(format string, data ...interface{}) { consolePrintf("Fatal", Theme["Fatal"], format, data...) if !IsTesting { os.Exit(1) } defer func() { IsExited = true }() return } // Fatalln print a error message with a new line and exit Fatalln = func(data ...interface{}) { consolePrintln("Fatal", Theme["Fatal"], data...) if !IsTesting { os.Exit(1) } defer func() { IsExited = true }() return } // Error prints a error message Error = func(data ...interface{}) { if IsTesting { defer func() { IsError = true }() } consolePrint("Error", Theme["Error"], data...) return } // Errorf print a error message with a format specified Errorf = func(format string, data ...interface{}) { if IsTesting { defer func() { IsError = true }() } consolePrintf("Error", Theme["Error"], format, data...) return } // Errorln prints a error message with a new line Errorln = func(data ...interface{}) { if IsTesting { defer func() { IsError = true }() } consolePrintln("Error", Theme["Error"], data...) return } // Info prints a informational message Info = func(data ...interface{}) { consolePrint("Info", Theme["Info"], data...) return } // Infof prints a informational message in custom format Infof = func(format string, data ...interface{}) { consolePrintf("Info", Theme["Info"], format, data...) return } // Infoln prints a informational message with a new line Infoln = func(data ...interface{}) { consolePrintln("Info", Theme["Info"], data...) return } // Debug prints a debug message without a new line // Debug prints a debug message Debug = func(data ...interface{}) { if !NoDebugPrint { consolePrint("Debug", Theme["Debug"], data...) } } // Debugf prints a debug message with a new line Debugf = func(format string, data ...interface{}) { if !NoDebugPrint { consolePrintf("Debug", Theme["Debug"], format, data...) } } // Debugln prints a debug message with a new line Debugln = func(data ...interface{}) { if !NoDebugPrint { consolePrintln("Debug", Theme["Debug"], data...) } } Colorize = func(tag string, data interface{}) string { if isatty.IsTerminal(os.Stdout.Fd()) { return Theme[tag].SprintFunc()(data) } return fmt.Sprint(data) } ) var ( // wrap around standard fmt functions // consolePrint prints a message prefixed with message type and program name consolePrint = func(tag string, c *color.Color, a ...interface{}) { mutex.Lock() defer mutex.Unlock() switch tag { case "Debug": output := color.Output color.Output = stderrColoredOutput if isatty.IsTerminal(os.Stderr.Fd()) { c.Print(ProgramName() + ": ") c.Print(a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprint(color.Output, a...) } color.Output = output case "Fatal": fallthrough case "Error": output := color.Output color.Output = stderrColoredOutput if isatty.IsTerminal(os.Stderr.Fd()) { c.Print(ProgramName() + ": ") c.Print(a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprint(color.Output, a...) } color.Output = output case "Info": if isatty.IsTerminal(os.Stdout.Fd()) { c.Print(ProgramName() + ": ") c.Print(a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprint(color.Output, a...) } default: if isatty.IsTerminal(os.Stdout.Fd()) { c.Print(a...) } else { fmt.Fprint(color.Output, a...) } } } // consolePrintf - same as print with a new line consolePrintf = func(tag string, c *color.Color, format string, a ...interface{}) { mutex.Lock() defer mutex.Unlock() switch tag { case "Debug": output := color.Output color.Output = stderrColoredOutput if isatty.IsTerminal(os.Stderr.Fd()) { c.Print(ProgramName() + ": ") c.Printf(format, a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprintf(color.Output, format, a...) } color.Output = output case "Fatal": fallthrough case "Error": output := color.Output color.Output = stderrColoredOutput if isatty.IsTerminal(os.Stderr.Fd()) { c.Print(ProgramName() + ": ") c.Printf(format, a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprintf(color.Output, format, a...) } color.Output = output case "Info": if isatty.IsTerminal(os.Stdout.Fd()) { c.Print(ProgramName() + ": ") c.Printf(format, a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprintf(color.Output, format, a...) } default: if isatty.IsTerminal(os.Stdout.Fd()) { c.Printf(format, a...) } else { fmt.Fprintf(color.Output, format, a...) } } } // consolePrintln - same as print with a new line consolePrintln = func(tag string, c *color.Color, a ...interface{}) { mutex.Lock() defer mutex.Unlock() switch tag { case "Debug": output := color.Output color.Output = stderrColoredOutput if isatty.IsTerminal(os.Stderr.Fd()) { c.Print(ProgramName() + ": ") c.Println(a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprintln(color.Output, a...) } color.Output = output case "Fatal": fallthrough case "Error": output := color.Output color.Output = stderrColoredOutput if isatty.IsTerminal(os.Stderr.Fd()) { c.Print(ProgramName() + ": ") c.Println(a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprintln(color.Output, a...) } color.Output = output case "Info": if isatty.IsTerminal(os.Stdout.Fd()) { c.Print(ProgramName() + ": ") c.Println(a...) } else { fmt.Fprint(color.Output, ProgramName()+": ") fmt.Fprintln(color.Output, a...) } default: if isatty.IsTerminal(os.Stdout.Fd()) { c.Println(a...) } else { fmt.Fprintln(color.Output, a...) } } } ) // Lock console func Lock() { mutex.Lock() } // Unlock locked console func Unlock() { mutex.Unlock() } // SetCustomTheme sets a color theme func SetCustomTheme(theme map[string]*color.Color) *probe.Error { mutex.Lock() defer mutex.Unlock() // add new theme for k, v := range theme { Theme[k] = v } return nil } // ProgramName - return the name of the executable program func ProgramName() string { _, progName := filepath.Split(os.Args[0]) return progName }