allow config option to only show standalone containers

This commit is contained in:
Jesse Duffield 2019-06-08 21:09:53 +10:00
parent 61a10f5cc7
commit a27b429807
6 changed files with 110 additions and 99 deletions

View file

@ -33,7 +33,9 @@ type DockerCommand struct {
ServiceMutex sync.Mutex
Services []*Service
Containers []*Container
Images []*Image
// DisplayContainers is the array of containers we will display in the containers panel. If Gui.ShowAllContainers is false, this will only be those containers which aren't based on a service. This reduces clutter and duplication in the UI
DisplayContainers []*Container
Images []*Image
}
// NewDockerCommand it runs git commands
@ -166,19 +168,13 @@ func (c *DockerCommand) GetContainersAndServices() error {
}
}
// find out which services have corresponding containers and assign them
for _, service := range services {
foundMatch := false
for _, container := range containers {
if container.ServiceID != "" && container.ServiceID == service.ID {
foundMatch = true
service.Container = container
break
}
}
if !foundMatch {
service.Container = nil
}
c.assignContainersToServices(containers, services)
var displayContainers []*Container
if c.Config.UserConfig.Gui.ShowAllContainers {
displayContainers = containers
} else {
displayContainers = c.obtainStandaloneContainers(containers, services)
}
// sort services first by whether they have a linked container, and second by alphabetical order
@ -196,10 +192,39 @@ func (c *DockerCommand) GetContainersAndServices() error {
c.Containers = containers
c.Services = services
c.DisplayContainers = displayContainers
return nil
}
func (c *DockerCommand) assignContainersToServices(containers []*Container, services []*Service) {
L:
for _, service := range services {
for _, container := range containers {
if container.ServiceID != "" && container.ServiceID == service.ID {
service.Container = container
continue L
}
}
service.Container = nil
}
}
func (c *DockerCommand) obtainStandaloneContainers(containers []*Container, services []*Service) []*Container {
standaloneContainers := []*Container{}
L:
for _, container := range containers {
for _, service := range services {
if container.ServiceID != "" && container.ServiceID == service.ID {
continue L
}
}
standaloneContainers = append(standaloneContainers, container)
}
return standaloneContainers
}
// GetContainers gets the docker containers
func (c *DockerCommand) GetContainers() ([]*Container, error) {
c.ContainerMutex.Lock()

View file

@ -94,10 +94,11 @@ type ThemeConfig struct {
}
type GuiConfig struct {
ScrollHeight int `yaml:"scrollHeight,omitempty"`
ScrollPastBottom bool `yaml:"scrollPastBottom,omitempty"`
MouseEvents bool `yaml:"mouseEvents,omitempty"`
Theme ThemeConfig `yaml:"theme,omitempty"`
ScrollHeight int `yaml:"scrollHeight,omitempty"`
ScrollPastBottom bool `yaml:"scrollPastBottom,omitempty"`
MouseEvents bool `yaml:"mouseEvents,omitempty"`
Theme ThemeConfig `yaml:"theme,omitempty"`
ShowAllContainers bool `yaml:"showAllContainers,omitempty"`
}
type CommandTemplatesConfig struct {
@ -139,6 +140,7 @@ type StatsConfig struct {
}
// GetDefaultConfig returns the application default configuration
// NOTE: do not default a boolean to true, because false is the boolean zero value and this will be ignored when parsing the user's config
func GetDefaultConfig() UserConfig {
return UserConfig{
Gui: GuiConfig{
@ -150,6 +152,7 @@ func GetDefaultConfig() UserConfig {
InactiveBorderColor: []string{"white"},
OptionsTextColor: []string{"blue"},
},
ShowAllContainers: false,
},
Reporting: "undetermined",
ConfirmOnQuit: false,

View file

@ -28,7 +28,7 @@ func (gui *Gui) getSelectedContainer(g *gocui.Gui) (*commands.Container, error)
return &commands.Container{}, gui.Errors.ErrNoContainers
}
return gui.DockerCommand.Containers[selectedLine], nil
return gui.DockerCommand.DisplayContainers[selectedLine], nil
}
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
newSelectedLine := cy - oy
if newSelectedLine > len(gui.DockerCommand.Containers)-1 || len(utils.Decolorise(gui.DockerCommand.Containers[newSelectedLine].Name)) < cx {
if newSelectedLine > len(gui.DockerCommand.DisplayContainers)-1 || len(utils.Decolorise(gui.DockerCommand.DisplayContainers[newSelectedLine].Name)) < cx {
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
}
if err := gui.focusPoint(0, gui.State.Panels.Containers.SelectedLine, len(gui.DockerCommand.Containers), v); err != nil {
if err := gui.focusPoint(0, gui.State.Panels.Containers.SelectedLine, len(gui.DockerCommand.DisplayContainers), v); err != nil {
return err
}
@ -147,15 +147,45 @@ func (gui *Gui) renderContainerLogs(mainView *gocui.View, container *commands.Co
}
func (gui *Gui) renderLogsForRegularContainer(container *commands.Container) error {
mainView := gui.getMainView()
go gui.T.NewTickerTask(time.Millisecond*200, nil, func(stop, notifyStopped chan struct{}) {
gui.clearMainView()
cmd := gui.OSCommand.RunCustomCommand(utils.ApplyTemplate(gui.Config.UserConfig.CommandTemplates.ContainerLogs, container))
gui.renderLogs(container, gui.Config.UserConfig.CommandTemplates.ContainerLogs, func(cmd *exec.Cmd) {
mainView := gui.getMainView()
cmd.Stdout = mainView
cmd.Stderr = mainView
})
return nil
}
func (gui *Gui) renderLogsForTTYContainer(container *commands.Container) error {
gui.renderLogs(container, gui.Config.UserConfig.CommandTemplates.ContainerTTYLogs, func(cmd *exec.Cmd) {
// for some reason just saying cmd.Stdout = mainView does not work here as it does for non-tty containers, so we feed it through line by line
r, err := cmd.StdoutPipe()
if err != nil {
gui.ErrorChan <- err
}
go func() {
mainView := gui.getMainView()
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'))
}
}()
})
return nil
}
func (gui *Gui) renderLogs(container *commands.Container, template string, setup func(*exec.Cmd)) {
gui.T.NewTickerTask(time.Millisecond*200, nil, func(stop, notifyStopped chan struct{}) {
gui.clearMainView()
command := utils.ApplyTemplate(gui.Config.UserConfig.CommandTemplates.ContainerTTYLogs, container)
cmd := gui.OSCommand.RunCustomCommand(command)
setup(cmd)
cmd.Start()
@ -187,59 +217,6 @@ func (gui *Gui) renderLogsForRegularContainer(container *commands.Container) err
}
}
})
return nil
}
func (gui *Gui) runProcessWithLock(cmd *exec.Cmd) {
go gui.T.NewTask(func(stop chan struct{}) {
gui.clearMainView()
cmd.Start()
go func() {
<-stop
cmd.Process.Kill()
}()
cmd.Wait()
})
}
func (gui *Gui) renderLogsForTTYContainer(container *commands.Container) error {
mainView := gui.getMainView()
gui.T.NewTickerTask(time.Millisecond*200, nil, func(stop, notifyStopped chan struct{}) {
gui.clearMainView()
command := utils.ApplyTemplate(gui.Config.UserConfig.CommandTemplates.ContainerTTYLogs, container)
cmd := gui.OSCommand.RunCustomCommand(command)
// for some reason just saying cmd.Stdout = mainView does not work here as it does for non-tty containers, so we feed it through line by line
r, err := cmd.StdoutPipe()
if err != nil {
gui.ErrorChan <- err
}
go func() {
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'))
}
}()
cmd.Start()
go func() {
<-stop
cmd.Process.Kill()
return
}()
cmd.Wait()
})
return nil
}
func (gui *Gui) refreshContainersAndServices() error {
@ -275,11 +252,11 @@ func (gui *Gui) refreshContainersAndServices() error {
}
}
if len(gui.DockerCommand.Containers) > 0 && gui.State.Panels.Containers.SelectedLine == -1 {
if len(gui.DockerCommand.DisplayContainers) > 0 && gui.State.Panels.Containers.SelectedLine == -1 {
gui.State.Panels.Containers.SelectedLine = 0
}
if len(gui.DockerCommand.Containers)-1 < gui.State.Panels.Containers.SelectedLine {
gui.State.Panels.Containers.SelectedLine = len(gui.DockerCommand.Containers) - 1
if len(gui.DockerCommand.DisplayContainers)-1 < gui.State.Panels.Containers.SelectedLine {
gui.State.Panels.Containers.SelectedLine = len(gui.DockerCommand.DisplayContainers) - 1
}
// doing the exact same thing for services
@ -293,7 +270,7 @@ func (gui *Gui) refreshContainersAndServices() error {
gui.g.Update(func(g *gocui.Gui) error {
containersView.Clear()
isFocused := gui.g.CurrentView().Name() == "containers"
list, err := utils.RenderList(gui.DockerCommand.Containers, utils.IsFocused(isFocused))
list, err := utils.RenderList(gui.DockerCommand.DisplayContainers, utils.IsFocused(isFocused))
if err != nil {
return err
}
@ -337,7 +314,7 @@ func (gui *Gui) handleContainersNextLine(g *gocui.Gui, v *gocui.View) error {
}
panelState := gui.State.Panels.Containers
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Containers), false)
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.DisplayContainers), false)
return gui.handleContainerSelect(gui.g, v)
}
@ -348,7 +325,7 @@ func (gui *Gui) handleContainersPrevLine(g *gocui.Gui, v *gocui.View) error {
}
panelState := gui.State.Panels.Containers
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Containers), true)
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.DisplayContainers), true)
return gui.handleContainerSelect(gui.g, v)
}

