mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
chore(images): filter images by name with wildcard pattern using Docker filter
This commit is contained in:
+7
-37
@@ -29,7 +29,7 @@ func NewListCommand() *cobra.Command {
|
|||||||
opts := listOptions{}
|
opts := listOptions{}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "ls [IMAGE]",
|
Use: "ls [REPO:[TAG]]",
|
||||||
Aliases: []string{"list"},
|
Aliases: []string{"list"},
|
||||||
Short: "List images on machines in the cluster.",
|
Short: "List images on machines in the cluster.",
|
||||||
Long: "List images on machines in the cluster. By default, on all machines. Optionally filter by image name.",
|
Long: "List images on machines in the cluster. By default, on all machines. Optionally filter by image name.",
|
||||||
@@ -45,8 +45,8 @@ func NewListCommand() *cobra.Command {
|
|||||||
# List images filtered by name (with any tag) on all machines.
|
# List images filtered by name (with any tag) on all machines.
|
||||||
uc image ls myapp
|
uc image ls myapp
|
||||||
|
|
||||||
# List images filtered by name and tag on specific machine.
|
# List images filtered by name pattern on specific machine.
|
||||||
uc image ls myapp:1.2.3 -m machine1`,
|
uc image ls "myapp:1.*" -m machine1`,
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
@@ -102,7 +102,10 @@ func list(ctx context.Context, uncli *cli.CLI, opts listOptions) error {
|
|||||||
|
|
||||||
machines := cli.ExpandCommaSeparatedValues(opts.machines)
|
machines := cli.ExpandCommaSeparatedValues(opts.machines)
|
||||||
|
|
||||||
clusterImages, err := clusterClient.ListImages(ctx, api.ImageFilter{Machines: machines})
|
clusterImages, err := clusterClient.ListImages(ctx, api.ImageFilter{
|
||||||
|
Machines: machines,
|
||||||
|
Name: opts.nameFilter,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("list images: %w", err)
|
return fmt.Errorf("list images: %w", err)
|
||||||
}
|
}
|
||||||
@@ -156,8 +159,6 @@ func list(ctx context.Context, uncli *cli.CLI, opts listOptions) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rows = filterImagesByName(rows, opts.nameFilter)
|
|
||||||
|
|
||||||
if len(rows) == 0 {
|
if len(rows) == 0 {
|
||||||
if opts.nameFilter != "" {
|
if opts.nameFilter != "" {
|
||||||
fmt.Printf("No images matching '%s' found.\n", opts.nameFilter)
|
fmt.Printf("No images matching '%s' found.\n", opts.nameFilter)
|
||||||
@@ -181,37 +182,6 @@ func list(ctx context.Context, uncli *cli.CLI, opts listOptions) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterImagesByName filters the image rows by image name. It matches any tag of the image if only the name
|
|
||||||
// is provided. For example, if filter is "nginx", it matches "nginx", "nginx:latest", "nginx:1.25", etc.
|
|
||||||
// If filter is "nginx:latest", it matches only "nginx:latest".
|
|
||||||
func filterImagesByName(rows []imageRow, nameFilter string) []imageRow {
|
|
||||||
if nameFilter == "" {
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
var filteredRows []imageRow
|
|
||||||
for _, row := range rows {
|
|
||||||
if row.name == "<none>" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(nameFilter, ":") {
|
|
||||||
// Exact match if filter contains a tag.
|
|
||||||
if row.name == nameFilter {
|
|
||||||
filteredRows = append(filteredRows, row)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match by name prefix if filter does not contain a tag.
|
|
||||||
if strings.HasPrefix(row.name, nameFilter) &&
|
|
||||||
len(row.name) > len(nameFilter) && row.name[len(nameFilter)] == ':' {
|
|
||||||
filteredRows = append(filteredRows, row)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filteredRows
|
|
||||||
}
|
|
||||||
|
|
||||||
// imagePlatforms returns a list of platforms supported by the image and a boolean indicating if it's multi-platform.
|
// imagePlatforms returns a list of platforms supported by the image and a boolean indicating if it's multi-platform.
|
||||||
func imagePlatforms(img image.Summary) ([]string, bool) {
|
func imagePlatforms(img image.Summary) ([]string, bool) {
|
||||||
var formattedPlatforms []string
|
var formattedPlatforms []string
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ type ImageFilter struct {
|
|||||||
// Machines filters images to those present on the specified machines (names or IDs).
|
// Machines filters images to those present on the specified machines (names or IDs).
|
||||||
// If empty, it matches images on all machines.
|
// If empty, it matches images on all machines.
|
||||||
Machines []string
|
Machines []string
|
||||||
|
// Name filters images by name (with or without tag). Accepts a wildcard pattern.
|
||||||
|
// If empty, it matches all image names.
|
||||||
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// MachineRemoteImage represents an image in a remote registry fetched by a particular machine.
|
// MachineRemoteImage represents an image in a remote registry fetched by a particular machine.
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
dockerclient "github.com/docker/docker/client"
|
dockerclient "github.com/docker/docker/client"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
@@ -52,6 +53,12 @@ func (cli *Client) ListImages(ctx context.Context, filter api.ImageFilter) ([]ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := image.ListOptions{Manifests: true}
|
opts := image.ListOptions{Manifests: true}
|
||||||
|
if filter.Name != "" {
|
||||||
|
opts.Filters = filters.NewArgs(
|
||||||
|
filters.Arg("reference", filter.Name),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
optsBytes, err := json.Marshal(opts)
|
optsBytes, err := json.Marshal(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("marshal options: %w", err)
|
return nil, fmt.Errorf("marshal options: %w", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user