mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-06-19 20:23:23 +00:00
Create printer pkg, fix color force enable/disable
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
parent
0ab135af99
commit
57f2bb1eb4
@ -6,6 +6,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/kubeconfig"
|
||||
"github.com/ahmetb/kubectx/internal/printer"
|
||||
)
|
||||
|
||||
// DeleteOp indicates intention to delete contexts.
|
||||
@ -23,10 +24,10 @@ func (op DeleteOp) Run(_, stderr io.Writer) error {
|
||||
}
|
||||
if wasActiveContext {
|
||||
// TODO we don't always run as kubectx (sometimes "kubectl ctx")
|
||||
printWarning(stderr, "You deleted the current context. use \"kubectx\" to select a different one.")
|
||||
printer.Warning(stderr, "You deleted the current context. use \"kubectx\" to select a different one.")
|
||||
}
|
||||
|
||||
printSuccess(stderr, "deleted context %q", deletedName)
|
||||
printer.Success(stderr, "deleted context %q", deletedName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,29 +1,2 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
const (
|
||||
// EnvFZFIgnore describes the environment variable to set to disable
|
||||
// interactive context selection when fzf is installed.
|
||||
EnvFZFIgnore = "KUBECTX_IGNORE_FZF"
|
||||
|
||||
// EnvForceColor describes the environment variable to disable color usage
|
||||
// when printing current context in a list.
|
||||
EnvNoColor = `NO_COLOR`
|
||||
|
||||
// EnvForceColor describes the "internal" environment variable to force
|
||||
// color usage to show current context in a list.
|
||||
EnvForceColor = `_KUBECTX_FORCE_COLOR`
|
||||
|
||||
// EnvDebug describes the internal environment variable for more verbose logging.
|
||||
EnvDebug = `DEBUG`
|
||||
)
|
||||
|
||||
func useColors() bool {
|
||||
if os.Getenv(EnvForceColor) != "" {
|
||||
return true
|
||||
} else if os.Getenv(EnvNoColor) != "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -7,10 +7,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Op interface {
|
||||
Run(stdout, stderr io.Writer) error
|
||||
}
|
||||
|
||||
// UnsupportedOp indicates an unsupported flag.
|
||||
type UnsupportedOp struct{ Err error }
|
||||
|
||||
|
@ -11,6 +11,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/env"
|
||||
"github.com/ahmetb/kubectx/internal/printer"
|
||||
)
|
||||
|
||||
type InteractiveSwitchOp struct {
|
||||
@ -26,7 +29,7 @@ func (op InteractiveSwitchOp) Run(_, stderr io.Writer) error {
|
||||
|
||||
cmd.Env = append(os.Environ(),
|
||||
fmt.Sprintf("FZF_DEFAULT_COMMAND=%s", op.SelfCmd),
|
||||
fmt.Sprintf("%s=1", EnvForceColor))
|
||||
fmt.Sprintf("%s=1", env.EnvForceColor))
|
||||
if err := cmd.Run(); err != nil {
|
||||
if _, ok := err.(*exec.ExitError); !ok {
|
||||
return err
|
||||
@ -40,7 +43,7 @@ func (op InteractiveSwitchOp) Run(_, stderr io.Writer) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to switch context")
|
||||
}
|
||||
printSuccess(stderr, "Switched to context %q.", name)
|
||||
printer.Success(stderr, "Switched to context %q.", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -60,6 +63,6 @@ func fzfInstalled() bool {
|
||||
|
||||
// isInteractiveMode determines if we can do choosing with fzf.
|
||||
func isInteractiveMode(stdout *os.File) bool {
|
||||
v := os.Getenv(EnvFZFIgnore)
|
||||
v := os.Getenv(env.EnvFZFIgnore)
|
||||
return v == "" && isTerminal(stdout) && fzfInstalled()
|
||||
}
|
||||
|
@ -8,6 +8,22 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func withTestVar(key, value string) func() {
|
||||
// TODO(ahmetb) this method is currently duplicated
|
||||
// consider extracting to internal/testutil or something
|
||||
|
||||
orig, ok := os.LookupEnv(key)
|
||||
os.Setenv(key, value)
|
||||
return func() {
|
||||
if ok {
|
||||
os.Setenv(key, orig)
|
||||
} else {
|
||||
os.Unsetenv(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_homeDir(t *testing.T) {
|
||||
type env struct{ k, v string }
|
||||
cases := []struct {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/kubeconfig"
|
||||
"github.com/ahmetb/kubectx/internal/printer"
|
||||
)
|
||||
|
||||
// ListOp describes listing contexts.
|
||||
@ -28,9 +29,9 @@ func (_ ListOp) Run(stdout, _ io.Writer) error {
|
||||
// TODO support KUBECTX_CURRENT_BGCOLOR
|
||||
|
||||
currentColor := color.New(color.FgGreen, color.Bold)
|
||||
if useColors() {
|
||||
if v := printer.UseColors(); v != nil && *v {
|
||||
currentColor.EnableColor()
|
||||
} else {
|
||||
} else if v != nil && !*v {
|
||||
currentColor.DisableColor()
|
||||
}
|
||||
|
||||
|
@ -5,15 +5,20 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/ahmetb/kubectx/internal/env"
|
||||
"github.com/ahmetb/kubectx/internal/printer"
|
||||
)
|
||||
|
||||
type Op interface {
|
||||
Run(stdout, stderr io.Writer) error
|
||||
}
|
||||
|
||||
func main() {
|
||||
op := parseArgs(os.Args[1:])
|
||||
if err := op.Run(os.Stdout, os.Stderr); err != nil {
|
||||
printError(os.Stderr, err.Error())
|
||||
printer.Error(os.Stderr, err.Error())
|
||||
|
||||
if _, ok := os.LookupEnv(EnvDebug); ok {
|
||||
if _, ok := os.LookupEnv(env.EnvDebug); ok {
|
||||
// print stack trace in verbose mode
|
||||
fmt.Fprintf(os.Stderr, "[DEBUG] error: %+v\n", err)
|
||||
}
|
||||
@ -21,14 +26,3 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func printError(w io.Writer, format string, args ...interface{}) {
|
||||
fmt.Fprintf(w, color.RedString("error: ")+format+"\n", args...)
|
||||
}
|
||||
|
||||
func printWarning(w io.Writer, format string, args ...interface{}) {
|
||||
fmt.Fprintf(w, color.YellowString("warning: ")+format+"\n", args...)
|
||||
}
|
||||
|
||||
func printSuccess(w io.Writer, format string, args ...interface{}) {
|
||||
fmt.Fprintf(w, color.GreenString(fmt.Sprintf(format+"\n", args...)))
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/kubeconfig"
|
||||
"github.com/ahmetb/kubectx/internal/printer"
|
||||
)
|
||||
|
||||
// RenameOp indicates intention to rename contexts.
|
||||
@ -49,7 +50,7 @@ func (op RenameOp) Run(_, stderr io.Writer) error {
|
||||
}
|
||||
|
||||
if kc.ContextExists(op.New) {
|
||||
printWarning(stderr, "context %q exists, overwriting it.", op.New)
|
||||
printer.Warning(stderr, "context %q exists, overwriting it.", op.New)
|
||||
if err := kc.DeleteContextEntry(op.New); err != nil {
|
||||
return errors.Wrap(err, "failed to delete new context to overwrite it")
|
||||
}
|
||||
@ -66,6 +67,6 @@ func (op RenameOp) Run(_, stderr io.Writer) error {
|
||||
if err := kc.Save(); err != nil {
|
||||
return errors.Wrap(err, "failed to save modified kubeconfig")
|
||||
}
|
||||
printSuccess(stderr, "Context %q renamed to %q.", op.Old, op.New)
|
||||
printer.Success(stderr, "Context %q renamed to %q.", op.Old, op.New)
|
||||
return nil
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/kubeconfig"
|
||||
"github.com/ahmetb/kubectx/internal/printer"
|
||||
)
|
||||
|
||||
// SwitchOp indicates intention to switch contexts.
|
||||
@ -24,7 +25,7 @@ func (op SwitchOp) Run(_, stderr io.Writer) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to switch context")
|
||||
}
|
||||
printSuccess(stderr, "Switched to context %q.", newCtx)
|
||||
printer.Success(stderr, "Switched to context %q.", newCtx)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
19
internal/env/constants.go
vendored
Normal file
19
internal/env/constants.go
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
package env
|
||||
|
||||
const (
|
||||
// EnvFZFIgnore describes the environment variable to set to disable
|
||||
// interactive context selection when fzf is installed.
|
||||
EnvFZFIgnore = "KUBECTX_IGNORE_FZF"
|
||||
|
||||
// EnvForceColor describes the environment variable to disable color usage
|
||||
// when printing current context in a list.
|
||||
EnvNoColor = `NO_COLOR`
|
||||
|
||||
// EnvForceColor describes the "internal" environment variable to force
|
||||
// color usage to show current context in a list.
|
||||
EnvForceColor = `_KUBECTX_FORCE_COLOR`
|
||||
|
||||
// EnvDebug describes the internal environment variable for more verbose logging.
|
||||
EnvDebug = `DEBUG`
|
||||
)
|
||||
|
20
internal/printer/color.go
Normal file
20
internal/printer/color.go
Normal file
@ -0,0 +1,20 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/env"
|
||||
)
|
||||
|
||||
// UseColors returns true if colors are force-enabled,
|
||||
// false if colors are disabled, or nil for default behavior
|
||||
// which is determined based on factors like if stdout is tty.
|
||||
func UseColors() *bool {
|
||||
tr, fa := true, false
|
||||
if os.Getenv(env.EnvForceColor) != "" {
|
||||
return &tr
|
||||
} else if os.Getenv(env.EnvNoColor) != "" {
|
||||
return &fa
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package main
|
||||
package printer
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func withTestVar(key, value string) func() {
|
||||
@ -17,20 +19,24 @@ func withTestVar(key, value string) func() {
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
tr, fa = true, false
|
||||
)
|
||||
|
||||
func Test_useColors_forceColors(t *testing.T) {
|
||||
defer withTestVar("_KUBECTX_FORCE_COLOR", "1")()
|
||||
defer withTestVar("NO_COLOR", "1")()
|
||||
|
||||
if !useColors() {
|
||||
t.Fatal("expected useColors() = true")
|
||||
if v := UseColors(); !cmp.Equal(v, &tr) {
|
||||
t.Fatalf("expected UseColors() = true; got = %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_useColors_disableColors(t *testing.T) {
|
||||
defer withTestVar("NO_COLOR", "1")()
|
||||
|
||||
if useColors() {
|
||||
t.Fatal("expected useColors() = false")
|
||||
if v := UseColors(); !cmp.Equal(v, &fa) {
|
||||
t.Fatalf("expected UseColors() = false; got = %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +44,7 @@ func Test_useColors_default(t *testing.T) {
|
||||
defer withTestVar("NO_COLOR", "")()
|
||||
defer withTestVar("_KUBECTX_FORCE_COLOR", "")()
|
||||
|
||||
if !useColors() {
|
||||
t.Fatal("expected useColors() = true")
|
||||
if v := UseColors(); v != nil {
|
||||
t.Fatalf("expected UseColors() = nil; got=%v", *v)
|
||||
}
|
||||
}
|
42
internal/printer/printer.go
Normal file
42
internal/printer/printer.go
Normal file
@ -0,0 +1,42 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
var (
|
||||
errorColor = color.New(color.FgRed, color.Bold)
|
||||
warningColor = color.New(color.FgYellow, color.Bold)
|
||||
successColor = color.New(color.FgGreen)
|
||||
)
|
||||
|
||||
func init() {
|
||||
colors := UseColors()
|
||||
if colors == nil {
|
||||
return
|
||||
}
|
||||
if *colors {
|
||||
errorColor.EnableColor()
|
||||
warningColor.EnableColor()
|
||||
successColor.EnableColor()
|
||||
} else {
|
||||
errorColor.DisableColor()
|
||||
warningColor.DisableColor()
|
||||
successColor.DisableColor()
|
||||
}
|
||||
}
|
||||
|
||||
func Error(w io.Writer, format string, args ...interface{}) {
|
||||
fmt.Fprintf(w, color.RedString("error: ")+format+"\n", args...)
|
||||
}
|
||||
|
||||
func Warning(w io.Writer, format string, args ...interface{}) {
|
||||
fmt.Fprintf(w, color.YellowString("warning: ")+format+"\n", args...)
|
||||
}
|
||||
|
||||
func Success(w io.Writer, format string, args ...interface{}) {
|
||||
fmt.Fprintf(w, color.GreenString(fmt.Sprintf(format+"\n", args...)))
|
||||
}
|
Loading…
Reference in New Issue
Block a user