This commit is contained in:
Clément PÉAU 2026-04-23 01:35:28 +02:00 committed by GitHub
commit ff87a1864d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 79 additions and 21 deletions

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: entfernen
<kbd>e</kbd>: hide/show stopped containers
<kbd>p</kbd>: pause
<kbd>s</kbd>: anhalten
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: neustarten
<kbd>a</kbd>: anbinden
<kbd>m</kbd>: zeige Protokolle

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: remove
<kbd>e</kbd>: hide/show stopped containers
<kbd>p</kbd>: pause
<kbd>s</kbd>: stop
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: restart
<kbd>a</kbd>: attach
<kbd>m</kbd>: view logs

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: borrar
<kbd>e</kbd>: esconder/mostrar contenedores parados
<kbd>p</kbd>: pausa
<kbd>s</kbd>: parar
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: reiniciar
<kbd>a</kbd>: attach
<kbd>m</kbd>: ver logs

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: supprimer
<kbd>e</kbd>: cacher/montrer les conteneurs arrêtés
<kbd>p</kbd>: pause
<kbd>s</kbd>: arrêter
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: redémarrer
<kbd>a</kbd>: attacher
<kbd>m</kbd>: voir les enregistrements

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: verwijder
<kbd>e</kbd>: verberg gestopte containers
<kbd>p</kbd>: pause
<kbd>s</kbd>: stop
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: herstart
<kbd>a</kbd>: verbinden
<kbd>m</kbd>: bekijk logs

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: usuń
<kbd>e</kbd>: hide/show stopped containers
<kbd>p</kbd>: pause
<kbd>s</kbd>: zatrzymaj
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: restartuj
<kbd>a</kbd>: przyczep
<kbd>m</kbd>: pokaż logi

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: remover
<kbd>e</kbd>: ocultar/mostrar contêineres parados
<kbd>p</kbd>: pausar
<kbd>s</kbd>: parar
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: reiniciar
<kbd>a</kbd>: anexar
<kbd>m</kbd>: ver logs

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: kaldır
<kbd>e</kbd>: hide/show stopped containers
<kbd>p</kbd>: pause
<kbd>s</kbd>: durdur
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: yeniden başlat
<kbd>a</kbd>: bağlan/iliştir
<kbd>m</kbd>: kayıt defterini görüntüle

View file

@ -20,7 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>d</kbd>: 移除
<kbd>e</kbd>: 隐藏/显示已停止的容器
<kbd>p</kbd>: 暂停
<kbd>s</kbd>: 停止
<kbd>s</kbd>: start/stop
<kbd>r</kbd>: 重新启动
<kbd>a</kbd>: attach
<kbd>m</kbd>: 查看日志

View file

