Skip to content

Commit

Permalink
Merge pull request #2482 from rvoh-tismith/fix/single_source_create
Browse files Browse the repository at this point in the history
Add `--prefer-index` flag for`imagetools create` on a single source
  • Loading branch information
tonistiigi authored May 31, 2024
2 parents 7427adb + 7bfae2b commit 4549283
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 15 deletions.
2 changes: 1 addition & 1 deletion build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
}
}

dt, desc, err := itpull.Combine(ctx, srcs, nil)
dt, desc, err := itpull.Combine(ctx, srcs, nil, false)
if err != nil {
return err
}
Expand Down
4 changes: 3 additions & 1 deletion commands/imagetools/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type createOptions struct {
dryrun bool
actionAppend bool
progress string
preferIndex bool
}

func runCreate(ctx context.Context, dockerCli command.Cli, in createOptions, args []string) error {
Expand Down Expand Up @@ -153,7 +154,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, in createOptions, arg
}
}

dt, desc, err := r.Combine(ctx, srcs, in.annotations)
dt, desc, err := r.Combine(ctx, srcs, in.annotations, in.preferIndex)
if err != nil {
return err
}
Expand Down Expand Up @@ -283,6 +284,7 @@ func createCmd(dockerCli command.Cli, opts RootOptions) *cobra.Command {
flags.BoolVar(&options.actionAppend, "append", false, "Append to existing manifest")
flags.StringVar(&options.progress, "progress", "auto", `Set type of progress output ("auto", "plain", "tty"). Use plain to show container output`)
flags.StringArrayVarP(&options.annotations, "annotation", "", []string{}, "Add annotation to the image")
flags.BoolVar(&options.preferIndex, "prefer-index", true, "When only a single source is specified, prefer outputting an image index or manifest list instead of performing a carbon copy")

return cmd
}
Expand Down
28 changes: 17 additions & 11 deletions docs/reference/buildx_imagetools_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ Create a new image based on source images

### Options

| Name | Type | Default | Description |
|:---------------------------------|:--------------|:--------|:-----------------------------------------------------------------------------------------|
| [`--annotation`](#annotation) | `stringArray` | | Add annotation to the image |
| [`--append`](#append) | | | Append to existing manifest |
| [`--builder`](#builder) | `string` | | Override the configured builder instance |
| [`--dry-run`](#dry-run) | | | Show final image instead of pushing |
| [`-f`](#file), [`--file`](#file) | `stringArray` | | Read source descriptor from file |
| `--progress` | `string` | `auto` | Set type of progress output (`auto`, `plain`, `tty`). Use plain to show container output |
| [`-t`](#tag), [`--tag`](#tag) | `stringArray` | | Set reference for new image |
| Name | Type | Default | Description |
|:---------------------------------|:--------------|:--------|:------------------------------------------------------------------------------------------------------------------------------|
| [`--annotation`](#annotation) | `stringArray` | | Add annotation to the image |
| [`--append`](#append) | | | Append to existing manifest |
| [`--builder`](#builder) | `string` | | Override the configured builder instance |
| [`--dry-run`](#dry-run) | | | Show final image instead of pushing |
| [`-f`](#file), [`--file`](#file) | `stringArray` | | Read source descriptor from file |
| `--prefer-index` | `bool` | `true` | When only a single source is specified, prefer outputting an image index or manifest list instead of performing a carbon copy |
| `--progress` | `string` | `auto` | Set type of progress output (`auto`, `plain`, `tty`). Use plain to show container output |
| [`-t`](#tag), [`--tag`](#tag) | `stringArray` | | Set reference for new image |


<!---MARKER_GEN_END-->
Expand All @@ -26,8 +27,13 @@ Create a new image based on source images

Create a new manifest list based on source manifests. The source manifests can
be manifest lists or single platform distribution manifests and must already
exist in the registry where the new manifest is created. If only one source is
specified, create performs a carbon copy.
exist in the registry where the new manifest is created.

If only one source is specified and that source is a manifest list or image index,
create performs a carbon copy. If one source is specified and that source is *not*
a list or index, the output will be a manifest list, however you can disable this
behavior with `--prefer-index=false` which attempts to preserve the source manifest
format in the output.

## Examples

Expand Down
31 changes: 31 additions & 0 deletions tests/imagetools.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,19 @@ func testImagetoolsCopyManifest(t *testing.T, sb integration.Sandbox) {
for i := range mfst.Layers {
require.Equal(t, mfst.Layers[i].Digest, mfst2.Layers[i].Digest)
}

cmd = buildxCmd(sb, withArgs("imagetools", "create", "--prefer-index=false", "-t", target2+"-not-index", target))
dt, err = cmd.CombinedOutput()
require.NoError(t, err, string(dt))

cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target2+"-not-index", "--raw"))
dt, err = cmd.CombinedOutput()
require.NoError(t, err, string(dt))

var idx3 ocispecs.Manifest
err = json.Unmarshal(dt, &idx3)
require.NoError(t, err)
require.Equal(t, images.MediaTypeDockerSchema2Manifest, idx3.MediaType)
}

func testImagetoolsCopyIndex(t *testing.T, sb integration.Sandbox) {
Expand Down Expand Up @@ -127,6 +140,24 @@ func testImagetoolsCopyIndex(t *testing.T, sb integration.Sandbox) {
for i := range idx.Manifests {
require.Equal(t, idx.Manifests[i].Digest, idx2.Manifests[i].Digest)
}

cmd = buildxCmd(sb, withArgs("imagetools", "create", "--prefer-index=false", "-t", target2+"-still-index", target))
dt, err = cmd.CombinedOutput()
require.NoError(t, err, string(dt))

cmd = buildxCmd(sb, withArgs("imagetools", "inspect", target2+"-still-index", "--raw"))
dt, err = cmd.CombinedOutput()
require.NoError(t, err, string(dt))

var idx3 ocispecs.Index
err = json.Unmarshal(dt, &idx3)
require.NoError(t, err)
require.Equal(t, images.MediaTypeDockerSchema2ManifestList, idx3.MediaType)

require.Equal(t, len(idx.Manifests), len(idx3.Manifests))
for i := range idx.Manifests {
require.Equal(t, idx.Manifests[i].Digest, idx3.Manifests[i].Digest)
}
}

func testImagetoolsInspectAndFilter(t *testing.T, sb integration.Sandbox) {
Expand Down
12 changes: 10 additions & 2 deletions util/imagetools/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type Source struct {
Ref reference.Named
}

func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann []string) ([]byte, ocispec.Descriptor, error) {
func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann []string, preferIndex bool) ([]byte, ocispec.Descriptor, error) {
eg, ctx := errgroup.WithContext(ctx)

dts := make([][]byte, len(srcs))
Expand Down Expand Up @@ -79,8 +79,16 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann []string) ([

// on single source, return original bytes
if len(srcs) == 1 && len(ann) == 0 {
if mt := srcs[0].Desc.MediaType; mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex {
switch srcs[0].Desc.MediaType {
// if the source is already an image index or manifest list, there is no need to consider the value
// of preferIndex since if set to true then the source is already in the preferred format, and if false
// it doesn't matter since we're not going to split it into separate manifests
case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
return dts[0], srcs[0].Desc, nil
default:
if !preferIndex {
return dts[0], srcs[0].Desc, nil
}
}
}

Expand Down

0 comments on commit 4549283

Please sign in to comment.