diff --git a/client.go b/client.go index 3c337db59..505704985 100644 --- a/client.go +++ b/client.go @@ -403,13 +403,9 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag if len(fetchCtx.Platforms) == 0 { fetchCtx.PlatformMatcher = platforms.All } else { - var ps []ocispec.Platform - for _, s := range fetchCtx.Platforms { - p, err := platforms.Parse(s) - if err != nil { - return images.Image{}, fmt.Errorf("invalid platform %s: %w", s, err) - } - ps = append(ps, p) + ps, err := platforms.ParseAll(fetchCtx.Platforms) + if err != nil { + return images.Image{}, err } fetchCtx.PlatformMatcher = platforms.Any(ps...) @@ -439,13 +435,9 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, } if pushCtx.PlatformMatcher == nil { if len(pushCtx.Platforms) > 0 { - var ps []ocispec.Platform - for _, platform := range pushCtx.Platforms { - p, err := platforms.Parse(platform) - if err != nil { - return fmt.Errorf("invalid platform %s: %w", platform, err) - } - ps = append(ps, p) + ps, err := platforms.ParseAll(pushCtx.Platforms) + if err != nil { + return err } pushCtx.PlatformMatcher = platforms.Any(ps...) } else { diff --git a/cmd/ctr/commands/images/convert.go b/cmd/ctr/commands/images/convert.go index 7e81c23df..fdfd06ddd 100644 --- a/cmd/ctr/commands/images/convert.go +++ b/cmd/ctr/commands/images/convert.go @@ -24,7 +24,6 @@ import ( "github.com/containerd/containerd/images/converter" "github.com/containerd/containerd/images/converter/uncompress" "github.com/containerd/containerd/platforms" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli" ) @@ -70,13 +69,9 @@ When '--all-platforms' is given all images in a manifest list must be available. if !context.Bool("all-platforms") { if pss := context.StringSlice("platform"); len(pss) > 0 { - var all []ocispec.Platform - for _, ps := range pss { - p, err := platforms.Parse(ps) - if err != nil { - return fmt.Errorf("invalid platform %q: %w", ps, err) - } - all = append(all, p) + all, err := platforms.ParseAll(pss) + if err != nil { + return err } convertOpts = append(convertOpts, converter.WithPlatform(platforms.Ordered(all...))) } else { diff --git a/cmd/ctr/commands/images/export.go b/cmd/ctr/commands/images/export.go index 4cd864ef4..5957e6f82 100644 --- a/cmd/ctr/commands/images/export.go +++ b/cmd/ctr/commands/images/export.go @@ -22,7 +22,6 @@ import ( "io" "os" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli" "github.com/containerd/containerd/cmd/ctr/commands" @@ -133,13 +132,9 @@ When '--all-platforms' is given all images in a manifest list must be available. } if pss := context.StringSlice("platform"); len(pss) > 0 { - var all []ocispec.Platform - for _, ps := range pss { - p, err := platforms.Parse(ps) - if err != nil { - return fmt.Errorf("invalid platform %q: %w", ps, err) - } - all = append(all, p) + all, err := platforms.ParseAll(pss) + if err != nil { + return err } exportOpts = append(exportOpts, archive.WithPlatform(platforms.Ordered(all...))) } else { diff --git a/cmd/ctr/commands/images/pull.go b/cmd/ctr/commands/images/pull.go index 64e27da76..24ff6d404 100644 --- a/cmd/ctr/commands/images/pull.go +++ b/cmd/ctr/commands/images/pull.go @@ -101,13 +101,9 @@ command. As part of this process, we do the following: var sopts []image.StoreOpt if !context.Bool("all-platforms") { - var p []ocispec.Platform - for _, s := range context.StringSlice("platform") { - ps, err := platforms.Parse(s) - if err != nil { - return fmt.Errorf("unable to parse platform %s: %w", s, err) - } - p = append(p, ps) + p, err := platforms.ParseAll(context.StringSlice("platform")) + if err != nil { + return err } if len(p) == 0 { p = append(p, platforms.DefaultSpec()) @@ -168,12 +164,9 @@ command. As part of this process, we do the following: return fmt.Errorf("unable to resolve image platforms: %w", err) } } else { - for _, s := range context.StringSlice("platform") { - ps, err := platforms.Parse(s) - if err != nil { - return fmt.Errorf("unable to parse platform %s: %w", s, err) - } - p = append(p, ps) + p, err = platforms.ParseAll(context.StringSlice("platform")) + if err != nil { + return err } } if len(p) == 0 { diff --git a/pkg/transfer/local/push.go b/pkg/transfer/local/push.go index cd635203f..54cc6c577 100644 --- a/pkg/transfer/local/push.go +++ b/pkg/transfer/local/push.go @@ -37,13 +37,9 @@ func (ts *localTransferService) push(ctx context.Context, ig transfer.ImageGette // TODO: Platform matching if pushCtx.PlatformMatcher == nil { if len(pushCtx.Platforms) > 0 { - var ps []ocispec.Platform - for _, platform := range pushCtx.Platforms { - p, err := platforms.Parse(platform) - if err != nil { - return fmt.Errorf("invalid platform %s: %w", platform, err) - } - ps = append(ps, p) + ps, err := platforms.ParseAll(pushCtx.Platforms) + if err != nil { + return err } pushCtx.PlatformMatcher = platforms.Any(ps...) } else { diff --git a/platforms/platforms.go b/platforms/platforms.go index 8dcde7db7..bf782220a 100644 --- a/platforms/platforms.go +++ b/platforms/platforms.go @@ -158,6 +158,19 @@ func (m *matcher) String() string { return Format(m.Platform) } +// ParseAll parses a list of platform specifiers into a list of platform. +func ParseAll(specifiers []string) ([]specs.Platform, error) { + platforms := make([]specs.Platform, len(specifiers)) + for i, s := range specifiers { + p, err := Parse(s) + if err != nil { + return nil, fmt.Errorf("invalid platform %s: %w", s, err) + } + platforms[i] = p + } + return platforms, nil +} + // Parse parses the platform specifier syntax into a platform declaration. // // Platform specifiers are in the format `||/[/]`. diff --git a/runtime/v2/manager.go b/runtime/v2/manager.go index 12f13c9b0..a90bbd8f8 100644 --- a/runtime/v2/manager.go +++ b/runtime/v2/manager.go @@ -39,7 +39,6 @@ import ( "github.com/containerd/containerd/runtime" shimbinary "github.com/containerd/containerd/runtime/v2/shim" "github.com/containerd/containerd/sandbox" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // Config for the v2 runtime @@ -63,7 +62,7 @@ func init() { }, InitFn: func(ic *plugin.InitContext) (interface{}, error) { config := ic.Config.(*Config) - supportedPlatforms, err := parsePlatforms(config.Platforms) + supportedPlatforms, err := platforms.ParseAll(config.Platforms) if err != nil { return nil, err } @@ -387,18 +386,6 @@ func (m *ShimManager) Delete(ctx context.Context, id string) error { return err } -func parsePlatforms(platformStr []string) ([]ocispec.Platform, error) { - p := make([]ocispec.Platform, len(platformStr)) - for i, v := range platformStr { - parsed, err := platforms.Parse(v) - if err != nil { - return nil, err - } - p[i] = parsed - } - return p, nil -} - // TaskManager wraps task service client on top of shim manager. type TaskManager struct { manager *ShimManager