mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-22 07:11:01 +00:00
much more stuff
This commit is contained in:
parent
9a5a01dfbd
commit
b65df625f4
8 changed files with 151 additions and 7 deletions
|
|
@ -254,7 +254,17 @@ type ContainerCliStat struct {
|
|||
|
||||
// GetDisplayStrings returns the dispaly string of Container
|
||||
func (c *Container) GetDisplayStrings(isFocused bool) []string {
|
||||
return []string{utils.ColoredString(c.Container.State, c.GetColor()), utils.ColoredString(c.Name, color.FgWhite), c.GetDisplayCPUPerc()}
|
||||
return []string{c.GetDisplayStatus(), utils.ColoredString(c.Name, color.FgWhite), c.GetDisplayCPUPerc()}
|
||||
}
|
||||
|
||||
// GetDisplayStatus returns the colored status of the container
|
||||
func (c *Container) GetDisplayStatus() string {
|
||||
state := c.Container.State
|
||||
if c.Container.State == "exited" {
|
||||
state += " (" + strconv.Itoa(c.Details.State.ExitCode) + ")"
|
||||
}
|
||||
|
||||
return utils.ColoredString(state, c.GetColor())
|
||||
}
|
||||
|
||||
// GetDisplayCPUPerc colors the cpu percentage based on how extreme it is
|
||||
|
|
@ -292,6 +302,9 @@ func (c *Container) ProducingLogs() bool {
|
|||
func (c *Container) GetColor() color.Attribute {
|
||||
switch c.Container.State {
|
||||
case "exited":
|
||||
if c.Details.State.ExitCode == 0 {
|
||||
return color.FgBlue
|
||||
}
|
||||
return color.FgRed
|
||||
case "created":
|
||||
return color.FgCyan
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
|
|
@ -366,3 +367,13 @@ func (c *OSCommand) PipeCommands(commandStrings ...string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Kill kills a process. If the process has Setpgid == true, then we have anticipated that it might spawn its own child processes, so we've given it a process group ID (PGID) equal to its process id (PID) and given its child processes will inherit the PGID, we can kill that group, rather than killing the process itself.
|
||||
func (c *OSCommand) Kill(cmd *exec.Cmd) error {
|
||||
if cmd.SysProcAttr != nil && cmd.SysProcAttr.Setpgid == true {
|
||||
// minus sign means we're talking about a PGID as opposed to a PID
|
||||
return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
|
||||
}
|
||||
|
||||
return cmd.Process.Kill()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ func (s *Service) GetDisplayStrings(isFocused bool) []string {
|
|||
}
|
||||
|
||||
cont := s.Container
|
||||
return []string{utils.ColoredString(cont.Container.State, cont.GetColor()), utils.ColoredString(s.Name, color.FgWhite), cont.GetDisplayCPUPerc()}
|
||||
return []string{cont.GetDisplayStatus(), utils.ColoredString(s.Name, color.FgWhite), cont.GetDisplayCPUPerc()}
|
||||
}
|
||||
|
||||
// Remove removes the service's containers
|
||||
|
|
@ -68,7 +68,6 @@ func (s *Service) ViewLogs() (*exec.Cmd, error) {
|
|||
// so long as this is commented in, the child process does not receive the interrupt
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
Setpgid: true,
|
||||
Pgid: 0,
|
||||
}
|
||||
|
||||
return cmd, nil
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ type CommandTemplatesConfig struct {
|
|||
RebuildService string `yaml:"rebuildService,omitempty"`
|
||||
ContainerLogs string `yaml:"containerLogs,omitempty"`
|
||||
ContainerTTYLogs string `yaml:"containerTTYLogs,omitempty"`
|
||||
AllLogs string `yaml:"allLogs,omitempty"`
|
||||
}
|
||||
|
||||
type OSConfig struct {
|
||||
|
|
@ -164,6 +165,7 @@ func GetDefaultConfig() UserConfig {
|
|||
ServiceLogs: "apdev logs {{ .Name }}",
|
||||
ContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .ID }}",
|
||||
ContainerTTYLogs: "docker logs --follow --tail=100 {{ .ID }}",
|
||||
AllLogs: "apdev logs --tail=100",
|
||||
},
|
||||
OS: GetPlatformDefaultConfig(),
|
||||
Update: UpdateConfig{
|
||||
|
|
|
|||
|
|
@ -77,6 +77,10 @@ type containerPanelState struct {
|
|||
ContextIndex int // for specifying if you are looking at logs/stats/config/etc
|
||||
}
|
||||
|
||||
type statusState struct {
|
||||
ContextIndex int // for specifying if you are looking at credits/logs
|
||||
}
|
||||
|
||||
type menuPanelState struct {
|
||||
SelectedLine int
|
||||
}
|
||||
|
|
@ -96,6 +100,7 @@ type panelStates struct {
|
|||
Menu *menuPanelState
|
||||
Main *mainPanelState
|
||||
Images *imagePanelState
|
||||
Status *statusState
|
||||
}
|
||||
|
||||
type guiState struct {
|
||||
|
|
@ -121,6 +126,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
|||
Main: &mainPanelState{
|
||||
ObjectKey: "",
|
||||
},
|
||||
Status: &statusState{ContextIndex: 0},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,20 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
Handler: gui.handleOpenConfig,
|
||||
Description: gui.Tr.OpenConfig,
|
||||
},
|
||||
{
|
||||
ViewName: "status",
|
||||
Key: '[',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleStatusPrevContext,
|
||||
Description: gui.Tr.PreviousContext,
|
||||
},
|
||||
{
|
||||
ViewName: "status",
|
||||
Key: ']',
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleStatusNextContext,
|
||||
Description: gui.Tr.NextContext,
|
||||
},
|
||||
{
|
||||
ViewName: "menu",
|
||||
Key: gocui.KeyEsc,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,16 @@ package gui
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
func (gui *Gui) getStatusContexts() []string {
|
||||
return []string{"logs", "credits"}
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshStatus() error {
|
||||
v := gui.getStatusView()
|
||||
|
||||
|
|
@ -28,6 +34,36 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
|
|||
return err
|
||||
}
|
||||
|
||||
key := gui.getStatusContexts()[gui.State.Panels.Status.ContextIndex]
|
||||
if gui.State.Panels.Main.ObjectKey == key {
|
||||
return nil
|
||||
} else {
|
||||
gui.State.Panels.Main.ObjectKey = key
|
||||
}
|
||||
|
||||
gui.clearMainView()
|
||||
|
||||
switch gui.getStatusContexts()[gui.State.Panels.Status.ContextIndex] {
|
||||
case "credits":
|
||||
if err := gui.renderCredits(); err != nil {
|
||||
return err
|
||||
}
|
||||
case "logs":
|
||||
if err := gui.renderAllLogs(); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("Unknown context for status panel")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) renderCredits() error {
|
||||
mainView := gui.getMainView()
|
||||
mainView.Autoscroll = false
|
||||
mainView.Title = "about"
|
||||
|
||||
dashboardString := strings.Join(
|
||||
[]string{
|
||||
lazydockerTitle(),
|
||||
|
|
@ -37,7 +73,40 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
|
|||
"Raise an Issue: https://github.com/jesseduffield/lazydocker/issues",
|
||||
}, "\n\n")
|
||||
|
||||
return gui.renderString(g, "main", dashboardString)
|
||||
go gui.T.NewTask(func(stop chan struct{}) {
|
||||
gui.renderString(gui.g, "main", dashboardString)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) renderAllLogs() error {
|
||||
mainView := gui.getMainView()
|
||||
mainView.Autoscroll = true
|
||||
mainView.Title = "logs"
|
||||
|
||||
go gui.T.NewTask(func(stop chan struct{}) {
|
||||
gui.clearMainView()
|
||||
|
||||
cmd := gui.OSCommand.RunCustomCommand(gui.Config.UserConfig.CommandTemplates.AllLogs)
|
||||
|
||||
cmd.Stdout = mainView
|
||||
cmd.Stderr = mainView
|
||||
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
cmd.Start()
|
||||
|
||||
go func() {
|
||||
<-stop
|
||||
if err := gui.OSCommand.Kill(cmd); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
cmd.Wait()
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleOpenConfig(g *gocui.Gui, v *gocui.View) error {
|
||||
|
|
@ -60,3 +129,29 @@ func lazydockerTitle() string {
|
|||
|___/
|
||||
`
|
||||
}
|
||||
|
||||
func (gui *Gui) handleStatusPrevContext(g *gocui.Gui, v *gocui.View) error {
|
||||
contexts := gui.getStatusContexts()
|
||||
if gui.State.Panels.Status.ContextIndex >= len(contexts)-1 {
|
||||
gui.State.Panels.Status.ContextIndex = 0
|
||||
} else {
|
||||
gui.State.Panels.Status.ContextIndex++
|
||||
}
|
||||
|
||||
gui.handleStatusSelect(gui.g, v)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleStatusNextContext(g *gocui.Gui, v *gocui.View) error {
|
||||
contexts := gui.getStatusContexts()
|
||||
if gui.State.Panels.Status.ContextIndex <= 0 {
|
||||
gui.State.Panels.Status.ContextIndex = len(contexts) - 1
|
||||
} else {
|
||||
gui.State.Panels.Status.ContextIndex--
|
||||
}
|
||||
|
||||
gui.handleStatusSelect(gui.g, v)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ func (gui *Gui) RunWithSubprocesses() error {
|
|||
if err == gocui.ErrQuit {
|
||||
break
|
||||
} else if err == gui.Errors.ErrSubProcess {
|
||||
// preparing the state for when we return
|
||||
gui.State.PreviousView = gui.currentViewName()
|
||||
gui.State.Panels.Main.ObjectKey = ""
|
||||
|
||||
if err := gui.runCommand(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -33,8 +37,6 @@ func (gui *Gui) RunWithSubprocesses() error {
|
|||
}
|
||||
|
||||
func (gui *Gui) runCommand() error {
|
||||
gui.State.PreviousView = gui.currentViewName()
|
||||
|
||||
gui.SubProcess.Stdout = os.Stdout
|
||||
gui.SubProcess.Stderr = os.Stdout
|
||||
gui.SubProcess.Stdin = os.Stdin
|
||||
|
|
@ -46,7 +48,9 @@ func (gui *Gui) runCommand() error {
|
|||
<-c
|
||||
signal.Stop(c)
|
||||
|
||||
gui.SubProcess.Process.Kill()
|
||||
if err := gui.OSCommand.Kill(gui.SubProcess); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
fmt.Fprintf(os.Stdout, "\n%s\n\n", utils.ColoredString("+ "+strings.Join(gui.SubProcess.Args, " "), color.FgBlue))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue