Add docker/archive.Reader.ManifestTagsForReference

to allow Podman default to localhost/$tag for unqualified $tag
values in docker-archive tarnballs.

(Note that only projectatomic/docker creates such tarballs;
almost no-one else should use this.)

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač 2020-08-13 15:11:48 +02:00 committed by Valentin Rothberg
parent 9e23cf4b16
commit 2de48430e9
3 changed files with 36 additions and 12 deletions

View File

@ -96,3 +96,25 @@ func (r *Reader) List() ([][]types.ImageReference, error) {
} }
return res, nil return res, nil
} }
// ManifestTagsForReference returns the set of tags “matching” ref in reader, as strings
// (i.e. exposing the short names before normalization).
// The function reports an error if ref does not identify a single image.
// If ref contains a NamedTagged reference, only a single tag “matching” ref is returned;
// If ref contains a source index, or neither a NamedTagged nor a source index, all tags
// matching the image are returned.
// Almost all users should use List() or ImageReference.DockerReference() instead.
func (r *Reader) ManifestTagsForReference(ref types.ImageReference) ([]string, error) {
archiveRef, ok := ref.(archiveReference)
if !ok {
return nil, errors.Errorf("Internal error: ManifestTagsForReference called for a non-docker/archive ImageReference %s", transports.ImageName(ref))
}
manifestItem, tagIndex, err := r.archive.ChooseManifestItem(archiveRef.ref, archiveRef.sourceIndex)
if err != nil {
return nil, err
}
if tagIndex != -1 {
return []string{manifestItem.RepoTags[tagIndex]}, nil
}
return manifestItem.RepoTags, nil
}

View File

@ -130,41 +130,43 @@ func (r *Reader) Close() error {
return nil return nil
} }
// chooseManifestItem selects a manifest item from r.Manifest matching (ref, sourceIndex), one or // ChooseManifestItem selects a manifest item from r.Manifest matching (ref, sourceIndex), one or
// both of which should be (nil, -1). // both of which should be (nil, -1).
func (r *Reader) chooseManifestItem(ref reference.NamedTagged, sourceIndex int) (*ManifestItem, error) { // On success, it returns the manifest item and an index of the matching tag, if a tag was used
// for matching; the index is -1 if a tag was not used.
func (r *Reader) ChooseManifestItem(ref reference.NamedTagged, sourceIndex int) (*ManifestItem, int, error) {
switch { switch {
case ref != nil && sourceIndex != -1: case ref != nil && sourceIndex != -1:
return nil, errors.Errorf("Internal error: Cannot have both ref %s and source index @%d", return nil, -1, errors.Errorf("Internal error: Cannot have both ref %s and source index @%d",
ref.String(), sourceIndex) ref.String(), sourceIndex)
case ref != nil: case ref != nil:
refString := ref.String() refString := ref.String()
for i := range r.Manifest { for i := range r.Manifest {
for _, tag := range r.Manifest[i].RepoTags { for tagIndex, tag := range r.Manifest[i].RepoTags {
parsedTag, err := reference.ParseNormalizedNamed(tag) parsedTag, err := reference.ParseNormalizedNamed(tag)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "Invalid tag %#v in manifest.json item @%d", tag, i) return nil, -1, errors.Wrapf(err, "Invalid tag %#v in manifest.json item @%d", tag, i)
} }
if parsedTag.String() == refString { if parsedTag.String() == refString {
return &r.Manifest[i], nil return &r.Manifest[i], tagIndex, nil
} }
} }
} }
return nil, errors.Errorf("Tag %#v not found", refString) return nil, -1, errors.Errorf("Tag %#v not found", refString)
case sourceIndex != -1: case sourceIndex != -1:
if sourceIndex >= len(r.Manifest) { if sourceIndex >= len(r.Manifest) {
return nil, errors.Errorf("Invalid source index @%d, only %d manifest items available", return nil, -1, errors.Errorf("Invalid source index @%d, only %d manifest items available",
sourceIndex, len(r.Manifest)) sourceIndex, len(r.Manifest))
} }
return &r.Manifest[sourceIndex], nil return &r.Manifest[sourceIndex], -1, nil
default: default:
if len(r.Manifest) != 1 { if len(r.Manifest) != 1 {
return nil, errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(r.Manifest)) return nil, -1, errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(r.Manifest))
} }
return &r.Manifest[0], nil return &r.Manifest[0], -1, nil
} }
} }

View File

@ -68,7 +68,7 @@ func (s *Source) ensureCachedDataIsPresent() error {
// ensureCachedDataIsPresentPrivate is a private implementation detail of ensureCachedDataIsPresent. // ensureCachedDataIsPresentPrivate is a private implementation detail of ensureCachedDataIsPresent.
// Call ensureCachedDataIsPresent instead. // Call ensureCachedDataIsPresent instead.
func (s *Source) ensureCachedDataIsPresentPrivate() error { func (s *Source) ensureCachedDataIsPresentPrivate() error {
tarManifest, err := s.archive.chooseManifestItem(s.ref, s.sourceIndex) tarManifest, _, err := s.archive.ChooseManifestItem(s.ref, s.sourceIndex)
if err != nil { if err != nil {
return err return err
} }