mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-23 15:41:02 +00:00
The config hash ends up not being a unique identifier of a Service. Additionally, Services may have multiple associated Containers.
``` yaml
# Sample docker-compose.yml
version: "2.2"
services:
named-service:
container_name: 'named-container'
image: 'alpine'
command: 'sh -c "while :; do sleep 1; done"'
anonymous-service:
image: 'alpine'
command: 'sh -c "while :; do sleep 1; done"'
scaled-service:
image: 'alpine'
scale: 3
command: 'sh -c "while :; do sleep 1; done"'
```
``` bash
$ docker-compose config --hash="*"
named-service e6e7c4564dfc435ba96725098c62e6b6cf8da9f0b76b0a08be2baddedad6d007
anonymous-service 254f4815ef36bc9fcc2ce80f82278187c9e233309a4106951551f3692657ce9c
scaled-service 254f4815ef36bc9fcc2ce80f82278187c9e233309a4106951551f3692657ce9c
```
This commit changes how Services are discovered (`docker-compose config --services`), how they're associated (by Container ID, rather than config hash or name), and allows for Services to reference multiple Containers (though only the first is directly used for anything at this time).
225 lines
5.7 KiB
Go
225 lines
5.7 KiB
Go
package gui
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"path"
|
|
"strings"
|
|
|
|
"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"
|
|
"github.com/jesseduffield/yaml"
|
|
)
|
|
|
|
func (gui *Gui) getProjectContexts() []string {
|
|
if gui.DockerCommand.InDockerComposeProject {
|
|
return []string{"logs", "config", "credits"}
|
|
}
|
|
return []string{"credits"}
|
|
}
|
|
|
|
func (gui *Gui) getProjectContextTitles() []string {
|
|
if gui.DockerCommand.InDockerComposeProject {
|
|
return []string{gui.Tr.LogsTitle, gui.Tr.DockerComposeConfigTitle, gui.Tr.CreditsTitle}
|
|
}
|
|
return []string{gui.Tr.CreditsTitle}
|
|
}
|
|
|
|
func (gui *Gui) refreshProject() error {
|
|
v := gui.getProjectView()
|
|
|
|
projectName := path.Base(gui.Config.ProjectDir)
|
|
if gui.DockerCommand.InDockerComposeProject {
|
|
for _, service := range gui.DockerCommand.Services {
|
|
if len(service.Containers) > 0 {
|
|
projectName = service.Containers[0].Details.Config.Labels["com.docker.compose.project"]
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
gui.g.Update(func(*gocui.Gui) error {
|
|
v.Clear()
|
|
fmt.Fprint(v, projectName)
|
|
return nil
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
func (gui *Gui) handleProjectClick(g *gocui.Gui, v *gocui.View) error {
|
|
if gui.popupPanelFocused() {
|
|
return nil
|
|
}
|
|
|
|
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
|
|
return err
|
|
}
|
|
|
|
return gui.handleProjectSelect(g, v)
|
|
}
|
|
|
|
func (gui *Gui) handleProjectSelect(g *gocui.Gui, v *gocui.View) error {
|
|
if gui.popupPanelFocused() {
|
|
return nil
|
|
}
|
|
|
|
key := gui.getProjectContexts()[gui.State.Panels.Project.ContextIndex]
|
|
if !gui.shouldRefresh(key) {
|
|
return nil
|
|
}
|
|
|
|
gui.clearMainView()
|
|
|
|
mainView := gui.getMainView()
|
|
mainView.Tabs = gui.getProjectContextTitles()
|
|
mainView.TabIndex = gui.State.Panels.Project.ContextIndex
|
|
|
|
switch gui.getProjectContexts()[gui.State.Panels.Project.ContextIndex] {
|
|
case "credits":
|
|
if err := gui.renderCredits(); err != nil {
|
|
return err
|
|
}
|
|
case "logs":
|
|
if err := gui.renderAllLogs(); err != nil {
|
|
return err
|
|
}
|
|
case "config":
|
|
if err := gui.renderDockerComposeConfig(); err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
return errors.New("Unknown context for status panel")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (gui *Gui) renderCredits() error {
|
|
return gui.T.NewTask(func(stop chan struct{}) {
|
|
mainView := gui.getMainView()
|
|
mainView.Autoscroll = false
|
|
mainView.Wrap = gui.Config.UserConfig.Gui.WrapMainPanel
|
|
|
|
var configBuf bytes.Buffer
|
|
yaml.NewEncoder(&configBuf, yaml.IncludeOmitted).Encode(gui.Config.UserConfig)
|
|
|
|
dashboardString := strings.Join(
|
|
[]string{
|
|
lazydockerTitle(),
|
|
"Copyright (c) 2019 Jesse Duffield",
|
|
"Keybindings: https://github.com/jesseduffield/lazydocker/blob/master/docs/keybindings",
|
|
"Config Options: https://github.com/jesseduffield/lazydocker/blob/master/docs/Config.md",
|
|
"Raise an Issue: https://github.com/jesseduffield/lazydocker/issues",
|
|
utils.ColoredString("Buy Jesse a coffee: https://donorbox.org/lazydocker", 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(),
|
|
}, "\n\n")
|
|
|
|
gui.renderString(gui.g, "main", dashboardString)
|
|
})
|
|
}
|
|
|
|
func (gui *Gui) renderAllLogs() error {
|
|
return gui.T.NewTask(func(stop chan struct{}) {
|
|
mainView := gui.getMainView()
|
|
mainView.Autoscroll = true
|
|
mainView.Wrap = gui.Config.UserConfig.Gui.WrapMainPanel
|
|
|
|
gui.clearMainView()
|
|
|
|
cmd := gui.OSCommand.RunCustomCommand(
|
|
utils.ApplyTemplate(
|
|
gui.Config.UserConfig.CommandTemplates.AllLogs,
|
|
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
|
),
|
|
)
|
|
|
|
cmd.Stdout = mainView
|
|
cmd.Stderr = mainView
|
|
|
|
gui.OSCommand.PrepareForChildren(cmd)
|
|
cmd.Start()
|
|
|
|
go func() {
|
|
<-stop
|
|
if err := gui.OSCommand.Kill(cmd); err != nil {
|
|
gui.Log.Error(err)
|
|
}
|
|
}()
|
|
|
|
cmd.Wait()
|
|
})
|
|
}
|
|
|
|
func (gui *Gui) renderDockerComposeConfig() error {
|
|
return gui.T.NewTask(func(stop chan struct{}) {
|
|
mainView := gui.getMainView()
|
|
mainView.Autoscroll = false
|
|
mainView.Wrap = gui.Config.UserConfig.Gui.WrapMainPanel
|
|
|
|
config := gui.DockerCommand.DockerComposeConfig()
|
|
gui.renderString(gui.g, "main", config)
|
|
})
|
|
}
|
|
|
|
func (gui *Gui) handleOpenConfig(g *gocui.Gui, v *gocui.View) error {
|
|
return gui.openFile(gui.Config.ConfigFilename())
|
|
}
|
|
|
|
func (gui *Gui) handleEditConfig(g *gocui.Gui, v *gocui.View) error {
|
|
return gui.editFile(gui.Config.ConfigFilename())
|
|
}
|
|
|
|
func lazydockerTitle() string {
|
|
return `
|
|
_ _ _
|
|
| | | | | |
|
|
| | __ _ _____ _ __| | ___ ___| | _____ _ __
|
|
| |/ _` + "`" + ` |_ / | | |/ _` + "`" + ` |/ _ \ / __| |/ / _ \ '__|
|
|
| | (_| |/ /| |_| | (_| | (_) | (__| < __/ |
|
|
|_|\__,_/___|\__, |\__,_|\___/ \___|_|\_\___|_|
|
|
__/ |
|
|
|___/
|
|
`
|
|
}
|
|
|
|
func (gui *Gui) handleProjectNextContext(g *gocui.Gui, v *gocui.View) error {
|
|
contexts := gui.getProjectContexts()
|
|
if gui.State.Panels.Project.ContextIndex >= len(contexts)-1 {
|
|
gui.State.Panels.Project.ContextIndex = 0
|
|
} else {
|
|
gui.State.Panels.Project.ContextIndex++
|
|
}
|
|
|
|
gui.handleProjectSelect(gui.g, v)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (gui *Gui) handleProjectPrevContext(g *gocui.Gui, v *gocui.View) error {
|
|
contexts := gui.getProjectContexts()
|
|
if gui.State.Panels.Project.ContextIndex <= 0 {
|
|
gui.State.Panels.Project.ContextIndex = len(contexts) - 1
|
|
} else {
|
|
gui.State.Panels.Project.ContextIndex--
|
|
}
|
|
|
|
gui.handleProjectSelect(gui.g, v)
|
|
|
|
return nil
|
|
}
|
|
|
|
// handleViewAllLogs switches to a subprocess viewing all the logs from docker-compose
|
|
func (gui *Gui) handleViewAllLogs(g *gocui.Gui, v *gocui.View) error {
|
|
c, err := gui.DockerCommand.ViewAllLogs()
|
|
if err != nil {
|
|
return gui.createErrorPanel(gui.g, err.Error())
|
|
}
|
|
|
|
gui.SubProcess = c
|
|
return gui.Errors.ErrSubProcess
|
|
}
|