support custom commands in services and containers panel

This commit is contained in:
Jesse Duffield 2019-06-15 14:08:12 +10:00
parent 90a04add32
commit 2474c0b34e
6 changed files with 138 additions and 4 deletions

View file

@ -82,6 +82,7 @@ type UserConfig struct {
Reporting string `yaml:"reporting,omitempty"`
ConfirmOnQuit bool `yaml:"confirmOnQuit,omitempty"`
CommandTemplates CommandTemplatesConfig `yaml:"commandTemplates,omitempty"`
CustomCommands CustomCommands `yaml:"customCommands,omitempty"`
OS OSConfig `yaml:"oS,omitempty"`
Update UpdateConfig `yaml:"update,omitempty"`
Stats StatsConfig `yaml:"stats,omitempty"`
@ -146,6 +147,16 @@ type StatsConfig struct {
MaxDuration time.Duration `yaml:"maxDuration,omitempty"`
}
type CustomCommands struct {
Containers []CustomCommand `yaml:"containers,omitempty"`
Services []CustomCommand `yaml:"services,omitempty"`
}
type CustomCommand struct {
Attach bool
Command string
}
// GetDefaultConfig returns the application default configuration
// NOTE: do not default a boolean to true, because false is the boolean zero value and this will be ignored when parsing the user's config
func GetDefaultConfig() UserConfig {
@ -178,6 +189,15 @@ func GetDefaultConfig() UserConfig {
ViewContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .Container.ID }}",
ContainerTTYLogs: "docker logs --follow --tail=100 {{ .Container.ID }}",
},
CustomCommands: CustomCommands{
Containers: []CustomCommand{
{
Attach: true,
Command: "docker exec -it {{ .Container.ID }} /bin/bash",
},
},
Services: []CustomCommand{},
},
OS: GetPlatformDefaultConfig(),
Update: UpdateConfig{
Method: "never",

View file

@ -497,3 +497,18 @@ func (gui *Gui) handleContainerViewLogs(g *gocui.Gui, v *gocui.View) error {
gui.SubProcess = c
return gui.Errors.ErrSubProcess
}
func (gui *Gui) handleContainersCustomCommand(g *gocui.Gui, v *gocui.View) error {
container, err := gui.getSelectedContainer()
if err != nil {
return nil
}
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
Container: container,
})
customCommands := gui.Config.UserConfig.CustomCommands.Containers
return gui.createCustomCommandMenu(customCommands, commandObject)
}

View file

@ -0,0 +1,62 @@
package gui
import (
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/utils"
)
type customCommandOption struct {
customCommand config.CustomCommand
description string
command string
runCommand bool
attach bool
}
// GetDisplayStrings is a function.
func (r *customCommandOption) GetDisplayStrings(isFocused bool) []string {
return []string{r.description}
}
func (gui *Gui) createCustomCommandMenu(customCommands []config.CustomCommand, commandObject commands.CommandObject) error {
options := make([]*customCommandOption, len(customCommands)+1)
for i, command := range customCommands {
resolvedCommand := utils.ApplyTemplate(command.Command, commandObject)
options[i] = &customCommandOption{
customCommand: command,
description: resolvedCommand,
command: resolvedCommand,
runCommand: true,
attach: command.Attach,
}
}
options[len(options)-1] = &customCommandOption{
description: gui.Tr.Cancel,
runCommand: false,
}
handleMenuPress := func(index int) error {
option := options[index]
if !option.runCommand {
return nil
}
// if we have a command for attaching, we attach and return the subprocess error
if option.customCommand.Attach {
cmd := gui.OSCommand.ExecutableFromString(option.command)
gui.SubProcess = cmd
return gui.Errors.ErrSubProcess
}
return gui.WithWaitingStatus(gui.Tr.RunningCustomCommandStatus, func() error {
if err := gui.OSCommand.RunCommand(option.command); err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
return nil
})
}
return gui.createMenu("", options, len(options), handleMenuPress)
}

View file

@ -228,6 +228,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleContainerViewLogs,
Description: gui.Tr.ViewLogs,
},
{
ViewName: "containers",
Key: 'c',
Modifier: gocui.ModNone,
Handler: gui.handleContainersCustomCommand,
Description: gui.Tr.RunCustomCommand,
},
{
ViewName: "services",
Key: 'd',
@ -284,6 +291,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleServiceRestartMenu,
Description: gui.Tr.ViewRestartOptions,
},
{
ViewName: "services",
Key: 'c',
Modifier: gocui.ModNone,
Handler: gui.handleServicesCustomCommand,
Description: gui.Tr.RunCustomCommand,
},
{
ViewName: "images",
Key: '[',

View file

@ -344,3 +344,22 @@ func (gui *Gui) createCommandMenu(options []*commandOption, status string) error
return gui.createMenu("", options, len(options), handleMenuPress)
}
func (gui *Gui) handleServicesCustomCommand(g *gocui.Gui, v *gocui.View) error {
service, err := gui.getSelectedService()
if err != nil {
return nil
}
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
Service: service,
Container: service.Container,
})
customCommands := gui.Config.UserConfig.CustomCommands.Services
if service.Container != nil {
customCommands = append(customCommands, gui.Config.UserConfig.CustomCommands.Containers...)
}
return gui.createCustomCommandMenu(customCommands, commandObject)
}

View file

@ -32,6 +32,7 @@ type TranslationSet struct {
RestartingStatus string
StoppingStatus string
RemovingStatus string
RunningCustomCommandStatus string
RemoveService string
Stop string
Restart string
@ -62,6 +63,7 @@ type TranslationSet struct {
StopService string
PressEnterToReturn string
ViewRestartOptions string
RunCustomCommand string
LogsTitle string
ConfigTitle string
@ -72,10 +74,11 @@ type TranslationSet struct {
func englishSet() TranslationSet {
return TranslationSet{
PruningStatus: "pruning",
RemovingStatus: "removing",
RestartingStatus: "restarting",
StoppingStatus: "stopping",
PruningStatus: "pruning",
RemovingStatus: "removing",
RestartingStatus: "restarting",
StoppingStatus: "stopping",
RunningCustomCommandStatus: "running custom command",
RunningSubprocess: "running subprocess",
NoViewMachingNewLineFocusedSwitchStatement: "No view matching newLineFocused switch statement",
@ -110,6 +113,7 @@ func englishSet() TranslationSet {
PruneVolumes: "prune unused volumes",
PruneImages: "prune unused images",
ViewRestartOptions: "view restart options",
RunCustomCommand: "run predefined custom command",
AnonymousReportingTitle: "Help make lazydocker better",
AnonymousReportingPrompt: "Would you like to enable anonymous reporting data to help improve lazydocker? (enter/esc)",