Skip to content

Commit 75fe37f

Browse files
committed
copy: add --multi-arch=sparse:...
Add a "sparse:..." value for the copy --multi-arch option, where the "..." is a comma-separated list of instance digests, platform specifications, or the literal word "system" to signify the local platform. Signed-off-by: Nalin Dahyabhai <[email protected]>
1 parent b48dea8 commit 75fe37f

22 files changed

+1720
-20
lines changed

cmd/skopeo/copy.go

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"strings"
99

10+
"github.com/containerd/containerd/platforms"
1011
commonFlag "github.com/containers/common/pkg/flag"
1112
"github.com/containers/common/pkg/retry"
1213
"github.com/containers/image/v5/copy"
@@ -19,6 +20,8 @@ import (
1920
"github.com/containers/image/v5/transports/alltransports"
2021
encconfig "github.com/containers/ocicrypt/config"
2122
enchelpers "github.com/containers/ocicrypt/helpers"
23+
"github.com/opencontainers/go-digest"
24+
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
2225
"github.com/spf13/cobra"
2326
)
2427

@@ -99,23 +102,40 @@ See skopeo(1) section "IMAGE NAMES" for the expected format
99102
}
100103

101104
// parseMultiArch parses the list processing selection
102-
// It returns the copy.ImageListSelection to use with image.Copy option
103-
func parseMultiArch(multiArch string) (copy.ImageListSelection, error) {
104-
switch multiArch {
105-
case "system":
106-
return copy.CopySystemImage, nil
107-
case "all":
108-
return copy.CopyAllImages, nil
109-
// There is no CopyNoImages value in copy.ImageListSelection, but because we
110-
// don't provide an option to select a set of images to copy, we can use
111-
// CopySpecificImages.
112-
case "index-only":
113-
return copy.CopySpecificImages, nil
114-
// We don't expose CopySpecificImages other than index-only above, because
115-
// we currently don't provide an option to choose the images to copy. That
116-
// could be added in the future.
105+
// It returns the copy.ImageListSelection, instance list, and platform list to use in image.Copy option
106+
func parseMultiArch(multiArch string) (copy.ImageListSelection, []digest.Digest, []imgspecv1.Platform, error) {
107+
switch {
108+
case multiArch == "system":
109+
return copy.CopySystemImage, nil, nil, nil
110+
case multiArch == "all":
111+
return copy.CopyAllImages, nil, nil, nil
112+
case multiArch == "index-only":
113+
// There is no CopyNoImages value in copy.ImageListSelection per se, but
114+
// we can get the desired effect by using CopySpecificImages.
115+
return copy.CopySpecificImages, nil, nil, nil
116+
case strings.HasPrefix(multiArch, "sparse:"):
117+
sparseArg := strings.TrimPrefix(multiArch, "sparse:")
118+
platformSpecs := strings.Split(sparseArg, ",")
119+
var platformList []imgspecv1.Platform
120+
var instanceList []digest.Digest
121+
for _, platformSpec := range platformSpecs {
122+
if instanceDigest, err := digest.Parse(platformSpec); err == nil {
123+
instanceList = append(instanceList, instanceDigest)
124+
continue
125+
}
126+
if platformSpec == "system" {
127+
platformList = append(platformList, imgspecv1.Platform{})
128+
} else {
129+
p, err := platforms.Parse(platformSpec)
130+
if err != nil {
131+
return copy.CopySpecificImages, nil, nil, fmt.Errorf("while parsing platform specifier %q: %w", platformSpec, err)
132+
}
133+
platformList = append(platformList, p)
134+
}
135+
}
136+
return copy.CopySpecificImages, instanceList, platformList, nil
117137
default:
118-
return copy.CopySystemImage, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'all', or 'index-only'", multiArch)
138+
return copy.CopySystemImage, nil, nil, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'sparse:...', 'all', or 'index-only'", multiArch)
119139
}
120140
}
121141

@@ -186,11 +206,13 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) (retErr error) {
186206
}
187207

188208
imageListSelection := copy.CopySystemImage
209+
var instanceDigests []digest.Digest
210+
var instancePlatforms []imgspecv1.Platform
189211
if opts.multiArch.Present() && opts.all {
190212
return fmt.Errorf("Cannot use --all and --multi-arch flags together")
191213
}
192214
if opts.multiArch.Present() {
193-
imageListSelection, err = parseMultiArch(opts.multiArch.Value())
215+
imageListSelection, instanceDigests, instancePlatforms, err = parseMultiArch(opts.multiArch.Value())
194216
if err != nil {
195217
return err
196218
}
@@ -296,6 +318,8 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) (retErr error) {
296318
DestinationCtx: destinationCtx,
297319
ForceManifestMIMEType: manifestType,
298320
ImageListSelection: imageListSelection,
321+
Instances: instanceDigests,
322+
InstancePlatforms: instancePlatforms,
299323
PreserveDigests: opts.preserveDigests,
300324
OciDecryptConfig: decConfig,
301325
OciEncryptLayers: encLayers,

docs/skopeo-copy.1.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ Print usage statement
7979
Control what is copied if _source-image_ refers to a multi-architecture image. Default is system.
8080

8181
Options:
82-
- system: Copy only the image that matches the system architecture
83-
- all: Copy the full multi-architecture image
84-
- index-only: Copy only the index
82+
- "system": Copy only the image that matches the system architecture
83+
- "all": Copy the full multi-architecture image
84+
- "index-only": Copy only the index
85+
- "sparse:_list_": Copy the index and images which match the comma-separated list of platform specifications, digests, or the local system ("system")
8586

8687
The index-only option usually fails unless the referenced per-architecture images are already present in the destination, or the target registry supports sparse indexes.
8788

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/containers/skopeo
33
go 1.18
44

55
require (
6+
github.com/containerd/containerd v1.7.0
67
github.com/containers/common v0.52.0
78
github.com/containers/image/v5 v5.25.0
89
github.com/containers/ocicrypt v1.1.7

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
2828
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
2929
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
3030
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
31+
github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg=
32+
github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc=
3133
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
3234
github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
3335
github.com/containers/common v0.52.0 h1:S5GApgpNEGBuPhDHTFgMc55y5gsuxHcQeElvUpO5kp4=

vendor/github.com/containerd/containerd/LICENSE

Lines changed: 191 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/containerd/containerd/NOTICE

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)