From 3a7982fe456127704d74063f4c402ed256be6558 Mon Sep 17 00:00:00 2001 From: Leonardo Peregrino <55335068+leoperegrino@users.noreply.github.com> Date: Wed, 18 Jun 2025 00:25:07 -0300 Subject: [PATCH] add service filter to volumes command Signed-off-by: Leonardo Peregrino <55335068+leoperegrino@users.noreply.github.com> --- cmd/compose/volumes.go | 25 +++++++++++++++++------ pkg/api/api.go | 1 + pkg/compose/volumes.go | 46 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/cmd/compose/volumes.go b/cmd/compose/volumes.go index fb79c7a4a..d98f71db3 100644 --- a/cmd/compose/volumes.go +++ b/cmd/compose/volumes.go @@ -19,6 +19,7 @@ package compose import ( "context" "fmt" + "slices" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/formatter" @@ -39,13 +40,12 @@ func volumesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic } cmd := &cobra.Command{ - Use: "volumes [OPTIONS]", + Use: "volumes [OPTIONS] [SERVICE...]", Short: "List volumes", RunE: Adapt(func(ctx context.Context, args []string) error { - return runVol(ctx, dockerCli, backend, options) + return runVol(ctx, dockerCli, backend, args, options) }), - Args: cobra.NoArgs, - ValidArgsFunction: noCompletion(), + ValidArgsFunction: completeServiceNames(dockerCli, p), } cmd.Flags().BoolVarP(&options.Quiet, "quiet", "q", false, "Only display volume names") @@ -54,13 +54,26 @@ func volumesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic return cmd } -func runVol(ctx context.Context, dockerCli command.Cli, backend api.Service, options volumesOptions) error { - project, _, err := options.projectOrName(ctx, dockerCli, []string{}...) +func runVol(ctx context.Context, dockerCli command.Cli, backend api.Service, services []string, options volumesOptions) error { + project, _, err := options.projectOrName(ctx, dockerCli, services...) if err != nil { return err } + names := project.ServiceNames() + + if len(services) == 0 { + services = names + } + + for _, service := range services { + if !slices.Contains(names, service) { + return fmt.Errorf("no such service: %s", service) + } + } + volumes, err := backend.Volumes(ctx, project, api.VolumesOptions{ + Services: services, }) if err != nil { return err diff --git a/pkg/api/api.go b/pkg/api/api.go index ccb44640c..d3e8f0e9f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -104,6 +104,7 @@ type Service interface { } type VolumesOptions struct { + Services []string } type VolumesSummary = *volume.Volume diff --git a/pkg/compose/volumes.go b/pkg/compose/volumes.go index 0ea3c9a1a..8df99cb19 100644 --- a/pkg/compose/volumes.go +++ b/pkg/compose/volumes.go @@ -18,7 +18,9 @@ package compose import ( "context" + "slices" + "github.com/docker/docker/api/types/container" "github.com/compose-spec/compose-go/v2/types" "github.com/docker/compose/v2/pkg/api" "github.com/docker/docker/api/types/filters" @@ -29,6 +31,26 @@ func (s *composeService) Volumes( ctx context.Context, project *types.Project, o projectName := project.Name + allContainers, err := s.apiClient().ContainerList(ctx, container.ListOptions{ + Filters: filters.NewArgs(projectFilter(projectName)), + }) + if err != nil { + return nil, err + } + + var containers []container.Summary + + if len(options.Services) > 0 { + // filter service containers + for _, c := range allContainers { + if slices.Contains(options.Services, c.Labels[api.ServiceLabel]) { + containers = append(containers, c) + } + } + } else { + containers = allContainers + } + volumesResponse, err := s.apiClient().VolumeList(ctx, volume.ListOptions{ Filters: filters.NewArgs(projectFilter(projectName)), }) @@ -38,5 +60,27 @@ func (s *composeService) Volumes( ctx context.Context, project *types.Project, o projectVolumes := volumesResponse.Volumes - return projectVolumes, nil + if len(options.Services) == 0 { + return projectVolumes, nil + } + + var volumes []api.VolumesSummary + + // create a name lookup of volumes used by containers + serviceVolumes := make(map[string]bool) + + for _, container := range containers { + for _, mount := range container.Mounts { + serviceVolumes[mount.Name] = true + } + } + + // append if volumes in this project are in serviceVolumes + for _, v := range projectVolumes { + if serviceVolumes[v.Name] { + volumes = append(volumes, v) + } + } + + return volumes, nil }