WIP on subprocesses

This commit is contained in:
Jesse Duffield 2019-06-03 21:52:25 +10:00
parent 54a5890485
commit f0f96de2b5
7 changed files with 146 additions and 60 deletions

View file

@ -2,6 +2,7 @@ package commands
import (
"os/exec"
"syscall"
"github.com/docker/docker/api/types"
"github.com/fatih/color"
@ -59,3 +60,17 @@ func (s *Service) Attach() (*exec.Cmd, error) {
func (s *Service) Top() (types.ContainerProcessList, error) {
return s.Container.Top()
}
// 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)
cmd := s.OSCommand.ExecutableFromString(command)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
Pgid: 0,
}
return cmd, nil
}

View file

@ -101,10 +101,11 @@ type GuiConfig struct {
}
type CommandTemplatesConfig struct {
RestartService string `yaml:"restartService,omitempty"`
DockerCompose string `yaml:"dockerCompose,omitempty"`
StopService string `yaml:"stopService,omitempty"`
ServiceLogs string `yaml:"serviceLogs,omitempty"`
RestartService string `yaml:"restartService,omitempty"`
DockerCompose string `yaml:"dockerCompose,omitempty"`
StopService string `yaml:"stopService,omitempty"`
ServiceLogs string `yaml:"serviceLogs,omitempty"`
ViewServiceLogs string `yaml:"viewServiceLogs,omitempty"`
}
type OSConfig struct {

View file

@ -1,20 +1,15 @@
package gui
import (
"fmt"
"math"
"strings"
"sync"
// "io"
// "io/ioutil"
"io/ioutil"
"os"
"os/exec"
"time"
"github.com/fatih/color"
"github.com/go-errors/errors"
// "strings"
@ -568,51 +563,6 @@ func (gui *Gui) reRenderMain() error {
return nil
}
// RunWithSubprocesses loops, instantiating a new gocui.Gui with each iteration
// if the error returned from a run is a ErrSubProcess, it runs the subprocess
// otherwise it handles the error, possibly by quitting the application
func (gui *Gui) RunWithSubprocesses() error {
for {
if err := gui.Run(); err != nil {
if err == gocui.ErrQuit {
break
} else if err == gui.Errors.ErrSubProcess {
if err := gui.runCommand(); err != nil {
return err
}
} else {
return err
}
}
}
return nil
}
func (gui *Gui) runCommand() error {
gui.SubProcess.Stdout = os.Stdout
gui.SubProcess.Stderr = os.Stdout
gui.SubProcess.Stdin = os.Stdin
fmt.Fprintf(os.Stdout, "\n%s\n\n", utils.ColoredString("+ "+strings.Join(gui.SubProcess.Args, " "), color.FgBlue))
if err := gui.SubProcess.Run(); err != nil {
// not handling the error explicitly because usually we're going to see it
// in the output anyway
gui.Log.Error(err)
}
gui.SubProcess.Stdout = ioutil.Discard
gui.SubProcess.Stderr = ioutil.Discard
gui.SubProcess.Stdin = nil
gui.SubProcess = nil
// fmt.Fprintf(os.Stdout, "\n%s", utils.ColoredString(gui.Tr.SLocalize("pressEnterToReturn"), color.FgGreen))
// fmt.Scanln() // wait for enter press
return nil
}
func (gui *Gui) quit(g *gocui.Gui, v *gocui.View) error {
if gui.Config.UserConfig.ConfirmOnQuit {
return gui.createConfirmationPanel(g, v, "", gui.Tr.SLocalize("ConfirmQuit"), func(g *gocui.Gui, v *gocui.View) error {

View file

@ -64,12 +64,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Key: 'q',
Modifier: gocui.ModNone,
Handler: gui.quit,
}, {
ViewName: "",
Key: gocui.KeyCtrlC,
Modifier: gocui.ModNone,
Handler: gui.quit,
}, {
},
// {
// ViewName: "",
// Key: gocui.KeyCtrlC,
// Modifier: gocui.ModNone,
// Handler: gui.quit,
// },
{
ViewName: "",
Key: gocui.KeyEsc,
Modifier: gocui.ModNone,
@ -201,6 +203,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleServiceAttach,
Description: gui.Tr.SLocalize("attach"),
},
{
ViewName: "services",
Key: 'm',
Modifier: gocui.ModNone,
Handler: gui.handleServiceViewLogs,
Description: gui.Tr.SLocalize("viewLogs"),
},
{
ViewName: "services",
Key: '[',

View file

@ -278,3 +278,18 @@ func (gui *Gui) handleServiceAttach(g *gocui.Gui, v *gocui.View) error {
gui.SubProcess = c
return gui.Errors.ErrSubProcess
}
func (gui *Gui) handleServiceViewLogs(g *gocui.Gui, v *gocui.View) error {
service, err := gui.getSelectedService()
if err != nil {
return nil
}
c, err := service.ViewLogs()
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
gui.SubProcess = c
return gui.Errors.ErrSubProcess
}

92
pkg/gui/subprocess.go Normal file
View file

@ -0,0 +1,92 @@
package gui
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
"os/signal"
"strings"
"github.com/fatih/color"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/utils"
)
// RunWithSubprocesses loops, instantiating a new gocui.Gui with each iteration
// if the error returned from a run is a ErrSubProcess, it runs the subprocess
// otherwise it handles the error, possibly by quitting the application
func (gui *Gui) RunWithSubprocesses() error {
for {
if err := gui.Run(); err != nil {
if err == gocui.ErrQuit {
break
} else if err == gui.Errors.ErrSubProcess {
if err := gui.runCommand(); err != nil {
return err
}
} else {
return err
}
}
}
return nil
}
func (gui *Gui) runCommand() error {
gui.SubProcess.Stdout = os.Stdout
gui.SubProcess.Stderr = os.Stdout
// gui.SubProcess.Stdin = os.Stdin
reader := bufio.NewReader(os.Stdin)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
gui.SubProcess.Process.Kill()
}()
w, err := gui.SubProcess.StdinPipe()
if err != nil {
return err
}
go func() {
for {
input, err := reader.ReadByte()
gui.Log.Warn("byte received")
gui.Log.Warn(input)
if input == 3 {
gui.SubProcess.Process.Kill()
break
}
if err != nil && err == io.EOF {
gui.SubProcess.Process.Kill()
break
}
w.Write([]byte{input})
}
}()
fmt.Fprintf(os.Stdout, "\n%s\n\n", utils.ColoredString("+ "+strings.Join(gui.SubProcess.Args, " "), color.FgBlue))
if err := gui.SubProcess.Run(); err != nil {
// not handling the error explicitly because usually we're going to see it
// in the output anyway
gui.Log.Error(err)
}
gui.SubProcess.Stdout = ioutil.Discard
gui.SubProcess.Stderr = ioutil.Discard
gui.SubProcess.Stdin = nil
gui.SubProcess = nil
// fmt.Fprintf(os.Stdout, "\n%s", utils.ColoredString(gui.Tr.SLocalize("pressEnterToReturn"), color.FgGreen))
// fmt.Scanln() // wait for enter press
return nil
}

View file

@ -816,6 +816,10 @@ func addEnglish(i18nObject *i18n.Bundle) error {
ID: "attach",
Other: "attach",
},
&i18n.Message{
ID: "viewLogs",
Other: "view logs",
},
&i18n.Message{
ID: "ServicesTitle",
Other: "Services",