more progress

This commit is contained in:
Jesse Duffield 2019-06-02 17:54:59 +10:00
parent 3cfa4a2bda
commit 5bf1a40d2f
9 changed files with 120 additions and 100 deletions

View file

@ -30,15 +30,10 @@ type Container struct {
OSCommand *OSCommand OSCommand *OSCommand
Log *logrus.Entry Log *logrus.Entry
Stats ContainerCliStat Stats ContainerCliStat
StatHistory []ContainerCliStat
Details Details Details Details
} }
type DetailsCollection struct {
InspectDetails Details
CLIStats ContainerCliStat
ClientStats ContainerStats
}
type Details struct { type Details struct {
ID string `json:"Id"` ID string `json:"Id"`
Created time.Time `json:"Created"` Created time.Time `json:"Created"`
@ -251,11 +246,13 @@ func (c *Container) GetDisplayStrings(isFocused bool) []string {
// GetDisplayCPUPerc colors the cpu percentage based on how extreme it is // GetDisplayCPUPerc colors the cpu percentage based on how extreme it is
func (c *Container) GetDisplayCPUPerc() string { func (c *Container) GetDisplayCPUPerc() string {
if c.Stats.CPUPerc == "" { stats := c.GetStats()
if stats.CPUPerc == "" {
return "" return ""
} }
percentage, err := strconv.ParseFloat(strings.TrimSuffix(c.Stats.CPUPerc, "%"), 32) percentage, err := strconv.ParseFloat(strings.TrimSuffix(stats.CPUPerc, "%"), 32)
if err != nil { if err != nil {
c.Log.Error(err) c.Log.Error(err)
return "" return ""
@ -270,7 +267,7 @@ func (c *Container) GetDisplayCPUPerc() string {
clr = color.FgWhite clr = color.FgWhite
} }
return utils.ColoredString(c.Stats.CPUPerc, clr) return utils.ColoredString(stats.CPUPerc, clr)
} }
// GetColor Container color // GetColor Container color
@ -344,3 +341,11 @@ func (c *Container) Attach() (*exec.Cmd, error) {
func (c *Container) Top() (types.ContainerProcessList, error) { func (c *Container) Top() (types.ContainerProcessList, error) {
return c.Client.ContainerTop(context.Background(), c.ID, []string{}) return c.Client.ContainerTop(context.Background(), c.ID, []string{})
} }
// GetStats gets the container's most recent stats
func (c *Container) GetStats() ContainerCliStat {
if len(c.StatHistory) == 0 {
return ContainerCliStat{}
}
return c.StatHistory[len(c.StatHistory)-1]
}

View file

@ -1,12 +1,15 @@
package commands package commands
import ( import (
"bufio"
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
"sync"
"github.com/acarl005/stripansi"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client" "github.com/docker/docker/client"
@ -25,6 +28,11 @@ type DockerCommand struct {
Client *client.Client Client *client.Client
InDockerComposeProject bool InDockerComposeProject bool
ErrorChan chan error ErrorChan chan error
ContainerMutex sync.Mutex
ServiceMutex sync.Mutex
Services []*Service
Containers []*Container
Images []*Image
} }
// NewDockerCommand it runs git commands // NewDockerCommand it runs git commands
@ -45,50 +53,54 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Localize
}, nil }, nil
} }
// UpdateContainerStats takes a slice of containers and returns the same slice but with new stats added // MonitorContainerStats monitors a stream of container stats and updates the containers as each new stats object is received
// TODO: consider using this for everything stats-related func (c *DockerCommand) MonitorContainerStats() {
func (c *DockerCommand) UpdateContainerStats(containers []*Container) {
// TODO: consider using a stream rather than polling command := `docker stats --all --no-trunc --format '{{json .}}'`
command := `docker stats --all --no-trunc --no-stream --format '{{json .}}'` cmd := c.OSCommand.RunCustomCommand(command)
output, err := c.OSCommand.RunCommandWithOutput(command)
r, err := cmd.StdoutPipe()
if err != nil { if err != nil {
c.ErrorChan <- err c.ErrorChan <- err
return return
} }
jsonStats := "[" + strings.Join( cmd.Start()
strings.Split(
strings.Trim(output, "\n"), "\n",
), ",",
) + "]"
c.Log.Warn(jsonStats) scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanLines)
var stats []ContainerCliStat for scanner.Scan() {
if err := json.Unmarshal([]byte(jsonStats), &stats); err != nil { var stats ContainerCliStat
c.ErrorChan <- err // need to strip ANSI codes because uses escape sequences to clear the screen with each refresh
return cleanString := stripansi.Strip(scanner.Text())
} if err := json.Unmarshal([]byte(cleanString), &stats); err != nil {
c.ErrorChan <- err
for _, stat := range stats { return
for _, container := range containers { }
if container.ID == stat.ID { c.ContainerMutex.Lock()
container.Stats = stat for _, container := range c.Containers {
if container.ID == stats.ID {
container.StatHistory = append(container.StatHistory, stats)
} }
} }
c.ContainerMutex.Unlock()
} }
c.Log.Warn("updated containers") cmd.Wait()
return return
} }
// GetContainersAndServices returns a slice of docker containers // GetContainersAndServices returns a slice of docker containers
func (c *DockerCommand) GetContainersAndServices(currentServices []*Service) ([]*Container, []*Service, error) { func (c *DockerCommand) GetContainersAndServices() error {
c.ServiceMutex.Lock()
defer c.ServiceMutex.Unlock()
currentServices := c.Services
containers, err := c.GetContainers() containers, err := c.GetContainers()
if err != nil { if err != nil {
return nil, nil, err return err
} }
var services []*Service var services []*Service
@ -98,7 +110,7 @@ func (c *DockerCommand) GetContainersAndServices(currentServices []*Service) ([]
} else { } else {
services, err = c.GetServices() services, err = c.GetServices()
if err != nil { if err != nil {
return nil, nil, err return err
} }
} }
@ -124,11 +136,19 @@ func (c *DockerCommand) GetContainersAndServices(currentServices []*Service) ([]
return services[i].Name < services[j].Name return services[i].Name < services[j].Name
}) })
return containers, services, nil c.Containers = containers
c.Services = services
return nil
} }
// GetContainers gets the docker containers // GetContainers gets the docker containers
func (c *DockerCommand) GetContainers() ([]*Container, error) { func (c *DockerCommand) GetContainers() ([]*Container, error) {
c.ContainerMutex.Lock()
defer c.ContainerMutex.Unlock()
currentContainers := c.Containers
containers, err := c.Client.ContainerList(context.Background(), types.ContainerListOptions{All: true}) containers, err := c.Client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if err != nil { if err != nil {
return nil, err return nil, err
@ -149,12 +169,16 @@ func (c *DockerCommand) GetContainers() ([]*Container, error) {
OSCommand: c.OSCommand, OSCommand: c.OSCommand,
Log: c.Log, Log: c.Log,
} }
// bring across old stats information
for _, currentContainer := range currentContainers {
if currentContainer.ID == container.ID {
ownContainers[i].StatHistory = currentContainer.StatHistory // might need to use pointers here in case we're deep copying everything
ownContainers[i].Details = currentContainer.Details
}
}
} }
c.UpdateContainerDetails(ownContainers)
c.UpdateContainerStats(ownContainers)
return ownContainers, nil return ownContainers, nil
} }
@ -191,7 +215,12 @@ func (c *DockerCommand) GetServices() ([]*Service, error) {
// UpdateContainerDetails attaches the details returned from docker inspect to each of the containers // UpdateContainerDetails attaches the details returned from docker inspect to each of the containers
// this contains a bit more info than what you get from the go-docker client // this contains a bit more info than what you get from the go-docker client
func (c *DockerCommand) UpdateContainerDetails(containers []*Container) error { func (c *DockerCommand) UpdateContainerDetails() error {
c.ContainerMutex.Lock()
defer c.ContainerMutex.Unlock()
containers := c.Containers
ids := make([]string, len(containers)) ids := make([]string, len(containers))
for i, container := range containers { for i, container := range containers {
ids[i] = container.ID ids[i] = container.ID

View file

@ -4,7 +4,6 @@ import (
"context" "context"
"strings" "strings"
"github.com/davecgh/go-spew/spew"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/fatih/color" "github.com/fatih/color"
@ -91,8 +90,6 @@ func (i *Image) RenderHistory() (string, error) {
return "", err return "", err
} }
i.Log.Warn(spew.Sdump(history))
layers := make([]*Layer, len(history)) layers := make([]*Layer, len(history))
for i, layer := range history { for i, layer := range history {
layers[i] = &Layer{layer} layers[i] = &Layer{layer}

View file

@ -1,12 +1,14 @@
package commands package commands
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"time"
"github.com/go-errors/errors" "github.com/go-errors/errors"
@ -58,9 +60,11 @@ func (c *OSCommand) SetCommand(cmd func(string, ...string) *exec.Cmd) {
// RunCommandWithOutput wrapper around commands returning their output and error // RunCommandWithOutput wrapper around commands returning their output and error
func (c *OSCommand) RunCommandWithOutput(command string) (string, error) { func (c *OSCommand) RunCommandWithOutput(command string) (string, error) {
c.Log.WithField("command", command).Info("RunCommand")
cmd := c.ExecutableFromString(command) cmd := c.ExecutableFromString(command)
return sanitisedCommandOutput(cmd.CombinedOutput()) before := time.Now()
output, err := sanitisedCommandOutput(cmd.CombinedOutput())
c.Log.Warn(fmt.Sprintf("'%s': %s", command, time.Since(before)))
return output, err
} }
// RunExecutableWithOutput runs an executable file and returns its output // RunExecutableWithOutput runs an executable file and returns its output
@ -77,7 +81,7 @@ func (c *OSCommand) RunExecutable(cmd *exec.Cmd) error {
// ExecutableFromString takes a string like `git status` and returns an executable command for it // ExecutableFromString takes a string like `git status` and returns an executable command for it
func (c *OSCommand) ExecutableFromString(commandStr string) *exec.Cmd { func (c *OSCommand) ExecutableFromString(commandStr string) *exec.Cmd {
splitCmd := str.ToArgv(commandStr) splitCmd := str.ToArgv(commandStr)
c.Log.Info(splitCmd) // c.Log.Info(splitCmd)
return c.command(splitCmd[0], splitCmd[1:]...) return c.command(splitCmd[0], splitCmd[1:]...)
} }

View file

@ -28,7 +28,7 @@ func (gui *Gui) getSelectedContainer(g *gocui.Gui) (*commands.Container, error)
return &commands.Container{}, gui.Errors.ErrNoContainers return &commands.Container{}, gui.Errors.ErrNoContainers
} }
return gui.State.Containers[selectedLine], nil return gui.DockerCommand.Containers[selectedLine], nil
} }
func (gui *Gui) handleContainersFocus(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleContainersFocus(g *gocui.Gui, v *gocui.View) error {
@ -42,7 +42,7 @@ func (gui *Gui) handleContainersFocus(g *gocui.Gui, v *gocui.View) error {
prevSelectedLine := gui.State.Panels.Containers.SelectedLine prevSelectedLine := gui.State.Panels.Containers.SelectedLine
newSelectedLine := cy - oy newSelectedLine := cy - oy
if newSelectedLine > len(gui.State.Containers)-1 || len(utils.Decolorise(gui.State.Containers[newSelectedLine].Name)) < cx { if newSelectedLine > len(gui.DockerCommand.Containers)-1 || len(utils.Decolorise(gui.DockerCommand.Containers[newSelectedLine].Name)) < cx {
return gui.handleContainerSelect(gui.g, v) return gui.handleContainerSelect(gui.g, v)
} }
@ -75,7 +75,7 @@ func (gui *Gui) handleContainerSelect(g *gocui.Gui, v *gocui.View) error {
gui.State.Panels.Main.ObjectKey = key gui.State.Panels.Main.ObjectKey = key
} }
if err := gui.focusPoint(0, gui.State.Panels.Containers.SelectedLine, len(gui.State.Containers), v); err != nil { if err := gui.focusPoint(0, gui.State.Panels.Containers.SelectedLine, len(gui.DockerCommand.Containers), v); err != nil {
return err return err
} }
@ -109,7 +109,7 @@ func (gui *Gui) renderContainerConfig(mainView *gocui.View, container *commands.
mainView.Autoscroll = false mainView.Autoscroll = false
mainView.Title = "Config" mainView.Title = "Config"
data, err := json.MarshalIndent(&container.Container, "", " ") data, err := json.MarshalIndent(&container.Details, "", " ")
if err != nil { if err != nil {
return err return err
} }
@ -242,25 +242,25 @@ func (gui *Gui) refreshContainersAndServices() error {
return err return err
} }
if len(gui.State.Containers) > 0 && gui.State.Panels.Containers.SelectedLine == -1 { if len(gui.DockerCommand.Containers) > 0 && gui.State.Panels.Containers.SelectedLine == -1 {
gui.State.Panels.Containers.SelectedLine = 0 gui.State.Panels.Containers.SelectedLine = 0
} }
if len(gui.State.Containers)-1 < gui.State.Panels.Containers.SelectedLine { if len(gui.DockerCommand.Containers)-1 < gui.State.Panels.Containers.SelectedLine {
gui.State.Panels.Containers.SelectedLine = len(gui.State.Containers) - 1 gui.State.Panels.Containers.SelectedLine = len(gui.DockerCommand.Containers) - 1
} }
// doing the exact same thing for services // doing the exact same thing for services
if len(gui.State.Services) > 0 && gui.State.Panels.Services.SelectedLine == -1 { if len(gui.DockerCommand.Services) > 0 && gui.State.Panels.Services.SelectedLine == -1 {
gui.State.Panels.Services.SelectedLine = 0 gui.State.Panels.Services.SelectedLine = 0
} }
if len(gui.State.Services)-1 < gui.State.Panels.Services.SelectedLine { if len(gui.DockerCommand.Services)-1 < gui.State.Panels.Services.SelectedLine {
gui.State.Panels.Services.SelectedLine = len(gui.State.Services) - 1 gui.State.Panels.Services.SelectedLine = len(gui.DockerCommand.Services) - 1
} }
gui.g.Update(func(g *gocui.Gui) error { gui.g.Update(func(g *gocui.Gui) error {
containersView.Clear() containersView.Clear()
isFocused := gui.g.CurrentView().Name() == "containers" isFocused := gui.g.CurrentView().Name() == "containers"
list, err := utils.RenderList(gui.State.Containers, utils.IsFocused(isFocused)) list, err := utils.RenderList(gui.DockerCommand.Containers, utils.IsFocused(isFocused))
if err != nil { if err != nil {
return err return err
} }
@ -279,7 +279,7 @@ func (gui *Gui) refreshContainersAndServices() error {
servicesView := gui.getServicesView() servicesView := gui.getServicesView()
servicesView.Clear() servicesView.Clear()
isFocused = gui.g.CurrentView().Name() == "services" isFocused = gui.g.CurrentView().Name() == "services"
list, err = utils.RenderList(gui.State.Services, utils.IsFocused(isFocused)) list, err = utils.RenderList(gui.DockerCommand.Services, utils.IsFocused(isFocused))
if err != nil { if err != nil {
return err return err
} }
@ -295,15 +295,7 @@ func (gui *Gui) refreshContainersAndServices() error {
} }
func (gui *Gui) refreshStateContainersAndServices() error { func (gui *Gui) refreshStateContainersAndServices() error {
containers, services, err := gui.DockerCommand.GetContainersAndServices(gui.State.Services) return gui.DockerCommand.GetContainersAndServices()
if err != nil {
return err
}
gui.State.Containers = containers
gui.State.Services = services
return nil
} }
func (gui *Gui) handleContainersNextLine(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleContainersNextLine(g *gocui.Gui, v *gocui.View) error {
@ -312,7 +304,7 @@ func (gui *Gui) handleContainersNextLine(g *gocui.Gui, v *gocui.View) error {
} }
panelState := gui.State.Panels.Containers panelState := gui.State.Panels.Containers
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Containers), false) gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Containers), false)
return gui.handleContainerSelect(gui.g, v) return gui.handleContainerSelect(gui.g, v)
} }
@ -323,7 +315,7 @@ func (gui *Gui) handleContainersPrevLine(g *gocui.Gui, v *gocui.View) error {
} }
panelState := gui.State.Panels.Containers panelState := gui.State.Panels.Containers
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Containers), true) gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Containers), true)
return gui.handleContainerSelect(gui.g, v) return gui.handleContainerSelect(gui.g, v)
} }

