mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-21 23:01:03 +00:00
better support for custom commands
This commit is contained in:
parent
b02c92da33
commit
3e49e299b9
9 changed files with 166 additions and 83 deletions
|
|
@ -36,6 +36,7 @@ type Container struct {
|
|||
StatHistory []RecordedStats
|
||||
Details Details
|
||||
MonitoringStats bool
|
||||
DockerCommand LimitedDockerCommand
|
||||
}
|
||||
|
||||
// RecordedStats contains both the container stats we've received from docker, and our own derived stats from those container stats. When configuring a graph, you're basically specifying the path of a value in this struct
|
||||
|
|
@ -354,13 +355,6 @@ func (c *Container) Restart() error {
|
|||
return c.Client.ContainerRestart(context.Background(), c.ID, nil)
|
||||
}
|
||||
|
||||
// RestartService restarts the container
|
||||
func (c *Container) RestartService() error {
|
||||
templateString := c.OSCommand.Config.UserConfig.CommandTemplates.RestartService
|
||||
command := utils.ApplyTemplate(templateString, c)
|
||||
return c.OSCommand.RunCommand(command)
|
||||
}
|
||||
|
||||
// Attach attaches the container
|
||||
func (c *Container) Attach() (*exec.Cmd, error) {
|
||||
// verify that we can in fact attach to this container
|
||||
|
|
@ -394,7 +388,10 @@ func (c *Container) EraseOldHistory() {
|
|||
// ViewLogs attaches to a subprocess viewing the container's logs
|
||||
func (c *Container) ViewLogs() (*exec.Cmd, error) {
|
||||
templateString := c.OSCommand.Config.UserConfig.CommandTemplates.ViewContainerLogs
|
||||
command := utils.ApplyTemplate(templateString, c)
|
||||
command := utils.ApplyTemplate(
|
||||
templateString,
|
||||
c.DockerCommand.NewCommandObject(CommandObject{Container: c}),
|
||||
)
|
||||
|
||||
cmd := c.OSCommand.ExecutableFromString(command)
|
||||
c.OSCommand.PrepareForChildren(cmd)
|
||||
|
|
@ -407,3 +404,17 @@ func (c *DockerCommand) PruneContainers() error {
|
|||
_, err := c.Client.ContainersPrune(context.Background(), filters.Args{})
|
||||
return err
|
||||
}
|
||||
|
||||
// TTYLogsCommand returns a command for obtaining the logs from a TTY container
|
||||
func (c *Container) TTYLogsCommand() *exec.Cmd {
|
||||
command := utils.ApplyTemplate(
|
||||
c.Config.UserConfig.CommandTemplates.ContainerTTYLogs,
|
||||
c.DockerCommand.NewCommandObject(CommandObject{Container: c}),
|
||||
)
|
||||
return c.OSCommand.RunCustomCommand(command)
|
||||
}
|
||||
|
||||
// Inspect returns details about the container
|
||||
func (c *Container) Inspect() (types.ContainerJSON, error) {
|
||||
return c.Client.ContainerInspect(context.Background(), c.ID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/acarl005/stripansi"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/jesseduffield/lazydocker/pkg/config"
|
||||
"github.com/jesseduffield/lazydocker/pkg/i18n"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
|
|
@ -39,6 +40,25 @@ type DockerCommand struct {
|
|||
Volumes []*Volume
|
||||
}
|
||||
|
||||
// LimitedDockerCommand is a stripped-down DockerCommand with just the methods the container/service/image might need
|
||||
type LimitedDockerCommand interface {
|
||||
NewCommandObject(CommandObject) CommandObject
|
||||
}
|
||||
|
||||
// CommandObject is what we pass to our template resolvers when we are running a custom command. We do not guarantee that all fields will be populated: just the ones that make sense for the current context
|
||||
type CommandObject struct {
|
||||
DockerCompose string
|
||||
Service *Service
|
||||
Container *Container
|
||||
}
|
||||
|
||||
// NewCommandObject takes a command object and returns a default command object with the passed command object merged in
|
||||
func (c *DockerCommand) NewCommandObject(obj CommandObject) CommandObject {
|
||||
defaultObj := CommandObject{DockerCompose: c.Config.UserConfig.CommandTemplates.DockerCompose}
|
||||
mergo.Merge(&defaultObj, obj)
|
||||
return defaultObj
|
||||
}
|
||||
|
||||
// NewDockerCommand it runs git commands
|
||||
func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*DockerCommand, error) {
|
||||
cli, err := client.NewEnvClient()
|
||||
|
|
@ -46,22 +66,35 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Translat
|
|||
return nil, err
|
||||
}
|
||||
|
||||
inDockerComposeProject := true
|
||||
err = osCommand.RunCommand(config.UserConfig.CommandTemplates.CheckDockerComposeConfig)
|
||||
if err != nil {
|
||||
inDockerComposeProject = false
|
||||
log.Warn(err.Error())
|
||||
}
|
||||
|
||||
return &DockerCommand{
|
||||
dockerCommand := &DockerCommand{
|
||||
Log: log,
|
||||
OSCommand: osCommand,
|
||||
Tr: tr,
|
||||
Config: config,
|
||||
Client: cli,
|
||||
InDockerComposeProject: inDockerComposeProject,
|
||||
ErrorChan: errorChan,
|
||||
}, nil
|
||||
InDockerComposeProject: true,
|
||||
}
|
||||
|
||||
command := utils.ApplyTemplate(
|
||||
config.UserConfig.CommandTemplates.CheckDockerComposeConfig,
|
||||
dockerCommand.NewCommandObject(CommandObject{}),
|
||||
)
|
||||
|
||||
log.Warn(command)
|
||||
|
||||
err = osCommand.RunCommand(
|
||||
utils.ApplyTemplate(
|
||||
config.UserConfig.CommandTemplates.CheckDockerComposeConfig,
|
||||
dockerCommand.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
dockerCommand.InDockerComposeProject = false
|
||||
log.Warn(err.Error())
|
||||
}
|
||||
|
||||
return dockerCommand, nil
|
||||
}
|
||||
|
||||
// MonitorContainerStats is a function
|
||||
|
|
@ -263,11 +296,12 @@ func (c *DockerCommand) GetContainers() ([]*Container, error) {
|
|||
// initialise the container if it's completely new
|
||||
if newContainer == nil {
|
||||
newContainer = &Container{
|
||||
ID: container.ID,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
Config: c.Config,
|
||||
ID: container.ID,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
Config: c.Config,
|
||||
DockerCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -310,10 +344,11 @@ func (c *DockerCommand) GetServices() ([]*Service, error) {
|
|||
for i, str := range lines {
|
||||
arr := strings.Split(str, " ")
|
||||
services[i] = &Service{
|
||||
Name: arr[0],
|
||||
ID: arr[1],
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
Name: arr[0],
|
||||
ID: arr[1],
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -353,7 +388,13 @@ func (c *DockerCommand) UpdateContainerDetails() error {
|
|||
|
||||
// ViewAllLogs attaches to a subprocess viewing all the logs from docker-compose
|
||||
func (c *DockerCommand) ViewAllLogs() (*exec.Cmd, error) {
|
||||
cmd := c.OSCommand.ExecutableFromString(c.OSCommand.Config.UserConfig.CommandTemplates.ViewAllLogs)
|
||||
cmd := c.OSCommand.ExecutableFromString(
|
||||
utils.ApplyTemplate(
|
||||
c.OSCommand.Config.UserConfig.CommandTemplates.ViewAllLogs,
|
||||
c.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
|
||||
c.OSCommand.PrepareForChildren(cmd)
|
||||
|
||||
return cmd, nil
|
||||
|
|
@ -361,7 +402,13 @@ func (c *DockerCommand) ViewAllLogs() (*exec.Cmd, error) {
|
|||
|
||||
// DockerComposeConfig returns the result of 'docker-compose config'
|
||||
func (c *DockerCommand) DockerComposeConfig() string {
|
||||
output, err := c.OSCommand.RunCommandWithOutput(c.OSCommand.Config.UserConfig.CommandTemplates.DockerComposeConfig)
|
||||
output, err := c.OSCommand.RunCommandWithOutput(
|
||||
utils.ApplyTemplate(
|
||||
c.OSCommand.Config.UserConfig.CommandTemplates.DockerComposeConfig,
|
||||
c.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
output = err.Error()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,13 +14,14 @@ import (
|
|||
|
||||
// Image : A docker Image
|
||||
type Image struct {
|
||||
Name string
|
||||
Tag string
|
||||
ID string
|
||||
Image types.ImageSummary
|
||||
Client *client.Client
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
Name string
|
||||
Tag string
|
||||
ID string
|
||||
Image types.ImageSummary
|
||||
Client *client.Client
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
DockerCommand LimitedDockerCommand
|
||||
}
|
||||
|
||||
// GetDisplayStrings returns the display string of Image
|
||||
|
|
@ -99,9 +100,6 @@ func (i *Image) RenderHistory() (string, error) {
|
|||
return utils.RenderList(layers, utils.WithHeader([]string{"ID", "TAG", "SIZE", "COMMAND"}))
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// GetImages returns a slice of docker images
|
||||
func (c *DockerCommand) GetImages() ([]*Image, error) {
|
||||
images, err := c.Client.ImageList(context.Background(), types.ImageListOptions{})
|
||||
|
|
@ -127,13 +125,14 @@ func (c *DockerCommand) GetImages() ([]*Image, error) {
|
|||
}
|
||||
|
||||
ownImages[i] = &Image{
|
||||
ID: image.ID,
|
||||
Name: nameParts[0],
|
||||
Tag: tag,
|
||||
Image: image,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
ID: image.ID,
|
||||
Name: nameParts[0],
|
||||
Tag: tag,
|
||||
Image: image,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@ import (
|
|||
|
||||
// Service : A docker Service
|
||||
type Service struct {
|
||||
Name string
|
||||
ID string
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
Container *Container
|
||||
Name string
|
||||
ID string
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
Container *Container
|
||||
DockerCommand LimitedDockerCommand
|
||||
}
|
||||
|
||||
// GetDisplayStrings returns the dispaly string of Container
|
||||
|
|
@ -37,14 +38,20 @@ func (s *Service) Remove(options types.ContainerRemoveOptions) error {
|
|||
// Stop stops the service's containers
|
||||
func (s *Service) Stop() error {
|
||||
templateString := s.OSCommand.Config.UserConfig.CommandTemplates.StopService
|
||||
command := utils.ApplyTemplate(templateString, s)
|
||||
command := utils.ApplyTemplate(
|
||||
templateString,
|
||||
s.DockerCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
)
|
||||
return s.OSCommand.RunCommand(command)
|
||||
}
|
||||
|
||||
// Restart restarts the service
|
||||
func (s *Service) Restart() error {
|
||||
templateString := s.OSCommand.Config.UserConfig.CommandTemplates.RestartService
|
||||
command := utils.ApplyTemplate(templateString, s)
|
||||
command := utils.ApplyTemplate(
|
||||
templateString,
|
||||
s.DockerCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
)
|
||||
return s.OSCommand.RunCommand(command)
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +68,10 @@ func (s *Service) Top() (types.ContainerProcessList, error) {
|
|||
// ViewLogs attaches to a subprocess viewing the service's logs
|
||||
func (s *Service) ViewLogs() (*exec.Cmd, error) {
|
||||
templateString := s.OSCommand.Config.UserConfig.CommandTemplates.ViewServiceLogs
|
||||
command := utils.ApplyTemplate(templateString, s)
|
||||
command := utils.ApplyTemplate(
|
||||
templateString,
|
||||
s.DockerCommand.NewCommandObject(CommandObject{Service: s}),
|
||||
)
|
||||
|
||||
cmd := s.OSCommand.ExecutableFromString(command)
|
||||
s.OSCommand.PrepareForChildren(cmd)
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ import (
|
|||
|
||||
// Volume : A docker Volume
|
||||
type Volume struct {
|
||||
Name string
|
||||
Volume *types.Volume
|
||||
Client *client.Client
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
Name string
|
||||
Volume *types.Volume
|
||||
Client *client.Client
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
DockerCommand LimitedDockerCommand
|
||||
}
|
||||
|
||||
// GetDisplayStrings returns the dispaly string of Container
|
||||
|
|
@ -41,11 +42,12 @@ func (c *DockerCommand) RefreshVolumes() error {
|
|||
|
||||
for i, volume := range volumes {
|
||||
ownVolumes[i] = &Volume{
|
||||
Name: volume.Name,
|
||||
Volume: volume,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
Name: volume.Name,
|
||||
Volume: volume,
|
||||
Client: c.Client,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,18 +164,18 @@ func GetDefaultConfig() UserConfig {
|
|||
Reporting: "undetermined",
|
||||
ConfirmOnQuit: false,
|
||||
CommandTemplates: CommandTemplatesConfig{
|
||||
RestartService: "docker-compose restart {{ .Name }}",
|
||||
RebuildService: "docker-compose up -d --build {{ .Name }}",
|
||||
DockerCompose: "docker-compose",
|
||||
StopService: "docker-compose stop {{ .Name }}",
|
||||
ServiceLogs: "docker-compose logs {{ .Name }}",
|
||||
AllLogs: "docker-compose logs --tail=100",
|
||||
ViewAllLogs: "docker-compose logs",
|
||||
DockerComposeConfig: "docker-compose config",
|
||||
CheckDockerComposeConfig: "docker-compose config --quiet",
|
||||
ContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .ID }}",
|
||||
ViewContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .ID }}",
|
||||
ContainerTTYLogs: "docker logs --follow --tail=100 {{ .ID }}",
|
||||
RestartService: "{{ .DockerCompose }} restart {{ .Service.Name }}",
|
||||
RebuildService: "{{ .DockerCompose }} up -d --build {{ .Service.Name }}",
|
||||
StopService: "{{ .DockerCompose }} stop {{ .Service.Name }}",
|
||||
ServiceLogs: "{{ .DockerCompose }} logs {{ .Service.Name }}",
|
||||
AllLogs: "{{ .DockerCompose }} logs --tail=100",
|
||||
ViewAllLogs: "{{ .DockerCompose }} logs",
|
||||
DockerComposeConfig: "{{ .DockerCompose }} config",
|
||||
CheckDockerComposeConfig: "{{ .DockerCompose }} config --quiet",
|
||||
ContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .Container.ID }}",
|
||||
ViewContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .Container.ID }}",
|
||||
ContainerTTYLogs: "docker logs --follow --tail=100 {{ .Container.ID }}",
|
||||
},
|
||||
OS: GetPlatformDefaultConfig(),
|
||||
Update: UpdateConfig{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package gui
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
|
@ -190,8 +189,7 @@ func (gui *Gui) renderLogs(container *commands.Container, template string, setup
|
|||
gui.T.NewTickerTask(time.Millisecond*200, nil, func(stop, notifyStopped chan struct{}) {
|
||||
gui.clearMainView()
|
||||
|
||||
command := utils.ApplyTemplate(gui.Config.UserConfig.CommandTemplates.ContainerTTYLogs, container)
|
||||
cmd := gui.OSCommand.RunCustomCommand(command)
|
||||
cmd := container.TTYLogsCommand()
|
||||
|
||||
setup(cmd)
|
||||
|
||||
|
|
@ -213,7 +211,7 @@ func (gui *Gui) renderLogs(container *commands.Container, template string, setup
|
|||
case <-stop:
|
||||
return
|
||||
default:
|
||||
result, err := gui.DockerCommand.Client.ContainerInspect(context.Background(), container.ID)
|
||||
result, err := container.Inspect()
|
||||
if err != nil {
|
||||
// if we get an error, then the container has probably been removed so we'll get out of here
|
||||
gui.Log.Error(err)
|
||||
|
|
|
|||
|
|
@ -284,12 +284,18 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
rebuildCommand := utils.ApplyTemplate(gui.Config.UserConfig.CommandTemplates.RebuildService, service)
|
||||
rebuildCommand := utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RebuildService,
|
||||
service,
|
||||
)
|
||||
|
||||
options := []*commandOption{
|
||||
{
|
||||
description: gui.Tr.Restart,
|
||||
command: utils.ApplyTemplate(gui.Config.UserConfig.CommandTemplates.RestartService, service),
|
||||
command: utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RestartService,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
),
|
||||
f: func() error {
|
||||
return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error {
|
||||
if err := service.Restart(); err != nil {
|
||||
|
|
@ -302,7 +308,10 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
|||
},
|
||||
{
|
||||
description: gui.Tr.Rebuild,
|
||||
command: utils.ApplyTemplate(gui.Config.UserConfig.CommandTemplates.RebuildService, service),
|
||||
command: utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.RebuildService,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}),
|
||||
),
|
||||
f: func() error {
|
||||
gui.SubProcess = gui.OSCommand.RunCustomCommand(rebuildCommand)
|
||||
return gui.Errors.ErrSubProcess
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import (
|
|||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
)
|
||||
|
||||
func (gui *Gui) getStatusContexts() []string {
|
||||
|
|
@ -105,7 +107,12 @@ func (gui *Gui) renderAllLogs() error {
|
|||
|
||||
gui.clearMainView()
|
||||
|
||||
cmd := gui.OSCommand.RunCustomCommand(gui.Config.UserConfig.CommandTemplates.AllLogs)
|
||||
cmd := gui.OSCommand.RunCustomCommand(
|
||||
utils.ApplyTemplate(
|
||||
gui.Config.UserConfig.CommandTemplates.AllLogs,
|
||||
gui.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
),
|
||||
)
|
||||
|
||||
cmd.Stdout = mainView
|
||||
cmd.Stderr = mainView
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue