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 <me@jedevc.com>
pull/1137/head
Justin Chadwell 3 years ago
parent 07992e66e0
commit d3412f1039

@ -925,7 +925,21 @@ func BuildWithResultHandler(ctx context.Context, drivers []DriverInfo, opt map[s
itpull := imagetools.New(imageopt) 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 { if err != nil {
return err return err
} }

@ -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) return errors.Errorf("multiple repositories currently not supported, found %v", repos)
} }
var repo string var defaultRepo *string
for r := range repos { if len(repos) == 1 {
repo = r for repo := range repos {
defaultRepo = &repo
}
} }
for i, s := range srcs { for i, s := range srcs {
if s.Ref == nil && s.Desc.MediaType == "" && s.Desc.Digest != "" { 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 { if err != nil {
return err return err
} }
@ -143,7 +149,6 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
if err != nil { if err != nil {
return err return err
} }
srcs[i].Ref = nil
if srcs[i].Desc.Digest == "" { if srcs[i].Desc.Digest == "" {
srcs[i].Desc = desc srcs[i].Desc = desc
} else { } else {
@ -162,12 +167,7 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
} }
} }
descs := make([]ocispec.Descriptor, len(srcs)) dt, desc, err := r.Combine(ctx, srcs)
for i := range descs {
descs[i] = srcs[i].Desc
}
dt, desc, err := r.Combine(ctx, repo, descs)
if err != nil { if err != nil {
return err return err
} }
@ -190,13 +190,8 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
return nil return nil
} }
type src struct { func parseSources(in []string) ([]*imagetools.Source, error) {
Desc ocispec.Descriptor out := make([]*imagetools.Source, len(in))
Ref reference.Named
}
func parseSources(in []string) ([]*src, error) {
out := make([]*src, len(in))
for i, in := range in { for i, in := range in {
s, err := parseSource(in) s, err := parseSource(in)
if err != nil { if err != nil {
@ -219,11 +214,11 @@ func parseRefs(in []string) ([]reference.Named, error) {
return refs, nil 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 // source can be a digest, reference or a descriptor JSON
dgst, err := digest.Parse(in) dgst, err := digest.Parse(in)
if err == nil { if err == nil {
return &src{ return &imagetools.Source{
Desc: ocispec.Descriptor{ Desc: ocispec.Descriptor{
Digest: dgst, Digest: dgst,
}, },
@ -234,14 +229,14 @@ func parseSource(in string) (*src, error) {
ref, err := reference.ParseNormalizedNamed(in) ref, err := reference.ParseNormalizedNamed(in)
if err == nil { if err == nil {
return &src{ return &imagetools.Source{
Ref: ref, Ref: ref,
}, nil }, nil
} else if !strings.HasPrefix(in, "{") { } else if !strings.HasPrefix(in, "{") {
return nil, err return nil, err
} }
var s src var s imagetools.Source
if err := json.Unmarshal([]byte(in), &s.Desc); err != nil { if err := json.Unmarshal([]byte(in), &s.Desc); err != nil {
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }

@ -17,46 +17,46 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
func (r *Resolver) Combine(ctx context.Context, in string, descs []ocispec.Descriptor) ([]byte, ocispec.Descriptor, error) { type Source struct {
ref, err := parseRef(in) Desc ocispec.Descriptor
if err != nil { Ref reference.Named
return nil, ocispec.Descriptor{}, err }
}
func (r *Resolver) Combine(ctx context.Context, srcs []*Source) ([]byte, ocispec.Descriptor, error) {
eg, ctx := errgroup.WithContext(ctx) eg, ctx := errgroup.WithContext(ctx)
dts := make([][]byte, len(descs)) dts := make([][]byte, len(srcs))
for i := range dts { for i := range dts {
func(i int) { func(i int) {
eg.Go(func() error { 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 { if err != nil {
return err return err
} }
dts[i] = dt dts[i] = dt
if descs[i].MediaType == "" { if srcs[i].Desc.MediaType == "" {
mt, err := detectMediaType(dt) mt, err := detectMediaType(dt)
if err != nil { if err != nil {
return err return err
} }
descs[i].MediaType = mt srcs[i].Desc.MediaType = mt
} }
mt := descs[i].MediaType mt := srcs[i].Desc.MediaType
switch mt { switch mt {
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p := descs[i].Platform p := srcs[i].Desc.Platform
if descs[i].Platform == nil { if srcs[i].Desc.Platform == nil {
p = &ocispec.Platform{} p = &ocispec.Platform{}
} }
if p.OS == "" || p.Architecture == "" { 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 return err
} }
} }
descs[i].Platform = p srcs[i].Desc.Platform = p
case images.MediaTypeDockerSchema1Manifest: case images.MediaTypeDockerSchema1Manifest:
return errors.Errorf("schema1 manifests are not allowed in manifest lists") 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 // on single source, return original bytes
if len(descs) == 1 { if len(srcs) == 1 {
if mt := descs[0].MediaType; mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex { if mt := srcs[0].Desc.MediaType; mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex {
return dts[0], descs[0], nil return dts[0], srcs[0].Desc, nil
} }
} }
m := map[digest.Digest]int{} m := map[digest.Digest]int{}
newDescs := make([]ocispec.Descriptor, 0, len(descs)) newDescs := make([]ocispec.Descriptor, 0, len(srcs))
addDesc := func(d ocispec.Descriptor) { addDesc := func(d ocispec.Descriptor) {
idx, ok := m[d.Digest] 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 { for i, src := range srcs {
switch desc.MediaType { switch src.Desc.MediaType {
case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
var mfst ocispec.Index var mfst ocispec.Index
if err := json.Unmarshal(dts[i], &mfst); err != nil { 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) addDesc(d)
} }
default: default:
addDesc(desc) addDesc(src.Desc)
} }
} }

Loading…
Cancel
Save