File: reader.go

package info (click to toggle)
golang-github-containers-image 5.23.1-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 4,368 kB
  • sloc: sh: 165; makefile: 75
file content (121 lines) | stat: -rw-r--r-- 4,563 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package archive

import (
	"fmt"

	"github.com/containers/image/v5/docker/internal/tarfile"
	"github.com/containers/image/v5/docker/reference"
	"github.com/containers/image/v5/transports"
	"github.com/containers/image/v5/types"
)

// Reader manages a single Docker archive, allows listing its contents and accessing
// individual images with less overhead than creating image references individually
// (because the archive is, if necessary, copied or decompressed only once).
type Reader struct {
	path    string // The original, user-specified path; not the maintained temporary file, if any
	archive *tarfile.Reader
}

// NewReader returns a Reader for path.
// The caller should call .Close() on the returned object.
func NewReader(sys *types.SystemContext, path string) (*Reader, error) {
	archive, err := tarfile.NewReaderFromFile(sys, path)
	if err != nil {
		return nil, err
	}
	return &Reader{
		path:    path,
		archive: archive,
	}, nil
}

// Close deletes temporary files associated with the Reader, if any.
func (r *Reader) Close() error {
	return r.archive.Close()
}

// NewReaderForReference creates a Reader from a Reader-independent imageReference, which must be from docker/archive.Transport,
// and a variant of imageReference that points at the same image within the reader.
// The caller should call .Close() on the returned Reader.
func NewReaderForReference(sys *types.SystemContext, ref types.ImageReference) (*Reader, types.ImageReference, error) {
	standalone, ok := ref.(archiveReference)
	if !ok {
		return nil, nil, fmt.Errorf("Internal error: NewReaderForReference called for a non-docker/archive ImageReference %s", transports.ImageName(ref))
	}
	if standalone.archiveReader != nil {
		return nil, nil, fmt.Errorf("Internal error: NewReaderForReference called for a reader-bound reference %s", standalone.StringWithinTransport())
	}
	reader, err := NewReader(sys, standalone.path)
	if err != nil {
		return nil, nil, err
	}
	succeeded := false
	defer func() {
		if !succeeded {
			reader.Close()
		}
	}()
	readerRef, err := newReference(standalone.path, standalone.ref, standalone.sourceIndex, reader.archive, nil)
	if err != nil {
		return nil, nil, err
	}
	succeeded = true
	return reader, readerRef, nil
}

// List returns the a set of references for images in the Reader,
// grouped by the image the references point to.
// The references are valid only until the Reader is closed.
func (r *Reader) List() ([][]types.ImageReference, error) {
	res := [][]types.ImageReference{}
	for imageIndex, image := range r.archive.Manifest {
		refs := []types.ImageReference{}
		for _, tag := range image.RepoTags {
			parsedTag, err := reference.ParseNormalizedNamed(tag)
			if err != nil {
				return nil, fmt.Errorf("Invalid tag %#v in manifest item @%d: %w", tag, imageIndex, err)
			}
			nt, ok := parsedTag.(reference.NamedTagged)
			if !ok {
				return nil, fmt.Errorf("Invalid tag %s (%s): does not contain a tag", tag, parsedTag.String())
			}
			ref, err := newReference(r.path, nt, -1, r.archive, nil)
			if err != nil {
				return nil, fmt.Errorf("creating a reference for tag %#v in manifest item @%d: %w", tag, imageIndex, err)
			}
			refs = append(refs, ref)
		}
		if len(refs) == 0 {
			ref, err := newReference(r.path, nil, imageIndex, r.archive, nil)
			if err != nil {
				return nil, fmt.Errorf("creating a reference for manifest item @%d: %w", imageIndex, err)
			}
			refs = append(refs, ref)
		}
		res = append(res, refs)
	}
	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, fmt.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
}