show platforms for `docker manifest ls`

Signed-off-by: Wayne Cheng <zhengwei@tiduyun.com>
This commit is contained in:
Wayne Cheng 2024-01-06 11:24:51 +08:00
parent 46b474267b
commit b039c0e9af
4 changed files with 45 additions and 17 deletions

View File

@ -1,16 +1,21 @@
package manifest package manifest
import ( import (
"fmt"
"strings"
"github.com/distribution/reference" "github.com/distribution/reference"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/manifest/types"
) )
const ( const (
defaultManifestListQuietFormat = "{{.Name}}" defaultManifestListQuietFormat = "{{.Name}}"
defaultManifestListTableFormat = "table {{.Repository}}\t{{.Tag}}" defaultManifestListTableFormat = "table {{.Repository}}\t{{.Tag}}\t{{.Platforms}}"
repositoryHeader = "REPOSITORY" repositoryHeader = "REPOSITORY"
tagHeader = "TAG" tagHeader = "TAG"
platformsHeader = "PLATFORMS"
) )
// NewFormat returns a Format for rendering using a manifest list Context // NewFormat returns a Format for rendering using a manifest list Context
@ -31,15 +36,16 @@ func NewFormat(source string, quiet bool) formatter.Format {
} }
// FormatWrite writes formatted manifestLists using the Context // FormatWrite writes formatted manifestLists using the Context
func FormatWrite(ctx formatter.Context, manifestLists []reference.Reference) error { func FormatWrite(ctx formatter.Context, manifestLists []reference.Reference, manifests map[string][]types.ImageManifest) error {
render := func(format func(subContext formatter.SubContext) error) error { render := func(format func(subContext formatter.SubContext) error) error {
for _, manifestList := range manifestLists { for _, manifestList := range manifestLists {
if n, ok := manifestList.(reference.Named); ok { if n, ok := manifestList.(reference.Named); ok {
if nt, ok := n.(reference.NamedTagged); ok { if nt, ok := n.(reference.NamedTagged); ok {
if err := format(&manifestListContext{ if err := format(&manifestListContext{
name: reference.FamiliarString(manifestList), name: reference.FamiliarString(manifestList),
repo: reference.FamiliarName(nt), repo: reference.FamiliarName(nt),
tag: nt.Tag(), tag: nt.Tag(),
imageManifests: manifests[manifestList.String()],
}); err != nil { }); err != nil {
return err return err
} }
@ -53,9 +59,10 @@ func FormatWrite(ctx formatter.Context, manifestLists []reference.Reference) err
type manifestListContext struct { type manifestListContext struct {
formatter.HeaderContext formatter.HeaderContext
name string name string
repo string repo string
tag string tag string
imageManifests []types.ImageManifest
} }
func newManifestListContext() *manifestListContext { func newManifestListContext() *manifestListContext {
@ -64,6 +71,7 @@ func newManifestListContext() *manifestListContext {
"Name": formatter.NameHeader, "Name": formatter.NameHeader,
"Repository": repositoryHeader, "Repository": repositoryHeader,
"Tag": tagHeader, "Tag": tagHeader,
"Platforms": platformsHeader,
} }
return &manifestListCtx return &manifestListCtx
} }
@ -83,3 +91,13 @@ func (c *manifestListContext) Repository() string {
func (c *manifestListContext) Tag() string { func (c *manifestListContext) Tag() string {
return c.tag return c.tag
} }
func (c *manifestListContext) Platforms() string {
platforms := []string{}
for _, manifest := range c.imageManifests {
os := manifest.Descriptor.Platform.OS
arch := manifest.Descriptor.Platform.Architecture
platforms = append(platforms, fmt.Sprintf("%s/%s", os, arch))
}
return strings.Join(platforms, ", ")
}

View File

@ -8,8 +8,8 @@ import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/cli/manifest/types"
"github.com/fvbommel/sortorder" "github.com/fvbommel/sortorder"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -42,9 +42,16 @@ func runList(dockerCli command.Cli, options listOptions) error {
var manifestLists []reference.Reference var manifestLists []reference.Reference
manifestLists, searchErr := manifestStore.List() manifestLists, err := manifestStore.List()
if searchErr != nil { if err != nil {
return errors.New(searchErr.Error()) return err
}
manifests := map[string][]types.ImageManifest{}
for _, manifestList := range manifestLists {
if imageManifests, err := manifestStore.GetList(manifestList); err == nil {
manifests[manifestList.String()] = imageManifests
}
} }
format := options.format format := options.format
@ -63,5 +70,5 @@ func runList(dockerCli command.Cli, options listOptions) error {
sort.Slice(manifestLists, func(i, j int) bool { sort.Slice(manifestLists, func(i, j int) bool {
return sortorder.NaturalLess(manifestLists[i].String(), manifestLists[j].String()) return sortorder.NaturalLess(manifestLists[i].String(), manifestLists[j].String())
}) })
return FormatWrite(manifestListsCtx, manifestLists) return FormatWrite(manifestListsCtx, manifestLists, manifests)
} }

View File

@ -58,7 +58,10 @@ func TestList(t *testing.T) {
err := manifestStore.Save(list1, namedRef, fullImageManifest(t, namedRef)) err := manifestStore.Save(list1, namedRef, fullImageManifest(t, namedRef))
assert.NilError(t, err) assert.NilError(t, err)
namedRef = ref(t, "alpine:3.1") namedRef = ref(t, "alpine:3.1")
err = manifestStore.Save(list1, namedRef, fullImageManifest(t, namedRef)) imageManifest := fullImageManifest(t, namedRef)
imageManifest.Descriptor.Platform.OS = "linux"
imageManifest.Descriptor.Platform.Architecture = "arm64"
err = manifestStore.Save(list1, namedRef, imageManifest)
assert.NilError(t, err) assert.NilError(t, err)
list2 := ref(t, "second:2") list2 := ref(t, "second:2")

View File

@ -1,3 +1,3 @@
REPOSITORY TAG REPOSITORY TAG PLATFORMS
example.com/first 1 example.com/first 1 linux/amd64, linux/arm64
example.com/second 2 example.com/second 2 linux/amd64