View file

@ -109,9 +109,6 @@ type panelStates struct {
} }
type guiState struct { type guiState struct {
Services []*commands.Service
Containers []*commands.Container
Images []*commands.Image
MenuItemCount int // can't store the actual list because it's of interface{} type MenuItemCount int // can't store the actual list because it's of interface{} type
PreviousView string PreviousView string
Platform commands.Platform Platform commands.Platform
@ -126,7 +123,6 @@ type guiState struct {
func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand *commands.OSCommand, tr *i18n.Localizer, config *config.AppConfig, errorChan chan error) (*Gui, error) { func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand *commands.OSCommand, tr *i18n.Localizer, config *config.AppConfig, errorChan chan error) (*Gui, error) {
initialState := guiState{ initialState := guiState{
Containers: make([]*commands.Container, 0),
PreviousView: "services", PreviousView: "services",
Platform: *oSCommand.Platform, Platform: *oSCommand.Platform,
Panels: &panelStates{ Panels: &panelStates{
@ -430,8 +426,8 @@ func (gui *Gui) layout(g *gocui.Gui) error {
} }
listViews := map[*gocui.View]listViewState{ listViews := map[*gocui.View]listViewState{
containersView: {selectedLine: gui.State.Panels.Containers.SelectedLine, lineCount: len(gui.State.Containers)}, containersView: {selectedLine: gui.State.Panels.Containers.SelectedLine, lineCount: len(gui.DockerCommand.Containers)},
imagesView: {selectedLine: gui.State.Panels.Images.SelectedLine, lineCount: len(gui.State.Images)}, imagesView: {selectedLine: gui.State.Panels.Images.SelectedLine, lineCount: len(gui.DockerCommand.Images)},
} }
// menu view might not exist so we check to be safe // menu view might not exist so we check to be safe
@ -501,6 +497,7 @@ func (gui *Gui) renderGlobalOptions() error {
} }
func (gui *Gui) goEvery(interval time.Duration, function func() error) { func (gui *Gui) goEvery(interval time.Duration, function func() error) {
_ = function() // time.Tick doesn't run immediately so we'll do that here // TODO: maybe change
go func() { go func() {
for range time.Tick(interval) { for range time.Tick(interval) {
_ = function() _ = function()
@ -536,9 +533,12 @@ func (gui *Gui) Run() error {
gui.waitForIntro.Wait() gui.waitForIntro.Wait()
gui.goEvery(time.Millisecond*50, gui.renderAppStatus) gui.goEvery(time.Millisecond*50, gui.renderAppStatus)
gui.goEvery(time.Millisecond*30, gui.reRenderMain) gui.goEvery(time.Millisecond*30, gui.reRenderMain)
gui.goEvery(time.Millisecond*500, gui.refreshContainersAndServices) gui.goEvery(time.Millisecond*100, gui.refreshContainersAndServices)
gui.goEvery(time.Millisecond*1000, gui.DockerCommand.UpdateContainerDetails)
}() }()
go gui.DockerCommand.MonitorContainerStats()
go func() { go func() {
for err := range gui.ErrorChan { for err := range gui.ErrorChan {
gui.createErrorPanel(gui.g, err.Error()) gui.createErrorPanel(gui.g, err.Error())

View file

@ -25,7 +25,7 @@ func (gui *Gui) getSelectedImage(g *gocui.Gui) (*commands.Image, error) {
return &commands.Image{}, gui.Errors.ErrNoImages return &commands.Image{}, gui.Errors.ErrNoImages
} }
return gui.State.Images[selectedLine], nil return gui.DockerCommand.Images[selectedLine], nil
} }
func (gui *Gui) handleImagesFocus(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleImagesFocus(g *gocui.Gui, v *gocui.View) error {
@ -39,7 +39,7 @@ func (gui *Gui) handleImagesFocus(g *gocui.Gui, v *gocui.View) error {
prevSelectedLine := gui.State.Panels.Images.SelectedLine prevSelectedLine := gui.State.Panels.Images.SelectedLine
newSelectedLine := cy - oy newSelectedLine := cy - oy
if newSelectedLine > len(gui.State.Images)-1 || len(utils.Decolorise(gui.State.Images[newSelectedLine].Name)) < cx { if newSelectedLine > len(gui.DockerCommand.Images)-1 || len(utils.Decolorise(gui.DockerCommand.Images[newSelectedLine].Name)) < cx {
return gui.handleImageSelect(gui.g, v) return gui.handleImageSelect(gui.g, v)
} }
@ -72,7 +72,7 @@ func (gui *Gui) handleImageSelect(g *gocui.Gui, v *gocui.View) error {
gui.State.Panels.Main.ObjectKey = key gui.State.Panels.Main.ObjectKey = key
} }
if err := gui.focusPoint(0, gui.State.Panels.Images.SelectedLine, len(gui.State.Images), v); err != nil { if err := gui.focusPoint(0, gui.State.Panels.Images.SelectedLine, len(gui.DockerCommand.Images), v); err != nil {
return err return err
} }
@ -129,18 +129,18 @@ func (gui *Gui) refreshImages() error {
return err return err
} }
if len(gui.State.Images) > 0 && gui.State.Panels.Images.SelectedLine == -1 { if len(gui.DockerCommand.Images) > 0 && gui.State.Panels.Images.SelectedLine == -1 {
gui.State.Panels.Images.SelectedLine = 0 gui.State.Panels.Images.SelectedLine = 0
} }
if len(gui.State.Images)-1 < gui.State.Panels.Images.SelectedLine { if len(gui.DockerCommand.Images)-1 < gui.State.Panels.Images.SelectedLine {
gui.State.Panels.Images.SelectedLine = len(gui.State.Images) - 1 gui.State.Panels.Images.SelectedLine = len(gui.DockerCommand.Images) - 1
} }
gui.g.Update(func(g *gocui.Gui) error { gui.g.Update(func(g *gocui.Gui) error {
ImagesView.Clear() ImagesView.Clear()
isFocused := gui.g.CurrentView().Name() == "Images" isFocused := gui.g.CurrentView().Name() == "Images"
list, err := utils.RenderList(gui.State.Images, utils.IsFocused(isFocused)) list, err := utils.RenderList(gui.DockerCommand.Images, utils.IsFocused(isFocused))
if err != nil { if err != nil {
return err return err
} }
@ -161,7 +161,7 @@ func (gui *Gui) refreshStateImages() error {
return err return err
} }
gui.State.Images = Images gui.DockerCommand.Images = Images
return nil return nil
} }
@ -172,7 +172,7 @@ func (gui *Gui) handleImagesNextLine(g *gocui.Gui, v *gocui.View) error {
} }
panelState := gui.State.Panels.Images panelState := gui.State.Panels.Images
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Images), false) gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Images), false)
return gui.handleImageSelect(gui.g, v) return gui.handleImageSelect(gui.g, v)
} }
@ -183,7 +183,7 @@ func (gui *Gui) handleImagesPrevLine(g *gocui.Gui, v *gocui.View) error {
} }
panelState := gui.State.Panels.Images panelState := gui.State.Panels.Images
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Images), true) gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Images), true)
return gui.handleImageSelect(gui.g, v) return gui.handleImageSelect(gui.g, v)
} }

