@@ -2,38 +2,53 @@ package archive
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"io"
6
7
"os"
7
8
9
+ "github.com/containers/image/v5/oci/layout"
8
10
"github.com/containers/image/v5/types"
9
11
"github.com/containers/storage/pkg/archive"
10
12
digest "github.com/opencontainers/go-digest"
11
- "github.com/pkg/errors"
12
- "github.com/sirupsen/logrus"
13
13
)
14
14
15
15
type ociArchiveImageDestination struct {
16
- ref ociArchiveReference
17
- unpackedDest types. ImageDestination
18
- tempDirRef tempDirOCIRef
16
+ ref ociArchiveReference
17
+ tmpDir string
18
+ types. ImageDestination
19
19
}
20
20
21
21
// newImageDestination returns an ImageDestination for writing to an existing directory.
22
22
func newImageDestination (ctx context.Context , sys * types.SystemContext , ref ociArchiveReference ) (types.ImageDestination , error ) {
23
- tempDirRef , err := createOCIRef (sys , ref .image )
23
+ var archive * Writer
24
+
25
+ if ref .sourceIndex != - 1 {
26
+ return nil , fmt .Errorf ("%w: destination reference must not contain a manifest index @%d" , invalidOciArchiveErr , ref .sourceIndex )
27
+ }
28
+
29
+ if ref .archiveWriter != nil {
30
+ archive = ref .archiveWriter
31
+ } else {
32
+ a , err := NewWriter (ctx , sys , ref .file )
33
+ if err != nil {
34
+ return nil , err
35
+ }
36
+ archive = a
37
+ }
38
+ newref , err := layout .NewReference (archive .tempDir , ref .image )
24
39
if err != nil {
25
- return nil , errors . Wrapf ( err , "creating oci reference" )
40
+ return nil , err
26
41
}
27
- unpackedDest , err := tempDirRef . ociRefExtracted .NewImageDestination (ctx , sys )
42
+ dst , err := newref .NewImageDestination (ctx , sys )
28
43
if err != nil {
29
- if err := tempDirRef .deleteTempDir (); err != nil {
30
- return nil , errors .Wrapf (err , "deleting temp directory %q" , tempDirRef .tempDirectory )
31
- }
32
44
return nil , err
33
45
}
34
- return & ociArchiveImageDestination {ref : ref ,
35
- unpackedDest : unpackedDest ,
36
- tempDirRef : tempDirRef }, nil
46
+
47
+ return & ociArchiveImageDestination {
48
+ ImageDestination : dst ,
49
+ tmpDir : archive .tempDir ,
50
+ ref : ref ,
51
+ }, nil
37
52
}
38
53
39
54
// Reference returns the reference used to set up this destination.
@@ -44,42 +59,41 @@ func (d *ociArchiveImageDestination) Reference() types.ImageReference {
44
59
// Close removes resources associated with an initialized ImageDestination, if any
45
60
// Close deletes the temp directory of the oci-archive image
46
61
func (d * ociArchiveImageDestination ) Close () error {
47
- defer func () {
48
- err := d .tempDirRef .deleteTempDir ()
49
- logrus .Debugf ("Error deleting temporary directory: %v" , err )
50
- }()
51
- return d .unpackedDest .Close ()
62
+ if d .ref .archiveWriter != nil {
63
+ return nil
64
+ }
65
+ return d .ImageDestination .Close ()
52
66
}
53
67
54
68
func (d * ociArchiveImageDestination ) SupportedManifestMIMETypes () []string {
55
- return d .unpackedDest .SupportedManifestMIMETypes ()
69
+ return d .ImageDestination .SupportedManifestMIMETypes ()
56
70
}
57
71
58
72
// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures
59
73
func (d * ociArchiveImageDestination ) SupportsSignatures (ctx context.Context ) error {
60
- return d .unpackedDest .SupportsSignatures (ctx )
74
+ return d .ImageDestination .SupportsSignatures (ctx )
61
75
}
62
76
63
77
func (d * ociArchiveImageDestination ) DesiredLayerCompression () types.LayerCompression {
64
- return d .unpackedDest .DesiredLayerCompression ()
78
+ return d .ImageDestination .DesiredLayerCompression ()
65
79
}
66
80
67
81
// AcceptsForeignLayerURLs returns false iff foreign layers in manifest should be actually
68
82
// uploaded to the image destination, true otherwise.
69
83
func (d * ociArchiveImageDestination ) AcceptsForeignLayerURLs () bool {
70
- return d .unpackedDest .AcceptsForeignLayerURLs ()
84
+ return d .ImageDestination .AcceptsForeignLayerURLs ()
71
85
}
72
86
73
87
// MustMatchRuntimeOS returns true iff the destination can store only images targeted for the current runtime architecture and OS. False otherwise
74
88
func (d * ociArchiveImageDestination ) MustMatchRuntimeOS () bool {
75
- return d .unpackedDest .MustMatchRuntimeOS ()
89
+ return d .ImageDestination .MustMatchRuntimeOS ()
76
90
}
77
91
78
92
// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(),
79
93
// and would prefer to receive an unmodified manifest instead of one modified for the destination.
80
94
// Does not make a difference if Reference().DockerReference() is nil.
81
95
func (d * ociArchiveImageDestination ) IgnoresEmbeddedDockerReference () bool {
82
- return d .unpackedDest .IgnoresEmbeddedDockerReference ()
96
+ return d .ImageDestination .IgnoresEmbeddedDockerReference ()
83
97
}
84
98
85
99
// HasThreadSafePutBlob indicates whether PutBlob can be executed concurrently.
@@ -96,7 +110,7 @@ func (d *ociArchiveImageDestination) HasThreadSafePutBlob() bool {
96
110
// to any other readers for download using the supplied digest.
97
111
// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far.
98
112
func (d * ociArchiveImageDestination ) PutBlob (ctx context.Context , stream io.Reader , inputInfo types.BlobInfo , cache types.BlobInfoCache , isConfig bool ) (types.BlobInfo , error ) {
99
- return d .unpackedDest .PutBlob (ctx , stream , inputInfo , cache , isConfig )
113
+ return d .ImageDestination .PutBlob (ctx , stream , inputInfo , cache , isConfig )
100
114
}
101
115
102
116
// TryReusingBlob checks whether the transport already contains, or can efficiently reuse, a blob, and if so, applies it to the current destination
@@ -109,7 +123,7 @@ func (d *ociArchiveImageDestination) PutBlob(ctx context.Context, stream io.Read
109
123
// If the transport can not reuse the requested blob, TryReusingBlob returns (false, {}, nil); it returns a non-nil error only on an unexpected failure.
110
124
// May use and/or update cache.
111
125
func (d * ociArchiveImageDestination ) TryReusingBlob (ctx context.Context , info types.BlobInfo , cache types.BlobInfoCache , canSubstitute bool ) (bool , types.BlobInfo , error ) {
112
- return d .unpackedDest .TryReusingBlob (ctx , info , cache , canSubstitute )
126
+ return d .ImageDestination .TryReusingBlob (ctx , info , cache , canSubstitute )
113
127
}
114
128
115
129
// PutManifest writes the manifest to the destination.
@@ -118,14 +132,14 @@ func (d *ociArchiveImageDestination) TryReusingBlob(ctx context.Context, info ty
118
132
// It is expected but not enforced that the instanceDigest, when specified, matches the digest of `manifest` as generated
119
133
// by `manifest.Digest()`.
120
134
func (d * ociArchiveImageDestination ) PutManifest (ctx context.Context , m []byte , instanceDigest * digest.Digest ) error {
121
- return d .unpackedDest .PutManifest (ctx , m , instanceDigest )
135
+ return d .ImageDestination .PutManifest (ctx , m , instanceDigest )
122
136
}
123
137
124
138
// PutSignatures writes a set of signatures to the destination.
125
139
// If instanceDigest is not nil, it contains a digest of the specific manifest instance to write or overwrite the signatures for
126
140
// (when the primary manifest is a manifest list); this should always be nil if the primary manifest is not a manifest list.
127
141
func (d * ociArchiveImageDestination ) PutSignatures (ctx context.Context , signatures [][]byte , instanceDigest * digest.Digest ) error {
128
- return d .unpackedDest .PutSignatures (ctx , signatures , instanceDigest )
142
+ return d .ImageDestination .PutSignatures (ctx , signatures , instanceDigest )
129
143
}
130
144
131
145
// Commit marks the process of storing the image as successful and asks for the image to be persisted
@@ -134,12 +148,16 @@ func (d *ociArchiveImageDestination) PutSignatures(ctx context.Context, signatur
134
148
// original manifest list digest, if desired.
135
149
// after the directory is made, it is tarred up into a file and the directory is deleted
136
150
func (d * ociArchiveImageDestination ) Commit (ctx context.Context , unparsedToplevel types.UnparsedImage ) error {
137
- if err := d .unpackedDest .Commit (ctx , unparsedToplevel ); err != nil {
138
- return errors .Wrapf (err , "storing image %q" , d .ref .image )
151
+ if err := d .ImageDestination .Commit (ctx , unparsedToplevel ); err != nil {
152
+ return fmt .Errorf ("%w: storing image %q" , err , d .ref .image )
153
+ }
154
+
155
+ if d .ref .archiveWriter != nil {
156
+ return nil
139
157
}
140
158
141
159
// path of directory to tar up
142
- src := d .tempDirRef . tempDirectory
160
+ src := d .tmpDir
143
161
// path to save tarred up file
144
162
dst := d .ref .resolvedFile
145
163
return tarDirectory (src , dst )
@@ -150,13 +168,13 @@ func tarDirectory(src, dst string) error {
150
168
// input is a stream of bytes from the archive of the directory at path
151
169
input , err := archive .Tar (src , archive .Uncompressed )
152
170
if err != nil {
153
- return errors . Wrapf ( err , " retrieving stream of bytes from %q" , src )
171
+ return fmt . Errorf ( "%w: retrieving stream of bytes from %q", err , src )
154
172
}
155
173
156
174
// creates the tar file
157
175
outFile , err := os .Create (dst )
158
176
if err != nil {
159
- return errors . Wrapf ( err , " creating tar file %q" , dst )
177
+ return fmt . Errorf ( "%w: creating tar file %q", err , dst )
160
178
}
161
179
defer outFile .Close ()
162
180
0 commit comments