add dir view
parent
f1111174aa
commit
5893cffb0d
|
|
@ -19,3 +19,4 @@ pod1.go
|
|||
faas
|
||||
.settings/*
|
||||
demos
|
||||
/code
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Thank you to all that contributed with flushing out issues and enhancements for K9s! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make K9s better is as ever very much noticed and appreciated!
|
||||
|
||||
Also if you dig this tool, consider joining our [sponsorhip program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
|
||||
If you feel K9s is helping your Kubernetes journey, please consider joining our [sponsorhip program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
|
||||
|
||||
On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM)
|
||||
|
||||
|
|
@ -19,7 +19,18 @@ First off, I would like to send a `Big Thank You` to the following generous K9s
|
|||
* [Remo Eichenberger](https://github.com/remoe)
|
||||
* [Ken Ahrens](https://github.com/kenahrens)
|
||||
|
||||
Maintenance Release!
|
||||
## Moving Forward!
|
||||
|
||||
In this drop, we've added a port-forward indicator to visually see if a port-forward is active on a pod/container. You can also navigate directly to the port-forward view using the new shortcut `f` available in
|
||||
pod and container view.
|
||||
|
||||
## Manifest That!
|
||||
|
||||
Ever wanted to manipulate your Kubernetes manifests directly in K9s? `Yes Please!!`
|
||||
|
||||
We are introducing a new view namely `directory` aka `dir`. Using this command you can list/traverse a given directory structure containing your Kubernetes manifests using a new `:dir /fred` command.
|
||||
From there you can view/edit your manifests and also deploy or delete these resources for your cluster directly from K9s. Just like `kubectl` you can apply/delete an entire directory or a single manifest.
|
||||
How cool is that?
|
||||
|
||||
## Resolved Bugs/Features/PRs
|
||||
|
||||
|
|
@ -27,7 +38,8 @@ Maintenance Release!
|
|||
* [Issue #774](https://github.com/derailed/k9s/issues/774)
|
||||
* [Issue #761](https://github.com/derailed/k9s/issues/761)
|
||||
* [Issue #759](https://github.com/derailed/k9s/issues/759)
|
||||
* [Issue #756](https://github.com/derailed/k9s/issues/756)
|
||||
* [Issue #758](https://github.com/derailed/k9s/issues/758)
|
||||
* [PR #746](https://github.com/derailed/k9s/pull/746) Big Thanks to [Groselt](https://github.com/groselt)!
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
6
go.mod
6
go.mod
|
|
@ -5,6 +5,7 @@ go 1.14
|
|||
require (
|
||||
9fans.net/go v0.0.2
|
||||
github.com/atotto/clipboard v0.1.2
|
||||
github.com/coreos/etcd v3.3.10+incompatible
|
||||
github.com/derailed/popeye v0.8.6
|
||||
github.com/derailed/tview v0.3.10
|
||||
github.com/drone/envsubst v1.0.2 // indirect
|
||||
|
|
@ -13,7 +14,9 @@ require (
|
|||
github.com/gdamore/tcell v1.3.0
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/golang/protobuf v1.4.2 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381
|
||||
github.com/mattn/go-isatty v0.0.11
|
||||
github.com/mattn/go-runewidth v0.0.9
|
||||
github.com/openfaas/faas v0.0.0-20200207215241-6afae214e3ec
|
||||
github.com/openfaas/faas-cli v0.0.0-20200124160744-30b7cec9634c
|
||||
|
|
@ -30,6 +33,7 @@ require (
|
|||
golang.org/x/text v0.3.2
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587 // indirect
|
||||
google.golang.org/grpc v1.29.1 // indirect
|
||||
gopkg.in/fsnotify.v1 v1.4.7
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
helm.sh/helm/v3 v3.2.0
|
||||
k8s.io/api v0.18.2
|
||||
|
|
|
|||
5
go.sum
5
go.sum
|
|
@ -114,15 +114,18 @@ github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH
|
|||
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
|
||||
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
|
|
@ -415,6 +418,8 @@ github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ func (a *Aliases) loadDefaultAliases() {
|
|||
a.declare("aliases", "alias", "a")
|
||||
a.declare("popeye", "pop")
|
||||
a.declare("helm", "charts", "chart", "hm")
|
||||
a.declare("dir", "d")
|
||||
a.declare("contexts", "context", "ctx")
|
||||
a.declare("users", "user", "usr")
|
||||
a.declare("groups", "group", "grp")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var _ Accessor = (*Dir)(nil)
|
||||
|
||||
// Dir tracks standard and custom command aliases.
|
||||
type Dir struct {
|
||||
NonResource
|
||||
}
|
||||
|
||||
// NewDir returns a new set of aliases.
|
||||
func NewDir(f Factory) *Dir {
|
||||
var a Dir
|
||||
a.Init(f, client.NewGVR("dir"))
|
||||
return &a
|
||||
}
|
||||
|
||||
var yamlRX = regexp.MustCompile(`.*\.(yml|yaml)`)
|
||||
|
||||
// List returns a collection of aliases.
|
||||
func (a *Dir) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||
dir, ok := ctx.Value(internal.KeyPath).(string)
|
||||
if !ok {
|
||||
return nil, errors.New("No dir in context")
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, 0, len(files))
|
||||
for _, f := range files {
|
||||
if strings.HasPrefix(f.Name(), ".") || !f.IsDir() && !yamlRX.MatchString(f.Name()) {
|
||||
continue
|
||||
}
|
||||
oo = append(oo, render.DirRes{
|
||||
Path: filepath.Join(dir, f.Name()),
|
||||
Info: f,
|
||||
})
|
||||
}
|
||||
|
||||
return oo, err
|
||||
}
|
||||
|
||||
// Get fetch a resource.
|
||||
func (a *Dir) Get(_ context.Context, _ string) (runtime.Object, error) {
|
||||
return nil, errors.New("NYI!!")
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ func AccessorFor(f Factory, gvr client.GVR) (Accessor, error) {
|
|||
client.NewGVR("popeye"): &Popeye{},
|
||||
client.NewGVR("sanitizer"): &Popeye{},
|
||||
client.NewGVR("helm"): &Helm{},
|
||||
client.NewGVR("dir"): &Dir{},
|
||||
}
|
||||
|
||||
r, ok := m[gvr]
|
||||
|
|
@ -152,6 +153,12 @@ func loadK9s(m ResourceMetas) {
|
|||
ShortNames: []string{"hz", "pu"},
|
||||
Categories: []string{"k9s"},
|
||||
}
|
||||
m[client.NewGVR("dir")] = metav1.APIResource{
|
||||
Name: "dir",
|
||||
Kind: "Dir",
|
||||
SingularName: "dir",
|
||||
Categories: []string{"k9s"},
|
||||
}
|
||||
m[client.NewGVR("xrays")] = metav1.APIResource{
|
||||
Name: "xray",
|
||||
Kind: "XRays",
|
||||
|
|
@ -176,7 +183,7 @@ func loadK9s(m ResourceMetas) {
|
|||
Name: "popeye",
|
||||
Kind: "Popeye",
|
||||
SingularName: "popeye",
|
||||
Namespaced: true,
|
||||
Namespaced: true,
|
||||
Verbs: []string{},
|
||||
Categories: []string{"k9s"},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ var Registry = map[string]ResourceMeta{
|
|||
DAO: &dao.Reference{},
|
||||
Renderer: &render.Reference{},
|
||||
},
|
||||
"dir": {
|
||||
DAO: &dao.Dir{},
|
||||
Renderer: &render.Dir{},
|
||||
},
|
||||
"helm": {
|
||||
DAO: &dao.Helm{},
|
||||
Renderer: &render.Helm{},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package render
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// Dir renders a directory entry to screen.
|
||||
type Dir struct{}
|
||||
|
||||
// ColorerFunc colors a resource row.
|
||||
func (Dir) ColorerFunc() ColorerFunc {
|
||||
return func(ns string, _ Header, re RowEvent) tcell.Color {
|
||||
return tcell.ColorCadetBlue
|
||||
}
|
||||
}
|
||||
|
||||
// Header returns a header row.
|
||||
func (Dir) Header(ns string) Header {
|
||||
return Header{
|
||||
HeaderColumn{Name: "NAME"},
|
||||
}
|
||||
}
|
||||
|
||||
// Render renders a K8s resource to screen.
|
||||
// BOZO!! Pass in a row with pre-alloc fields??
|
||||
func (Dir) Render(o interface{}, ns string, r *Row) error {
|
||||
d, ok := o.(DirRes)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected DirRes, but got %T", o)
|
||||
}
|
||||
|
||||
name := "🦄 "
|
||||
if d.Info.IsDir() {
|
||||
name = "📁 "
|
||||
}
|
||||
name += d.Info.Name()
|
||||
r.ID, r.Fields = d.Path, append(r.Fields, name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
// DirRes represents an alias resource.
|
||||
type DirRes struct {
|
||||
Info os.FileInfo
|
||||
Path string
|
||||
}
|
||||
|
||||
// GetObjectKind returns a schema object.
|
||||
func (DirRes) GetObjectKind() schema.ObjectKind {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a container copy.
|
||||
func (d DirRes) DeepCopyObject() runtime.Object {
|
||||
return d
|
||||
}
|
||||
|
|
@ -58,6 +58,10 @@ func (a *Alias) bindKeys(aa ui.KeyActions) {
|
|||
}
|
||||
|
||||
func (a *Alias) gotoCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if a.GetTable().CmdBuff().IsActive() {
|
||||
return a.GetTable().activateCmd(evt)
|
||||
}
|
||||
|
||||
r, _ := a.GetTable().GetSelection()
|
||||
if r != 0 {
|
||||
s := ui.TrimCell(a.GetTable().SelectTable, r, 1)
|
||||
|
|
@ -68,8 +72,5 @@ func (a *Alias) gotoCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
if a.GetTable().CmdBuff().IsActive() {
|
||||
return a.GetTable().activateCmd(evt)
|
||||
}
|
||||
return evt
|
||||
}
|
||||
|
|
|
|||
|
|
@ -523,6 +523,24 @@ func (a *App) meowCmd(msg string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *App) dirCmd(path string) error {
|
||||
log.Debug().Msgf("DIR PATH %q", path)
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if path == "." {
|
||||
dir, err := os.Getwd()
|
||||
if err == nil {
|
||||
path = dir
|
||||
}
|
||||
}
|
||||
a.Content.Stack.Clear()
|
||||
a.cmdHistory.Push("dir " + path)
|
||||
|
||||
return a.inject(NewDir(path))
|
||||
}
|
||||
|
||||
func (a *App) helpCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if a.CmdBuff().InCmdMode() {
|
||||
return evt
|
||||
|
|
|
|||
|
|
@ -124,6 +124,11 @@ func (c *Command) run(cmd, path string, clearStack bool) error {
|
|||
return useContext(c.app, cmds[1])
|
||||
}
|
||||
return c.exec(cmd, gvr, c.componentFor(gvr, path, v), clearStack)
|
||||
case "dir":
|
||||
if len(cmds) != 2 {
|
||||
return errors.New("You must specify a directory")
|
||||
}
|
||||
return c.app.dirCmd(cmds[1])
|
||||
default:
|
||||
// checks if Command includes a namespace
|
||||
ns := c.app.Config.ActiveNamespace()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,203 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/derailed/k9s/internal/ui/dialog"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Dir represents a command directory view.
|
||||
type Dir struct {
|
||||
ResourceViewer
|
||||
path string
|
||||
}
|
||||
|
||||
func NewDir(path string) ResourceViewer {
|
||||
d := Dir{
|
||||
ResourceViewer: NewBrowser(client.NewGVR("dir")),
|
||||
path: path,
|
||||
}
|
||||
d.GetTable().SetBorderFocusColor(tcell.ColorAliceBlue)
|
||||
d.GetTable().SetSelectedStyle(tcell.ColorWhite, tcell.ColorAliceBlue, tcell.AttrNone)
|
||||
d.SetBindKeysFn(d.bindKeys)
|
||||
d.SetContextFn(d.dirContext)
|
||||
d.GetTable().SetColorerFn(render.Dir{}.ColorerFunc())
|
||||
|
||||
return &d
|
||||
}
|
||||
|
||||
// Init initializes the view.
|
||||
func (d *Dir) Init(ctx context.Context) error {
|
||||
if err := d.ResourceViewer.Init(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Dir) dirContext(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, internal.KeyPath, d.path)
|
||||
}
|
||||
|
||||
func (d *Dir) bindKeys(aa ui.KeyActions) {
|
||||
aa.Delete(ui.KeyShiftA, tcell.KeyCtrlS, tcell.KeyCtrlSpace, ui.KeySpace)
|
||||
aa.Delete(tcell.KeyCtrlW, tcell.KeyCtrlL, tcell.KeyCtrlD, tcell.KeyCtrlZ)
|
||||
aa.Add(ui.KeyActions{
|
||||
ui.KeyA: ui.NewKeyAction("Apply", d.applyCmd, true),
|
||||
ui.KeyD: ui.NewKeyAction("Delete", d.delCmd, true),
|
||||
ui.KeyE: ui.NewKeyAction("Edit", d.editCmd, true),
|
||||
ui.KeyY: ui.NewKeyAction("YAML", d.viewCmd, true),
|
||||
tcell.KeyEnter: ui.NewKeyAction("Goto", d.gotoCmd, true),
|
||||
})
|
||||
}
|
||||
|
||||
func (d *Dir) viewCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
sel := d.GetTable().GetSelectedItem()
|
||||
if sel == "" {
|
||||
return evt
|
||||
}
|
||||
|
||||
if path.Ext(sel) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
yaml, err := ioutil.ReadFile(sel)
|
||||
if err != nil {
|
||||
d.App().Flash().Err(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
details := NewDetails(d.App(), "YAML", sel, true).Update(string(yaml))
|
||||
if err := d.App().inject(details); err != nil {
|
||||
d.App().Flash().Err(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isManifest(s string) bool {
|
||||
ext := path.Ext(s)
|
||||
return ext == ".yml" || ext == ".yaml"
|
||||
}
|
||||
|
||||
func (d *Dir) editCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
sel := d.GetTable().GetSelectedItem()
|
||||
if sel == "" {
|
||||
return evt
|
||||
}
|
||||
|
||||
log.Debug().Msgf("Selected %q", sel)
|
||||
if !isManifest(sel) {
|
||||
d.App().Flash().Errf("you must select a manifest")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Stop()
|
||||
defer d.Start()
|
||||
if !edit(d.App(), shellOpts{clear: true, args: []string{sel}}) {
|
||||
d.App().Flash().Err(errors.New("Failed to launch editor"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Dir) gotoCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if d.GetTable().CmdBuff().IsActive() {
|
||||
return d.GetTable().activateCmd(evt)
|
||||
}
|
||||
|
||||
sel := d.GetTable().GetSelectedItem()
|
||||
if sel == "" {
|
||||
return evt
|
||||
}
|
||||
|
||||
if isManifest(sel) {
|
||||
d.App().Flash().Errf("you must select a directory")
|
||||
return nil
|
||||
}
|
||||
|
||||
v := NewDir(sel)
|
||||
if err := d.App().inject(v); err != nil {
|
||||
d.App().Flash().Err(err)
|
||||
}
|
||||
|
||||
return evt
|
||||
}
|
||||
|
||||
func (d *Dir) applyCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
sel := d.GetTable().GetSelectedItem()
|
||||
if sel == "" {
|
||||
return evt
|
||||
}
|
||||
|
||||
if !isManifest(sel) {
|
||||
d.App().Flash().Errf("you must select a manifest")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Stop()
|
||||
defer d.Start()
|
||||
{
|
||||
args := make([]string, 0, 10)
|
||||
args = append(args, "apply")
|
||||
args = append(args, "-f")
|
||||
args = append(args, sel)
|
||||
res, err := runKu(d.App(), shellOpts{clear: false, args: args})
|
||||
if err != nil {
|
||||
res = "error:\n " + err.Error()
|
||||
} else {
|
||||
res = "message:\n " + res
|
||||
}
|
||||
|
||||
details := NewDetails(d.App(), "Applied Manifest", sel, true).Update(res)
|
||||
if err := d.App().inject(details); err != nil {
|
||||
d.App().Flash().Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Dir) delCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
sel := d.GetTable().GetSelectedItem()
|
||||
if sel == "" {
|
||||
return evt
|
||||
}
|
||||
|
||||
if !isManifest(sel) {
|
||||
d.App().Flash().Errf("you must select a manifest")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Stop()
|
||||
defer d.Start()
|
||||
msg := fmt.Sprintf("Delete resource(s) in manifest %s", sel)
|
||||
dialog.ShowConfirm(d.App().Content.Pages, "Confirm Delete", msg, func() {
|
||||
args := make([]string, 0, 10)
|
||||
args = append(args, "delete")
|
||||
args = append(args, "-f")
|
||||
args = append(args, sel)
|
||||
res, err := runKu(d.App(), shellOpts{clear: false, args: args})
|
||||
if err != nil {
|
||||
res = "error:\n " + err.Error() + "\nmessage:\n " + res
|
||||
} else {
|
||||
res = "message:\n " + res
|
||||
}
|
||||
details := NewDetails(d.App(), "Deleted Manifest", sel, true).Update(res)
|
||||
if err := d.App().inject(details); err != nil {
|
||||
d.App().Flash().Err(err)
|
||||
}
|
||||
}, func() {})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -123,6 +124,49 @@ func execute(opts shellOpts) error {
|
|||
}
|
||||
}
|
||||
|
||||
func runKu(a *App, opts shellOpts) (string, error) {
|
||||
bin, err := exec.LookPath("kubectl")
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("kubectl command is not in your path")
|
||||
return "", err
|
||||
}
|
||||
var args []string
|
||||
if u, err := a.Conn().Config().ImpersonateUser(); err == nil {
|
||||
args = append(args, "--as", u)
|
||||
}
|
||||
if g, err := a.Conn().Config().ImpersonateGroups(); err == nil {
|
||||
args = append(args, "--as-group", g)
|
||||
}
|
||||
args = append(args, "--context", a.Config.K9s.CurrentContext)
|
||||
if cfg := a.Conn().Config().Flags().KubeConfig; cfg != nil && *cfg != "" {
|
||||
args = append(args, "--kubeconfig", *cfg)
|
||||
}
|
||||
if len(args) > 0 {
|
||||
opts.args = append(args, opts.args...)
|
||||
}
|
||||
opts.binary, opts.background = bin, false
|
||||
|
||||
return oneShoot(opts)
|
||||
}
|
||||
|
||||
func oneShoot(opts shellOpts) (string, error) {
|
||||
if opts.clear {
|
||||
clearScreen()
|
||||
}
|
||||
|
||||
log.Debug().Msgf("Running command> %s %s", opts.binary, strings.Join(opts.args, " "))
|
||||
cmd := exec.Command(opts.binary, opts.args...)
|
||||
|
||||
var err error
|
||||
buff := bytes.NewBufferString("")
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, buff, buff
|
||||
_, _ = cmd.Stdout.Write([]byte(opts.banner))
|
||||
err = cmd.Run()
|
||||
log.Debug().Msgf("RES %q", buff)
|
||||
|
||||
return strings.Trim(buff.String(), "\n"), err
|
||||
}
|
||||
|
||||
func clearScreen() {
|
||||
fmt.Print("\033[H\033[2J")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ func (h *Help) showGeneral() model.MenuHints {
|
|||
Description: "Toggle Header",
|
||||
},
|
||||
{
|
||||
Mnemonic: "q",
|
||||
Mnemonic: ":q",
|
||||
Description: "Quit",
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ func (m *Meow) ExtraHints() map[string]string {
|
|||
}
|
||||
|
||||
func (m *Meow) updateTitle() {
|
||||
m.SetTitle(" Meow! ")
|
||||
m.SetTitle(" Error ")
|
||||
}
|
||||
|
||||
var cow = []string{
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ func miscViewers(vv MetaViewers) {
|
|||
vv[client.NewGVR("sanitizer")] = MetaViewer{
|
||||
viewerFn: NewSanitizer,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func appsViewers(vv MetaViewers) {
|
||||
|
|
|
|||
|
|
@ -103,8 +103,8 @@ func (f *Factory) HasSynced(gvr, ns string) (bool, error) {
|
|||
}
|
||||
|
||||
// Get retrieves a given resource.
|
||||
func (f *Factory) Get(gvr, path string, wait bool, sel labels.Selector) (runtime.Object, error) {
|
||||
ns, n := namespaced(path)
|
||||
func (f *Factory) Get(gvr, fqn string, wait bool, sel labels.Selector) (runtime.Object, error) {
|
||||
ns, n := namespaced(fqn)
|
||||
inf, err := f.CanForResource(ns, gvr, []string{client.GetVerb})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
Loading…
Reference in New Issue