View file

@ -164,7 +164,11 @@ func (gui *Gui) layout(g *gocui.Gui) error {
return err
}
containersView.Highlight = true
containersView.Title = gui.Tr.ContainersTitle
if gui.Config.UserConfig.Gui.ShowAllContainers {
containersView.Title = gui.Tr.ContainersTitle
} else {
containersView.Title = gui.Tr.StandaloneContainersTitle
}
containersView.FgColor = gocui.ColorWhite
gui.focusPoint(0, gui.State.Panels.Containers.SelectedLine, len(gui.DockerCommand.Containers), containersView)

View file

@ -57,16 +57,16 @@ func (gui *Gui) runCommand() error {
gui.Log.Error(err)
}
gui.SubProcess.Stdin = nil
gui.SubProcess.Stdout = ioutil.Discard
gui.SubProcess.Stderr = ioutil.Discard
gui.SubProcess = nil
signal.Stop(c)
fmt.Fprintf(os.Stdout, "\n%s", utils.ColoredString(gui.Tr.PressEnterToReturn, color.FgGreen))
fmt.Scanln() // wait for enter press
gui.SubProcess.Stdout = ioutil.Discard
gui.SubProcess.Stderr = ioutil.Discard
gui.SubProcess.Stdin = nil
gui.SubProcess = nil
return nil
}

View file

@ -41,6 +41,7 @@ type TranslationSet struct {
ViewLogs string
ServicesTitle string
ContainersTitle string
StandaloneContainersTitle string
ImagesTitle string
NoContainers string
NoImages string
@ -97,12 +98,13 @@ func englishSet() TranslationSet {
AnonymousReportingTitle: "Help make lazydocker better",
AnonymousReportingPrompt: "Would you like to enable anonymous reporting data to help improve lazydocker? (enter/esc)",
StatusTitle: "Status",
ServicesTitle: "Services",
ContainersTitle: "Containers",
ImagesTitle: "Images",
CustomCommandTitle: "Custom Command:",
ErrorTitle: "Error",
StatusTitle: "Status",
ServicesTitle: "Services",
ContainersTitle: "Containers",
StandaloneContainersTitle: "Standalone Containers",
ImagesTitle: "Images",
CustomCommandTitle: "Custom Command:",
ErrorTitle: "Error",
NoContainers: "No containers",
NoImages: "No images",