@ -220,6 +220,9 @@ type CommandTemplatesConfig struct {
// ServiceTop is the command for viewing the processes under a given service
ServiceTop string `yaml:"serviceTop,omitempty"`
// List of shells that, in given order, will be tried when attaching to a container.
PreferredExecShells []string `yaml:"preferedExecShell,omitempty"`
}
// OSConfig contains config on the level of the os
@ -402,6 +405,7 @@ func GetDefaultConfig() UserConfig {
DockerComposeConfig: "{{ .DockerCompose }} config",
CheckDockerComposeConfig: "{{ .DockerCompose }} config --quiet",
ServiceTop: "{{ .DockerCompose }} top {{ .Service.Name }}",
PreferredExecShells: []string{},
},
CustomCommands: CustomCommands{
Containers: []CustomCommand{},

View file

@ -359,6 +359,8 @@ func (gui *Gui) handleContainersRemoveMenu(g *gocui.Gui, v *gocui.View) error {
})
}
// TODO: do same thing for start
// Fix UI not showing it being paused (it should say unpaused)
func (gui *Gui) PauseContainer(container *commands.Container) error {
return gui.WithWaitingStatus(gui.Tr.PausingStatus, func() (err error) {
if container.Details.State.Paused {
@ -384,12 +386,22 @@ func (gui *Gui) handleContainerPause(g *gocui.Gui, v *gocui.View) error {
return gui.PauseContainer(ctr)
}
func (gui *Gui) handleContainerStop(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleContainerStartStop(g *gocui.Gui, v *gocui.View) error {
ctr, err := gui.Panels.Containers.GetSelectedItem()
if err != nil {
return nil
}
if !(ctr.Container.State == "exited" || ctr.Container.State == "running") {
return gui.createErrorPanel(gui.Tr.CannotStartStop)
}
if ctr.Container.State == "exited" {
return gui.WithWaitingStatus(gui.Tr.StoppingStatus, func() error {
return ctr.Start()
})
}
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.StopContainer, func(g *gocui.Gui, v *gocui.View) error {
return gui.WithWaitingStatus(gui.Tr.StoppingStatus, func() error {
if err := ctr.Stop(); err != nil {
@ -466,11 +478,32 @@ func (gui *Gui) containerExecShell(container *commands.Container) error {
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
Container: container,
})
var command string
shell := ""
preferredExecShells := gui.Config.UserConfig.CommandTemplates.PreferredExecShells
if len(preferredExecShells) > 0 {
for _, preferredExecShell := range preferredExecShells {
command := utils.ApplyTemplate(fmt.Sprintf("docker exec {{ .Container.ID }} which %s", preferredExecShell), commandObject)
err := gui.runCommandSilently(gui.OSCommand.ExecutableFromString(command))
if err == nil {
shell = preferredExecShell
break
}
}
}
// TODO: Use SDK
// Use default implementation in case we cannot fulfill user's preference
if shell == "" {
command = utils.ApplyTemplate("docker exec -it {{ .Container.ID }} /bin/sh -c 'eval $(grep ^$(id -un): /etc/passwd | cut -d : -f 7-)'", commandObject)
} else {
command = utils.ApplyTemplate(fmt.Sprintf("docker exec -it {{ .Container.ID }} %s", shell), commandObject)
}
// TODO: use SDK
resolvedCommand := utils.ApplyTemplate("docker exec -it {{ .Container.ID }} /bin/sh -c 'eval $(grep ^$(id -un): /etc/passwd | cut -d : -f 7-)'", commandObject)
// attach and return the subprocess error
cmd := gui.OSCommand.ExecutableFromString(resolvedCommand)
cmd := gui.OSCommand.ExecutableFromString(command)
return gui.runSubprocess(cmd)
}

View file

@ -210,8 +210,8 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "containers",
Key: 's',
Modifier: gocui.ModNone,
Handler: gui.handleContainerStop,
Description: gui.Tr.Stop,
Handler: gui.handleContainerStartStop,
Description: gui.Tr.StartStop,
},
{
ViewName: "containers",

View file

@ -26,7 +26,7 @@ func (gui *Gui) runSubprocessWithMessage(cmd *exec.Cmd, msg string) error {
gui.PauseBackgroundThreads = true
gui.runCommand(cmd, msg)
err := gui.runCommand(cmd, msg)
if err := gui.g.Resume(); err != nil {
return gui.createErrorPanel(err.Error())
@ -34,10 +34,26 @@ func (gui *Gui) runSubprocessWithMessage(cmd *exec.Cmd, msg string) error {
gui.PauseBackgroundThreads = false
return nil
return err
}
func (gui *Gui) runCommand(cmd *exec.Cmd, msg string) {
func (gui *Gui) runCommandSilently(cmd *exec.Cmd) error {
stop := make(chan os.Signal, 1)
defer signal.Stop(stop)
go func() {
signal.Notify(stop, os.Interrupt)
<-stop
if err := gui.OSCommand.Kill(cmd); err != nil {
gui.Log.Error(err)
}
}()
return cmd.Run()
}
func (gui *Gui) runCommand(cmd *exec.Cmd, msg string) error {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout
cmd.Stdin = os.Stdin
@ -58,9 +74,8 @@ func (gui *Gui) runCommand(cmd *exec.Cmd, msg string) {
if msg != "" {
fmt.Fprintf(os.Stdout, "\n%s\n\n", utils.ColoredString(msg, color.FgGreen))
}
if err := cmd.Run(); err != nil {
// not handling the error explicitly because usually we're going to see it
// in the output anyway
err := cmd.Run()
if err != nil {
gui.Log.Error(err)
}
@ -69,4 +84,6 @@ func (gui *Gui) runCommand(cmd *exec.Cmd, msg string) {
cmd.Stderr = io.Discard
gui.promptToReturn()
return err
}

View file

@ -26,6 +26,7 @@ type TranslationSet struct {
CannotAttachStoppedContainerError string
CannotAccessDockerSocketError string
CannotKillChildError string
CannotStartStop string
Donate string
Cancel string
@ -59,6 +60,7 @@ type TranslationSet struct {
Down string
DownWithVolumes string
Start string
StartStop string
Rebuild string
Recreate string
PreviousContext string
@ -161,6 +163,7 @@ func englishSet() TranslationSet {
CannotAttachStoppedContainerError: "You cannot attach to a stopped container, you need to start it first (which you can actually do with the 'r' key) (yes I'm too lazy to do this automatically for you) (pretty cool that I get to communicate one-on-one with you in the form of an error message though)",
CannotAccessDockerSocketError: "Can't access docker socket at: unix:///var/run/docker.sock\nRun lazydocker as root or read https://docs.docker.com/install/linux/linux-postinstall/",
CannotKillChildError: "Waited three seconds for child process to stop. There may be an orphan process that continues to run on your system.",
CannotStartStop: "Cannot start stop this container",
Donate: "Donate",
Confirm: "Confirm",
@ -190,6 +193,7 @@ func englishSet() TranslationSet {
Down: "down project",
DownWithVolumes: "down project with volumes",
Start: "start",
StartStop: "start/stop",
Rebuild: "rebuild",
Recreate: "recreate",
PreviousContext: "previous tab",