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
cf5ec17197
commit
09eaab23f4
9 changed files with 174 additions and 34 deletions
4
main.go
4
main.go
|
|
@ -34,6 +34,10 @@ func main() {
|
||||||
fmt.Printf("%s\n", config.GetDefaultConfig())
|
fmt.Printf("%s\n", config.GetDefaultConfig())
|
||||||
os.Exit(0)
|
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)
|
appConfig, err := config.NewAppConfig("lazydocker", version, commit, date, buildSource, *debuggingFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
|
|
|
||||||
|
|
@ -9,32 +9,34 @@ import (
|
||||||
// Container : A git Container
|
// Container : A git Container
|
||||||
type Container struct {
|
type Container struct {
|
||||||
Name string
|
Name string
|
||||||
|
ServiceName string
|
||||||
ID string
|
ID string
|
||||||
State string
|
|
||||||
Container types.Container
|
Container types.Container
|
||||||
DisplayString string
|
DisplayString string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisplayStrings returns the dispaly string of Container
|
// GetDisplayStrings returns the dispaly string of Container
|
||||||
func (b *Container) GetDisplayStrings(isFocused bool) []string {
|
func (c *Container) GetDisplayStrings(isFocused bool) []string {
|
||||||
displayName := utils.ColoredString(b.Name, b.GetColor())
|
displayName := utils.ColoredString(c.Name, c.GetColor())
|
||||||
|
|
||||||
return []string{displayName}
|
return []string{c.ServiceName, displayName}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetColor Container color
|
// GetColor Container color
|
||||||
func (b *Container) GetColor() color.Attribute {
|
func (c *Container) GetColor() color.Attribute {
|
||||||
return color.FgWhite
|
switch c.Container.State {
|
||||||
|
case "exited":
|
||||||
// todo: change color based on state.
|
|
||||||
|
|
||||||
switch b.State {
|
|
||||||
case "feature":
|
|
||||||
return color.FgGreen
|
|
||||||
case "bugfix":
|
|
||||||
return color.FgYellow
|
|
||||||
case "hotfix":
|
|
||||||
return color.FgRed
|
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:
|
default:
|
||||||
return color.FgWhite
|
return color.FgWhite
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ package commands
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"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/jesseduffield/lazydocker/pkg/config"
|
"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
|
// GetContainers returns a slice of docker containers
|
||||||
func (c *DockerCommand) GetContainers() ([]*Container, error) {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ownContainers := make([]*Container, len(containers))
|
ownContainers := make([]*Container, len(containers))
|
||||||
|
|
||||||
for i, container := range containers {
|
for i, container := range containers {
|
||||||
fmt.Printf("%s %s\n", container.ID[:10], container.Image)
|
c.Log.Warn(spew.Sdump(container))
|
||||||
ownContainers[i] = &Container{ID: container.ID, Name: "test", Container: 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
|
return ownContainers, nil
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ func GetDefaultConfig() []byte {
|
||||||
`gui:
|
`gui:
|
||||||
## stuff relating to the UI
|
## stuff relating to the UI
|
||||||
scrollHeight: 2
|
scrollHeight: 2
|
||||||
scrollPastBottom: true
|
scrollPastBottom: false
|
||||||
mouseEvents: false # will default to true when the feature is complete
|
mouseEvents: false # will default to true when the feature is complete
|
||||||
theme:
|
theme:
|
||||||
activeBorderColor:
|
activeBorderColor:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
package gui
|
package gui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
"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"
|
||||||
|
|
@ -48,21 +54,71 @@ func (gui *Gui) handleContainerSelect(g *gocui.Gui, v *gocui.View, alreadySelect
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// container, err := gui.getSelectedContainer(g)
|
container, err := gui.getSelectedContainer(g)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// if err != gui.Errors.ErrNoContainers {
|
if err != gui.Errors.ErrNoContainers {
|
||||||
// return err
|
return err
|
||||||
// }
|
}
|
||||||
// return gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedContainers"))
|
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 {
|
if err := gui.focusPoint(0, gui.State.Panels.Containers.SelectedLine, len(gui.State.Containers), v); err != nil {
|
||||||
return err
|
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 {
|
func (gui *Gui) refreshContainers() error {
|
||||||
|
|
@ -77,6 +133,10 @@ func (gui *Gui) refreshContainers() error {
|
||||||
return err
|
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 {
|
gui.g.Update(func(g *gocui.Gui) error {
|
||||||
|
|
||||||
containersView.Clear()
|
containersView.Clear()
|
||||||
|
|
@ -114,9 +174,17 @@ func (gui *Gui) handleContainersNextLine(g *gocui.Gui, v *gocui.View) error {
|
||||||
return nil
|
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
|
panelState := gui.State.Panels.Containers
|
||||||
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.State.Containers), false)
|
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)
|
return gui.handleContainerSelect(gui.g, v, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ type guiState struct {
|
||||||
Updating bool
|
Updating bool
|
||||||
Panels *panelStates
|
Panels *panelStates
|
||||||
SubProcessOutput string
|
SubProcessOutput string
|
||||||
|
MainWriterID int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGui builds a new gui handler
|
// NewGui builds a new gui handler
|
||||||
|
|
@ -107,6 +108,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
||||||
Containers: &containerPanelState{SelectedLine: -1},
|
Containers: &containerPanelState{SelectedLine: -1},
|
||||||
Menu: &menuPanelState{SelectedLine: 0},
|
Menu: &menuPanelState{SelectedLine: 0},
|
||||||
},
|
},
|
||||||
|
MainWriterID: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
gui := &Gui{
|
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 {
|
func (gui *Gui) scrollUpMain(g *gocui.Gui, v *gocui.View) error {
|
||||||
mainView, _ := g.View("main")
|
mainView, _ := g.View("main")
|
||||||
|
mainView.Autoscroll = false
|
||||||
ox, oy := mainView.Origin()
|
ox, oy := mainView.Origin()
|
||||||
newOy := int(math.Max(0, float64(oy-gui.Config.GetUserConfig().GetInt("gui.scrollHeight"))))
|
newOy := int(math.Max(0, float64(oy-gui.Config.GetUserConfig().GetInt("gui.scrollHeight"))))
|
||||||
return mainView.SetOrigin(ox, newOy)
|
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()) {
|
if y < len(mainView.BufferLines()) {
|
||||||
return mainView.SetOrigin(ox, oy+gui.Config.GetUserConfig().GetInt("gui.scrollHeight"))
|
return mainView.SetOrigin(ox, oy+gui.Config.GetUserConfig().GetInt("gui.scrollHeight"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainView.Autoscroll = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,6 +196,9 @@ func (gui *Gui) onFocusLost(v *gocui.View, newView *gocui.View) error {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if v.Name() == "containers" {
|
||||||
|
gui.State.MainWriterID++
|
||||||
|
}
|
||||||
gui.Log.Info(v.Name() + " focus lost")
|
gui.Log.Info(v.Name() + " focus lost")
|
||||||
return nil
|
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
|
extraSpace := usableSpace - (usableSpace/3)*3
|
||||||
|
|
||||||
vHeights := map[string]int{
|
vHeights := map[string]int{
|
||||||
"status": 3,
|
"status": 3,
|
||||||
"containers": (usableSpace / 3) + extraSpace,
|
"containers": (usableSpace) + extraSpace,
|
||||||
"options": 1,
|
"options": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,7 +346,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// doing this here because it'll only happen once
|
// doing this here because it'll only happen once
|
||||||
if err := gui.loadNewRepo(); err != nil {
|
if err := gui.loadNewDirectory(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -390,7 +398,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||||
return gui.resizeCurrentPopupPanel(g)
|
return gui.resizeCurrentPopupPanel(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) loadNewRepo() error {
|
func (gui *Gui) loadNewDirectory() error {
|
||||||
gui.Updater.CheckForNewUpdate(gui.onBackgroundUpdateCheckFinish, false)
|
gui.Updater.CheckForNewUpdate(gui.onBackgroundUpdateCheckFinish, false)
|
||||||
|
|
||||||
gui.waitForIntro.Done()
|
gui.waitForIntro.Done()
|
||||||
|
|
@ -469,7 +477,7 @@ func (gui *Gui) Run() error {
|
||||||
go func() {
|
go func() {
|
||||||
gui.waitForIntro.Wait()
|
gui.waitForIntro.Wait()
|
||||||
// TODO: see if this is right
|
// 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)
|
gui.goEvery(time.Millisecond*50, gui.renderAppStatus)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
||||||
24
test/printrandom/Dockerfile
Normal file
24
test/printrandom/Dockerfile
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# building the binary
|
||||||
|
FROM golang:1.11 as builder
|
||||||
|
|
||||||
|
# Add Maintainer Info
|
||||||
|
LABEL maintainer="Jesse Duffield <jessedduffield@gmail.com>"
|
||||||
|
|
||||||
|
# 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"]
|
||||||
26
test/printrandom/main.go
Normal file
26
test/printrandom/main.go
Normal file
|
|
@ -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)
|
||||||
|
}()
|
||||||
|
}
|
||||||
BIN
test/printrandom/printrandom
Executable file
BIN
test/printrandom/printrandom
Executable file
Binary file not shown.
Loading…
Add table
Reference in a new issue