Compare commits

..

No commits in common. "dc144dd79e7a4d4cfddac3ef735fc8b915cd07e2" and "c900900a35bd1e85baa05a28a351fecb78eedfaa" have entirely different histories.

13 changed files with 47 additions and 241 deletions

View File

@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6.0.1
uses: actions/checkout@v6.0.0
- name: Install Go
uses: actions/setup-go@v6.1.0
@ -18,7 +18,7 @@ jobs:
cache-dependency-path: go.sum
- name: Lint
uses: golangci/golangci-lint-action@v9.2.0
uses: golangci/golangci-lint-action@v9.1.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
version: v2.1.1

View File

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6.0.1
uses: actions/checkout@v6.0.0
- name: Install Go
uses: actions/setup-go@v6.1.0

View File

@ -1,6 +1,6 @@
# -----------------------------------------------------------------------------
# The base image for building the k9s binary
FROM --platform=$BUILDPLATFORM golang:1.25.5-alpine3.21 AS build
FROM --platform=$BUILDPLATFORM golang:1.25.4-alpine3.21 AS build
ARG TARGETOS
ARG TARGETARCH
@ -16,7 +16,7 @@ RUN apk --no-cache add --update make libx11-dev git gcc libc-dev curl \
# -----------------------------------------------------------------------------
# Build the final Docker image
FROM --platform=$BUILDPLATFORM alpine:3.23.0
FROM --platform=$BUILDPLATFORM alpine:3.22.2
ARG KUBECTL_VERSION="v1.32.2"
COPY --from=build /k9s/execs/k9s /bin/k9s

View File

@ -69,7 +69,9 @@ func init() {
// Execute root command.
func Execute() {
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
if !errors.As(err, &flagError{}) {
panic(err)
}
}
}

12
go.mod
View File

