mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
wip on projects
This commit is contained in:
parent
099ae97e68
commit
01f9b3973f
7 changed files with 149 additions and 48 deletions
|
|
@ -41,17 +41,30 @@ func NewApp(config *config.AppConfig) (*App, error) {
|
|||
}
|
||||
app.OSCommand = commands.NewOSCommand(app.Log, config)
|
||||
|
||||
// here is the place to make use of the docker-compose.yml file in the current directory
|
||||
|
||||
app.DockerCommand, err = commands.NewDockerCommand(app.Log, app.OSCommand, app.Tr, app.Config, app.ErrorChan)
|
||||
if err != nil {
|
||||
return app, err
|
||||
}
|
||||
|
||||
app.closers = append(app.closers, app.DockerCommand)
|
||||
app.Gui, err = gui.NewGui(app.Log, app.DockerCommand, app.OSCommand, app.Tr, config, app.ErrorChan)
|
||||
if err != nil {
|
||||
return app, err
|
||||
}
|
||||
|
||||
// here is the place to make use of the docker-compose.yml file in the current directory
|
||||
err = app.OSCommand.RunCommand(
|
||||
utils.ApplyTemplate(
|
||||
config.UserConfig.CommandTemplates.CheckDockerComposeConfig,
|
||||
app.DockerCommand.NewCommandObject(commands.CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
app.DockerCommand.InDockerComposeProject = false
|
||||
app.Log.Warn(err.Error())
|
||||
} else {
|
||||
app.Gui.State.Project = &commands.Project{Name: app.Gui.GetProjectName()}
|
||||
}
|
||||
return app, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,15 +34,16 @@ const (
|
|||
|
||||
// DockerCommand is our main docker interface
|
||||
type DockerCommand struct {
|
||||
Log *logrus.Entry
|
||||
OSCommand *OSCommand
|
||||
Tr *i18n.TranslationSet
|
||||
Config *config.AppConfig
|
||||
Client *client.Client
|
||||
InDockerComposeProject bool
|
||||
ErrorChan chan error
|
||||
ContainerMutex deadlock.Mutex
|
||||
ServiceMutex deadlock.Mutex
|
||||
Log *logrus.Entry
|
||||
OSCommand *OSCommand
|
||||
Tr *i18n.TranslationSet
|
||||
Config *config.AppConfig
|
||||
Client *client.Client
|
||||
InDockerComposeProject bool
|
||||
CurrentDockerComposeProject string
|
||||
ErrorChan chan error
|
||||
ContainerMutex deadlock.Mutex
|
||||
ServiceMutex deadlock.Mutex
|
||||
|
||||
Closers []io.Closer
|
||||
}
|
||||
|
|
@ -112,17 +113,6 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Translat
|
|||
|
||||
dockerCommand.setDockerComposeCommand(config)
|
||||
|
||||
err = osCommand.RunCommand(
|
||||
utils.ApplyTemplate(
|
||||
config.UserConfig.CommandTemplates.CheckDockerComposeConfig,
|
||||
dockerCommand.NewCommandObject(CommandObject{}),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
dockerCommand.InDockerComposeProject = false
|
||||
log.Warn(err.Error())
|
||||
}
|
||||
|
||||
return dockerCommand, nil
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +166,7 @@ func (c *DockerCommand) CreateClientStatMonitor(container *Container) {
|
|||
container.MonitoringStats = false
|
||||
}
|
||||
|
||||
func (c *DockerCommand) RefreshContainersAndServices(currentServices []*Service, currentContainers []*Container) ([]*Container, []*Service, error) {
|
||||
func (c *DockerCommand) RefreshContainersAndServices(currentServices []*Service, currentContainers []*Container, currentProject *Project) ([]*Container, []*Service, error) {
|
||||
c.ServiceMutex.Lock()
|
||||
defer c.ServiceMutex.Unlock()
|
||||
|
||||
|
|
@ -186,17 +176,15 @@ func (c *DockerCommand) RefreshContainersAndServices(currentServices []*Service,
|
|||
}
|
||||
|
||||
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 currentProject != nil {
|
||||
services, err = c.GetServicesFromContainers(containers, currentProject)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
c.assignContainersToServices(containers, services)
|
||||
c.assignContainersToServices(containers, services)
|
||||
//c.assignContainersToProjects(containers)
|
||||
}
|
||||
|
||||
return containers, services, nil
|
||||
}
|
||||
|
|
@ -214,6 +202,11 @@ L:
|
|||
}
|
||||
}
|
||||
|
||||
// GetDockerProjects
|
||||
func (c *DockerCommand) GetDockerProjects() ([]*Project, error) {
|
||||
return []*Project{}, nil
|
||||
}
|
||||
|
||||
// GetContainers gets the docker containers
|
||||
func (c *DockerCommand) GetContainers(existingContainers []*Container) ([]*Container, error) {
|
||||
c.ContainerMutex.Lock()
|
||||
|
|
@ -269,6 +262,42 @@ func (c *DockerCommand) GetContainers(existingContainers []*Container) ([]*Conta
|
|||
return ownContainers, nil
|
||||
}
|
||||
|
||||
// GetServicesFromContainers gets services
|
||||
func (c *DockerCommand) GetServicesFromContainers(containers []*Container, currentProject *Project) ([]*Service, error) {
|
||||
var services []*Service
|
||||
|
||||
if currentProject.Name == "" {
|
||||
return services, nil
|
||||
}
|
||||
|
||||
for _, cont := range containers {
|
||||
if cont.ProjectName != currentProject.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
service := &Service{
|
||||
Name: cont.Name,
|
||||
ID: cont.ID,
|
||||
OSCommand: c.OSCommand,
|
||||
Log: c.Log,
|
||||
DockerCommand: c,
|
||||
}
|
||||
services = append(services, service)
|
||||
}
|
||||
|
||||
//TODO: Should be run once every time the project changes
|
||||
if len(services) == 0 {
|
||||
//If no services are found in running containers fetch services from dockerCompose
|
||||
var err error
|
||||
services, err = c.GetServices()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
// GetServices gets services
|
||||
func (c *DockerCommand) GetServices() ([]*Service, error) {
|
||||
if !c.InDockerComposeProject {
|
||||
|
|
@ -276,6 +305,7 @@ func (c *DockerCommand) GetServices() ([]*Service, error) {
|
|||
}
|
||||
|
||||
composeCommand := c.Config.UserConfig.CommandTemplates.DockerCompose
|
||||
// TODO: Handle remote docker compose files
|
||||
output, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("%s config --services", composeCommand))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ func (gui *Gui) refreshContainersAndServices() error {
|
|||
containers, services, err := gui.DockerCommand.RefreshContainersAndServices(
|
||||
gui.Panels.Services.List.GetAllItems(),
|
||||
gui.Panels.Containers.List.GetAllItems(),
|
||||
gui.State.Project,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -87,8 +87,15 @@ type guiState struct {
|
|||
// Maintains the state of manual filtering i.e. typing in a substring
|
||||
// to filter on in the current panel.
|
||||
Filter filterState
|
||||
|
||||
// Project used for navigation in projects
|
||||
Project *commands.Project
|
||||
}
|
||||
|
||||
//type projectState struct {
|
||||
// name string
|
||||
//}
|
||||
|
||||
type filterState struct {
|
||||
// If true then we're either currently inside the filter view
|
||||
// or we've committed the filter and we're back in the list view
|
||||
|
|
@ -297,7 +304,7 @@ func (gui *Gui) updateContainerDetails() error {
|
|||
|
||||
func (gui *Gui) refresh() {
|
||||
go func() {
|
||||
if err := gui.refreshProject(); err != nil {
|
||||
if err := gui.refreshProjects(); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
|
|
|||
|
|
@ -135,6 +135,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
|||
Handler: gui.handleEditConfig,
|
||||
Description: gui.Tr.EditConfig,
|
||||
},
|
||||
{
|
||||
ViewName: "project",
|
||||
Key: gocui.KeyCtrlP,
|
||||
Modifier: gocui.ModNone,
|
||||
Handler: gui.handleCreateProjectMenu,
|
||||
Description: gui.Tr.SwitchProject,
|
||||
},
|
||||
{
|
||||
ViewName: "project",
|
||||
Key: 'o',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ package gui
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/jesseduffield/lazydocker/pkg/gui/types"
|
||||
"log"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
|
|
@ -60,35 +63,51 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
|
|||
List: panels.NewFilteredList[*commands.Project](),
|
||||
View: gui.Views.Project,
|
||||
},
|
||||
NoItemsMessage: "",
|
||||
NoItemsMessage: "No docker compose projects found.",
|
||||
Gui: gui.intoInterface(),
|
||||
|
||||
Sort: func(a *commands.Project, b *commands.Project) bool {
|
||||
return false
|
||||
return (gui.State.Project != nil && gui.State.Project.Name == a.Name) || a.Name < b.Name
|
||||
},
|
||||
GetTableCells: presentation.GetProjectDisplayStrings,
|
||||
// It doesn't make sense to filter a list of only one item.
|
||||
DisableFilter: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshProject() error {
|
||||
gui.Panels.Projects.SetItems([]*commands.Project{{Name: gui.getProjectName()}})
|
||||
return gui.Panels.Projects.RerenderList()
|
||||
}
|
||||
func (gui *Gui) refreshProjects() error {
|
||||
containers, err := gui.DockerCommand.Client.ContainerList(context.Background(), container.ListOptions{All: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func (gui *Gui) getProjectName() string {
|
||||
projectName := path.Base(gui.Config.ProjectDir)
|
||||
if gui.DockerCommand.InDockerComposeProject {
|
||||
for _, service := range gui.Panels.Services.List.GetAllItems() {
|
||||
container := service.Container
|
||||
if container != nil && container.DetailsLoaded() {
|
||||
return container.Details.Config.Labels["com.docker.compose.project"]
|
||||
}
|
||||
projectsMap := make(map[string]*commands.Project)
|
||||
|
||||
for _, container := range containers {
|
||||
if projectName, exists := container.Labels["com.docker.compose.project"]; exists && projectName != "" {
|
||||
projectsMap[projectName] = &commands.Project{Name: projectName}
|
||||
}
|
||||
}
|
||||
|
||||
return projectName
|
||||
projectsList := make([]*commands.Project, 0, len(projectsMap))
|
||||
for _, project := range projectsMap {
|
||||
projectsList = append(projectsList, project)
|
||||
}
|
||||
|
||||
// Add current's folder project if exists
|
||||
if gui.DockerCommand.InDockerComposeProject {
|
||||
projectsList = append(projectsList, &commands.Project{Name: gui.GetProjectName()})
|
||||
}
|
||||
gui.Panels.Projects.SetItems(projectsList)
|
||||
|
||||
return gui.Panels.Projects.RerenderList()
|
||||
}
|
||||
|
||||
func (gui *Gui) GetProjectName() string {
|
||||
if gui.State.Project != nil {
|
||||
return gui.State.Project.Name
|
||||
}
|
||||
|
||||
// Default to the command line argument
|
||||
return path.Base(gui.Config.ProjectDir)
|
||||
}
|
||||
|
||||
func (gui *Gui) renderCredits(_project *commands.Project) tasks.TaskFunc {
|
||||
|
|
@ -180,3 +199,25 @@ func (gui *Gui) handleViewAllLogs(g *gocui.Gui, v *gocui.View) error {
|
|||
|
||||
return gui.runSubprocess(c)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleCreateProjectMenu(g *gocui.Gui, v *gocui.View) error {
|
||||
if gui.isPopupPanel(v.Name()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
testMenuItem := &types.MenuItem{
|
||||
LabelColumns: []string{"t", "test"},
|
||||
OnPress: func() error {
|
||||
log.Println("tested")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
menuItems := []*types.MenuItem{testMenuItem}
|
||||
|
||||
return gui.Menu(CreateMenuOptions{
|
||||
Title: gui.Tr.MenuTitle,
|
||||
Items: menuItems,
|
||||
HideCancel: true,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ type TranslationSet struct {
|
|||
FilterList string
|
||||
OpenInBrowser string
|
||||
SortContainersByState string
|
||||
SwitchProject string
|
||||
|
||||
LogsTitle string
|
||||
ConfigTitle string
|
||||
|
|
@ -216,6 +217,7 @@ func englishSet() TranslationSet {
|
|||
FilterList: "filter list",
|
||||
OpenInBrowser: "open in browser (first port is http)",
|
||||
SortContainersByState: "sort containers by state",
|
||||
SwitchProject: "switch project",
|
||||
|
||||
GlobalTitle: "Global",
|
||||
MainTitle: "Main",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue