added yaml syntax color + secret decoding + bugz

mine
derailed 2019-03-31 09:37:03 -06:00
parent d72166ccbf
commit 8924f6002d
12 changed files with 265 additions and 28 deletions

11
go.mod
View File

@ -3,12 +3,18 @@ module github.com/derailed/k9s
require (
contrib.go.opencensus.io/exporter/ocagent v0.4.3 // indirect
github.com/Azure/go-autorest v11.4.0+incompatible // indirect
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e // indirect
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
github.com/derailed/tview v0.1.4
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v1.13.1 // indirect
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect
github.com/evanphx/json-patch v4.1.0+incompatible // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fatih/camelcase v1.0.0 // indirect
github.com/gdamore/tcell v1.1.1
github.com/go-openapi/spec v0.19.0 // indirect
github.com/gogo/protobuf v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
@ -21,6 +27,7 @@ require (
github.com/json-iterator/go v1.1.5 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/mattn/go-runewidth v0.0.4
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/onsi/gomega v1.4.3 // indirect
@ -29,6 +36,8 @@ require (
github.com/petergtz/pegomock v0.0.0-20181206220228-b113d17a7e81
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 // indirect
github.com/rs/zerolog v1.12.0
github.com/russross/blackfriday v2.0.0+incompatible // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/sirupsen/logrus v1.4.0 // indirect
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3 // indirect
@ -51,5 +60,5 @@ require (
k8s.io/metrics v0.0.0-20181121073115-d8618695b08f
k8s.io/utils v0.0.0-20190212002617-cdba02414f76 // indirect
sigs.k8s.io/structured-merge-diff v0.0.0-20190130003954-e5e029740eb8 // indirect
sigs.k8s.io/yaml v1.1.0 // indirect
sigs.k8s.io/yaml v1.1.0
)

31
go.sum
View File

@ -7,10 +7,18 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
git.apache.org/thrift.git v0.0.0-20181218151757-9b75e4fe745a/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/Azure/go-autorest v11.4.0+incompatible h1:z3Yr6KYqs0nhSNwqGXEBpWK977hxVqsLv2n9PVYcixY=
github.com/Azure/go-autorest v11.4.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA=
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/census-instrumentation/opencensus-proto v0.1.0-0.20181214143942-ba49f56771b8 h1:gUqsFVdUKoRHNg8fkFd8gB5OOEa/g5EwlAHznb4zjbI=
github.com/census-instrumentation/opencensus-proto v0.1.0-0.20181214143942-ba49f56771b8/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 h1:HD4PLRzjuCVW79mQ0/pdsalOLHJ+FaEoqJLxfltpb2U=
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -22,8 +30,14 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc=
github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
@ -33,6 +47,14 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo
github.com/gdamore/tcell v1.1.1 h1:U73YL+jMem2XfhvaIUfPO6MpJawaG92B2funXVb9qLs=
github.com/gdamore/tcell v1.1.1/go.mod h1:K1udHkiR3cOtlpKG5tZPD5XxrF7v2y7lDq7Whcj+xkQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonreference v0.17.0 h1:yJW3HCkTHg7NOA+gZ83IPHzUSnUzGXhGmsdiCcMexbA=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4=
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
@ -77,10 +99,14 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08 h1:5MnxBC15uMxFv5FY/J/8vzyaBiArCOkMdFT9Jsw78iY=
github.com/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08/go.mod h1:NXg0ArsFk0Y01623LgUqoqcouGDB+PwCCQlrwrG6xJ4=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
@ -117,6 +143,10 @@ github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 h1:x7xEyJDP7Hv3LVgvWhz
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rs/zerolog v1.12.0 h1:aqZ1XRadoS8IBknR5IDFvGzbHly1X9ApIqOroooQF/c=
github.com/rs/zerolog v1.12.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.0 h1:yKenngtzGh+cUSSh6GWbxW2abRqhYUSR/t/6+2QqNvE=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@ -139,6 +169,7 @@ golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181217023233-e147a9138326 h1:iCzOf0xz39Tstp+Tu/WwyGjUXCk34QhQORRxBeXXTA4=

View File

@ -26,11 +26,6 @@ type detailsView struct {
numSelections int
}
var (
regionRX = regexp.MustCompile(`\["([a-zA-Z0-9_,;: \-\.]*)"\]`)
escapeRX = regexp.MustCompile(`\[([a-zA-Z0-9_,;: \-\."#]+)\[(\[*)\]`)
)
func newDetailsView(app *appView, backFn actionHandler) *detailsView {
v := detailsView{TextView: tview.NewTextView(), app: app, actions: make(keyActions)}
{
@ -53,8 +48,6 @@ func newDetailsView(app *appView, backFn actionHandler) *detailsView {
})
}
// v.actions[KeySlash] = newKeyAction("Search", v.activateCmd)
// v.actions[tcell.KeyEnter] = newKeyAction("Search", v.searchCmd)
v.actions[tcell.KeyBackspace2] = newKeyAction("Erase", v.eraseCmd, false)
v.actions[tcell.KeyBackspace] = newKeyAction("Erase", v.eraseCmd, false)
v.actions[tcell.KeyDelete] = newKeyAction("Erase", v.eraseCmd, false)
@ -207,6 +200,11 @@ func (v *detailsView) setTitle(t string) {
v.SetTitle(title)
}
var (
regionRX = regexp.MustCompile(`\["([a-zA-Z0-9_,;: \-\.]*)"\]`)
escapeRX = regexp.MustCompile(`\[([a-zA-Z0-9_,;: \-\."#]+)\[(\[*)\]`)
)
func (v *detailsView) decorateLines(buff, q string) string {
rx := regexp.MustCompile(`(?i)` + q)
lines := strings.Split(buff, "\n")

View File

@ -27,7 +27,7 @@ func newLogView(title string, parent loggable) *logView {
}
func (l *logView) logLine(line string) {
fmt.Fprintln(l.ansiWriter, line)
fmt.Fprintln(l.ansiWriter, tview.Escape(line))
}
func (l *logView) log(lines fmt.Stringer) {

View File

@ -0,0 +1,24 @@
package views
import (
"bytes"
"fmt"
"testing"
"github.com/derailed/tview"
"github.com/stretchr/testify/assert"
)
func TestAnsi(t *testing.T) {
buff := bytes.NewBufferString("")
w := tview.ANSIWriter(buff)
fmt.Fprintf(w, "[YELLOW] ok")
assert.Equal(t, "[YELLOW] ok", buff.String())
v := tview.NewTextView()
v.SetDynamicColors(true)
aw := tview.ANSIWriter(v)
s := "[2019-03-27T15:05:15,246][INFO ][o.e.c.r.a.AllocationService] [es-0] Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[.monitoring-es-6-2019.03.27][0]]"
fmt.Fprintf(aw, s)
assert.Equal(t, s+"\n", v.GetText(false))
}

View File

@ -270,7 +270,7 @@ func resourceViews(c k8s.Connection) map[string]resCmd {
"sec": {
title: "Secrets",
api: "",
viewFn: newResourceView,
viewFn: newSecretView,
listFn: resource.NewSecretList,
},
"sts": {

View File

@ -190,7 +190,7 @@ func (v *resourceView) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
func (v *resourceView) defaultEnter(app *appView, ns, resource, selection string) {
sel := v.getSelectedItem()
raw, err := v.list.Resource().Describe(v.title, sel, v.app.flags)
yaml, err := v.list.Resource().Describe(v.title, sel, v.app.flags)
if err != nil {
v.app.flash(flashErr, err.Error())
log.Warn().Msgf("Describe %v", err.Error())
@ -202,7 +202,7 @@ func (v *resourceView) defaultEnter(app *appView, ns, resource, selection string
details.setCategory("Describe")
details.setTitle(sel)
details.SetTextColor(tcell.ColorAqua)
details.SetText(string(raw))
details.SetText(colorizeYAML(yaml))
details.ScrollToBeginning()
}
v.switchPage("details")
@ -212,7 +212,6 @@ func (v *resourceView) describeCmd(evt *tcell.EventKey) *tcell.EventKey {
if !v.rowSelected() {
return evt
}
v.defaultEnter(v.app, v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
return nil
@ -234,7 +233,7 @@ func (v *resourceView) viewCmd(evt *tcell.EventKey) *tcell.EventKey {
details.setCategory("View")
details.setTitle(sel)
details.SetTextColor(tcell.ColorMediumAquamarine)
details.SetText(string(raw))
details.SetText(colorizeYAML(raw))
details.ScrollToBeginning()
}
v.switchPage("details")
@ -345,9 +344,12 @@ func (v *resourceView) switchPage(p string) {
{
v.SwitchToPage(p)
v.selectedNS = v.list.GetNamespace()
h := v.GetPrimitive(p).(hinter)
v.app.setHints(h.hints())
v.app.SetFocus(v.CurrentPage().Item)
if h, ok := v.GetPrimitive(p).(hinter); ok {
v.app.setHints(h.hints())
v.app.SetFocus(v.CurrentPage().Item)
} else {
log.Error().Msgf("Hinter not implemented on %s", p)
}
}
v.update.Unlock()
}

65
internal/views/secret.go Normal file
View File

@ -0,0 +1,65 @@
package views
import (
"sigs.k8s.io/yaml"
"github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell"
"github.com/rs/zerolog/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type secretView struct {
*resourceView
}
func newSecretView(t string, app *appView, list resource.List) resourceViewer {
v := secretView{newResourceView(t, app, list).(*resourceView)}
{
v.extraActionsFn = v.extraActions
v.switchPage("secret")
}
return &v
}
func (v *secretView) extraActions(aa keyActions) {
aa[tcell.KeyCtrlX] = newKeyAction("Decode", v.decodeCmd, true)
}
func (v *secretView) decodeCmd(evt *tcell.EventKey) *tcell.EventKey {
if !v.rowSelected() {
return evt
}
sel := v.getSelectedItem()
ns, n := namespaced(sel)
sec, err := v.app.conn().DialOrDie().CoreV1().Secrets(ns).Get(n, metav1.GetOptions{})
if err != nil {
v.app.flash(flashErr, "Unable to retrieve secret", sel)
return evt
}
d := make(map[string]string, len(sec.Data))
for k, val := range sec.Data {
d[k] = string(val)
}
raw, err := yaml.Marshal(d)
if err != nil {
v.app.flash(flashErr, "Error decoding secret for `", sel)
log.Error().Err(err).Msgf("Marshal error getting secret %s", sel)
return nil
}
details := v.GetPrimitive("details").(*detailsView)
{
details.setCategory("Decoder")
details.setTitle(sel)
details.SetTextColor(tcell.ColorMediumAquamarine)
details.SetText(colorizeYAML(string(raw)))
details.ScrollToBeginning()
}
v.switchPage("details")
return nil
}

View File

@ -4,8 +4,10 @@ import (
"regexp"
"strconv"
"strings"
"time"
"github.com/derailed/k9s/internal/resource"
res "k8s.io/apimachinery/pkg/api/resource"
)
type rowSorter struct {
@ -53,6 +55,10 @@ func less(asc bool, c1, c2 string) bool {
return o
}
if o, ok := isDurationSort(asc, c1, c2); ok {
return o
}
if o, ok := isIntegerSort(asc, c1, c2); ok {
return o
}
@ -64,18 +70,30 @@ func less(asc bool, c1, c2 string) bool {
return c > 0
}
func isMetricSort(asc bool, c1, c2 string) (bool, bool) {
m1, ok := isMetric(c1)
if !ok {
func isDurationSort(asc bool, c1, c2 string) (bool, bool) {
d1, ok1 := isDuration(c1)
d2, ok2 := isDuration(c2)
if !ok1 || !ok2 {
return false, false
}
m2, _ := isMetric(c2)
i1, _ := strconv.Atoi(m1)
i2, _ := strconv.Atoi(m2)
if asc {
return i1 < i2, true
return d1 < d2, true
}
return i1 > i2, true
return d1 > d2, true
}
func isMetricSort(asc bool, c1, c2 string) (bool, bool) {
q1, err1 := res.ParseQuantity(c1)
q2, err2 := res.ParseQuantity(c2)
if err1 != nil || err2 != nil {
return false, false
}
if asc {
return q1.Cmp(q2) <= 0, true
}
return q1.Cmp(q2) > 0, true
}
func isIntegerSort(asc bool, c1, c2 string) (bool, bool) {
@ -98,3 +116,11 @@ func isMetric(s string) (string, bool) {
}
return s, false
}
func isDuration(s string) (time.Duration, bool) {
d, err := time.ParseDuration(s)
if err != nil {
return d, false
}
return d, true
}

View File

@ -22,6 +22,8 @@ func TestGroupSort(t *testing.T) {
{false, []string{"100Mi", "10Mi"}, []string{"100Mi", "10Mi"}},
{true, []string{"xyz", "abc"}, []string{"abc", "xyz"}},
{false, []string{"xyz", "abc"}, []string{"xyz", "abc"}},
{true, []string{"2m30s", "1m10s"}, []string{"1m10s", "2m30s"}},
{true, []string{"3d", "1d"}, []string{"1d", "3d"}},
}
for _, u := range uu {
@ -33,9 +35,8 @@ func TestGroupSort(t *testing.T) {
func TestRowSort(t *testing.T) {
uu := []struct {
order bool
rows resource.Rows
expect resource.Rows
order bool
rows, expect resource.Rows
}{
{
true,

35
internal/views/yaml.go Normal file
View File

@ -0,0 +1,35 @@
package views
import (
"fmt"
"regexp"
"strings"
)
var (
keyValRX = regexp.MustCompile(`\A(\s*)([\w|\-|\.|\s]+):\s(.+)\z`)
keyRX = regexp.MustCompile(`\A(\s*)([\w|\-|\.|\s]+):\s*\z`)
)
func colorizeYAML(raw string) string {
lines := strings.Split(raw, "\n")
buff := make([]string, 0, len(lines))
for _, l := range lines {
res := keyValRX.FindStringSubmatch(l)
if len(res) == 4 {
buff = append(buff, fmt.Sprintf("%s[steelblue::b]%s[white::-]: [papayawhip::]%s", res[1], res[2], res[3]))
continue
}
res = keyRX.FindStringSubmatch(l)
if len(res) == 3 {
buff = append(buff, fmt.Sprintf("%s[steelblue::b]%s[white::-]:", res[1], res[2]))
continue
}
buff = append(buff, fmt.Sprintf("[papayawhip::]%s", l))
}
return strings.Join(buff, "\n")
}

View File

@ -0,0 +1,46 @@
package views
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestYaml(t *testing.T) {
uu := []struct {
s, e string
}{
{
`api: fred
version: v1`,
`[steelblue::b]api[white::-]: [papayawhip::]fred
[steelblue::b]version[white::-]: [papayawhip::]v1`,
},
{
`api:
version: v1`,
`[steelblue::b]api[white::-]:
[steelblue::b]version[white::-]: [papayawhip::]v1`,
},
{
" fred:blee",
"[papayawhip::] fred:blee",
},
{
"fred blee: blee",
"[steelblue::b]fred blee[white::-]: [papayawhip::]blee",
},
{
"Node-Selectors: <none>",
"[steelblue::b]Node-Selectors[white::-]: [papayawhip::] <none>",
},
{
"fred.blee: <none>",
"[steelblue::b]fred.blee[white::-]: [papayawhip::] <none>",
},
}
for _, u := range uu {
assert.Equal(t, u.e, colorizeYAML(u.s))
}
}