View file

@ -23,7 +23,7 @@ func (gui *Gui) getSelectedService(g *gocui.Gui) (*commands.Service, error) {
return &commands.Service{}, errors.New("no service selected") return &commands.Service{}, errors.New("no service selected")
} }
return gui.State.Services[selectedLine], nil return gui.DockerCommand.Services[selectedLine], nil
} }
func (gui *Gui) handleServicesFocus(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleServicesFocus(g *gocui.Gui, v *gocui.View) error {
@ -37,7 +37,7 @@ func (gui *Gui) handleServicesFocus(g *gocui.Gui, v *gocui.View) error {
prevSelectedLine := gui.State.Panels.Services.SelectedLine prevSelectedLine := gui.State.Panels.Services.SelectedLine
newSelectedLine := cy - oy newSelectedLine := cy - oy
if newSelectedLine > len(gui.State.Services)-1 || len(utils.Decolorise(gui.State.Services[newSelectedLine].Name)) < cx { if newSelectedLine > len(gui.DockerCommand.Services)-1 || len(utils.Decolorise(gui.DockerCommand.Services[newSelectedLine].Name)) < cx {
return gui.handleServiceSelect(gui.g, v) return gui.handleServiceSelect(gui.g, v)
} }
@ -67,7 +67,7 @@ func (gui *Gui) handleServiceSelect(g *gocui.Gui, v *gocui.View) error {
gui.State.Panels.Main.ObjectKey = key gui.State.Panels.Main.ObjectKey = key
} }
if err := gui.focusPoint(0, gui.State.Panels.Services.SelectedLine, len(gui.State.Services), v); err != nil { if err := gui.focusPoint(0, gui.State.Panels.Services.SelectedLine, len(gui.DockerCommand.Services), v); err != nil {
return err return err
} }
@ -137,7 +137,7 @@ func (gui *Gui) handleServicesNextLine(g *gocui.Gui, v *gocui.View) error {
} }
panelState := gui.State.Panels.Services panelState := gui.State.Panels.Services
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Services), false) gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Services), false)
return gui.handleServiceSelect(gui.g, v) return gui.handleServiceSelect(gui.g, v)
} }
@ -148,7 +148,7 @@ func (gui *Gui) handleServicesPrevLine(g *gocui.Gui, v *gocui.View) error {
} }
panelState := gui.State.Panels.Services panelState := gui.State.Panels.Services
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Services), true) gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Services), true)
return gui.handleServiceSelect(gui.g, v) return gui.handleServiceSelect(gui.g, v)
} }

View file

@ -24,15 +24,10 @@ func NewTaskManager(log *logrus.Entry) *TaskManager {
} }
func (t *TaskManager) NewTask(f func(stop chan struct{})) error { func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
t.Log.Warn("new task")
t.waitingMutex.Lock() t.waitingMutex.Lock()
defer t.waitingMutex.Unlock() defer t.waitingMutex.Unlock()
t.Log.Warn("locked mutex")
if t.currentTask != nil { if t.currentTask != nil {
t.Log.Warn("about to ask current task to stop")
t.currentTask.Stop() t.currentTask.Stop()
} }
@ -46,7 +41,6 @@ func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
} }
go func() { go func() {
t.Log.Warn("running new task")
f(stop) f(stop)
notifyStopped <- struct{}{} notifyStopped <- struct{}{}
}() }()
@ -57,6 +51,5 @@ func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
func (t *Task) Stop() { func (t *Task) Stop() {
t.stop <- struct{}{} t.stop <- struct{}{}
<-t.notifyStopped <-t.notifyStopped
t.Log.Warn("task successfully stopped")
return return
} }