mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-06-04 05:10:21 +00:00
kubens: Start implementing stubs
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
parent
342d21683b
commit
1982becb15
@ -1,2 +1 @@
|
||||
package main
|
||||
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/cmdutil"
|
||||
)
|
||||
|
||||
// UnsupportedOp indicates an unsupported flag.
|
||||
@ -18,7 +20,7 @@ func (op UnsupportedOp) Run(_, _ io.Writer) error {
|
||||
// and decides which operation should be taken.
|
||||
func parseArgs(argv []string) Op {
|
||||
if len(argv) == 0 {
|
||||
if isInteractiveMode(os.Stdout) {
|
||||
if env.IsInteractiveMode(os.Stdout) {
|
||||
return InteractiveSwitchOp{SelfCmd: os.Args[0]}
|
||||
}
|
||||
return ListOp{}
|
||||
@ -26,7 +28,7 @@ func parseArgs(argv []string) Op {
|
||||
|
||||
if argv[0] == "-d" {
|
||||
if len(argv) == 1 {
|
||||
return UnsupportedOp{Err:fmt.Errorf("'-d' needs arguments")}
|
||||
return UnsupportedOp{Err: fmt.Errorf("'-d' needs arguments")}
|
||||
}
|
||||
return DeleteOp{Contexts: argv[1:]}
|
||||
}
|
||||
|
@ -10,8 +10,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/env"
|
||||
"github.com/ahmetb/kubectx/internal/kubeconfig"
|
||||
"github.com/ahmetb/kubectx/internal/printer"
|
||||
@ -58,23 +56,3 @@ func (op InteractiveSwitchOp) Run(_, stderr io.Writer) error {
|
||||
printer.Success(stderr, "Switched to context %s.", printer.SuccessColor.Sprint(name))
|
||||
return nil
|
||||
}
|
||||
|
||||
// isTerminal determines if given fd is a TTY.
|
||||
func isTerminal(fd *os.File) bool {
|
||||
return isatty.IsTerminal(fd.Fd())
|
||||
}
|
||||
|
||||
// fzfInstalled determines if fzf(1) is in PATH.
|
||||
func fzfInstalled() bool {
|
||||
v, _ := exec.LookPath("fzf")
|
||||
if v != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isInteractiveMode determines if we can do choosing with fzf.
|
||||
func isInteractiveMode(stdout *os.File) bool {
|
||||
v := os.Getenv(env.EnvFZFIgnore)
|
||||
return v == "" && isTerminal(stdout) && fzfInstalled()
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"github.com/ahmetb/kubectx/internal/testutil"
|
||||
)
|
||||
|
||||
|
||||
func Test_homeDir(t *testing.T) {
|
||||
type env struct{ k, v string }
|
||||
cases := []struct {
|
||||
|
9
cmd/kubens/current.go
Normal file
9
cmd/kubens/current.go
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import "io"
|
||||
|
||||
type CurrentOp struct{}
|
||||
|
||||
func (c CurrentOp) Run(stdout, stderr io.Writer) error {
|
||||
panic("implement me")
|
||||
}
|
40
cmd/kubens/flags.go
Normal file
40
cmd/kubens/flags.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UnsupportedOp indicates an unsupported flag.
|
||||
type UnsupportedOp struct{ Err error }
|
||||
|
||||
func (op UnsupportedOp) Run(_, _ io.Writer) error {
|
||||
return op.Err
|
||||
}
|
||||
|
||||
// parseArgs looks at flags (excl. executable name, i.e. argv[0])
|
||||
// and decides which operation should be taken.
|
||||
func parseArgs(argv []string) Op {
|
||||
if len(argv) == 0 {
|
||||
//if env.IsInteractiveMode(os.Stdout) {
|
||||
// return InteractiveSwitchOp{SelfCmd: os.Args[0]}
|
||||
//}
|
||||
return ListOp{}
|
||||
}
|
||||
|
||||
if len(argv) == 1 {
|
||||
v := argv[0]
|
||||
if v == "--help" || v == "-h" {
|
||||
return HelpOp{}
|
||||
}
|
||||
if v == "--current" || v == "-c" {
|
||||
return CurrentOp{}
|
||||
}
|
||||
if strings.HasPrefix(v, "-") && v != "-" {
|
||||
return UnsupportedOp{Err: fmt.Errorf("unsupported option '%s'", v)}
|
||||
}
|
||||
return SwitchOp{Target: argv[0]}
|
||||
}
|
||||
return UnsupportedOp{Err: fmt.Errorf("too many arguments")}
|
||||
}
|
63
cmd/kubens/flags_test.go
Normal file
63
cmd/kubens/flags_test.go
Normal file
@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func Test_parseArgs_new(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
want Op
|
||||
}{
|
||||
{name: "nil Args",
|
||||
args: nil,
|
||||
want: ListOp{}},
|
||||
{name: "empty Args",
|
||||
args: []string{},
|
||||
want: ListOp{}},
|
||||
{name: "help shorthand",
|
||||
args: []string{"-h"},
|
||||
want: HelpOp{}},
|
||||
{name: "help long form",
|
||||
args: []string{"--help"},
|
||||
want: HelpOp{}},
|
||||
{name: "current shorthand",
|
||||
args: []string{"-c"},
|
||||
want: CurrentOp{}},
|
||||
{name: "current long form",
|
||||
args: []string{"--current"},
|
||||
want: CurrentOp{}},
|
||||
{name: "switch by name",
|
||||
args: []string{"foo"},
|
||||
want: SwitchOp{Target: "foo"}},
|
||||
{name: "switch by swap",
|
||||
args: []string{"-"},
|
||||
want: SwitchOp{Target: "-"}},
|
||||
{name: "unrecognized flag",
|
||||
args: []string{"-x"},
|
||||
want: UnsupportedOp{Err: fmt.Errorf("unsupported option '-x'")}},
|
||||
{name: "too many args",
|
||||
args: []string{"a", "b", "c"},
|
||||
want: UnsupportedOp{Err: fmt.Errorf("too many arguments")}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := parseArgs(tt.args)
|
||||
|
||||
var opts cmp.Options
|
||||
if _, ok := tt.want.(UnsupportedOp); ok {
|
||||
opts = append(opts, cmp.Comparer(func(x, y UnsupportedOp) bool {
|
||||
return (x.Err == nil && y.Err == nil) || (x.Err.Error() == y.Err.Error())
|
||||
}))
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(got, tt.want, opts...); diff != "" {
|
||||
t.Errorf("parseArgs(%#v) diff: %s", tt.args, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
44
cmd/kubens/help.go
Normal file
44
cmd/kubens/help.go
Normal file
@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// HelpOp describes printing help.
|
||||
type HelpOp struct{}
|
||||
|
||||
func (_ HelpOp) Run(stdout, _ io.Writer) error {
|
||||
return printUsage(stdout)
|
||||
}
|
||||
|
||||
func printUsage(out io.Writer) error {
|
||||
help := `USAGE:
|
||||
%PROG% : list the namespaces in the current context
|
||||
%PROG% <NAME> : change the active namespace of current context
|
||||
%PROG% - : switch to the previous namespace in this context
|
||||
%PROG% -c, --current : show the current namespace
|
||||
%PROG% -h,--help : show this message
|
||||
`
|
||||
// TODO this replace logic is duplicated between this and kubectx
|
||||
help = strings.ReplaceAll(help, "%PROG%", selfName())
|
||||
|
||||
_, err := fmt.Fprintf(out, "%s\n", help)
|
||||
return errors.Wrap(err, "write error")
|
||||
}
|
||||
|
||||
// selfName guesses how the user invoked the program.
|
||||
func selfName() string {
|
||||
// TODO this method is duplicated between this and kubectx
|
||||
me := filepath.Base(os.Args[0])
|
||||
pluginPrefix := "kubectl-"
|
||||
if strings.HasPrefix(me, pluginPrefix) {
|
||||
return "kubectl " + strings.TrimPrefix(me, pluginPrefix)
|
||||
}
|
||||
return "kubectx"
|
||||
}
|
11
cmd/kubens/list.go
Normal file
11
cmd/kubens/list.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type ListOp struct{}
|
||||
|
||||
func (op ListOp) Run(stdout, stderr io.Writer) error {
|
||||
panic("implement me")
|
||||
}
|
27
cmd/kubens/main.go
Normal file
27
cmd/kubens/main.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"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 {
|
||||
printer.Error(os.Stderr, err.Error())
|
||||
|
||||
if _, ok := os.LookupEnv(env.EnvDebug); ok {
|
||||
// print stack trace in verbose mode
|
||||
fmt.Fprintf(os.Stderr, "[DEBUG] error: %+v\n", err)
|
||||
}
|
||||
defer os.Exit(1)
|
||||
}
|
||||
}
|
11
cmd/kubens/switch.go
Normal file
11
cmd/kubens/switch.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type SwitchOp struct{ Target string }
|
||||
|
||||
func (s SwitchOp) Run(stdout, stderr io.Writer) error {
|
||||
panic("implement me")
|
||||
}
|
30
internal/cmdutil/interactive.go
Normal file
30
internal/cmdutil/interactive.go
Normal file
@ -0,0 +1,30 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
|
||||
"github.com/ahmetb/kubectx/internal/env"
|
||||
)
|
||||
|
||||
// isTerminal determines if given fd is a TTY.
|
||||
func isTerminal(fd *os.File) bool {
|
||||
return isatty.IsTerminal(fd.Fd())
|
||||
}
|
||||
|
||||
// fzfInstalled determines if fzf(1) is in PATH.
|
||||
func fzfInstalled() bool {
|
||||
v, _ := exec.LookPath("fzf")
|
||||
if v != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsInteractiveMode determines if we can do choosing with fzf.
|
||||
func IsInteractiveMode(stdout *os.File) bool {
|
||||
v := os.Getenv(env.EnvFZFIgnore)
|
||||
return v == "" && isTerminal(stdout) && fzfInstalled()
|
||||
}
|
1
internal/env/constants.go
vendored
1
internal/env/constants.go
vendored
@ -16,4 +16,3 @@ const (
|
||||
// EnvDebug describes the internal environment variable for more verbose logging.
|
||||
EnvDebug = `DEBUG`
|
||||
)
|
||||
|
||||
|
@ -1,2 +1 @@
|
||||
package kubeconfig
|
||||
|
||||
|
@ -1,2 +1 @@
|
||||
package testutil
|
||||
|
||||
|
@ -15,4 +15,3 @@ func WithEnvVar(key, value string) func() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user