@ -15,11 +15,11 @@ require (
github.com/fsnotify/fsnotify v1.9.0
github.com/fvbommel/sortorder v1.1.0
github.com/go-errors/errors v1.5.1
github.com/itchyny/gojq v0.12.18
github.com/itchyny/gojq v0.12.17
github.com/lmittmann/tint v1.0.7
github.com/mattn/go-colorable v0.1.14
github.com/mattn/go-runewidth v0.0.19
github.com/olekukonko/tablewriter v1.1.2
github.com/olekukonko/tablewriter v1.1.1
github.com/petergtz/pegomock v2.9.0+incompatible
github.com/rakyll/hey v0.1.4
github.com/sahilm/fuzzy v0.1.1
@ -129,9 +129,9 @@ require (
github.com/charmbracelet/x/ansi v0.10.1 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/clipperhouse/displaywidth v0.6.0 // indirect
github.com/clipperhouse/displaywidth v0.3.1 // indirect
github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
github.com/containerd/cgroups/v3 v3.0.3 // indirect
@ -224,7 +224,7 @@ require (
github.com/huandu/xstrings v1.5.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/itchyny/timefmt-go v0.1.7 // indirect
github.com/itchyny/timefmt-go v0.1.6 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
@ -274,7 +274,7 @@ require (
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.1.3 // indirect
github.com/olekukonko/ll v0.1.2 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.35.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect

24
go.sum
View File

@ -298,12 +298,12 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/clipperhouse/displaywidth v0.6.0 h1:k32vueaksef9WIKCNcoqRNyKbyvkvkysNYnAWz2fN4s=
github.com/clipperhouse/displaywidth v0.6.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
github.com/clipperhouse/displaywidth v0.3.1 h1:k07iN9gD32177o1y4O1jQMzbLdCrsGJh+blirVYybsk=
github.com/clipperhouse/displaywidth v0.3.1/go.mod h1:tgLJKKyaDOCadywag3agw4snxS5kYEuYR6Y9+qWDDYM=
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
@ -732,10 +732,10 @@ github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/itchyny/gojq v0.12.18 h1:gFGHyt/MLbG9n6dqnvlliiya2TaMMh6FFaR2b1H6Drc=
github.com/itchyny/gojq v0.12.18/go.mod h1:4hPoZ/3lN9fDL1D+aK7DY1f39XZpY9+1Xpjz8atrEkg=
github.com/itchyny/timefmt-go v0.1.7 h1:xyftit9Tbw+Dc/huSSPJaEmX1TVL8lw5vxjJLK4GMMA=
github.com/itchyny/timefmt-go v0.1.7/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI=
github.com/itchyny/gojq v0.12.17 h1:8av8eGduDb5+rvEdaOO+zQUjA04MS0m3Ps8HiD+fceg=
github.com/itchyny/gojq v0.12.17/go.mod h1:WBrEMkgAfAGO1LUcGOckBl5O726KPp+OlkKug0I/FEY=
github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q=
github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
@ -922,10 +922,10 @@ github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.1.3 h1:sV2jrhQGq5B3W0nENUISCR6azIPf7UBUpVq0x/y70Fg=
github.com/olekukonko/ll v0.1.3/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew=
github.com/olekukonko/tablewriter v1.1.2 h1:L2kI1Y5tZBct/O/TyZK1zIE9GlBj/TVs+AY5tZDCDSc=
github.com/olekukonko/tablewriter v1.1.2/go.mod h1:z7SYPugVqGVavWoA2sGsFIoOVNmEHxUAAMrhXONtfkg=
github.com/olekukonko/ll v0.1.2 h1:lkg/k/9mlsy0SxO5aC+WEpbdT5K83ddnNhAepz7TQc0=
github.com/olekukonko/ll v0.1.2/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew=
github.com/olekukonko/tablewriter v1.1.1 h1:b3reP6GCfrHwmKkYwNRFh2rxidGHcT6cgxj/sHiDDx0=
github.com/olekukonko/tablewriter v1.1.1/go.mod h1:De/bIcTF+gpBDB3Alv3fEsZA+9unTsSzAg/ZGADCtn4=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=

View File

@ -144,7 +144,6 @@ func (a *App) Conn() client.Connection {
func (a *App) bindKeys() {
a.actions = NewKeyActionsFromMap(KeyMap{
KeyColon: NewKeyAction("Cmd", a.activateCmd, false),
KeyComma: NewKeyAction("Cmd", a.activateCmd, false),
tcell.KeyCtrlR: NewKeyAction("Redraw", a.redrawCmd, false),
tcell.KeyCtrlP: NewKeyAction("Persist", a.saveCmd, false),
tcell.KeyCtrlU: NewSharedKeyAction("Clear Filter", a.clearCmd, false),

View File

@ -79,7 +79,6 @@ const (
KeyHelp = 63
KeySlash = 47
KeyColon = 58
KeyComma = 44
KeySpace = 32
KeyDash = 45
KeyLeftBracket = 91

View File

@ -6,7 +6,6 @@ package ui
import (
"fmt"
"sync"
"unicode"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/model"
@ -153,13 +152,7 @@ func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey {
p.model.Delete()
case tcell.KeyRune:
r := evt.Rune()
// Filter out control characters and non-printable runes that may come from
// terminal escape sequences (e.g., cursor position reports like [7;15R)
// Only accept printable characters for user input
if isValidInputRune(r) {
p.model.Add(r)
}
p.model.Add(evt.Rune())
case tcell.KeyEscape:
p.model.ClearText(true)
@ -300,18 +293,6 @@ func (p *Prompt) prefixesFor(k model.BufferKind) (ic, prefix rune) {
// ----------------------------------------------------------------------------
// Helpers...
// isValidInputRune checks if a rune is valid for user input.
// It filters out control characters and non-printable characters that may
// come from terminal escape sequences (e.g., cursor position reports).
func isValidInputRune(r rune) bool {
// Reject control characters (0x00-0x1F, 0x7F) except for common whitespace
if unicode.IsControl(r) && r != '\t' && r != '\n' && r != '\r' {
return false
}
// Only accept printable characters
return unicode.IsPrint(r) || unicode.IsSpace(r)
}
func (p *Prompt) colorFor(k model.BufferKind) tcell.Color {
//nolint:exhaustive
switch k {

View File

@ -1,128 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s
package ui_test
import (
"fmt"
"testing"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/ui"
"github.com/derailed/tcell/v2"
"github.com/stretchr/testify/assert"
)
// TestPrompt_FiltersControlCharacters tests that control characters from
// terminal escape sequences are filtered out and not added to the buffer.
func TestPrompt_FiltersControlCharacters(t *testing.T) {
m := model.NewFishBuff(':', model.CommandBuffer)
p := ui.NewPrompt(nil, true, config.NewStyles())
p.SetModel(m)
m.AddListener(p)
m.SetActive(true)
// Test control characters that should be filtered
controlChars := []rune{
0x00, // NULL
0x01, // SOH
0x1B, // ESC (escape character)
0x7F, // DEL
}
for _, c := range controlChars {
t.Run(fmt.Sprintf("control_char_0x%02X", c), func(t *testing.T) {
evt := tcell.NewEventKey(tcell.KeyRune, c, tcell.ModNone)
p.SendKey(evt)
// Control characters should not be added to buffer
assert.Empty(t, m.GetText(), "Control character 0x%02X should be filtered", c)
})
}
}
// TestPrompt_AcceptsPrintableCharacters tests that valid printable
// characters are accepted and added to the buffer.
func TestPrompt_AcceptsPrintableCharacters(t *testing.T) {
m := model.NewFishBuff(':', model.CommandBuffer)
p := ui.NewPrompt(nil, true, config.NewStyles())
p.SetModel(m)
m.AddListener(p)
m.SetActive(true)
// Test valid printable characters
validChars := []rune{
'a', 'Z', '0', '9',
'!', '@', '#', '$',
' ', // space
'[', ']', ';', 'R', // characters from escape sequences (should be accepted if typed)
}
for _, c := range validChars {
t.Run(fmt.Sprintf("valid_char_%c", c), func(t *testing.T) {
evt := tcell.NewEventKey(tcell.KeyRune, c, tcell.ModNone)
p.SendKey(evt)
// Valid characters should be added
assert.Contains(t, m.GetText(), string(c), "Valid character %c should be accepted", c)
// Clear for next test
m.ClearText(true)
})
}
// Test tab separately (it's a control char but should be accepted)
t.Run("valid_char_tab", func(t *testing.T) {
evt := tcell.NewEventKey(tcell.KeyRune, '\t', tcell.ModNone)
p.SendKey(evt)
// Tab should be accepted (it's a special case in the validation)
// Note: Tab might be converted to spaces or handled differently by the buffer
text := m.GetText()
// Tab is accepted by validation, but may be handled specially by the buffer
// Just verify the buffer isn't empty (meaning something was processed)
assert.NotNil(t, text, "Tab character should be processed")
m.ClearText(true)
})
}
// TestPrompt_FiltersEscapeSequencePattern tests that escape sequence
// patterns are not automatically added when they appear as individual runes.
// Note: This test verifies the validation works, but escape sequences
// should ideally be handled by tcell before reaching KeyRune.
func TestPrompt_FiltersEscapeSequencePattern(t *testing.T) {
m := model.NewFishBuff(':', model.CommandBuffer)
p := ui.NewPrompt(nil, true, config.NewStyles())
p.SetModel(m)
m.AddListener(p)
m.SetActive(true)
// Simulate the problematic escape sequence pattern [7;15R
// Each character individually is printable, but we want to ensure
// they don't appear unexpectedly
escapeSequence := "[7;15R"
// Send each character
for _, r := range escapeSequence {
evt := tcell.NewEventKey(tcell.KeyRune, r, tcell.ModNone)
p.SendKey(evt)
}
// The characters themselves are printable, so they will be added
// This test documents the current behavior - the fix prevents
// control characters, but printable escape sequence chars would
// still be added if tcell doesn't filter them first
text := m.GetText()
// If all characters are printable, they will be in the buffer
// This is expected behavior - the fix prevents control chars,
// but can't prevent legitimate printable characters
assert.NotEmpty(t, text, "Printable escape sequence chars may still appear")
// However, we can verify no control characters made it through
for _, r := range text {
assert.False(t, isControlChar(r), "No control characters should be in buffer")
}
}
// Helper function to check if a rune is a control character
func isControlChar(r rune) bool {
return r >= 0x00 && r <= 0x1F || r == 0x7F
}

View File

@ -113,11 +113,6 @@ func gotoCmd(r Runner, cmd, path string, clearStack bool) ui.ActionHandler {
}
func pluginActions(r Runner, aa *ui.KeyActions) error {
// Skip plugin loading if no valid connection
if r.App().Conn() == nil || !r.App().Conn().ConnectionOK() {
return nil
}
aa.Range(func(k tcell.Key, a ui.KeyAction) {
if a.Opts.Plugin {
aa.Delete(k)

View File

@ -5,6 +5,7 @@ package view
import (
"context"
"errors"
"fmt"
"log/slog"
"maps"
@ -105,21 +106,20 @@ func (a *App) Init(version string, _ int) error {
a.App.Init()
a.SetInputCapture(a.keyboard)
a.bindKeys()
if a.Conn() == nil {
return errors.New("no client connection detected")
}
ns := a.Config.ActiveNamespace()
// Allow initialization even without a valid connection
// We'll fall back to context view in defaultCmd
if a.Conn() != nil {
ns := a.Config.ActiveNamespace()
a.factory = watch.NewFactory(a.Conn())
a.initFactory(ns)
a.factory = watch.NewFactory(a.Conn())
a.initFactory(ns)
a.clusterModel = model.NewClusterInfo(a.factory, a.version, a.Config.K9s)
a.clusterModel.AddListener(a.clusterInfo())
a.clusterModel.AddListener(a.statusIndicator())
if a.Conn().ConnectionOK() {
a.clusterModel.Refresh()
a.clusterInfo().Init()
}
a.clusterModel = model.NewClusterInfo(a.factory, a.version, a.Config.K9s)
a.clusterModel.AddListener(a.clusterInfo())
a.clusterModel.AddListener(a.statusIndicator())
if a.Conn().ConnectionOK() {
a.clusterModel.Refresh()
a.clusterInfo().Init()
}
a.command = NewCommand(a)
@ -223,10 +223,6 @@ func (a *App) suggestCommand() model.SuggestionFunc {
}
func (a *App) contextNames() ([]string, error) {
// Return empty list if no factory
if a.factory == nil {
return []string{}, nil
}
contexts, err := a.factory.Client().Config().Contexts()
if err != nil {
return nil, err
@ -307,7 +303,7 @@ func (a *App) buildHeader() tview.Primitive {
}
clWidth := clusterInfoWidth
if a.Conn() != nil && a.Conn().ConnectionOK() {
if a.Conn().ConnectionOK() {
n, err := a.Conn().Config().CurrentClusterName()
if err == nil {
size := len(n) + clusterInfoPad
@ -355,11 +351,6 @@ func (a *App) Resume() {
}
func (a *App) clusterUpdater(ctx context.Context) {
if a.Conn() == nil || !a.Conn().ConnectionOK() || a.factory == nil || a.clusterModel == nil {
slog.Debug("Skipping cluster updater - no valid connection")
return
}
if err := a.refreshCluster(ctx); err != nil {
slog.Error("Cluster updater failed!", slogs.Error, err)
return
@ -388,10 +379,6 @@ func (a *App) clusterUpdater(ctx context.Context) {
}
func (a *App) refreshCluster(context.Context) error {
if a.Conn() == nil || a.factory == nil || a.clusterModel == nil {
return nil
}
c := a.Content.Top()
if ok := a.Conn().CheckConnectivity(); ok {
if atomic.LoadInt32(&a.conRetry) > 0 {
@ -487,18 +474,7 @@ func (a *App) switchContext(ci *cmd.Interpreter, force bool) error {
if err := a.Config.Save(true); err != nil {
slog.Error("Fail to save config to disk", slogs.Subsys, "config", slogs.Error, err)
}
if a.factory == nil && a.Conn() != nil {
a.factory = watch.NewFactory(a.Conn())
a.clusterModel = model.NewClusterInfo(a.factory, a.version, a.Config.K9s)
a.clusterModel.AddListener(a.clusterInfo())
a.clusterModel.AddListener(a.statusIndicator())
}
if a.factory != nil {
a.initFactory(ns)
}
a.initFactory(ns)
if err := a.command.Reset(a.Config.ContextAliasesPath(), true); err != nil {
return err
}
@ -511,10 +487,7 @@ func (a *App) switchContext(ci *cmd.Interpreter, force bool) error {
a.Flash().Infof("Switching context to %q::%q", contextName, ns)
a.ReloadStyles()
a.gotoResource(a.Config.ActiveView(), "", true, true)
if a.clusterModel != nil {
a.clusterModel.Reset(a.factory)
}
a.clusterModel.Reset(a.factory)
}
return nil

View File

@ -47,20 +47,15 @@ func NewCommand(app *App) *Command {
// AliasesFor gather all known aliases for a given resource.
func (c *Command) AliasesFor(gvr *client.GVR) sets.Set[string] {
if c.alias == nil {
return sets.New[string]()
}
return c.alias.AliasesFor(gvr)
}
// Init initializes the command.
func (c *Command) Init(path string) error {
if c.app.factory != nil {
c.alias = dao.NewAlias(c.app.factory)
if _, err := c.alias.Ensure(path); err != nil {
slog.Error("Ensure aliases failed", slogs.Error, err)
return err
}
c.alias = dao.NewAlias(c.app.factory)
if _, err := c.alias.Ensure(path); err != nil {
slog.Error("Ensure aliases failed", slogs.Error, err)
return err
}
customViewers = loadCustomViewers()
@ -72,10 +67,6 @@ func (c *Command) Reset(path string, nuke bool) error {
c.mx.Lock()
defer c.mx.Unlock()
if c.alias == nil {
return nil
}
if nuke {
c.alias.Clear()
}
@ -148,9 +139,6 @@ func (c *Command) xrayCmd(p *cmd.Interpreter, pushCmd bool) error {
if !ok {
return errors.New("invalid command. use `xray xxx`")
}
if c.alias == nil {
return fmt.Errorf("no connection available")
}
gvr, ok := c.alias.Resolve(cmd.NewInterpreter(arg))
if !ok {
return fmt.Errorf("invalid resource name: %q", arg)
@ -313,9 +301,6 @@ func (c *Command) specialCmd(p *cmd.Interpreter, pushCmd bool) bool {
}
func (c *Command) viewMetaFor(p *cmd.Interpreter) (*client.GVR, *MetaViewer, *cmd.Interpreter, error) {
if c.alias == nil {
return client.NoGVR, nil, nil, fmt.Errorf("no connection available")
}
gvr, ok := c.alias.Resolve(p)
if !ok {
return client.NoGVR, nil, nil, fmt.Errorf("`%s` command not found", p.Cmd())