mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-24 16:11:04 +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
|
// GetDisplayStrings returns the dispaly string of Container
|
||||||
func (c *Container) GetDisplayStrings(isFocused bool) []string {
|
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
|
// 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 {
|
func (c *Container) GetColor() color.Attribute {
|
||||||
switch c.Container.State {
|
switch c.Container.State {
|
||||||
case "exited":
|
case "exited":
|
||||||
|
if c.Details.State.ExitCode == 0 {
|
||||||
|
return color.FgBlue
|
||||||
|
}
|
||||||
return color.FgRed
|
return color.FgRed
|
||||||
case "created":
|
case "created":
|
||||||
return color.FgCyan
|
return color.FgCyan
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
|
@ -366,3 +367,13 @@ func (c *OSCommand) PipeCommands(commandStrings ...string) error {
|
||||||
}
|
}
|
||||||
return nil
|
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
|
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
|
// 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
|
// so long as this is commented in, the child process does not receive the interrupt
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
Setpgid: true,
|
Setpgid: true,
|
||||||
Pgid: 0,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd, nil
|
return cmd, nil
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ type CommandTemplatesConfig struct {
|
||||||
RebuildService string `yaml:"rebuildService,omitempty"`
|
RebuildService string `yaml:"rebuildService,omitempty"`
|
||||||
ContainerLogs string `yaml:"containerLogs,omitempty"`
|
ContainerLogs string `yaml:"containerLogs,omitempty"`
|
||||||
ContainerTTYLogs string `yaml:"containerTTYLogs,omitempty"`
|
ContainerTTYLogs string `yaml:"containerTTYLogs,omitempty"`
|
||||||
|
AllLogs string `yaml:"allLogs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OSConfig struct {
|
type OSConfig struct {
|
||||||
|
|
@ -164,6 +165,7 @@ func GetDefaultConfig() UserConfig {
|
||||||
ServiceLogs: "apdev logs {{ .Name }}",
|
ServiceLogs: "apdev logs {{ .Name }}",
|
||||||
ContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .ID }}",
|
ContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .ID }}",
|
||||||
ContainerTTYLogs: "docker logs --follow --tail=100 {{ .ID }}",
|
ContainerTTYLogs: "docker logs --follow --tail=100 {{ .ID }}",
|
||||||
|
AllLogs: "apdev logs --tail=100",
|
||||||
},
|
},
|
||||||
OS: GetPlatformDefaultConfig(),
|
OS: GetPlatformDefaultConfig(),
|
||||||
Update: UpdateConfig{
|
Update: UpdateConfig{
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,10 @@ type containerPanelState struct {
|
||||||
ContextIndex int // for specifying if you are looking at logs/stats/config/etc
|
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 {
|
type menuPanelState struct {
|
||||||
SelectedLine int
|
SelectedLine int
|
||||||
}
|
}
|
||||||
|
|
@ -96,6 +100,7 @@ type panelStates struct {
|
||||||
Menu *menuPanelState
|
Menu *menuPanelState
|
||||||
Main *mainPanelState
|
Main *mainPanelState
|
||||||
Images *imagePanelState
|
Images *imagePanelState
|
||||||
|
Status *statusState
|
||||||
}
|
}
|
||||||
|
|
||||||
type guiState struct {
|
type guiState struct {
|
||||||
|
|
@ -121,6 +126,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
||||||
Main: &mainPanelState{
|
Main: &mainPanelState{
|
||||||
ObjectKey: "",
|
ObjectKey: "",
|
||||||
},
|
},
|
||||||
|
Status: &statusState{ContextIndex: 0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,20 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
Handler: gui.handleOpenConfig,
|
Handler: gui.handleOpenConfig,
|
||||||
Description: gui.Tr.OpenConfig,
|
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",
|
ViewName: "menu",
|
||||||
Key: gocui.KeyEsc,
|
Key: gocui.KeyEsc,
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,16 @@ package gui
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (gui *Gui) getStatusContexts() []string {
|
||||||
|
return []string{"logs", "credits"}
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) refreshStatus() error {
|
func (gui *Gui) refreshStatus() error {
|
||||||
v := gui.getStatusView()
|
v := gui.getStatusView()
|
||||||
|
|
||||||
|
|
@ -28,6 +34,36 @@ func (gui *Gui) handleStatusSelect(g *gocui.Gui, v *gocui.View) error {
|
||||||
return err
|
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(
|
dashboardString := strings.Join(
|
||||||
[]string{
|
[]string{
|
||||||
lazydockerTitle(),
|
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",
|
"Raise an Issue: https://github.com/jesseduffield/lazydocker/issues",
|
||||||
}, "\n\n")
|
}, "\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 {
|
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 {
|
if err == gocui.ErrQuit {
|
||||||
break
|
break
|
||||||
} else if err == gui.Errors.ErrSubProcess {
|
} 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 {
|
if err := gui.runCommand(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -33,8 +37,6 @@ func (gui *Gui) RunWithSubprocesses() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) runCommand() error {
|
func (gui *Gui) runCommand() error {
|
||||||
gui.State.PreviousView = gui.currentViewName()
|
|
||||||
|
|
||||||
gui.SubProcess.Stdout = os.Stdout
|
gui.SubProcess.Stdout = os.Stdout
|
||||||
gui.SubProcess.Stderr = os.Stdout
|
gui.SubProcess.Stderr = os.Stdout
|
||||||
gui.SubProcess.Stdin = os.Stdin
|
gui.SubProcess.Stdin = os.Stdin
|
||||||
|
|
@ -46,7 +48,9 @@ func (gui *Gui) runCommand() error {
|
||||||
<-c
|
<-c
|
||||||
signal.Stop(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))
|
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