@@ -3260,6 +3260,103 @@ def make_disk(
3260
3260
return make_image (context , msg = msg , skip = skip , split = split , tabs = tabs , root = context .root , definitions = definitions )
3261
3261
3262
3262
3263
+ def make_oci (context : Context , root_layer : Path , dst : Path ) -> None :
3264
+ ca_store = dst / "blobs" / "sha256"
3265
+ with umask (~ 0o755 ):
3266
+ ca_store .mkdir (parents = True )
3267
+
3268
+ layer_diff_digest = hash_file (root_layer )
3269
+ maybe_compress (
3270
+ context ,
3271
+ context .config .compress_output ,
3272
+ context .staging / "rootfs.layer" ,
3273
+ # Pass explicit destination to suppress adding an extension
3274
+ context .staging / "rootfs.layer" ,
3275
+ )
3276
+ layer_digest = hash_file (root_layer )
3277
+ root_layer .rename (ca_store / layer_digest )
3278
+
3279
+ creation_time = (
3280
+ datetime .datetime .fromtimestamp (context .config .source_date_epoch , tz = datetime .timezone .utc )
3281
+ if context .config .source_date_epoch is not None
3282
+ else datetime .datetime .now (tz = datetime .timezone .utc )
3283
+ ).isoformat ()
3284
+
3285
+ oci_config = {
3286
+ "created" : creation_time ,
3287
+ "architecture" : context .config .architecture .to_oci (),
3288
+ # Name of the operating system which the image is built to run on as defined by
3289
+ # https://github.com/opencontainers/image-spec/blob/v1.0.2/config.md#properties.
3290
+ "os" : "linux" ,
3291
+ "rootfs" : {
3292
+ "type" : "layers" ,
3293
+ "diff_ids" : [f"sha256:{ layer_diff_digest } " ],
3294
+ },
3295
+ "config" : {
3296
+ "Cmd" : [
3297
+ "/sbin/init" ,
3298
+ * context .config .kernel_command_line ,
3299
+ ],
3300
+ },
3301
+ "history" : [
3302
+ {
3303
+ "created" : creation_time ,
3304
+ "comment" : "Created by mkosi" ,
3305
+ },
3306
+ ],
3307
+ }
3308
+ oci_config_blob = json .dumps (oci_config )
3309
+ oci_config_digest = hashlib .sha256 (oci_config_blob .encode ()).hexdigest ()
3310
+ with umask (~ 0o644 ):
3311
+ (ca_store / oci_config_digest ).write_text (oci_config_blob )
3312
+
3313
+ layer_suffix = context .config .compress_output .oci_media_type_suffix ()
3314
+ oci_manifest = {
3315
+ "schemaVersion" : 2 ,
3316
+ "mediaType" : "application/vnd.oci.image.manifest.v1+json" ,
3317
+ "config" : {
3318
+ "mediaType" : "application/vnd.oci.image.config.v1+json" ,
3319
+ "digest" : f"sha256:{ oci_config_digest } " ,
3320
+ "size" : (ca_store / oci_config_digest ).stat ().st_size ,
3321
+ },
3322
+ "layers" : [
3323
+ {
3324
+ "mediaType" : f"application/vnd.oci.image.layer.v1.tar{ layer_suffix } " ,
3325
+ "digest" : f"sha256:{ layer_digest } " ,
3326
+ "size" : (ca_store / layer_digest ).stat ().st_size ,
3327
+ }
3328
+ ],
3329
+ "annotations" : {
3330
+ "io.systemd.mkosi.version" : __version__ ,
3331
+ ** ({
3332
+ "org.opencontainers.image.version" : context .config .image_version ,
3333
+ } if context .config .image_version else {}),
3334
+ }
3335
+ }
3336
+ oci_manifest_blob = json .dumps (oci_manifest )
3337
+ oci_manifest_digest = hashlib .sha256 (oci_manifest_blob .encode ()).hexdigest ()
3338
+ with umask (~ 0o644 ):
3339
+ (ca_store / oci_manifest_digest ).write_text (oci_manifest_blob )
3340
+
3341
+ (dst / "index.json" ).write_text (
3342
+ json .dumps (
3343
+ {
3344
+ "schemaVersion" : 2 ,
3345
+ "mediaType" : "application/vnd.oci.image.index.v1+json" ,
3346
+ "manifests" : [
3347
+ {
3348
+ "mediaType" : "application/vnd.oci.image.manifest.v1+json" ,
3349
+ "digest" : f"sha256:{ oci_manifest_digest } " ,
3350
+ "size" : (ca_store / oci_manifest_digest ).stat ().st_size ,
3351
+ }
3352
+ ],
3353
+ }
3354
+ )
3355
+ )
3356
+
3357
+ (dst / "oci-layout" ).write_text (json .dumps ({"imageLayoutVersion" : "1.0.0" }))
3358
+
3359
+
3263
3360
def make_esp (context : Context , uki : Path ) -> list [Partition ]:
3264
3361
if not (arch := context .config .architecture .to_efi ()):
3265
3362
die (f"Architecture { context .config .architecture } does not support UEFI" )
@@ -3561,6 +3658,17 @@ def build_image(context: Context) -> None:
3561
3658
tools = context .config .tools (),
3562
3659
sandbox = context .sandbox ,
3563
3660
)
3661
+ elif context .config .output_format == OutputFormat .oci :
3662
+ make_tar (
3663
+ context .root , context .staging / "rootfs.layer" ,
3664
+ tools = context .config .tools (),
3665
+ sandbox = context .sandbox ,
3666
+ )
3667
+ make_oci (
3668
+ context ,
3669
+ context .staging / "rootfs.layer" ,
3670
+ context .staging / context .config .output_with_format ,
3671
+ )
3564
3672
elif context .config .output_format == OutputFormat .cpio :
3565
3673
make_cpio (
3566
3674
context .root , context .staging / context .config .output_with_format ,
0 commit comments