mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-21 23:01:03 +00:00
fix this insane CPU usage issue
This commit is contained in:
parent
46d27c477e
commit
159a1883e5
10 changed files with 86 additions and 40 deletions
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/fatih/color"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/xerrors"
|
||||
|
|
@ -298,9 +299,14 @@ func (c *Container) RestartService() error {
|
|||
}
|
||||
|
||||
// Attach attaches the container
|
||||
func (c *Container) Attach() *exec.Cmd {
|
||||
func (c *Container) Attach() (*exec.Cmd, error) {
|
||||
// verify that we can in fact attach to this container
|
||||
if !c.Details.Config.AttachStdin {
|
||||
return nil, errors.New("Container does not support attaching. You must either run the service with the '-it' flag or use `stdin_open: true, tty: true` in the docker-compose.yml file")
|
||||
}
|
||||
|
||||
cmd := c.OSCommand.PrepareSubProcess("docker", "attach", "--sig-proxy=false", c.ID)
|
||||
return cmd
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
// Top returns process information
|
||||
|
|
|
|||
|
|
@ -78,16 +78,22 @@ func (c *DockerCommand) UpdateContainerStats(containers []*Container) ([]*Contai
|
|||
}
|
||||
|
||||
// GetContainersAndServices returns a slice of docker containers
|
||||
func (c *DockerCommand) GetContainersAndServices() ([]*Container, []*Service, error) {
|
||||
func (c *DockerCommand) GetContainersAndServices(currentServices []*Service) ([]*Container, []*Service, error) {
|
||||
|
||||
containers, err := c.GetContainers()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
services, err := c.GetServices()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
var services []*Service
|
||||
// we only need to get these services once because they won't change in the runtime of the program
|
||||
if currentServices != nil {
|
||||
services = currentServices
|
||||
} else {
|
||||
services, err = c.GetServices()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// find out which services have corresponding containers and assign them
|
||||
|
|
@ -170,8 +176,10 @@ func (c *DockerCommand) GetServices() ([]*Service, error) {
|
|||
for i, str := range lines {
|
||||
arr := strings.Split(str, " ")
|
||||
services[i] = &Service{
|
||||
Name: arr[0],
|
||||
ID: arr[1],
|
||||
Name: arr[0],
|
||||
ID: arr[1],
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,12 +11,11 @@ import (
|
|||
|
||||
// Service : A docker Service
|
||||
type Service struct {
|
||||
Name string
|
||||
ID string
|
||||
DisplayString string
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
Container *Container
|
||||
Name string
|
||||
ID string
|
||||
OSCommand *OSCommand
|
||||
Log *logrus.Entry
|
||||
Container *Container
|
||||
}
|
||||
|
||||
// GetDisplayStrings returns the dispaly string of Container
|
||||
|
|
@ -50,7 +49,7 @@ func (s *Service) Restart() error {
|
|||
}
|
||||
|
||||
// Attach attaches to the service
|
||||
func (s *Service) Attach() *exec.Cmd {
|
||||
func (s *Service) Attach() (*exec.Cmd, error) {
|
||||
// TODO: if you have a custom command for attaching to a service here is the place to use it
|
||||
|
||||
return s.Container.Attach()
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ type CommandTemplatesConfig struct {
|
|||
RestartService string `yaml:"restartService,omitempty"`
|
||||
DockerCompose string `yaml:"dockerCompose,omitempty"`
|
||||
StopService string `yaml:"stopService,omitempty"`
|
||||
ServiceLogs string `yaml:"serviceLogs,omitempty"`
|
||||
}
|
||||
|
||||
type OSConfig struct {
|
||||
|
|
@ -132,6 +133,7 @@ func GetDefaultConfig() UserConfig {
|
|||
RestartService: "docker-compose restart {{ .Name }}",
|
||||
DockerCompose: "apdev compose",
|
||||
StopService: "apdev stop {{ .Name }}",
|
||||
ServiceLogs: "apdev logs {{ .Name }}",
|
||||
},
|
||||
OS: GetPlatformDefaultConfig(),
|
||||
Update: UpdateConfig{
|
||||
|
|
|
|||
|
|
@ -220,13 +220,11 @@ func (gui *Gui) renderLogsForTTYContainer(mainView *gocui.View, container *comma
|
|||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
s := bufio.NewScanner(r)
|
||||
s.Split(bufio.ScanLines)
|
||||
for s.Scan() {
|
||||
// I might put a check on the stopped channel here. Would mean more code duplication though
|
||||
mainView.Write(append(s.Bytes(), '\n'))
|
||||
}
|
||||
s := bufio.NewScanner(r)
|
||||
s.Split(bufio.ScanLines)
|
||||
for s.Scan() {
|
||||
// I might put a check on the stopped channel here. Would mean more code duplication though
|
||||
mainView.Write(append(s.Bytes(), '\n'))
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -297,7 +295,7 @@ func (gui *Gui) refreshContainersAndServices() error {
|
|||
}
|
||||
|
||||
func (gui *Gui) refreshStateContainersAndServices() error {
|
||||
containers, services, err := gui.DockerCommand.GetContainersAndServices()
|
||||
containers, services, err := gui.DockerCommand.GetContainersAndServices(gui.State.Services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -457,7 +455,10 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
c := container.Attach()
|
||||
c, err := container.Attach()
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
|
||||
gui.SubProcess = c
|
||||
return gui.Errors.ErrSubProcess
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
|||
Config: config,
|
||||
Tr: tr,
|
||||
statusManager: &statusManager{},
|
||||
T: tasks.NewTaskManager(),
|
||||
T: tasks.NewTaskManager(log),
|
||||
}
|
||||
|
||||
gui.GenerateSentinelErrors()
|
||||
|
|
@ -415,7 +415,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := gui.switchFocus(gui.g, nil, gui.getContainersView()); err != nil {
|
||||
if err := gui.switchFocus(gui.g, nil, gui.getServicesView()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,16 @@ func (gui *Gui) renderServiceStats(mainView *gocui.View, service *commands.Servi
|
|||
}
|
||||
|
||||
func (gui *Gui) renderServiceLogs(mainView *gocui.View, service *commands.Service) error {
|
||||
return nil
|
||||
service, err := gui.getSelectedService(gui.g)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if service.Container == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.renderContainerLogs(gui.getMainView(), service.Container)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleServicesNextLine(g *gocui.Gui, v *gocui.View) error {
|
||||
|
|
@ -255,7 +264,10 @@ func (gui *Gui) handleServiceAttach(g *gocui.Gui, v *gocui.View) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
c := service.Attach()
|
||||
c, err := service.Attach()
|
||||
if err != nil {
|
||||
return gui.createErrorPanel(gui.g, err.Error())
|
||||
}
|
||||
|
||||
gui.SubProcess = c
|
||||
return gui.Errors.ErrSubProcess
|
||||
|
|
|
|||
|
|
@ -7,15 +7,10 @@ import (
|
|||
"github.com/jesseduffield/gocui"
|
||||
)
|
||||
|
||||
func (gui *Gui) refreshStatus(g *gocui.Gui) error {
|
||||
v, err := g.View("status")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// for some reason if this isn't wrapped in an update the clear seems to
|
||||
// be applied after the other things or something like that; the panel's
|
||||
// contents end up cleared
|
||||
g.Update(func(*gocui.Gui) error {
|
||||
func (gui *Gui) refreshStatus() error {
|
||||
v := gui.getStatusView()
|
||||
|
||||
gui.g.Update(func(*gocui.Gui) error {
|
||||
v.Clear()
|
||||
fmt.Fprint(v, "lazydocker")
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
|
|||
if err := gui.refreshImages(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.refreshStatus(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -245,6 +249,11 @@ func (gui *Gui) getMainView() *gocui.View {
|
|||
return v
|
||||
}
|
||||
|
||||
func (gui *Gui) getStatusView() *gocui.View {
|
||||
v, _ := gui.g.View("status")
|
||||
return v
|
||||
}
|
||||
|
||||
func (gui *Gui) trimmedContent(v *gocui.View) string {
|
||||
return strings.TrimSpace(v.Buffer())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,38 @@
|
|||
package tasks
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type TaskManager struct {
|
||||
waitingTasks []*Task
|
||||
currentTask *Task
|
||||
waitingMutex sync.Mutex
|
||||
Log *logrus.Entry
|
||||
}
|
||||
|
||||
type Task struct {
|
||||
stop chan struct{}
|
||||
notifyStopped chan struct{}
|
||||
Log *logrus.Entry
|
||||
}
|
||||
|
||||
func NewTaskManager() *TaskManager {
|
||||
return &TaskManager{}
|
||||
func NewTaskManager(log *logrus.Entry) *TaskManager {
|
||||
return &TaskManager{Log: log}
|
||||
}
|
||||
|
||||
func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
|
||||
t.Log.Warn("new task")
|
||||
|
||||
t.waitingMutex.Lock()
|
||||
defer t.waitingMutex.Unlock()
|
||||
|
||||
t.Log.Warn("locked mutex")
|
||||
|
||||
if t.currentTask != nil {
|
||||
t.Log.Warn("about to ask current task to stop")
|
||||
t.currentTask.Stop()
|
||||
}
|
||||
|
||||
|
|
@ -31,9 +42,11 @@ func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
|
|||
t.currentTask = &Task{
|
||||
stop: stop,
|
||||
notifyStopped: notifyStopped,
|
||||
Log: t.Log,
|
||||
}
|
||||
|
||||
go func() {
|
||||
t.Log.Warn("running new task")
|
||||
f(stop)
|
||||
notifyStopped <- struct{}{}
|
||||
}()
|
||||
|
|
@ -44,5 +57,6 @@ func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
|
|||
func (t *Task) Stop() {
|
||||
t.stop <- struct{}{}
|
||||
<-t.notifyStopped
|
||||
t.Log.Warn("task successfully stopped")
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue