From d3412f1039acd5f13e7891fa2d6b149fc7954d22 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Tue, 10 May 2022 15:23:26 +0100 Subject: [PATCH] imagetools: refactor combining repository logic This patch modifies the existing combining code in imagetools create to provide better support for multiple repositories down the road. Specifically, the code should no longer rely on a single repository being used for all sources and tags, and should resolve descriptors in their relevant repositories. Signed-off-by: Justin Chadwell --- build/build.go | 16 ++++++++++++- commands/imagetools/create.go | 39 ++++++++++++++------------------ util/imagetools/create.go | 42 +++++++++++++++++------------------ 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/build/build.go b/build/build.go index c3e3a5ac..aeacbab5 100644 --- a/build/build.go +++ b/build/build.go @@ -925,7 +925,21 @@ func BuildWithResultHandler(ctx context.Context, drivers []DriverInfo, opt map[s itpull := imagetools.New(imageopt) - dt, desc, err := itpull.Combine(ctx, names[0], descs) + ref, err := reference.ParseNormalizedNamed(names[0]) + if err != nil { + return err + } + ref = reference.TagNameOnly(ref) + + srcs := make([]*imagetools.Source, len(descs)) + for i, desc := range descs { + srcs[i] = &imagetools.Source{ + Desc: desc, + Ref: ref, + } + } + + dt, desc, err := itpull.Combine(ctx, srcs) if err != nil { return err } diff --git a/commands/imagetools/create.go b/commands/imagetools/create.go index 7a75d2c7..7e9db288 100644 --- a/commands/imagetools/create.go +++ b/commands/imagetools/create.go @@ -82,14 +82,20 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error { return errors.Errorf("multiple repositories currently not supported, found %v", repos) } - var repo string - for r := range repos { - repo = r + var defaultRepo *string + if len(repos) == 1 { + for repo := range repos { + defaultRepo = &repo + } } for i, s := range srcs { if s.Ref == nil && s.Desc.MediaType == "" && s.Desc.Digest != "" { - n, err := reference.ParseNormalizedNamed(repo) + if defaultRepo == nil { + return errors.Errorf("multiple repositories specified, cannot determine default from %v", repos) + } + + n, err := reference.ParseNormalizedNamed(*defaultRepo) if err != nil { return err } @@ -143,7 +149,6 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error { if err != nil { return err } - srcs[i].Ref = nil if srcs[i].Desc.Digest == "" { srcs[i].Desc = desc } else { @@ -162,12 +167,7 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error { } } - descs := make([]ocispec.Descriptor, len(srcs)) - for i := range descs { - descs[i] = srcs[i].Desc - } - - dt, desc, err := r.Combine(ctx, repo, descs) + dt, desc, err := r.Combine(ctx, srcs) if err != nil { return err } @@ -190,13 +190,8 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error { return nil } -type src struct { - Desc ocispec.Descriptor - Ref reference.Named -} - -func parseSources(in []string) ([]*src, error) { - out := make([]*src, len(in)) +func parseSources(in []string) ([]*imagetools.Source, error) { + out := make([]*imagetools.Source, len(in)) for i, in := range in { s, err := parseSource(in) if err != nil { @@ -219,11 +214,11 @@ func parseRefs(in []string) ([]reference.Named, error) { return refs, nil } -func parseSource(in string) (*src, error) { +func parseSource(in string) (*imagetools.Source, error) { // source can be a digest, reference or a descriptor JSON dgst, err := digest.Parse(in) if err == nil { - return &src{ + return &imagetools.Source{ Desc: ocispec.Descriptor{ Digest: dgst, }, @@ -234,14 +229,14 @@ func parseSource(in string) (*src, error) { ref, err := reference.ParseNormalizedNamed(in) if err == nil { - return &src{ + return &imagetools.Source{ Ref: ref, }, nil } else if !strings.HasPrefix(in, "{") { return nil, err } - var s src + var s imagetools.Source if err := json.Unmarshal([]byte(in), &s.Desc); err != nil { return nil, errors.WithStack(err) } diff --git a/util/imagetools/create.go b/util/imagetools/create.go index bd7191f2..4b21e75c 100644 --- a/util/imagetools/create.go +++ b/util/imagetools/create.go @@ -17,46 +17,46 @@ import ( "golang.org/x/sync/errgroup" ) -func (r *Resolver) Combine(ctx context.Context, in string, descs []ocispec.Descriptor) ([]byte, ocispec.Descriptor, error) { - ref, err := parseRef(in) - if err != nil { - return nil, ocispec.Descriptor{}, err - } +type Source struct { + Desc ocispec.Descriptor + Ref reference.Named +} +func (r *Resolver) Combine(ctx context.Context, srcs []*Source) ([]byte, ocispec.Descriptor, error) { eg, ctx := errgroup.WithContext(ctx) - dts := make([][]byte, len(descs)) + dts := make([][]byte, len(srcs)) for i := range dts { func(i int) { eg.Go(func() error { - dt, err := r.GetDescriptor(ctx, ref.String(), descs[i]) + dt, err := r.GetDescriptor(ctx, srcs[i].Ref.String(), srcs[i].Desc) if err != nil { return err } dts[i] = dt - if descs[i].MediaType == "" { + if srcs[i].Desc.MediaType == "" { mt, err := detectMediaType(dt) if err != nil { return err } - descs[i].MediaType = mt + srcs[i].Desc.MediaType = mt } - mt := descs[i].MediaType + mt := srcs[i].Desc.MediaType switch mt { case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: - p := descs[i].Platform - if descs[i].Platform == nil { + p := srcs[i].Desc.Platform + if srcs[i].Desc.Platform == nil { p = &ocispec.Platform{} } if p.OS == "" || p.Architecture == "" { - if err := r.loadPlatform(ctx, p, in, dt); err != nil { + if err := r.loadPlatform(ctx, p, srcs[i].Ref.String(), dt); err != nil { return err } } - descs[i].Platform = p + srcs[i].Desc.Platform = p case images.MediaTypeDockerSchema1Manifest: return errors.Errorf("schema1 manifests are not allowed in manifest lists") } @@ -71,14 +71,14 @@ func (r *Resolver) Combine(ctx context.Context, in string, descs []ocispec.Descr } // on single source, return original bytes - if len(descs) == 1 { - if mt := descs[0].MediaType; mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex { - return dts[0], descs[0], nil + if len(srcs) == 1 { + if mt := srcs[0].Desc.MediaType; mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex { + return dts[0], srcs[0].Desc, nil } } m := map[digest.Digest]int{} - newDescs := make([]ocispec.Descriptor, 0, len(descs)) + newDescs := make([]ocispec.Descriptor, 0, len(srcs)) addDesc := func(d ocispec.Descriptor) { idx, ok := m[d.Digest] @@ -103,8 +103,8 @@ func (r *Resolver) Combine(ctx context.Context, in string, descs []ocispec.Descr } } - for i, desc := range descs { - switch desc.MediaType { + for i, src := range srcs { + switch src.Desc.MediaType { case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: var mfst ocispec.Index if err := json.Unmarshal(dts[i], &mfst); err != nil { @@ -114,7 +114,7 @@ func (r *Resolver) Combine(ctx context.Context, in string, descs []ocispec.Descr addDesc(d) } default: - addDesc(desc) + addDesc(src.Desc) } }