From 60f2dd42ee9a4e57c3f14f505f1dc886bb5eaac2 Mon Sep 17 00:00:00 2001 From: Daniil Groysman Date: Tue, 11 Feb 2025 20:24:45 +0300 Subject: [PATCH] Add project name to docker command Determing docker compose project name provides the ability to work with services of each docker compose project separately in various Lazydocker instances, even if services have the same names Determing project name is only available if name explicitly specified in docker compose project config (docker compose v2) --- pkg/commands/docker.go | 33 ++++++++++++++++++++++++++++++++- pkg/gui/project_panel.go | 12 ++++++++---- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/pkg/commands/docker.go b/pkg/commands/docker.go index 28c12c23..07f76f23 100644 --- a/pkg/commands/docker.go +++ b/pkg/commands/docker.go @@ -18,6 +18,7 @@ import ( ctxstore "github.com/docker/cli/cli/context/store" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" + "github.com/goccy/go-yaml" "github.com/imdario/mergo" "github.com/jesseduffield/lazydocker/pkg/commands/ssh" "github.com/jesseduffield/lazydocker/pkg/config" @@ -40,6 +41,7 @@ type DockerCommand struct { Config *config.AppConfig Client *client.Client InDockerComposeProject bool + ProjectName string ErrorChan chan error ContainerMutex deadlock.Mutex ServiceMutex deadlock.Mutex @@ -124,6 +126,17 @@ func NewDockerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Translat if err != nil { dockerCommand.InDockerComposeProject = false log.Warn(err.Error()) + } else { + composeCommand := config.UserConfig.CommandTemplates.DockerCompose + yamlDockerComposeConfig, err := osCommand.RunCommandWithOutput(fmt.Sprintf("%s config --format=yaml", composeCommand)) + + if err == nil { + dockerCommand.ProjectName, err = determineProjectName(yamlDockerComposeConfig) + } + + if err != nil { + log.Warn(err.Error()) + } } return dockerCommand, nil @@ -208,7 +221,7 @@ func (c *DockerCommand) assignContainersToServices(containers []*Container, serv L: for _, service := range services { for _, ctr := range containers { - if !ctr.OneOff && ctr.ServiceName == service.Name { + if !ctr.OneOff && ctr.ServiceName == service.Name && (c.ProjectName == "" || ctr.ProjectName == c.ProjectName) { service.Container = ctr continue L } @@ -360,6 +373,24 @@ func (c *DockerCommand) DockerComposeConfig() string { return output } +// determineProjectName tries to the determine the docker compose project name +func determineProjectName(yamlDockerComposeConfig string) (string, error) { + var projectName string + var config map[string]any + + err := yaml.Unmarshal([]byte(yamlDockerComposeConfig), &config) + if err != nil { + return projectName, err + } + + projectName, ok := config["name"].(string) + if !ok { + return projectName, fmt.Errorf("Incorrect value of docker compose project name in config: %s", config["name"]) + } + + return projectName, nil +} + // determineDockerHost tries to the determine the docker host that we should connect to // in the following order of decreasing precedence: // - value of "DOCKER_HOST" environment variable diff --git a/pkg/gui/project_panel.go b/pkg/gui/project_panel.go index 32c5ad99..2ae537f4 100644 --- a/pkg/gui/project_panel.go +++ b/pkg/gui/project_panel.go @@ -80,10 +80,14 @@ func (gui *Gui) refreshProject() error { 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"] + if gui.DockerCommand.ProjectName != "" { + return gui.DockerCommand.ProjectName + } else { + 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"] + } } } }