mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-21 23:01:03 +00:00
more progress
This commit is contained in:
parent
f0ffdcd81f
commit
d3ea878fc4
2 changed files with 58 additions and 96 deletions
|
|
@ -5,11 +5,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/fatih/color"
|
||||
|
|
@ -17,8 +13,6 @@ import (
|
|||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
"github.com/jesseduffield/pty"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
|
|
@ -74,12 +68,6 @@ func (gui *Gui) handleContainerSelect(g *gocui.Gui, v *gocui.View) error {
|
|||
return gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedContainers"))
|
||||
}
|
||||
|
||||
// if we are in an attached state, we won't do anything here
|
||||
// TODO: generalise
|
||||
if strings.HasPrefix(gui.State.Panels.Main.ObjectKey, "attached-") {
|
||||
return nil
|
||||
}
|
||||
|
||||
key := container.ID + "-" + gui.getContainerContexts()[gui.State.Panels.Containers.ContextIndex]
|
||||
if gui.State.Panels.Main.ObjectKey == key {
|
||||
return nil
|
||||
|
|
@ -189,17 +177,32 @@ func (gui *Gui) renderContainerLogs(mainView *gocui.View, container *commands.Co
|
|||
var cmd *exec.Cmd
|
||||
cmd = gui.OSCommand.RunCustomCommand("docker logs --since=60m --timestamps --follow " + container.ID)
|
||||
|
||||
cmd.Stdout = mainView
|
||||
cmd.Start()
|
||||
r, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Second / 100)
|
||||
if gui.State.Panels.Main.WriterID != writerID {
|
||||
cmd.Process.Kill()
|
||||
return
|
||||
gui.State.MainProcessChan <- struct{}{}
|
||||
gui.State.MainProcessMutex.Lock()
|
||||
cmd.Start()
|
||||
|
||||
go func() {
|
||||
<-gui.State.MainProcessChan
|
||||
cmd.Process.Kill()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
s := bufio.NewScanner(r)
|
||||
s.Split(bufio.ScanLines)
|
||||
for s.Scan() {
|
||||
mainView.Write(append(s.Bytes(), '\n'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
cmd.Wait()
|
||||
gui.State.MainProcessMutex.Unlock()
|
||||
}()
|
||||
|
||||
return nil
|
||||
|
|
@ -404,55 +407,10 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
gui.State.Panels.Main.WriterID++
|
||||
c := container.Attach()
|
||||
|
||||
// c := container.Attach()
|
||||
|
||||
// // Create arbitrary command.
|
||||
c := exec.Command("bash")
|
||||
|
||||
// Start the command with a pty.
|
||||
ptmx, err := pty.Start(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
// Set stdin in raw mode.
|
||||
oldState, err := terminal.MakeRaw(int(os.Stdin.Fd()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() { _ = terminal.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.
|
||||
defer func() { _ = ptmx.Close() }() // Best effort.
|
||||
|
||||
go func() { _, _ = io.Copy(ptmx, os.Stdin) }()
|
||||
|
||||
mainView := gui.getMainView()
|
||||
mainView.Clear()
|
||||
mainView.Autoscroll = true
|
||||
gui.State.Panels.Main.ObjectKey = "attached-" + container.ID
|
||||
|
||||
scanner := bufio.NewScanner(ptmx)
|
||||
scanner.Split(bufio.ScanBytes)
|
||||
|
||||
content := ""
|
||||
for scanner.Scan() {
|
||||
content += scanner.Text()
|
||||
gui.Log.Warn("content")
|
||||
gui.Log.Warn(content)
|
||||
|
||||
gui.renderString(gui.g, "main", content)
|
||||
}
|
||||
|
||||
// reset object key
|
||||
gui.State.Panels.Main.ObjectKey = ""
|
||||
gui.State.Panels.Main.WriterID++
|
||||
|
||||
gui.handleContainerSelect(gui.g, v)
|
||||
}()
|
||||
|
||||
return nil
|
||||
gui.SubProcess = c
|
||||
return gui.Errors.ErrSubProcess
|
||||
}
|
||||
|
||||
func (gui *Gui) handleServiceRestart(g *gocui.Gui, v *gocui.View) error {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
// "io"
|
||||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/go-errors/errors"
|
||||
|
||||
// "strings"
|
||||
|
|
@ -110,6 +111,8 @@ type guiState struct {
|
|||
Updating bool
|
||||
Panels *panelStates
|
||||
SubProcessOutput string
|
||||
MainProcessMutex sync.Mutex
|
||||
MainProcessChan chan struct{}
|
||||
}
|
||||
|
||||
// NewGui builds a new gui handler
|
||||
|
|
@ -128,8 +131,17 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
|||
ObjectKey: "",
|
||||
},
|
||||
},
|
||||
MainProcessChan: make(chan struct{}),
|
||||
}
|
||||
|
||||
go func() {
|
||||
// setting up a goroutine for listening to the first stop signal on this channel
|
||||
// because whenever something wants to lock the mutex, it tells the existing process to stop
|
||||
// but on startup we don't have a process so we just mock it
|
||||
// this is because we're using an unbuffered channel
|
||||
<-initialState.MainProcessChan
|
||||
}()
|
||||
|
||||
gui := &Gui{
|
||||
Log: log,
|
||||
DockerCommand: dockerCommand,
|
||||
|
|
@ -392,16 +404,6 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
|||
}
|
||||
}
|
||||
|
||||
if gui.State.SubProcessOutput != "" {
|
||||
output := gui.State.SubProcessOutput
|
||||
gui.State.SubProcessOutput = ""
|
||||
x, y := gui.g.Size()
|
||||
// if we just came back from vim, we don't want vim's output to show up in our popup
|
||||
if float64(len(output))*1.5 < float64(x*y) {
|
||||
return gui.createMessagePanel(gui.g, nil, "Output", output)
|
||||
}
|
||||
}
|
||||
|
||||
type listViewState struct {
|
||||
selectedLine int
|
||||
lineCount int
|
||||
|
|
@ -541,16 +543,9 @@ func (gui *Gui) RunWithSubprocesses() error {
|
|||
if err == gocui.ErrQuit {
|
||||
break
|
||||
} else if err == gui.Errors.ErrSubProcess {
|
||||
gui.SubProcess.Stdin = os.Stdin
|
||||
output, err := gui.runCommand(gui.SubProcess)
|
||||
if err != nil {
|
||||
if err := gui.runCommand(); err != nil {
|
||||
return err
|
||||
}
|
||||
gui.State.SubProcessOutput = output
|
||||
gui.SubProcess.Stdout = ioutil.Discard
|
||||
gui.SubProcess.Stderr = ioutil.Discard
|
||||
gui.SubProcess.Stdin = nil
|
||||
gui.SubProcess = nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
|
@ -559,20 +554,29 @@ func (gui *Gui) RunWithSubprocesses() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// adapted from https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html
|
||||
func (gui *Gui) runCommand(cmd *exec.Cmd) (string, error) {
|
||||
var stdoutBuf bytes.Buffer
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, &stdoutBuf)
|
||||
func (gui *Gui) runCommand() error {
|
||||
gui.SubProcess.Stdout = os.Stdout
|
||||
gui.SubProcess.Stderr = os.Stdout
|
||||
gui.SubProcess.Stdin = os.Stdin
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
outStr := stdoutBuf.String()
|
||||
return outStr, nil
|
||||
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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue