Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render container stats and configs as yaml #444

Merged
merged 5 commits into from
May 21, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/boz/go-throttle v0.0.0-20160922054636-fdc4eab740c1
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/docker/docker v20.10.15+incompatible
github.com/fatih/color v1.7.0
github.com/fatih/color v1.10.0
github.com/go-errors/errors v1.4.2
github.com/gookit/color v1.5.0
github.com/imdario/mergo v0.3.8
Expand Down Expand Up @@ -37,11 +37,12 @@ require (
github.com/docker/go-units v0.4.0 // indirect
github.com/gdamore/encoding v1.0.0 // indirect
github.com/gdamore/tcell/v2 v2.5.3 // indirect
github.com/goccy/go-yaml v1.11.0
github.com/gogo/protobuf v1.3.2 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.11 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
github.com/onsi/ginkgo v1.8.0 // indirect
Expand All @@ -54,7 +55,7 @@ require (
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 // indirect
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/term v0.1.0 // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
Expand All @@ -31,6 +33,8 @@ github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tv
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54=
github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -67,9 +71,13 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
Expand Down Expand Up @@ -153,6 +161,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -161,6 +171,8 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand Down
5 changes: 5 additions & 0 deletions pkg/config/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ type GuiConfig struct {
// When true, increases vertical space used by focused side panel,
// creating an accordion effect
ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`

// DetailsFormat determines in which format will be printed container stats and configs
// By default "yaml", available values "json", "yaml"
DetailsFormat string `yaml:"detailsFormat,omitempty"`
}

// CommandTemplatesConfig determines what commands actually get called when we
Expand Down Expand Up @@ -362,6 +366,7 @@ func GetDefaultConfig() UserConfig {
SidePanelWidth: 0.3333,
ShowBottomLine: true,
ExpandFocusedSidePanel: false,
DetailsFormat: "yaml",
},
ConfirmOnQuit: false,
Logs: LogsConfig{
Expand Down
5 changes: 2 additions & 3 deletions pkg/gui/containers_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package gui

import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
Expand Down Expand Up @@ -200,12 +199,12 @@ func (gui *Gui) containerConfigStr(container *commands.Container) string {
output += "none\n"
}

data, err := json.MarshalIndent(&container.Details, "", " ")
data, err := utils.MarshalIntoFormat(&container.Details, gui.Config.UserConfig.Gui.DetailsFormat)
if err != nil {
return fmt.Sprintf("Error marshalling container details: %v", err)
}

output += fmt.Sprintf("\nFull details:\n\n%s", string(data))
output += fmt.Sprintf("\nFull details:\n\n%s", utils.ColoredYamlString(string(data)))

return output
}
Expand Down
5 changes: 2 additions & 3 deletions pkg/gui/presentation/container_stats.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package presentation

import (
"encoding/json"
"fmt"
"math"
"reflect"
Expand Down Expand Up @@ -38,7 +37,7 @@ func RenderStats(userConfig *config.UserConfig, container *commands.Container, v
dataReceived := fmt.Sprintf("Traffic received: %s", utils.FormatDecimalBytes(stats.ClientStats.Networks.Eth0.RxBytes))
dataSent := fmt.Sprintf("Traffic sent: %s", utils.FormatDecimalBytes(stats.ClientStats.Networks.Eth0.TxBytes))

originalJSON, err := json.MarshalIndent(stats, "", " ")
originalStats, err := utils.MarshalIntoFormat(stats, userConfig.Gui.DetailsFormat)
if err != nil {
return "", err
}
Expand All @@ -48,7 +47,7 @@ func RenderStats(userConfig *config.UserConfig, container *commands.Container, v
pidsCount,
dataReceived,
dataSent,
string(originalJSON),
utils.ColoredYamlString(string(originalStats)),
)

return contents, nil
Expand Down
6 changes: 4 additions & 2 deletions pkg/gui/project_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (gui *Gui) creditsStr() string {
"Raise an Issue: https://github.com/jesseduffield/lazydocker/issues",
utils.ColoredString("Buy Jesse a coffee: https://github.com/sponsors/jesseduffield", color.FgMagenta), // caffeine ain't free
"Here's your lazydocker config when merged in with the defaults (you can open your config by pressing 'o'):",
configBuf.String(),
utils.ColoredYamlString(configBuf.String()),
}, "\n\n")
}

Expand Down Expand Up @@ -145,7 +145,9 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
}

func (gui *Gui) renderDockerComposeConfig(_project *commands.Project) tasks.TaskFunc {
return gui.NewSimpleRenderStringTask(func() string { return gui.DockerCommand.DockerComposeConfig() })
return gui.NewSimpleRenderStringTask(func() string {
return utils.ColoredYamlString(gui.DockerCommand.DockerComposeConfig())
})
}

func (gui *Gui) handleOpenConfig(g *gocui.Gui, v *gocui.View) error {
Expand Down
65 changes: 65 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package utils

import (
"bytes"
"encoding/json"
"fmt"
"html/template"
"io"
Expand All @@ -14,7 +15,12 @@ import (
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"

// "github.com/jesseduffield/yaml"

"github.com/fatih/color"
"github.com/goccy/go-yaml"
"github.com/goccy/go-yaml/lexer"
"github.com/goccy/go-yaml/printer"
)

// SplitLines takes a multiline string and splits it on newlines
Expand Down Expand Up @@ -52,6 +58,45 @@ func ColoredString(str string, colorAttribute color.Attribute) string {
return ColoredStringDirect(str, colour)
}

// ColoredYamlString takes an YAML formatted string and returns a colored string
// with colors hardcoded as:
// keys: cyan
// Booleans: magenta
// Numbers: yellow
// Strings: green
func ColoredYamlString(str string) string {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a unit test for this? (Accidentally just left this as a general comment cos I'm reviewing from phone :) )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jesseduffield sure, done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And sadly, i don't get about scrapping "the JSON-related code" :c

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is, let's remove DetailsFormat and always use yaml formatting.

format := func(attr color.Attribute) string {
return fmt.Sprintf("%s[%dm", "\x1b", attr)
}
tokens := lexer.Tokenize(str)
var p printer.Printer
p.Bool = func() *printer.Property {
return &printer.Property{
Prefix: format(color.FgMagenta),
Suffix: format(color.Reset),
}
}
p.Number = func() *printer.Property {
return &printer.Property{
Prefix: format(color.FgYellow),
Suffix: format(color.Reset),
}
}
p.MapKey = func() *printer.Property {
return &printer.Property{
Prefix: format(color.FgCyan),
Suffix: format(color.Reset),
}
}
p.String = func() *printer.Property {
return &printer.Property{
Prefix: format(color.FgGreen),
Suffix: format(color.Reset),
}
}
return p.PrintTokens(tokens)
}

// MultiColoredString takes a string and an array of colour attributes and returns a colored
// string with those attributes
func MultiColoredString(str string, colorAttribute ...color.Attribute) string {
Expand Down Expand Up @@ -339,3 +384,23 @@ func IsValidHexValue(v string) bool {
func OpensMenuStyle(str string) string {
return ColoredString(fmt.Sprintf("%s...", str), color.FgMagenta)
}

func MarshalIntoFormat(data interface{}, format string) ([]byte, error) {
dataJSON, err := json.MarshalIndent(data, "", " ")
if err != nil {
return nil, err
}
switch format {
case "json":
return dataJSON, err
case "yaml":
// Use Unmarshal->Marshal hack to convert vendor-locked objects to YAML with same structure as JSON
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain a bit more about what's happening here? What do you mean by vendor locked?

Copy link
Contributor Author

@tony-sol tony-sol May 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, container.Details declared in vendor/github.com/docker/docker/api/types/stats.go already has json tags, but not yaml.

So, in order to keep ./vendor/ files consistent and not changed in any inappropriate way, like

-- CPUUsage CPUUsage `json:"cpu_usage"`
++ CPUUsage CPUUsage `json:"cpu_usage" yaml:"cpu_usage"`

and keep the resulting yaml structure exactly as json is, let's at first marshal into json as tagged, then into "any" yaml

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that makes sense. Could you capture that in a comment in the code?

var dataMirror yaml.MapSlice
if err := yaml.Unmarshal(dataJSON, &dataMirror); err != nil {
return nil, err
}
return yaml.Marshal(dataMirror)
default:
return nil, errors.New(fmt.Sprintf("Unsupported detailization format: %s", format))
}
}
62 changes: 62 additions & 0 deletions pkg/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,65 @@ func TestRenderTable(t *testing.T) {
}
}
}

func TestMarshalIntoFormat(t *testing.T) {
type innerData struct {
Foo int `json:"foo"`
Bar string `json:"bar"`
Baz bool `json:"baz"`
}
type data struct {
Qux int `json:"quz"`
Quux innerData `json:"quux"`
}

type scenario struct {
input data
format string
expected []byte
expectedErr error
}

scenarios := []scenario{
{
input: data{1, innerData{2, "foo", true}},
format: "json",
expected: []byte(`{
"quz": 1,
"quux": {
"foo": 2,
"bar": "foo",
"baz": true
}
}`),
expectedErr: nil,
},
{
input: data{1, innerData{2, "foo", true}},
format: "yaml",
expected: []byte(`quz: 1
quux:
bar: foo
baz: true
foo: 2
`),
expectedErr: nil,
},
{
input: data{1, innerData{2, "foo", true}},
format: "xml",
expected: nil,
expectedErr: errors.New("Unsupported detailization format: xml"),
},
}

for _, s := range scenarios {
output, err := MarshalIntoFormat(s.input, s.format)
assert.EqualValues(t, s.expected, output)
if s.expectedErr != nil {
assert.EqualError(t, err, s.expectedErr.Error())
} else {
assert.NoError(t, err)
}
}
}
5 changes: 0 additions & 5 deletions vendor/github.com/fatih/color/.travis.yml

This file was deleted.

27 changes: 0 additions & 27 deletions vendor/github.com/fatih/color/Gopkg.lock

This file was deleted.

30 changes: 0 additions & 30 deletions vendor/github.com/fatih/color/Gopkg.toml

This file was deleted.

Loading