mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
Support dumb terminals by turning off color (#6246)
ANSI colors do not work on dumb terminals, in situations when minio is running as a service under systemd. This PR ensures we turn off color in those situations.
This commit is contained in:
parent
2dede2fdc2
commit
a82500f162
@ -18,10 +18,12 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
isatty "github.com/mattn/go-isatty"
|
||||||
"github.com/minio/minio-go/pkg/set"
|
"github.com/minio/minio-go/pkg/set"
|
||||||
|
|
||||||
etcd "github.com/coreos/etcd/clientv3"
|
etcd "github.com/coreos/etcd/clientv3"
|
||||||
@ -219,12 +221,72 @@ var (
|
|||||||
|
|
||||||
// global colors.
|
// global colors.
|
||||||
var (
|
var (
|
||||||
colorBold = color.New(color.Bold).SprintFunc()
|
// Check if we stderr, stdout are dumb terminals, we do not apply
|
||||||
colorRed = color.New(color.FgRed).SprintfFunc()
|
// ansi coloring on dumb terminals.
|
||||||
colorBlue = color.New(color.FgBlue).SprintfFunc()
|
isTerminal = func() bool {
|
||||||
colorYellow = color.New(color.FgYellow).SprintfFunc()
|
return isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stderr.Fd())
|
||||||
colorBgYellow = color.New(color.BgYellow).SprintfFunc()
|
}
|
||||||
colorBlack = color.New(color.FgBlack).SprintfFunc()
|
|
||||||
|
colorBold = func() func(a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.Bold).SprintFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprint
|
||||||
|
}()
|
||||||
|
colorRed = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgRed).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorBlue = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgBlue).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorYellow = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgYellow).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorCyanBold = func() func(a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
color.New(color.FgCyan, color.Bold).SprintFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprint
|
||||||
|
}()
|
||||||
|
colorYellowBold = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgYellow, color.Bold).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorBgYellow = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.BgYellow).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorBlack = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgBlack).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorGreenBold = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgGreen, color.Bold).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorRedBold = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgRed, color.Bold).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns minio global information, as a key value map.
|
// Returns minio global information, as a key value map.
|
||||||
|
@ -18,17 +18,45 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
isatty "github.com/mattn/go-isatty"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Global colors.
|
// Global colors.
|
||||||
var (
|
var (
|
||||||
colorBold = color.New(color.Bold).SprintFunc()
|
// Check if we stderr, stdout are dumb terminals, we do not apply
|
||||||
colorFgRed = color.New(color.FgRed).SprintfFunc()
|
// ansi coloring on dumb terminals.
|
||||||
colorBgRed = color.New(color.BgRed).SprintfFunc()
|
isTerminal = func() bool {
|
||||||
colorFgWhite = color.New(color.FgWhite).SprintfFunc()
|
return isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stderr.Fd())
|
||||||
|
}
|
||||||
|
|
||||||
|
colorBold = func() func(a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.Bold).SprintFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprint
|
||||||
|
}()
|
||||||
|
colorFgRed = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgRed).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorBgRed = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.BgRed).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
|
colorFgWhite = func() func(format string, a ...interface{}) string {
|
||||||
|
if isTerminal() {
|
||||||
|
return color.New(color.FgWhite).SprintfFunc()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf
|
||||||
|
}()
|
||||||
)
|
)
|
||||||
|
|
||||||
var ansiRE = regexp.MustCompile("(\x1b[^m]*m)")
|
var ansiRE = regexp.MustCompile("(\x1b[^m]*m)")
|
||||||
@ -40,15 +68,21 @@ func ansiEscape(format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ansiMoveRight(n int) {
|
func ansiMoveRight(n int) {
|
||||||
ansiEscape("[%dC", n)
|
if isTerminal() {
|
||||||
|
ansiEscape("[%dC", n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ansiSaveAttributes() {
|
func ansiSaveAttributes() {
|
||||||
ansiEscape("7")
|
if isTerminal() {
|
||||||
|
ansiEscape("7")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ansiRestoreAttributes() {
|
func ansiRestoreAttributes() {
|
||||||
ansiEscape("8")
|
if isTerminal() {
|
||||||
|
ansiEscape("8")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func uniqueEntries(paths []string) []string {
|
func uniqueEntries(paths []string) []string {
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/inconshreveable/go-update"
|
"github.com/inconshreveable/go-update"
|
||||||
"github.com/minio/cli"
|
"github.com/minio/cli"
|
||||||
"github.com/minio/minio/cmd/logger"
|
"github.com/minio/minio/cmd/logger"
|
||||||
@ -458,7 +457,7 @@ func getUpdateInfo(timeout time.Duration, mode string) (updateMsg string, sha256
|
|||||||
|
|
||||||
func doUpdate(sha256Hex string, latestReleaseTime time.Time, ok bool) (updateStatusMsg string, err error) {
|
func doUpdate(sha256Hex string, latestReleaseTime time.Time, ok bool) (updateStatusMsg string, err error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
updateStatusMsg = greenColorSprintf("Minio update to version RELEASE.%s canceled.",
|
updateStatusMsg = colorGreenBold("Minio update to version RELEASE.%s canceled.",
|
||||||
latestReleaseTime.Format(minioReleaseTagTimeLayout))
|
latestReleaseTime.Format(minioReleaseTagTimeLayout))
|
||||||
return updateStatusMsg, nil
|
return updateStatusMsg, nil
|
||||||
}
|
}
|
||||||
@ -484,21 +483,18 @@ func doUpdate(sha256Hex string, latestReleaseTime time.Time, ok bool) (updateSta
|
|||||||
return updateStatusMsg, err
|
return updateStatusMsg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return greenColorSprintf("Minio updated to version RELEASE.%s successfully.",
|
return colorGreenBold("Minio updated to version RELEASE.%s successfully.",
|
||||||
latestReleaseTime.Format(minioReleaseTagTimeLayout)), nil
|
latestReleaseTime.Format(minioReleaseTagTimeLayout)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldUpdate(quiet bool, sha256Hex string, latestReleaseTime time.Time) (ok bool) {
|
func shouldUpdate(quiet bool, sha256Hex string, latestReleaseTime time.Time) (ok bool) {
|
||||||
ok = true
|
ok = true
|
||||||
if !quiet {
|
if !quiet {
|
||||||
ok = prompt.Confirm(greenColorSprintf("Update to RELEASE.%s [%s]", latestReleaseTime.Format(minioReleaseTagTimeLayout), "yes"))
|
ok = prompt.Confirm(colorGreenBold("Update to RELEASE.%s [%s]", latestReleaseTime.Format(minioReleaseTagTimeLayout), "yes"))
|
||||||
}
|
}
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
var greenColorSprintf = color.New(color.FgGreen, color.Bold).SprintfFunc()
|
|
||||||
var redColorSprintf = color.New(color.FgRed, color.Bold).SprintfFunc()
|
|
||||||
|
|
||||||
func mainUpdate(ctx *cli.Context) {
|
func mainUpdate(ctx *cli.Context) {
|
||||||
if len(ctx.Args()) != 0 {
|
if len(ctx.Args()) != 0 {
|
||||||
cli.ShowCommandHelpAndExit(ctx, "update", -1)
|
cli.ShowCommandHelpAndExit(ctx, "update", -1)
|
||||||
@ -520,7 +516,7 @@ func mainUpdate(ctx *cli.Context) {
|
|||||||
|
|
||||||
// Nothing to update running the latest release.
|
// Nothing to update running the latest release.
|
||||||
if updateMsg == "" {
|
if updateMsg == "" {
|
||||||
logger.Info(greenColorSprintf("You are already running the most recent version of ‘minio’."))
|
logger.Info(colorGreenBold("You are already running the most recent version of ‘minio’."))
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,7 +527,7 @@ func mainUpdate(ctx *cli.Context) {
|
|||||||
var updateStatusMsg string
|
var updateStatusMsg string
|
||||||
updateStatusMsg, err = doUpdate(sha256Hex, latestReleaseTime, shouldUpdate(quiet, sha256Hex, latestReleaseTime))
|
updateStatusMsg, err = doUpdate(sha256Hex, latestReleaseTime, shouldUpdate(quiet, sha256Hex, latestReleaseTime))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Info(redColorSprintf("Unable to update ‘minio’."))
|
logger.Info(colorRedBold("Unable to update ‘minio’."))
|
||||||
logger.Info(err.Error())
|
logger.Info(err.Error())
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import (
|
|||||||
|
|
||||||
"github.com/cheggaaa/pb"
|
"github.com/cheggaaa/pb"
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
"github.com/fatih/color"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// prepareUpdateMessage - prepares the update message, only if a
|
// prepareUpdateMessage - prepares the update message, only if a
|
||||||
@ -46,10 +45,6 @@ func prepareUpdateMessage(downloadURL string, older time.Duration) string {
|
|||||||
|
|
||||||
// colorizeUpdateMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier
|
// colorizeUpdateMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier
|
||||||
func colorizeUpdateMessage(updateString string, newerThan string) string {
|
func colorizeUpdateMessage(updateString string, newerThan string) string {
|
||||||
// Initialize coloring.
|
|
||||||
cyan := color.New(color.FgCyan, color.Bold).SprintFunc()
|
|
||||||
yellow := color.New(color.FgYellow, color.Bold).SprintfFunc()
|
|
||||||
|
|
||||||
msgLine1Fmt := " You are running an older version of Minio released %s "
|
msgLine1Fmt := " You are running an older version of Minio released %s "
|
||||||
msgLine2Fmt := " Update: %s "
|
msgLine2Fmt := " Update: %s "
|
||||||
|
|
||||||
@ -59,8 +54,8 @@ func colorizeUpdateMessage(updateString string, newerThan string) string {
|
|||||||
line2Length := len(fmt.Sprintf(msgLine2Fmt, updateString))
|
line2Length := len(fmt.Sprintf(msgLine2Fmt, updateString))
|
||||||
|
|
||||||
// Populate lines with color coding.
|
// Populate lines with color coding.
|
||||||
line1InColor := fmt.Sprintf(msgLine1Fmt, yellow(newerThan))
|
line1InColor := fmt.Sprintf(msgLine1Fmt, colorYellowBold(newerThan))
|
||||||
line2InColor := fmt.Sprintf(msgLine2Fmt, cyan(updateString))
|
line2InColor := fmt.Sprintf(msgLine2Fmt, colorCyanBold(updateString))
|
||||||
|
|
||||||
// calculate the rectangular box size.
|
// calculate the rectangular box size.
|
||||||
maxContentWidth := int(math.Max(float64(line1Length), float64(line2Length)))
|
maxContentWidth := int(math.Max(float64(line1Length), float64(line2Length)))
|
||||||
@ -94,10 +89,10 @@ func colorizeUpdateMessage(updateString string, newerThan string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lines := []string{
|
lines := []string{
|
||||||
yellow(topLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + topRightChar),
|
colorYellowBold(topLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + topRightChar),
|
||||||
vertBarChar + line1InColor + strings.Repeat(" ", maxContentWidth-line1Length) + vertBarChar,
|
vertBarChar + line1InColor + strings.Repeat(" ", maxContentWidth-line1Length) + vertBarChar,
|
||||||
vertBarChar + line2InColor + strings.Repeat(" ", maxContentWidth-line2Length) + vertBarChar,
|
vertBarChar + line2InColor + strings.Repeat(" ", maxContentWidth-line2Length) + vertBarChar,
|
||||||
yellow(bottomLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + bottomRightChar),
|
colorYellowBold(bottomLeftChar + strings.Repeat(horizBarChar, maxContentWidth) + bottomRightChar),
|
||||||
}
|
}
|
||||||
return "\n" + strings.Join(lines, "\n") + "\n"
|
return "\n" + strings.Join(lines, "\n") + "\n"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user