more progress

pull/1/head
Jesse Duffield 5 years ago
parent bfa4d24810
commit 2d858955e6

@ -17,9 +17,7 @@ type Container struct {
// GetDisplayStrings returns the dispaly string of Container
func (c *Container) GetDisplayStrings(isFocused bool) []string {
displayName := utils.ColoredString(c.Name, c.GetColor())
return []string{c.ServiceName, displayName}
return []string{utils.ColoredString(c.Container.State, c.GetColor()), utils.ColoredString(c.Name, color.FgWhite)}
}
// GetColor Container color

@ -152,8 +152,6 @@ func (s *ContainerStats) CalculateContainerMemoryUsage() float64 {
// RenderStats returns a string containing the rendered stats of the container
func (s *ContainerStats) RenderStats(viewWidth int, cpuUsageHistory []float64, memoryUsageHistory []float64) (string, error) {
percentMemory := s.CalculateContainerMemoryUsage()
memoryUsageHistory = append(memoryUsageHistory, percentMemory)
memoryGraph := asciigraph.Plot(
memoryUsageHistory,
asciigraph.Height(10),
@ -163,22 +161,20 @@ func (s *ContainerStats) RenderStats(viewWidth int, cpuUsageHistory []float64, m
asciigraph.Caption(
fmt.Sprintf(
"%.2f%% Memory (%s/%s)",
percentMemory,
memoryUsageHistory[len(memoryUsageHistory)-1],
formatBinaryBytes(s.MemoryStats.Usage),
formatBinaryBytes(int(s.MemoryStats.Limit)),
),
),
)
percentageCPU := s.CalculateContainerCPUPercentage()
cpuUsageHistory = append(cpuUsageHistory, percentageCPU)
cpuGraph := asciigraph.Plot(
cpuUsageHistory,
asciigraph.Height(10),
asciigraph.Width(viewWidth-10),
asciigraph.Min(0),
asciigraph.Max(100),
asciigraph.Caption(fmt.Sprintf("%.2f%% CPU", percentageCPU)),
asciigraph.Caption(fmt.Sprintf("%.2f%% CPU", cpuUsageHistory[len(cpuUsageHistory)-1])),
)
pidsCount := fmt.Sprintf("PIDs: %d", s.PidsStats.Current)

@ -11,6 +11,7 @@ import (
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/i18n"
"github.com/sirupsen/logrus"
"golang.org/x/xerrors"
)
// DockerCommand is our main git interface
@ -60,3 +61,54 @@ func (c *DockerCommand) GetContainers() ([]*Container, error) {
return ownContainers, nil
}
type removeContainerConfig struct {
// RemoveVolumes removes any volumes attached to the container
RemoveVolumes bool
// Force forces the container to be removed, even if it's running
Force bool
}
type RemoveContainerOption func(c *removeContainerConfig)
// RemoveVolumes is an option to remove volumes attached to the container
func RemoveVolumes(c *removeContainerConfig) {
c.RemoveVolumes = true
}
// Force is an option to remove volumes attached to the container
func Force(c *removeContainerConfig) {
c.Force = true
}
// MustStopContainer tells us that we must stop the container before removing it
const MustStopContainer = iota
// RemoveContainer removes a container
func (c *DockerCommand) RemoveContainer(containerID string, options ...RemoveContainerOption) error {
config := &removeContainerConfig{}
for _, option := range options {
option(config)
}
flags := ""
if config.RemoveVolumes {
flags += " --volumes "
}
if config.Force {
flags += " --force "
}
err := c.OSCommand.RunCommand(fmt.Sprintf("docker rm %s %s", flags, containerID))
if err != nil {
if strings.Contains(err.Error(), "Stop the container before attempting removal or force remove") {
return ComplexError{
Code: MustStopContainer,
Message: err.Error(),
frame: xerrors.Caller(1),
}
}
return err
}
return nil
}

@ -1,6 +1,11 @@
package commands
import "github.com/go-errors/errors"
import (
"fmt"
"github.com/go-errors/errors"
"golang.org/x/xerrors"
)
// WrapError wraps an error for the sake of showing a stack trace at the top level
// the go-errors package, for some reason, does not return nil when you try to wrap
@ -12,3 +17,23 @@ func WrapError(err error) error {
return errors.Wrap(err, 0)
}
// ComplexError an error which carries a code so that calling code has an easier job to do
// adapted from https://medium.com/yakka/better-go-error-handling-with-xerrors-1987650e0c79
type ComplexError struct {
Message string
Code int
frame xerrors.Frame
}
func (ce ComplexError) FormatError(p xerrors.Printer) error {
p.Printf("%d %s", ce.Code, ce.Message)
ce.frame.Format(p)
return nil
}
func (ce ComplexError) Format(f fmt.State, c rune) {
xerrors.FormatError(ce, f, c)
}
func (ce ComplexError) Error() string {
return fmt.Sprint(ce)
}

@ -8,10 +8,12 @@ import (
"os/exec"
"time"
"github.com/fatih/color"
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/utils"
"golang.org/x/xerrors"
)
// list panel functions
@ -130,10 +132,12 @@ func (gui *Gui) renderStats(mainView *gocui.View, container *commands.Container,
var stats commands.ContainerStats
json.Unmarshal(data, &stats)
cpuUsageHistory = append(cpuUsageHistory, stats.CalculateContainerCPUPercentage())
if len(cpuUsageHistory) >= 20 {
cpuUsageHistory = cpuUsageHistory[1:]
}
memoryUsageHistory = append(memoryUsageHistory, stats.CalculateContainerMemoryUsage())
if len(memoryUsageHistory) >= 20 {
memoryUsageHistory = memoryUsageHistory[1:]
}
@ -281,3 +285,66 @@ func (gui *Gui) handleContainersNextContext(g *gocui.Gui, v *gocui.View) error {
return nil
}
type removeOption struct {
description string
command string
configOptions []commands.RemoveContainerOption
runCommand bool
}
// GetDisplayStrings is a function.
func (r *removeOption) GetDisplayStrings(isFocused bool) []string {
return []string{r.description, color.New(color.FgRed).Sprint(r.command)}
}
func (gui *Gui) handleContainersRemoveMenu(g *gocui.Gui, v *gocui.View) error {
container, err := gui.getSelectedContainer(g)
if err != nil {
return nil
}
options := []*removeOption{
{
description: gui.Tr.SLocalize("remove"),
command: "docker rm " + container.ID[1:10],
runCommand: true,
},
{
description: gui.Tr.SLocalize("removeWithVolumes"),
command: "docker rm --volumes " + container.ID[1:10],
configOptions: []commands.RemoveContainerOption{commands.RemoveVolumes},
runCommand: true,
},
{
description: gui.Tr.SLocalize("cancel"),
runCommand: false,
},
}
handleMenuPress := func(index int) error {
if !options[index].runCommand {
return nil
}
configOptions := options[index].configOptions
if cerr := gui.DockerCommand.RemoveContainer(container.ID, configOptions...); cerr != nil {
var originalErr commands.ComplexError
if xerrors.As(cerr, &originalErr) {
if originalErr.Code == commands.MustStopContainer {
return gui.createConfirmationPanel(gui.g, v, gui.Tr.SLocalize("Confirm"), gui.Tr.SLocalize("mustForceToRemove"), func(g *gocui.Gui, v *gocui.View) error {
if err := gui.DockerCommand.RemoveContainer(container.ID, append(configOptions, commands.Force)...); err != nil {
return err
}
return gui.refreshContainers()
}, nil)
}
} else {
return gui.createErrorPanel(gui.g, err.Error())
}
}
return gui.refreshContainers()
}
return gui.createMenu("", options, len(options), handleMenuPress)
}

@ -148,6 +148,11 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Key: ']',
Modifier: gocui.ModNone,
Handler: gui.handleContainersNextContext,
}, {
ViewName: "containers",
Key: 'd',
Modifier: gocui.ModNone,
Handler: gui.handleContainersRemoveMenu,
},
}

@ -760,5 +760,23 @@ func addEnglish(i18nObject *i18n.Bundle) error {
ID: "resetTo",
Other: `reset to`,
},
// ALL LAZYDOCKER STUFF BELOW:
&i18n.Message{
ID: "remove",
Other: `remove`,
},
&i18n.Message{
ID: "removeWithVolumes",
Other: `remove with volumes`,
},
&i18n.Message{
ID: "mustForceToRemove",
Other: "You cannot remove a running container unless you force it. Do you want to force it?",
},
&i18n.Message{
ID: "Confirm",
Other: "Confirm",
},
)
}

Loading…
Cancel
Save