mirror of
https://github.com/minio/mc.git
synced 2025-11-12 01:02:26 +03:00
- over the course of a project history every maintainer needs to update
its dependency packages, the problem essentially with godep is manipulating
GOPATH - this manipulation leads to static objects created at different locations
which end up conflicting with the overall functionality of golang.
This also leads to broken builds on many platforms. There is no easier way out of
this other than asking users to do 'godep restore' all the time which perhaps as
a practice doesn't sound clean, also has its own set of problems.
- govendor on the other hand is a right tool but a stop gap tool until we wait for
golangs official 1.5 version which fixes this vendoring issue once and for all.
- govendor makes sure that the import paths are re-written instead of manipulating
GOPATH.
This has advantages
- no more compiled objects being referenced in GOPATH and build time GOPATH
manging which leads to conflicts.
- proper import paths referencing the exact package a project is dependent on.
govendor is simple and provides the minimal necessary tooling to achieve this.
For now this is the right solution.
475 lines
12 KiB
Go
475 lines
12 KiB
Go
/*
|
|
* 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 instead of os.Exit(1)
|
|
var IsExited = false
|
|
|
|
// Theme holds console color scheme
|
|
type Theme struct {
|
|
Fatal *color.Color
|
|
Error *color.Color
|
|
Info *color.Color
|
|
Debug *color.Color
|
|
Size *color.Color
|
|
Time *color.Color
|
|
File *color.Color
|
|
Dir *color.Color
|
|
Command *color.Color
|
|
SessionID *color.Color
|
|
JSON *color.Color
|
|
Bar *color.Color
|
|
PrintC *color.Color
|
|
Print *color.Color
|
|
}
|
|
|
|
var (
|
|
mutex = &sync.RWMutex{}
|
|
|
|
stderrColoredOutput = ansicolor.NewAnsiColorWriter(os.Stderr)
|
|
|
|
// themesDB contains supported list of Themes
|
|
themesDB = map[string]Theme{
|
|
"minimal": MiniTheme,
|
|
"nocolor": NoColorTheme,
|
|
"white": WhiteTheme,
|
|
}
|
|
|
|
// currTheme is current theme
|
|
currThemeName = GetDefaultThemeName()
|
|
|
|
// Bar print progress bar
|
|
Bar = func(data ...interface{}) {
|
|
print(themesDB[currThemeName].Bar, data...)
|
|
}
|
|
|
|
// Print prints a message
|
|
Print = func(data ...interface{}) {
|
|
print(themesDB[currThemeName].Print, data...)
|
|
return
|
|
}
|
|
|
|
// PrintC prints a message with color
|
|
PrintC = func(data ...interface{}) {
|
|
print(themesDB[currThemeName].PrintC, data...)
|
|
return
|
|
}
|
|
|
|
// Printf prints a formatted message
|
|
Printf = func(f string, data ...interface{}) {
|
|
printf(themesDB[currThemeName].Print, f, data...)
|
|
return
|
|
}
|
|
|
|
// Println prints a message with a newline
|
|
Println = func(data ...interface{}) {
|
|
println(themesDB[currThemeName].Print, data...)
|
|
}
|
|
|
|
// Fatal print a error message and exit
|
|
Fatal = func(data ...interface{}) {
|
|
print(themesDB[currThemeName].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(f string, data ...interface{}) {
|
|
printf(themesDB[currThemeName].Fatal, f, 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{}) {
|
|
println(themesDB[currThemeName].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() {
|
|
IsExited = true
|
|
}()
|
|
}
|
|
print(themesDB[currThemeName].Error, data...)
|
|
return
|
|
}
|
|
|
|
// Errorf print a error message with a format specified
|
|
Errorf = func(f string, data ...interface{}) {
|
|
if IsTesting {
|
|
defer func() {
|
|
IsExited = true
|
|
}()
|
|
}
|
|
printf(themesDB[currThemeName].Error, f, data...)
|
|
return
|
|
}
|
|
|
|
// Errorln prints a error message with a new line
|
|
Errorln = func(data ...interface{}) {
|
|
if IsTesting {
|
|
defer func() {
|
|
IsExited = true
|
|
}()
|
|
}
|
|
println(themesDB[currThemeName].Error, data...)
|
|
return
|
|
}
|
|
|
|
// Info prints a informational message
|
|
Info = func(data ...interface{}) {
|
|
print(themesDB[currThemeName].Info, data...)
|
|
return
|
|
}
|
|
|
|
// Infof prints a informational message in custom format
|
|
Infof = func(f string, data ...interface{}) {
|
|
printf(themesDB[currThemeName].Info, f, data...)
|
|
return
|
|
}
|
|
|
|
// Infoln prints a informational message with a new line
|
|
Infoln = func(data ...interface{}) {
|
|
println(themesDB[currThemeName].Info, data...)
|
|
return
|
|
}
|
|
|
|
// Debug prints a debug message without a new line
|
|
// Debug prints a debug message
|
|
Debug = func(data ...interface{}) {
|
|
if !NoDebugPrint {
|
|
print(themesDB[currThemeName].Debug, data...)
|
|
}
|
|
}
|
|
|
|
// Debugf prints a debug message with a new line
|
|
Debugf = func(f string, data ...interface{}) {
|
|
if !NoDebugPrint {
|
|
printf(themesDB[currThemeName].Debug, f, data...)
|
|
}
|
|
}
|
|
|
|
// Debugln prints a debug message with a new line
|
|
Debugln = func(data ...interface{}) {
|
|
if !NoDebugPrint {
|
|
println(themesDB[currThemeName].Debug, data...)
|
|
}
|
|
}
|
|
|
|
// Time helper to print Time theme
|
|
Time = func(format string, data ...interface{}) string {
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
return themesDB[currThemeName].Time.SprintfFunc()(format, data...)
|
|
}
|
|
return fmt.Sprintf(format, data...)
|
|
}
|
|
|
|
// Size helper to print Size theme
|
|
Size = func(format string, data ...interface{}) string {
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
return themesDB[currThemeName].Size.SprintfFunc()(format, data...)
|
|
}
|
|
return fmt.Sprintf(format, data...)
|
|
}
|
|
|
|
// File helper to print File theme
|
|
File = func(format string, data ...interface{}) string {
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
return themesDB[currThemeName].File.SprintfFunc()(format, data...)
|
|
}
|
|
return fmt.Sprintf(format, data...)
|
|
}
|
|
|
|
// Dir helper to print Dir theme
|
|
Dir = func(format string, data ...interface{}) string {
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
return themesDB[currThemeName].Dir.SprintfFunc()(format, data...)
|
|
}
|
|
return fmt.Sprintf(format, data...)
|
|
}
|
|
|
|
// Command helper to print command theme
|
|
Command = func(format string, data ...interface{}) string {
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
return themesDB[currThemeName].Command.SprintfFunc()(format, data...)
|
|
}
|
|
return fmt.Sprintf(format, data...)
|
|
}
|
|
|
|
// SessionID helper to print sessionid theme
|
|
SessionID = func(format string, data ...interface{}) string {
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
return themesDB[currThemeName].SessionID.SprintfFunc()(format, data...)
|
|
}
|
|
return fmt.Sprintf(format, data...)
|
|
}
|
|
|
|
// JSON helper to print json strings
|
|
JSON = func(format string, data ...interface{}) string {
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
return themesDB[currThemeName].JSON.SprintfFunc()(format, data...)
|
|
}
|
|
return fmt.Sprintf(format, data...)
|
|
}
|
|
)
|
|
|
|
var (
|
|
// wrap around standard fmt functions
|
|
// print prints a message prefixed with message type and program name
|
|
print = func(c *color.Color, a ...interface{}) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
|
|
switch c {
|
|
case themesDB[currThemeName].Debug:
|
|
output := color.Output
|
|
color.Output = stderrColoredOutput
|
|
if isatty.IsTerminal(os.Stderr.Fd()) {
|
|
c.Print(ProgramName() + ": <DEBUG> ")
|
|
c.Print(a...)
|
|
} else {
|
|
fmt.Fprint(color.Output, ProgramName()+": <DEBUG> ")
|
|
fmt.Fprint(color.Output, a...)
|
|
}
|
|
color.Output = output
|
|
case themesDB[currThemeName].Fatal:
|
|
fallthrough
|
|
case themesDB[currThemeName].Error:
|
|
output := color.Output
|
|
color.Output = stderrColoredOutput
|
|
if isatty.IsTerminal(os.Stderr.Fd()) {
|
|
c.Print(ProgramName() + ": <ERROR> ")
|
|
c.Print(a...)
|
|
} else {
|
|
fmt.Fprint(color.Output, ProgramName()+": <ERROR> ")
|
|
fmt.Fprint(color.Output, a...)
|
|
}
|
|
color.Output = output
|
|
case themesDB[currThemeName].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...)
|
|
}
|
|
}
|
|
}
|
|
|
|
// printf - same as print with a new line
|
|
printf = func(c *color.Color, f string, a ...interface{}) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
|
|
switch c {
|
|
case themesDB[currThemeName].Debug:
|
|
output := color.Output
|
|
color.Output = stderrColoredOutput
|
|
if isatty.IsTerminal(os.Stderr.Fd()) {
|
|
c.Print(ProgramName() + ": <DEBUG> ")
|
|
c.Printf(f, a...)
|
|
} else {
|
|
fmt.Fprint(color.Output, ProgramName()+": <DEBUG> ")
|
|
fmt.Fprintf(color.Output, f, a...)
|
|
}
|
|
color.Output = output
|
|
case themesDB[currThemeName].Fatal:
|
|
fallthrough
|
|
case themesDB[currThemeName].Error:
|
|
output := color.Output
|
|
color.Output = stderrColoredOutput
|
|
if isatty.IsTerminal(os.Stderr.Fd()) {
|
|
c.Print(ProgramName() + ": <ERROR> ")
|
|
c.Printf(f, a...)
|
|
} else {
|
|
fmt.Fprint(color.Output, ProgramName()+": <ERROR> ")
|
|
fmt.Fprintf(color.Output, f, a...)
|
|
}
|
|
color.Output = output
|
|
case themesDB[currThemeName].Info:
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
c.Print(ProgramName() + ": ")
|
|
c.Printf(f, a...)
|
|
} else {
|
|
fmt.Fprint(color.Output, ProgramName()+": ")
|
|
fmt.Fprintf(color.Output, f, a...)
|
|
}
|
|
default:
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
c.Printf(f, a...)
|
|
} else {
|
|
fmt.Fprintf(color.Output, f, a...)
|
|
}
|
|
}
|
|
}
|
|
|
|
// println - same as print with a new line
|
|
println = func(c *color.Color, a ...interface{}) {
|
|
mutex.Lock()
|
|
defer mutex.Unlock()
|
|
|
|
switch c {
|
|
case themesDB[currThemeName].Debug:
|
|
output := color.Output
|
|
color.Output = stderrColoredOutput
|
|
if isatty.IsTerminal(os.Stderr.Fd()) {
|
|
c.Print(ProgramName() + ": <DEBUG> ")
|
|
c.Println(a...)
|
|
} else {
|
|
fmt.Fprint(color.Output, ProgramName()+": <DEBUG> ")
|
|
fmt.Fprintln(color.Output, a...)
|
|
}
|
|
color.Output = output
|
|
case themesDB[currThemeName].Fatal:
|
|
fallthrough
|
|
case themesDB[currThemeName].Error:
|
|
output := color.Output
|
|
color.Output = stderrColoredOutput
|
|
if isatty.IsTerminal(os.Stderr.Fd()) {
|
|
c.Print(ProgramName() + ": <ERROR> ")
|
|
c.Println(a...)
|
|
} else {
|
|
fmt.Fprint(color.Output, ProgramName()+": <ERROR> ")
|
|
fmt.Fprintln(color.Output, a...)
|
|
}
|
|
color.Output = output
|
|
case themesDB[currThemeName].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()
|
|
}
|
|
|
|
// SetTheme sets a color theme
|
|
func SetTheme(themeName string) *probe.Error {
|
|
if !IsValidTheme(themeName) {
|
|
return probe.NewError(fmt.Errorf("Unsupported theme name [%s]", themeName))
|
|
}
|
|
|
|
mutex.Lock()
|
|
|
|
// Just another additional precaution to completely disable color.
|
|
// Color theme is also necessary, because it does other useful things like exit-on-fatal..
|
|
switch currThemeName {
|
|
case "nocolor":
|
|
color.NoColor = true
|
|
default:
|
|
color.NoColor = false
|
|
}
|
|
|
|
currThemeName = themeName
|
|
|
|
mutex.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetThemeName returns currently set theme name
|
|
func GetThemeName() string {
|
|
return currThemeName
|
|
}
|
|
|
|
// GetDefaultThemeName returns the default theme
|
|
func GetDefaultThemeName() string {
|
|
return "minimal"
|
|
}
|
|
|
|
// GetThemeNames returns currently supported list of themes
|
|
func GetThemeNames() (themeNames []string) {
|
|
for themeName := range themesDB {
|
|
themeNames = append(themeNames, themeName)
|
|
}
|
|
return themeNames
|
|
}
|
|
|
|
// IsValidTheme returns true if "themeName" is currently supported
|
|
func IsValidTheme(themeName string) bool {
|
|
_, ok := themesDB[themeName]
|
|
return ok
|
|
}
|
|
|
|
// ProgramName - return the name of the executable program
|
|
func ProgramName() string {
|
|
_, progName := filepath.Split(os.Args[0])
|
|
return progName
|
|
}
|