diff --git a/main.go b/main.go index b13fdb02..9716f00c 100644 --- a/main.go +++ b/main.go @@ -34,6 +34,10 @@ func main() { fmt.Printf("%s\n", config.GetDefaultConfig()) os.Exit(0) } + + // for now we're always in debug mode so we're not passing *debuggingFlag + *debuggingFlag = true + appConfig, err := config.NewAppConfig("lazydocker", version, commit, date, buildSource, *debuggingFlag) if err != nil { log.Fatal(err.Error()) diff --git a/pkg/commands/container.go b/pkg/commands/container.go index bf6dc4ed..4942fda9 100644 --- a/pkg/commands/container.go +++ b/pkg/commands/container.go @@ -9,32 +9,34 @@ import ( // Container : A git Container type Container struct { Name string + ServiceName string ID string - State string Container types.Container DisplayString string } // GetDisplayStrings returns the dispaly string of Container -func (b *Container) GetDisplayStrings(isFocused bool) []string { - displayName := utils.ColoredString(b.Name, b.GetColor()) +func (c *Container) GetDisplayStrings(isFocused bool) []string { + displayName := utils.ColoredString(c.Name, c.GetColor()) - return []string{displayName} + return []string{c.ServiceName, displayName} } // GetColor Container color -func (b *Container) GetColor() color.Attribute { - return color.FgWhite - - // todo: change color based on state. - - switch b.State { - case "feature": - return color.FgGreen - case "bugfix": - return color.FgYellow - case "hotfix": +func (c *Container) GetColor() color.Attribute { + switch c.Container.State { + case "exited": return color.FgRed + case "created": + return color.FgCyan + case "running": + return color.FgGreen + case "paused": + return color.FgYellow + case "dead": + return color.FgRed + case "restarting": + return color.FgBlue default: return color.FgWhite } diff --git a/pkg/commands/docker.go b/pkg/commands/docker.go index c1d0cb55..b3ba231e 100644 --- a/pkg/commands/docker.go +++ b/pkg/commands/docker.go @@ -3,7 +3,9 @@ package commands import ( "context" "fmt" + "strings" + "github.com/davecgh/go-spew/spew" "github.com/docker/docker/api/types" "github.com/docker/docker/client" "github.com/jesseduffield/lazydocker/pkg/config" @@ -38,16 +40,22 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Localize // GetContainers returns a slice of docker containers func (c *DockerCommand) GetContainers() ([]*Container, error) { - containers, err := c.Client.ContainerList(context.Background(), types.ContainerListOptions{}) + containers, err := c.Client.ContainerList(context.Background(), types.ContainerListOptions{All: true}) if err != nil { - panic(err) + return nil, err } ownContainers := make([]*Container, len(containers)) for i, container := range containers { - fmt.Printf("%s %s\n", container.ID[:10], container.Image) - ownContainers[i] = &Container{ID: container.ID, Name: "test", Container: container} + c.Log.Warn(spew.Sdump(container)) + c.Log.Warn(fmt.Sprintf("%s %s\n", container.ID[:10], container.Image)) + serviceName, ok := container.Labels["com.docker.compose.service"] + if !ok { + serviceName = "" + c.Log.Warn("Could not get service name from docker container") + } + ownContainers[i] = &Container{ID: container.ID, Name: strings.TrimLeft(container.Names[0], "/"), ServiceName: serviceName, Container: container} } return ownContainers, nil diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 9666aed6..21402900 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -233,7 +233,7 @@ func GetDefaultConfig() []byte { `gui: ## stuff relating to the UI scrollHeight: 2 - scrollPastBottom: true + scrollPastBottom: false mouseEvents: false # will default to true when the feature is complete theme: activeBorderColor: diff --git a/pkg/gui/containers_panel.go b/pkg/gui/containers_panel.go index 7c81ca51..ab558cde 100644 --- a/pkg/gui/containers_panel.go +++ b/pkg/gui/containers_panel.go @@ -1,8 +1,14 @@ package gui import ( + "bufio" + "context" "fmt" + "io" + "time" + "github.com/davecgh/go-spew/spew" + "github.com/docker/docker/api/types" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/utils" @@ -48,21 +54,71 @@ func (gui *Gui) handleContainerSelect(g *gocui.Gui, v *gocui.View, alreadySelect return err } - // container, err := gui.getSelectedContainer(g) - // if err != nil { - // if err != gui.Errors.ErrNoContainers { - // return err - // } - // return gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedContainers")) - // } + container, err := gui.getSelectedContainer(g) + if err != nil { + if err != gui.Errors.ErrNoContainers { + return err + } + return gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedContainers")) + } if err := gui.focusPoint(0, gui.State.Panels.Containers.SelectedLine, len(gui.State.Containers), v); err != nil { return err } - // TODO: render logs + // data, err := json.MarshalIndent(&container.Container, "", " ") + // if err != nil { + // return err + // } - return gui.renderString(g, "main", "haha") + logsReader, err := gui.DockerCommand.Client.ContainerLogs(context.Background(), container.Container.ID, types.ContainerLogsOptions{ + ShowStdout: true, + ShowStderr: true, + Follow: true, + Tail: "20", + Timestamps: true, + }) + if err != nil { + return err + } + + mainView := gui.getMainView() + + gui.State.MainWriterID++ + writerID := gui.State.MainWriterID + mainView.Clear() + gui.Log.Warn(writerID) + + go func() { + defer logsReader.Close() + + time.Sleep(time.Second / 10) + + rd := bufio.NewReader(logsReader) + for { + if gui.State.MainWriterID != writerID { + return + } + + line, err := rd.ReadString('\n') + if err != nil { + if err == io.EOF { + return + } + + gui.Log.Errorf("read file line error: %v", err) + return + } + gui.g.Update(func(g *gocui.Gui) error { + mainView.Write([]byte(line)) + return nil + }) + } + }() + + return nil + + // return gui.renderString(g, "main", string(data)) } func (gui *Gui) refreshContainers() error { @@ -77,6 +133,10 @@ func (gui *Gui) refreshContainers() error { return err } + if len(gui.State.Containers) > 0 && gui.State.Panels.Containers.SelectedLine == -1 { + gui.State.Panels.Containers.SelectedLine = 0 + } + gui.g.Update(func(g *gocui.Gui) error { containersView.Clear() @@ -114,9 +174,17 @@ func (gui *Gui) handleContainersNextLine(g *gocui.Gui, v *gocui.View) error { return nil } + gui.Log.Warn("nexting") + gui.Log.Warn(spew.Sdump(gui.State.Panels.Containers)) + gui.Log.Warn(len(gui.State.Containers)) + panelState := gui.State.Panels.Containers gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Containers), false) + gui.Log.Warn("nexting2") + gui.Log.Warn(spew.Sdump(gui.State.Panels.Containers)) + gui.Log.Warn(len(gui.State.Containers)) + return gui.handleContainerSelect(gui.g, v, false) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 0b194009..3c837c9f 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -94,6 +94,7 @@ type guiState struct { Updating bool Panels *panelStates SubProcessOutput string + MainWriterID int } // NewGui builds a new gui handler @@ -107,6 +108,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand Containers: &containerPanelState{SelectedLine: -1}, Menu: &menuPanelState{SelectedLine: 0}, }, + MainWriterID: 0, } gui := &Gui{ @@ -127,6 +129,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand func (gui *Gui) scrollUpMain(g *gocui.Gui, v *gocui.View) error { mainView, _ := g.View("main") + mainView.Autoscroll = false ox, oy := mainView.Origin() newOy := int(math.Max(0, float64(oy-gui.Config.GetUserConfig().GetInt("gui.scrollHeight")))) return mainView.SetOrigin(ox, newOy) @@ -143,6 +146,8 @@ func (gui *Gui) scrollDownMain(g *gocui.Gui, v *gocui.View) error { if y < len(mainView.BufferLines()) { return mainView.SetOrigin(ox, oy+gui.Config.GetUserConfig().GetInt("gui.scrollHeight")) } + + mainView.Autoscroll = true return nil } @@ -191,6 +196,9 @@ func (gui *Gui) onFocusLost(v *gocui.View, newView *gocui.View) error { if v == nil { return nil } + if v.Name() == "containers" { + gui.State.MainWriterID++ + } gui.Log.Info(v.Name() + " focus lost") return nil } @@ -242,12 +250,12 @@ func (gui *Gui) layout(g *gocui.Gui) error { } } - usableSpace := height - 7 + usableSpace := height - 4 extraSpace := usableSpace - (usableSpace/3)*3 vHeights := map[string]int{ "status": 3, - "containers": (usableSpace / 3) + extraSpace, + "containers": (usableSpace) + extraSpace, "options": 1, } @@ -338,7 +346,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { } // doing this here because it'll only happen once - if err := gui.loadNewRepo(); err != nil { + if err := gui.loadNewDirectory(); err != nil { return err } } @@ -390,7 +398,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { return gui.resizeCurrentPopupPanel(g) } -func (gui *Gui) loadNewRepo() error { +func (gui *Gui) loadNewDirectory() error { gui.Updater.CheckForNewUpdate(gui.onBackgroundUpdateCheckFinish, false) gui.waitForIntro.Done() @@ -469,7 +477,7 @@ func (gui *Gui) Run() error { go func() { gui.waitForIntro.Wait() // TODO: see if this is right - gui.goEvery(time.Second*10, gui.refreshContainers) + // gui.goEvery(time.Second*10, gui.refreshContainers) gui.goEvery(time.Millisecond*50, gui.renderAppStatus) }() diff --git a/test/printrandom/Dockerfile b/test/printrandom/Dockerfile new file mode 100644 index 00000000..9faa4c57 --- /dev/null +++ b/test/printrandom/Dockerfile @@ -0,0 +1,24 @@ +# building the binary +FROM golang:1.11 as builder + +# Add Maintainer Info +LABEL maintainer="Jesse Duffield " + +# Set the Current Working Directory inside the container +WORKDIR /src/github.com/jesseduffield/lazydocker/test/printrandom + +# Copy everything from the current directory to the PWD(Present Working Directory) inside the container +COPY . . + +# Build the package +RUN go build + +# putting binary into a minimal image +FROM scratch + +WORKDIR /root/ + +COPY --from=builder /src/github.com/jesseduffield/lazydocker/test/printrandom/printrandom . + +# Run the executable +CMD ["./printrandom"] \ No newline at end of file diff --git a/test/printrandom/main.go b/test/printrandom/main.go new file mode 100644 index 00000000..41e6fac4 --- /dev/null +++ b/test/printrandom/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "math/rand" + "os" + "os/signal" + "time" +) + +func main() { + exitOnInterrupt() + + for range time.Tick(time.Second / 3) { + fmt.Println(rand.Intn(1000)) + } +} + +func exitOnInterrupt() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + go func() { + <-c + os.Exit(0) + }() +} diff --git a/test/printrandom/printrandom b/test/printrandom/printrandom new file mode 100755 index 00000000..b6f06c8e Binary files /dev/null and b/test/printrandom/printrandom differ