diff --git a/cli/command/manifest/formatter.go b/cli/command/manifest/formatter.go index 35491a41f2..9c30aeeeff 100644 --- a/cli/command/manifest/formatter.go +++ b/cli/command/manifest/formatter.go @@ -1,16 +1,21 @@ package manifest import ( + "fmt" + "strings" + "github.com/distribution/reference" "github.com/docker/cli/cli/command/formatter" + "github.com/docker/cli/cli/manifest/types" ) const ( defaultManifestListQuietFormat = "{{.Name}}" - defaultManifestListTableFormat = "table {{.Repository}}\t{{.Tag}}" + defaultManifestListTableFormat = "table {{.Repository}}\t{{.Tag}}\t{{.Platforms}}" repositoryHeader = "REPOSITORY" tagHeader = "TAG" + platformsHeader = "PLATFORMS" ) // 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 -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 { for _, manifestList := range manifestLists { if n, ok := manifestList.(reference.Named); ok { if nt, ok := n.(reference.NamedTagged); ok { if err := format(&manifestListContext{ - name: reference.FamiliarString(manifestList), - repo: reference.FamiliarName(nt), - tag: nt.Tag(), + name: reference.FamiliarString(manifestList), + repo: reference.FamiliarName(nt), + tag: nt.Tag(), + imageManifests: manifests[manifestList.String()], }); err != nil { return err } @@ -53,9 +59,10 @@ func FormatWrite(ctx formatter.Context, manifestLists []reference.Reference) err type manifestListContext struct { formatter.HeaderContext - name string - repo string - tag string + name string + repo string + tag string + imageManifests []types.ImageManifest } func newManifestListContext() *manifestListContext { @@ -64,6 +71,7 @@ func newManifestListContext() *manifestListContext { "Name": formatter.NameHeader, "Repository": repositoryHeader, "Tag": tagHeader, + "Platforms": platformsHeader, } return &manifestListCtx } @@ -83,3 +91,13 @@ func (c *manifestListContext) Repository() string { func (c *manifestListContext) Tag() string { 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, ", ") +} diff --git a/cli/command/manifest/list.go b/cli/command/manifest/list.go index 759f0a51aa..2357575396 100644 --- a/cli/command/manifest/list.go +++ b/cli/command/manifest/list.go @@ -8,8 +8,8 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/formatter" flagsHelper "github.com/docker/cli/cli/flags" + "github.com/docker/cli/cli/manifest/types" "github.com/fvbommel/sortorder" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -42,9 +42,16 @@ func runList(dockerCli command.Cli, options listOptions) error { var manifestLists []reference.Reference - manifestLists, searchErr := manifestStore.List() - if searchErr != nil { - return errors.New(searchErr.Error()) + manifestLists, err := manifestStore.List() + if err != nil { + 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 @@ -63,5 +70,5 @@ func runList(dockerCli command.Cli, options listOptions) error { sort.Slice(manifestLists, func(i, j int) bool { return sortorder.NaturalLess(manifestLists[i].String(), manifestLists[j].String()) }) - return FormatWrite(manifestListsCtx, manifestLists) + return FormatWrite(manifestListsCtx, manifestLists, manifests) } diff --git a/cli/command/manifest/list_test.go b/cli/command/manifest/list_test.go index bd7ee46224..a8ac74f481 100644 --- a/cli/command/manifest/list_test.go +++ b/cli/command/manifest/list_test.go @@ -58,7 +58,10 @@ func TestList(t *testing.T) { err := manifestStore.Save(list1, namedRef, fullImageManifest(t, namedRef)) assert.NilError(t, err) 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) list2 := ref(t, "second:2") diff --git a/cli/command/manifest/testdata/manifest-list.golden b/cli/command/manifest/testdata/manifest-list.golden index d4e6ddeb5e..a9dd162089 100644 --- a/cli/command/manifest/testdata/manifest-list.golden +++ b/cli/command/manifest/testdata/manifest-list.golden @@ -1,3 +1,3 @@ -REPOSITORY TAG -example.com/first 1 -example.com/second 2 +REPOSITORY TAG PLATFORMS +example.com/first 1 linux/amd64, linux/arm64 +example.com/second 2 linux/amd64