31
31
import land .oras .utils .JsonUtils ;
32
32
import land .oras .utils .SupportedAlgorithm ;
33
33
import org .jspecify .annotations .Nullable ;
34
- import org .slf4j .Logger ;
35
- import org .slf4j .LoggerFactory ;
36
34
37
35
/**
38
36
* Index from an OCI layout
39
37
*/
40
38
public final class OCILayout extends OCI <LayoutRef > {
41
39
42
- /**
43
- * The logger
44
- */
45
- private static final Logger LOG = LoggerFactory .getLogger (OCILayout .class );
46
-
47
40
private final String imageLayoutVersion = "1.0.0" ;
48
41
49
42
/**
@@ -120,6 +113,41 @@ public InputStream fetchBlob(LayoutRef ref) {
120
113
}
121
114
}
122
115
116
+ @ Override
117
+ public Layer pushBlob (LayoutRef ref , Path blob , Map <String , String > annotations ) {
118
+ ensureDigest (ref );
119
+ ensureMinimalLayout ();
120
+ Path blobPath = getBlobPath (ref );
121
+ String digest = ref .getAlgorithm ().digest (blob );
122
+ ensureAlgorithmPath (digest );
123
+ LOG .debug ("Digest: {}" , digest );
124
+ try {
125
+ if (Files .exists (blobPath )) {
126
+ LOG .debug ("Blob already exists: {}" , blobPath );
127
+ return Layer .fromFile (blobPath ).withAnnotations (annotations );
128
+ }
129
+ Files .copy (blob , blobPath );
130
+ return Layer .fromFile (blobPath ).withAnnotations (annotations );
131
+ } catch (IOException e ) {
132
+ throw new OrasException ("Failed to push blob" , e );
133
+ }
134
+ }
135
+
136
+ @ Override
137
+ public Layer pushBlob (LayoutRef ref , byte [] data ) {
138
+ ensureDigest (ref );
139
+ ensureMinimalLayout ();
140
+ String digest = ref .getAlgorithm ().digest (data );
141
+ ensureAlgorithmPath (digest );
142
+ try {
143
+ Path path = Files .createTempFile ("oras" , "blob" );
144
+ Files .write (path , data );
145
+ return pushBlob (ref , path , Map .of ());
146
+ } catch (IOException e ) {
147
+ throw new OrasException ("Failed to push blob to OCI layout" , e );
148
+ }
149
+ }
150
+
123
151
private void setPath (Path path ) {
124
152
this .path = path ;
125
153
}
@@ -158,6 +186,31 @@ public void copy(Registry registry, ContainerRef containerRef) {
158
186
copy (registry , containerRef , false );
159
187
}
160
188
189
+ private void ensureMinimalLayout () {
190
+ try {
191
+ Files .createDirectories (getBlobPath ());
192
+ if (!Files .exists (getOciLayoutPath ())) {
193
+ Files .writeString (getOciLayoutPath (), toJson ());
194
+ }
195
+ if (!Files .exists (getIndexPath ())) {
196
+ Files .writeString (getIndexPath (), Index .fromManifests (List .of ()).toJson ());
197
+ }
198
+ } catch (IOException e ) {
199
+ throw new OrasException ("Failed to create layout" , e );
200
+ }
201
+ }
202
+
203
+ private void ensureAlgorithmPath (String digest ) {
204
+ Path prefixDirectory = getBlobAlgorithmPath (digest );
205
+ try {
206
+ if (!Files .exists (prefixDirectory )) {
207
+ Files .createDirectory (prefixDirectory );
208
+ }
209
+ } catch (IOException e ) {
210
+ throw new OrasException ("Failed to create algorithm path" , e );
211
+ }
212
+ }
213
+
161
214
/**
162
215
* Copy the container ref from registry into oci-layout
163
216
* @param registry The registry
@@ -168,13 +221,7 @@ public void copy(Registry registry, ContainerRef containerRef, boolean recursive
168
221
169
222
try {
170
223
171
- // Create blobs directory if needed
172
- Files .createDirectories (getBlobPath ());
173
-
174
- // Write oci layout JSON
175
- if (!Files .exists (getOciLayoutPath ())) {
176
- Files .writeString (getOciLayoutPath (), toJson ());
177
- }
224
+ ensureMinimalLayout ();
178
225
179
226
Map <String , String > headers = registry .getHeaders (containerRef );
180
227
String contentType = headers .get (Const .CONTENT_TYPE_HEADER .toLowerCase ());
@@ -235,10 +282,7 @@ else if (registry.isIndexMediaType(contentType)) {
235
282
for (Layer layer : registry .collectLayers (containerRef , contentType , true )) {
236
283
try (InputStream is = registry .fetchBlob (containerRef .withDigest (layer .getDigest ()))) {
237
284
238
- Path prefixDirectory = getBlobAlgorithmPath (layer .getDigest ());
239
- if (!Files .exists (prefixDirectory )) {
240
- Files .createDirectory (prefixDirectory );
241
- }
285
+ ensureAlgorithmPath (layer .getDigest ());
242
286
243
287
Path blobFile = getBlobPath (layer );
244
288
@@ -256,6 +300,15 @@ else if (registry.isIndexMediaType(contentType)) {
256
300
}
257
301
}
258
302
303
+ private void ensureDigest (LayoutRef ref ) {
304
+ if (ref .getTag () == null ) {
305
+ throw new OrasException ("Missing ref" );
306
+ }
307
+ if (!SupportedAlgorithm .isSupported (ref .getTag ())) {
308
+ throw new OrasException ("Unsupported digest: %s" .formatted (ref .getTag ()));
309
+ }
310
+ }
311
+
259
312
private Path getOciLayoutPath () {
260
313
return path .resolve (Const .OCI_LAYOUT_FILE );
261
314
}
0 commit comments