Skip to content

Commit

Permalink
Add docker/archive.Reader.ManifestTagsForReference
Browse files Browse the repository at this point in the history
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č <[email protected]>
  • Loading branch information
mtrmac committed Aug 19, 2020
1 parent c62a5a3 commit 84a8611
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 12 deletions.
22 changes: 22 additions & 0 deletions docker/archive/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,25 @@ func (r *Reader) List() ([][]types.ImageReference, error) {
}
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
}
24 changes: 13 additions & 11 deletions docker/internal/tarfile/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,41 +130,43 @@ func (r *Reader) Close() error {
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).
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 {
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)

case ref != nil:
refString := ref.String()
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)
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 {
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:
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))
}
return &r.Manifest[sourceIndex], nil
return &r.Manifest[sourceIndex], -1, nil

default:
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
}
}

Expand Down
2 changes: 1 addition & 1 deletion docker/internal/tarfile/src.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (s *Source) ensureCachedDataIsPresent() error {
// ensureCachedDataIsPresentPrivate is a private implementation detail of ensureCachedDataIsPresent.
// Call ensureCachedDataIsPresent instead.
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 {
return err
}
Expand Down

0 comments on commit 84a8611

Please sign in to comment.