Browse Source

add service filter to volumes command

Signed-off-by: Leonardo Peregrino <[email protected]>
Leonardo Peregrino 5 months ago
parent
commit
3a7982fe45
3 changed files with 65 additions and 7 deletions
  1. 19 6
      cmd/compose/volumes.go
  2. 1 0
      pkg/api/api.go
  3. 45 1
      pkg/compose/volumes.go

+ 19 - 6
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

+ 1 - 0
pkg/api/api.go

@@ -104,6 +104,7 @@ type Service interface {
 }
 
 type VolumesOptions struct {
+	Services []string
 }
 
 type VolumesSummary = *volume.Volume

+ 45 - 1
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
 }