mirror of
https://github.com/flatpak/flatpak.git
synced 2026-03-14 13:15:35 -04:00
This is a major change in the OCI support, as the format of the OCI image registries changed. Instead of now having a "ref" file for each image in the repo it has a single index json file, where the ref name is now a per-image annotation. This allows us to support OCI much better, as we can now use the actual flatpak ref as the OCI ref name, and we can find all the flatpak refs in a remote. So, with this you can just use: flatpak remote-add --oci remote-name URL and then you can use the regular flatpak operations on the remote.
858 lines
25 KiB
C
858 lines
25 KiB
C
/*
|
|
* Copyright (C) 2015 Red Hat, Inc
|
|
*
|
|
* This file is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This file is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Authors:
|
|
* Alexander Larsson <alexl@redhat.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "string.h"
|
|
|
|
#include "flatpak-json-oci.h"
|
|
#include "flatpak-utils.h"
|
|
#include "libglnx.h"
|
|
|
|
const char *
|
|
flatpak_arch_to_oci_arch (const char *flatpak_arch)
|
|
{
|
|
if (strcmp (flatpak_arch, "x86_64") == 0)
|
|
return "amd64";
|
|
if (strcmp (flatpak_arch, "aarch64") == 0)
|
|
return "arm64";
|
|
if (strcmp (flatpak_arch, "i386") == 0)
|
|
return "386";
|
|
return flatpak_arch;
|
|
}
|
|
|
|
FlatpakOciDescriptor *
|
|
flatpak_oci_descriptor_new (const char *mediatype,
|
|
const char *digest,
|
|
gint64 size)
|
|
{
|
|
FlatpakOciDescriptor *desc = g_new0 (FlatpakOciDescriptor, 1);
|
|
|
|
desc->mediatype = g_strdup (mediatype);
|
|
desc->digest = g_strdup (digest);
|
|
desc->size = size;
|
|
desc->annotations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
|
return desc;
|
|
}
|
|
|
|
void
|
|
flatpak_oci_descriptor_copy (FlatpakOciDescriptor *source,
|
|
FlatpakOciDescriptor *dest)
|
|
{
|
|
flatpak_oci_descriptor_destroy (dest);
|
|
|
|
dest->mediatype = g_strdup (source->mediatype);
|
|
dest->digest = g_strdup (source->digest);
|
|
dest->size = source->size;
|
|
dest->urls = g_strdupv ((char **)source->urls);
|
|
dest->annotations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
if (source->annotations)
|
|
flatpak_oci_copy_annotations (source->annotations, dest->annotations);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_descriptor_destroy (FlatpakOciDescriptor *self)
|
|
{
|
|
g_free (self->mediatype);
|
|
g_free (self->digest);
|
|
g_strfreev (self->urls);
|
|
if (self->annotations)
|
|
g_hash_table_destroy (self->annotations);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_descriptor_free (FlatpakOciDescriptor *self)
|
|
{
|
|
flatpak_oci_descriptor_destroy (self);
|
|
g_free (self);
|
|
}
|
|
|
|
static FlatpakJsonProp flatpak_oci_descriptor_props[] = {
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciDescriptor, mediatype, "mediaType"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciDescriptor, digest, "digest"),
|
|
FLATPAK_JSON_INT64_PROP (FlatpakOciDescriptor, size, "size"),
|
|
FLATPAK_JSON_STRV_PROP (FlatpakOciDescriptor, urls, "urls"),
|
|
FLATPAK_JSON_STRMAP_PROP(FlatpakOciDescriptor, annotations, "annotations"),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
|
|
static void
|
|
flatpak_oci_manifest_platform_destroy (FlatpakOciManifestPlatform *self)
|
|
{
|
|
g_free (self->architecture);
|
|
g_free (self->os);
|
|
g_free (self->os_version);
|
|
g_strfreev (self->os_features);
|
|
g_free (self->variant);
|
|
g_strfreev (self->features);
|
|
}
|
|
|
|
FlatpakOciManifestDescriptor *
|
|
flatpak_oci_manifest_descriptor_new (void)
|
|
{
|
|
return g_new0 (FlatpakOciManifestDescriptor, 1);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_manifest_descriptor_destroy (FlatpakOciManifestDescriptor *self)
|
|
{
|
|
flatpak_oci_manifest_platform_destroy (&self->platform);
|
|
flatpak_oci_descriptor_destroy (&self->parent);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_manifest_descriptor_free (FlatpakOciManifestDescriptor *self)
|
|
{
|
|
flatpak_oci_manifest_descriptor_destroy (self);
|
|
g_free (self);
|
|
}
|
|
|
|
static FlatpakJsonProp flatpak_oci_manifest_platform_props[] = {
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciManifestPlatform, architecture, "architecture"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciManifestPlatform, os, "os"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciManifestPlatform, os_version, "os.version"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciManifestPlatform, variant, "variant"),
|
|
FLATPAK_JSON_STRV_PROP (FlatpakOciManifestPlatform, os_features, "os.features"),
|
|
FLATPAK_JSON_STRV_PROP (FlatpakOciManifestPlatform, features, "features"),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
static FlatpakJsonProp flatpak_oci_manifest_descriptor_props[] = {
|
|
FLATPAK_JSON_PARENT_PROP (FlatpakOciManifestDescriptor, parent, flatpak_oci_descriptor_props),
|
|
FLATPAK_JSON_OPT_STRUCT_PROP (FlatpakOciManifestDescriptor, platform, "platform", flatpak_oci_manifest_platform_props),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
|
|
|
|
G_DEFINE_TYPE (FlatpakOciVersioned, flatpak_oci_versioned, FLATPAK_TYPE_JSON);
|
|
|
|
static void
|
|
flatpak_oci_versioned_finalize (GObject *object)
|
|
{
|
|
FlatpakOciVersioned *self = FLATPAK_OCI_VERSIONED (object);
|
|
|
|
g_free (self->mediatype);
|
|
|
|
G_OBJECT_CLASS (flatpak_oci_versioned_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_versioned_class_init (FlatpakOciVersionedClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
FlatpakJsonClass *json_class = FLATPAK_JSON_CLASS (klass);
|
|
static FlatpakJsonProp props[] = {
|
|
FLATPAK_JSON_INT64_PROP (FlatpakOciVersioned, version, "schemaVersion"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciVersioned, mediatype, "mediaType"),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
|
|
object_class->finalize = flatpak_oci_versioned_finalize;
|
|
json_class->props = props;
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_versioned_init (FlatpakOciVersioned *self)
|
|
{
|
|
}
|
|
|
|
FlatpakOciVersioned *
|
|
flatpak_oci_versioned_from_json (GBytes *bytes, GError **error)
|
|
{
|
|
g_autoptr(JsonParser) parser = NULL;
|
|
JsonNode *root = NULL;
|
|
const gchar *mediatype;
|
|
JsonObject *object;
|
|
|
|
parser = json_parser_new ();
|
|
if (!json_parser_load_from_data (parser,
|
|
g_bytes_get_data (bytes, NULL),
|
|
g_bytes_get_size (bytes),
|
|
error))
|
|
return NULL;
|
|
|
|
root = json_parser_get_root (parser);
|
|
object = json_node_get_object (root);
|
|
|
|
mediatype = json_object_get_string_member (object, "mediaType");
|
|
if (mediatype == NULL)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Versioned object lacks mediatype");
|
|
return NULL;
|
|
}
|
|
|
|
if (strcmp (mediatype, FLATPAK_OCI_MEDIA_TYPE_IMAGE_MANIFEST) == 0)
|
|
return (FlatpakOciVersioned *) flatpak_json_from_node (root, FLATPAK_TYPE_OCI_MANIFEST, error);
|
|
|
|
if (strcmp (mediatype, FLATPAK_OCI_MEDIA_TYPE_IMAGE_INDEX) == 0)
|
|
return (FlatpakOciVersioned *) flatpak_json_from_node (root, FLATPAK_TYPE_OCI_INDEX, error);
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Unsupported media type %s", mediatype);
|
|
return NULL;
|
|
}
|
|
|
|
const char *
|
|
flatpak_oci_versioned_get_mediatype (FlatpakOciVersioned *self)
|
|
{
|
|
return self->mediatype;
|
|
}
|
|
|
|
gint64
|
|
flatpak_oci_versioned_get_version (FlatpakOciVersioned *self)
|
|
{
|
|
return self->version;
|
|
}
|
|
|
|
G_DEFINE_TYPE (FlatpakOciManifest, flatpak_oci_manifest, FLATPAK_TYPE_OCI_VERSIONED);
|
|
|
|
static void
|
|
flatpak_oci_manifest_finalize (GObject *object)
|
|
{
|
|
FlatpakOciManifest *self = (FlatpakOciManifest *) object;
|
|
int i;
|
|
|
|
for (i = 0; self->layers != NULL && self->layers[i] != NULL; i++)
|
|
flatpak_oci_descriptor_free (self->layers[i]);
|
|
g_free (self->layers);
|
|
flatpak_oci_descriptor_destroy (&self->config);
|
|
if (self->annotations)
|
|
g_hash_table_destroy (self->annotations);
|
|
|
|
G_OBJECT_CLASS (flatpak_oci_manifest_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_manifest_class_init (FlatpakOciManifestClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
FlatpakJsonClass *json_class = FLATPAK_JSON_CLASS (klass);
|
|
static FlatpakJsonProp props[] = {
|
|
FLATPAK_JSON_STRUCT_PROP(FlatpakOciManifest, config, "config", flatpak_oci_descriptor_props),
|
|
FLATPAK_JSON_STRUCTV_PROP(FlatpakOciManifest, layers, "layers", flatpak_oci_descriptor_props),
|
|
FLATPAK_JSON_STRMAP_PROP(FlatpakOciManifest, annotations, "annotations"),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
|
|
object_class->finalize = flatpak_oci_manifest_finalize;
|
|
json_class->props = props;
|
|
json_class->mediatype = FLATPAK_OCI_MEDIA_TYPE_IMAGE_MANIFEST;
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_manifest_init (FlatpakOciManifest *self)
|
|
{
|
|
}
|
|
|
|
FlatpakOciManifest *
|
|
flatpak_oci_manifest_new (void)
|
|
{
|
|
FlatpakOciManifest *manifest;
|
|
|
|
manifest = g_object_new (FLATPAK_TYPE_OCI_MANIFEST, NULL);
|
|
manifest->parent.version = 2;
|
|
manifest->parent.mediatype = g_strdup (FLATPAK_OCI_MEDIA_TYPE_IMAGE_MANIFEST);
|
|
|
|
manifest->annotations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
|
return manifest;
|
|
}
|
|
|
|
void
|
|
flatpak_oci_manifest_set_config (FlatpakOciManifest *self,
|
|
FlatpakOciDescriptor *desc)
|
|
{
|
|
g_free (self->config.mediatype);
|
|
self->config.mediatype = g_strdup (desc->mediatype);
|
|
g_free (self->config.digest);
|
|
self->config.digest = g_strdup (desc->digest);
|
|
self->config.size = desc->size;
|
|
}
|
|
|
|
static int
|
|
ptrv_count (gpointer *ptrs)
|
|
{
|
|
int count;
|
|
|
|
for (count = 0; ptrs != NULL && ptrs[count] != NULL; count++)
|
|
;
|
|
|
|
return count;
|
|
}
|
|
|
|
void
|
|
flatpak_oci_manifest_set_layer (FlatpakOciManifest *self,
|
|
FlatpakOciDescriptor *desc)
|
|
{
|
|
FlatpakOciDescriptor *descs[2] = { desc, NULL };
|
|
flatpak_oci_manifest_set_layers (self, descs);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_manifest_set_layers (FlatpakOciManifest *self,
|
|
FlatpakOciDescriptor **descs)
|
|
{
|
|
int i, count;
|
|
|
|
for (i = 0; self->layers != NULL && self->layers[i] != NULL; i++)
|
|
flatpak_oci_descriptor_free (self->layers[i]);
|
|
g_free (self->layers);
|
|
|
|
count = ptrv_count ((gpointer *)descs);
|
|
|
|
self->layers = g_new0 (FlatpakOciDescriptor *, count + 1);
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
self->layers[i] = g_new0 (FlatpakOciDescriptor, 1);
|
|
self->layers[i]->mediatype = g_strdup (descs[i]->mediatype);
|
|
self->layers[i]->digest = g_strdup (descs[i]->digest);
|
|
self->layers[i]->size = descs[i]->size;
|
|
}
|
|
}
|
|
|
|
int
|
|
flatpak_oci_manifest_get_n_layers (FlatpakOciManifest *self)
|
|
{
|
|
return ptrv_count ((gpointer *)self->layers);
|
|
}
|
|
|
|
const char *
|
|
flatpak_oci_manifest_get_layer_digest (FlatpakOciManifest *self,
|
|
int i)
|
|
{
|
|
return self->layers[i]->digest;
|
|
}
|
|
|
|
GHashTable *
|
|
flatpak_oci_manifest_get_annotations (FlatpakOciManifest *self)
|
|
{
|
|
return self->annotations;
|
|
}
|
|
|
|
G_DEFINE_TYPE (FlatpakOciIndex, flatpak_oci_index, FLATPAK_TYPE_OCI_VERSIONED);
|
|
|
|
static void
|
|
flatpak_oci_index_finalize (GObject *object)
|
|
{
|
|
FlatpakOciIndex *self = (FlatpakOciIndex *) object;
|
|
int i;
|
|
|
|
for (i = 0; self->manifests != NULL && self->manifests[i] != NULL; i++)
|
|
flatpak_oci_manifest_descriptor_free (self->manifests[i]);
|
|
g_free (self->manifests);
|
|
|
|
if (self->annotations)
|
|
g_hash_table_destroy (self->annotations);
|
|
|
|
G_OBJECT_CLASS (flatpak_oci_index_parent_class)->finalize (object);
|
|
}
|
|
|
|
|
|
static void
|
|
flatpak_oci_index_class_init (FlatpakOciIndexClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
FlatpakJsonClass *json_class = FLATPAK_JSON_CLASS (klass);
|
|
static FlatpakJsonProp props[] = {
|
|
FLATPAK_JSON_STRUCTV_PROP(FlatpakOciIndex, manifests, "manifests", flatpak_oci_manifest_descriptor_props),
|
|
FLATPAK_JSON_STRMAP_PROP(FlatpakOciIndex, annotations, "annotations"),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
|
|
object_class->finalize = flatpak_oci_index_finalize;
|
|
json_class->props = props;
|
|
json_class->mediatype = FLATPAK_OCI_MEDIA_TYPE_IMAGE_INDEX;
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_index_init (FlatpakOciIndex *self)
|
|
{
|
|
}
|
|
|
|
FlatpakOciIndex *
|
|
flatpak_oci_index_new (void)
|
|
{
|
|
FlatpakOciIndex *index;
|
|
|
|
index = g_object_new (FLATPAK_TYPE_OCI_INDEX, NULL);
|
|
|
|
index->parent.version = 2;
|
|
index->parent.mediatype = g_strdup (FLATPAK_OCI_MEDIA_TYPE_IMAGE_INDEX);
|
|
index->annotations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
|
|
return index;
|
|
}
|
|
|
|
static FlatpakOciManifestDescriptor *
|
|
manifest_desc_for_desc (FlatpakOciDescriptor *src_descriptor)
|
|
{
|
|
FlatpakOciManifestDescriptor *desc;
|
|
|
|
desc = flatpak_oci_manifest_descriptor_new ();
|
|
flatpak_oci_descriptor_copy (src_descriptor, &desc->parent);
|
|
|
|
return desc;
|
|
}
|
|
|
|
int
|
|
flatpak_oci_index_get_n_manifests (FlatpakOciIndex *self)
|
|
{
|
|
return ptrv_count ((gpointer *)self->manifests);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_index_add_manifest (FlatpakOciIndex *self,
|
|
FlatpakOciDescriptor *desc)
|
|
{
|
|
FlatpakOciManifestDescriptor *m;
|
|
const char *m_ref = NULL;
|
|
int count;
|
|
|
|
if (desc->annotations != NULL)
|
|
m_ref = g_hash_table_lookup (desc->annotations, "org.opencontainers.ref.name");
|
|
|
|
if (m_ref != NULL)
|
|
flatpak_oci_index_remove_manifest (self, m_ref);
|
|
|
|
count = flatpak_oci_index_get_n_manifests (self);
|
|
|
|
m = manifest_desc_for_desc (desc);
|
|
self->manifests = g_renew (FlatpakOciManifestDescriptor *, self->manifests, count + 2);
|
|
self->manifests[count] = m;
|
|
self->manifests[count+1] = NULL;
|
|
}
|
|
|
|
const char *
|
|
flatpak_oci_manifest_descriptor_get_ref (FlatpakOciManifestDescriptor *m)
|
|
{
|
|
if (m->parent.mediatype == NULL ||
|
|
strcmp (m->parent.mediatype, FLATPAK_OCI_MEDIA_TYPE_IMAGE_MANIFEST) != 0)
|
|
return NULL;
|
|
|
|
if (m->parent.annotations == NULL)
|
|
return NULL;
|
|
|
|
return g_hash_table_lookup (m->parent.annotations, "org.opencontainers.ref.name");
|
|
}
|
|
|
|
static int
|
|
index_find_ref (FlatpakOciIndex *self,
|
|
const char *ref)
|
|
{
|
|
int i;
|
|
|
|
if (self->manifests == NULL)
|
|
return -1;
|
|
|
|
for (i = 0; self->manifests[i] != NULL; i++)
|
|
{
|
|
const char *m_ref = flatpak_oci_manifest_descriptor_get_ref (self->manifests[i]);
|
|
|
|
if (m_ref == NULL)
|
|
continue;
|
|
|
|
if (strcmp (ref, m_ref) == 0)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
FlatpakOciManifestDescriptor *
|
|
flatpak_oci_index_get_manifest (FlatpakOciIndex *self,
|
|
const char *ref)
|
|
{
|
|
int i = index_find_ref (self, ref);
|
|
|
|
if (i >= 0)
|
|
return self->manifests[i];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
FlatpakOciManifestDescriptor *
|
|
flatpak_oci_index_get_only_manifest (FlatpakOciIndex *self)
|
|
{
|
|
int i, found = -1;
|
|
|
|
if (self->manifests == NULL)
|
|
return NULL;
|
|
|
|
for (i = 0; self->manifests[i] != NULL; i++)
|
|
{
|
|
const char *m_ref = flatpak_oci_manifest_descriptor_get_ref (self->manifests[i]);
|
|
|
|
if (m_ref == NULL)
|
|
continue;
|
|
|
|
if (found == -1)
|
|
found = i;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
if (found >= 0)
|
|
return self->manifests[found];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
gboolean
|
|
flatpak_oci_index_remove_manifest (FlatpakOciIndex *self,
|
|
const char *ref)
|
|
{
|
|
int i = index_find_ref (self, ref);
|
|
|
|
if (i < 0)
|
|
return FALSE;
|
|
|
|
for (; self->manifests[i] != NULL; i++)
|
|
self->manifests[i] = self->manifests[i+1];
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
G_DEFINE_TYPE (FlatpakOciImage, flatpak_oci_image, FLATPAK_TYPE_JSON);
|
|
|
|
static void
|
|
flatpak_oci_image_rootfs_destroy (FlatpakOciImageRootfs *self)
|
|
{
|
|
g_free (self->type);
|
|
g_strfreev (self->diff_ids);
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_image_config_destroy (FlatpakOciImageConfig *self)
|
|
{
|
|
g_free (self->user);
|
|
g_free (self->working_dir);
|
|
g_strfreev (self->env);
|
|
g_strfreev (self->cmd);
|
|
g_strfreev (self->entrypoint);
|
|
g_strfreev (self->exposed_ports);
|
|
g_strfreev (self->volumes);
|
|
if (self->labels)
|
|
g_hash_table_destroy (self->labels);
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_image_history_free (FlatpakOciImageHistory *self)
|
|
{
|
|
g_free (self->created);
|
|
g_free (self->created_by);
|
|
g_free (self->author);
|
|
g_free (self->comment);
|
|
g_free (self);
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_image_finalize (GObject *object)
|
|
{
|
|
FlatpakOciImage *self = (FlatpakOciImage *) object;
|
|
int i;
|
|
|
|
g_free (self->created);
|
|
g_free (self->author);
|
|
g_free (self->architecture);
|
|
g_free (self->os);
|
|
flatpak_oci_image_rootfs_destroy (&self->rootfs);
|
|
flatpak_oci_image_config_destroy (&self->config);
|
|
|
|
for (i = 0; self->history != NULL && self->history[i] != NULL; i++)
|
|
flatpak_oci_image_history_free (self->history[i]);
|
|
g_free (self->history);
|
|
|
|
G_OBJECT_CLASS (flatpak_oci_image_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_image_class_init (FlatpakOciImageClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
FlatpakJsonClass *json_class = FLATPAK_JSON_CLASS (klass);
|
|
static FlatpakJsonProp config_props[] = {
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImageConfig, user, "User"),
|
|
FLATPAK_JSON_INT64_PROP (FlatpakOciImageConfig, memory, "Memory"),
|
|
FLATPAK_JSON_INT64_PROP (FlatpakOciImageConfig, memory_swap, "MemorySwap"),
|
|
FLATPAK_JSON_INT64_PROP (FlatpakOciImageConfig, cpu_shares, "CpuShares"),
|
|
FLATPAK_JSON_BOOLMAP_PROP (FlatpakOciImageConfig, exposed_ports, "ExposedPorts"),
|
|
FLATPAK_JSON_STRV_PROP (FlatpakOciImageConfig, env, "Env"),
|
|
FLATPAK_JSON_STRV_PROP (FlatpakOciImageConfig, entrypoint, "Entrypoint"),
|
|
FLATPAK_JSON_STRV_PROP (FlatpakOciImageConfig, cmd, "Cmd"),
|
|
FLATPAK_JSON_BOOLMAP_PROP (FlatpakOciImageConfig, volumes, "Volumes"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImageConfig, working_dir, "WorkingDir"),
|
|
FLATPAK_JSON_STRMAP_PROP(FlatpakOciImageConfig, labels, "Labels"),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
static FlatpakJsonProp rootfs_props[] = {
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImageRootfs, type, "type"),
|
|
FLATPAK_JSON_STRV_PROP (FlatpakOciImageRootfs, diff_ids, "diff_ids"),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
static FlatpakJsonProp history_props[] = {
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImageHistory, created, "created"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImageHistory, created_by, "created_by"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImageHistory, author, "author"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImageHistory, comment, "comment"),
|
|
FLATPAK_JSON_BOOL_PROP (FlatpakOciImageHistory, empty_layer, "empty_layer"),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
static FlatpakJsonProp props[] = {
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImage, created, "created"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImage, author, "author"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImage, architecture, "architecture"),
|
|
FLATPAK_JSON_STRING_PROP (FlatpakOciImage, os, "os"),
|
|
FLATPAK_JSON_STRUCT_PROP (FlatpakOciImage, config, "config", config_props),
|
|
FLATPAK_JSON_STRUCT_PROP (FlatpakOciImage, rootfs, "rootfs", rootfs_props),
|
|
FLATPAK_JSON_STRUCTV_PROP (FlatpakOciImage, history, "history", history_props),
|
|
FLATPAK_JSON_LAST_PROP
|
|
};
|
|
|
|
object_class->finalize = flatpak_oci_image_finalize;
|
|
json_class->props = props;
|
|
json_class->mediatype = FLATPAK_OCI_MEDIA_TYPE_IMAGE_CONFIG;
|
|
}
|
|
|
|
static void
|
|
flatpak_oci_image_init (FlatpakOciImage *self)
|
|
{
|
|
}
|
|
|
|
FlatpakOciImage *
|
|
flatpak_oci_image_new (void)
|
|
{
|
|
FlatpakOciImage *image;
|
|
GTimeVal stamp;
|
|
|
|
stamp.tv_sec = time (NULL);
|
|
stamp.tv_usec = 0;
|
|
|
|
image = g_object_new (FLATPAK_TYPE_OCI_IMAGE, NULL);
|
|
|
|
/* Some default values */
|
|
image->created = g_time_val_to_iso8601 (&stamp);
|
|
image->architecture = g_strdup ("arm64");
|
|
image->os = g_strdup ("linux");
|
|
|
|
image->rootfs.type = g_strdup ("layers");
|
|
image->rootfs.diff_ids = g_new0 (char *, 1);
|
|
|
|
return image;
|
|
}
|
|
|
|
void
|
|
flatpak_oci_image_set_created (FlatpakOciImage *image,
|
|
const char *created)
|
|
{
|
|
g_free (image->created);
|
|
image->created = g_strdup (created);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_image_set_architecture (FlatpakOciImage *image,
|
|
const char *arch)
|
|
{
|
|
g_free (image->architecture);
|
|
image->architecture = g_strdup (arch);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_image_set_os (FlatpakOciImage *image,
|
|
const char *os)
|
|
{
|
|
g_free (image->os);
|
|
image->os = g_strdup (os);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_image_set_layers (FlatpakOciImage *image,
|
|
const char **layers)
|
|
{
|
|
g_strfreev (image->rootfs.diff_ids);
|
|
image->rootfs.diff_ids = g_strdupv ((char **)layers);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_image_set_layer (FlatpakOciImage *image,
|
|
const char *layer)
|
|
{
|
|
const char *layers[] = {layer, NULL};
|
|
|
|
flatpak_oci_image_set_layers (image, layers);
|
|
}
|
|
|
|
void
|
|
flatpak_oci_export_annotations (GHashTable *source,
|
|
GHashTable *dest)
|
|
{
|
|
const char *keys[] = {
|
|
"org.opencontainers.ref.name",
|
|
"org.flatpak.installed-size",
|
|
"org.flatpak.download-size",
|
|
"org.flatpak.metadata",
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (keys); i++)
|
|
{
|
|
const char *key = keys[i];
|
|
const char *value = g_hash_table_lookup (source, key);
|
|
if (value)
|
|
g_hash_table_replace (dest,
|
|
g_strdup (key),
|
|
g_strdup (value));
|
|
}
|
|
}
|
|
|
|
void
|
|
flatpak_oci_copy_annotations (GHashTable *source,
|
|
GHashTable *dest)
|
|
{
|
|
GHashTableIter iter;
|
|
gpointer key, value;
|
|
|
|
g_hash_table_iter_init (&iter, source);
|
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
|
g_hash_table_replace (dest,
|
|
g_strdup ((char *)key),
|
|
g_strdup ((char *)value));
|
|
}
|
|
|
|
static void
|
|
add_annotation (GHashTable *annotations, const char *key, const char *value)
|
|
{
|
|
g_hash_table_replace (annotations,
|
|
g_strdup (key),
|
|
g_strdup (value));
|
|
}
|
|
|
|
void
|
|
flatpak_oci_add_annotations_for_commit (GHashTable *annotations,
|
|
const char *ref,
|
|
const char *commit,
|
|
GVariant *commit_data)
|
|
{
|
|
if (ref)
|
|
add_annotation (annotations,"org.opencontainers.ref.name", ref);
|
|
|
|
if (commit)
|
|
add_annotation (annotations,"org.flatpak.commit", commit);
|
|
|
|
if (commit_data)
|
|
{
|
|
g_autofree char *parent = NULL;
|
|
g_autofree char *subject = NULL;
|
|
g_autofree char *body = NULL;
|
|
g_autofree char *timestamp = NULL;
|
|
g_autoptr(GVariant) metadata = NULL;
|
|
int i;
|
|
|
|
parent = ostree_commit_get_parent (commit_data);
|
|
if (parent)
|
|
add_annotation (annotations, "org.flatpak.parent-commit", parent);
|
|
|
|
metadata = g_variant_get_child_value (commit_data, 0);
|
|
for (i = 0; i < g_variant_n_children (metadata); i++)
|
|
{
|
|
g_autoptr(GVariant) elm = g_variant_get_child_value (metadata, i);
|
|
g_autoptr(GVariant) value = g_variant_get_child_value (elm, 1);
|
|
g_autofree char *key = NULL;
|
|
g_autofree char *full_key = NULL;
|
|
g_autofree char *value_base64 = NULL;
|
|
|
|
g_variant_get_child (elm, 0, "s", &key);
|
|
full_key = g_strdup_printf ("org.flatpak.commit-metadata.%s", key);
|
|
|
|
value_base64 = g_base64_encode (g_variant_get_data (value), g_variant_get_size (value));
|
|
add_annotation (annotations, full_key, value_base64);
|
|
}
|
|
|
|
timestamp = g_strdup_printf ("%"G_GUINT64_FORMAT, ostree_commit_get_timestamp (commit_data));
|
|
add_annotation (annotations, "org.flatpak.timestamp", timestamp);
|
|
|
|
g_variant_get_child (commit_data, 3, "s", &subject);
|
|
add_annotation (annotations, "org.flatpak.subject", subject);
|
|
|
|
g_variant_get_child (commit_data, 4, "s", &body);
|
|
add_annotation (annotations, "org.flatpak.body", body);
|
|
}
|
|
}
|
|
|
|
void
|
|
flatpak_oci_parse_commit_annotations (GHashTable *annotations,
|
|
guint64 *out_timestamp,
|
|
char **out_subject,
|
|
char **out_body,
|
|
char **out_ref,
|
|
char **out_commit,
|
|
char **out_parent_commit,
|
|
GVariantBuilder *metadata_builder)
|
|
{
|
|
const char *oci_timestamp, *oci_subject, *oci_body, *oci_parent_commit, *oci_commit, *oci_ref;
|
|
GHashTableIter iter;
|
|
gpointer _key, _value;
|
|
|
|
oci_ref = g_hash_table_lookup (annotations, "org.opencontainers.ref.name");
|
|
if (oci_ref != NULL && out_ref != NULL && *out_ref == NULL)
|
|
*out_ref = g_strdup (oci_ref);
|
|
|
|
oci_commit = g_hash_table_lookup (annotations, "org.flatpak.commit");
|
|
if (oci_commit != NULL && out_commit != NULL && *out_commit == NULL)
|
|
*out_commit = g_strdup (oci_commit);
|
|
|
|
oci_parent_commit = g_hash_table_lookup (annotations, "org.flatpak.parent-commit");
|
|
if (oci_parent_commit != NULL && out_parent_commit != NULL && *out_parent_commit == NULL)
|
|
*out_parent_commit = g_strdup (oci_parent_commit);
|
|
|
|
oci_timestamp = g_hash_table_lookup (annotations, "org.flatpak.timestamp");
|
|
if (oci_timestamp != NULL && out_timestamp != NULL && *out_timestamp == 0)
|
|
*out_timestamp = g_ascii_strtoull (oci_timestamp, NULL, 10);
|
|
|
|
oci_subject = g_hash_table_lookup (annotations, "org.flatpak.subject");
|
|
if (oci_subject != NULL && out_subject != NULL && *out_subject == NULL)
|
|
*out_subject = g_strdup (oci_subject);
|
|
|
|
oci_body = g_hash_table_lookup (annotations, "org.flatpak.body");
|
|
if (oci_body != NULL && out_body != NULL && *out_body == NULL)
|
|
*out_body = g_strdup (oci_body);
|
|
|
|
if (metadata_builder)
|
|
{
|
|
g_hash_table_iter_init (&iter, annotations);
|
|
while (g_hash_table_iter_next (&iter, &_key, &_value))
|
|
{
|
|
const char *key = _key;
|
|
const char *value = _value;
|
|
guchar *bin;
|
|
gsize bin_len;
|
|
g_autoptr(GVariant) data = NULL;
|
|
|
|
if (!g_str_has_prefix (key, "org.flatpak.commit-metadata."))
|
|
continue;
|
|
key += strlen ("org.flatpak.commit-metadata.");
|
|
|
|
bin = g_base64_decode (value, &bin_len);
|
|
data = g_variant_ref_sink (g_variant_new_from_data (G_VARIANT_TYPE("v"), bin, bin_len, FALSE,
|
|
g_free, bin));
|
|
g_variant_builder_add (metadata_builder, "{s@v}", key, data);
|
|
}
|
|
}
|
|
}
|