mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31: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"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
|
@ -17,8 +13,6 @@ import (
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||||
"github.com/jesseduffield/pty"
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
"golang.org/x/xerrors"
|
"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"))
|
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]
|
key := container.ID + "-" + gui.getContainerContexts()[gui.State.Panels.Containers.ContextIndex]
|
||||||
if gui.State.Panels.Main.ObjectKey == key {
|
if gui.State.Panels.Main.ObjectKey == key {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -189,17 +177,32 @@ func (gui *Gui) renderContainerLogs(mainView *gocui.View, container *commands.Co
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
cmd = gui.OSCommand.RunCustomCommand("docker logs --since=60m --timestamps --follow " + container.ID)
|
cmd = gui.OSCommand.RunCustomCommand("docker logs --since=60m --timestamps --follow " + container.ID)
|
||||||
|
|
||||||
cmd.Stdout = mainView
|
r, err := cmd.StdoutPipe()
|
||||||
cmd.Start()
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
gui.State.MainProcessChan <- struct{}{}
|
||||||
time.Sleep(time.Second / 100)
|
gui.State.MainProcessMutex.Lock()
|
||||||
if gui.State.Panels.Main.WriterID != writerID {
|
cmd.Start()
|
||||||
cmd.Process.Kill()
|
|
||||||
return
|
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
|
return nil
|
||||||
|
|
@ -404,55 +407,10 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.State.Panels.Main.WriterID++
|
c := container.Attach()
|
||||||
|
|
||||||
// c := container.Attach()
|
gui.SubProcess = c
|
||||||
|
return gui.Errors.ErrSubProcess
|
||||||
// // 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleServiceRestart(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleServiceRestart(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package gui
|
package gui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"fmt"
|
||||||
"io"
|
|
||||||
"math"
|
"math"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
// "io"
|
// "io"
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
|
||||||
// "strings"
|
// "strings"
|
||||||
|
|
@ -110,6 +111,8 @@ type guiState struct {
|
||||||
Updating bool
|
Updating bool
|
||||||
Panels *panelStates
|
Panels *panelStates
|
||||||
SubProcessOutput string
|
SubProcessOutput string
|
||||||
|
MainProcessMutex sync.Mutex
|
||||||
|
MainProcessChan chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGui builds a new gui handler
|
// NewGui builds a new gui handler
|
||||||
|
|
@ -128,8 +131,17 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
||||||
ObjectKey: "",
|
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{
|
gui := &Gui{
|
||||||
Log: log,
|
Log: log,
|
||||||
DockerCommand: dockerCommand,
|
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 {
|
type listViewState struct {
|
||||||
selectedLine int
|
selectedLine int
|
||||||
lineCount int
|
lineCount int
|
||||||
|
|
@ -541,16 +543,9 @@ func (gui *Gui) RunWithSubprocesses() error {
|
||||||
if err == gocui.ErrQuit {
|
if err == gocui.ErrQuit {
|
||||||
break
|
break
|
||||||
} else if err == gui.Errors.ErrSubProcess {
|
} else if err == gui.Errors.ErrSubProcess {
|
||||||
gui.SubProcess.Stdin = os.Stdin
|
if err := gui.runCommand(); err != nil {
|
||||||
output, err := gui.runCommand(gui.SubProcess)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
gui.State.SubProcessOutput = output
|
|
||||||
gui.SubProcess.Stdout = ioutil.Discard
|
|
||||||
gui.SubProcess.Stderr = ioutil.Discard
|
|
||||||
gui.SubProcess.Stdin = nil
|
|
||||||
gui.SubProcess = nil
|
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -559,20 +554,29 @@ func (gui *Gui) RunWithSubprocesses() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// adapted from https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html
|
func (gui *Gui) runCommand() error {
|
||||||
func (gui *Gui) runCommand(cmd *exec.Cmd) (string, error) {
|
gui.SubProcess.Stdout = os.Stdout
|
||||||
var stdoutBuf bytes.Buffer
|
gui.SubProcess.Stderr = os.Stdout
|
||||||
cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
|
gui.SubProcess.Stdin = os.Stdin
|
||||||
cmd.Stderr = io.MultiWriter(os.Stderr, &stdoutBuf)
|
|
||||||
|
|
||||||
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
|
// not handling the error explicitly because usually we're going to see it
|
||||||
// in the output anyway
|
// in the output anyway
|
||||||
gui.Log.Error(err)
|
gui.Log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
outStr := stdoutBuf.String()
|
gui.SubProcess.Stdout = ioutil.Discard
|
||||||
return outStr, nil
|
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 {
|
func (gui *Gui) quit(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue