diff --git a/builder/Makefile.am.inc b/builder/Makefile.am.inc
index 0e932354..a9592f05 100644
--- a/builder/Makefile.am.inc
+++ b/builder/Makefile.am.inc
@@ -8,6 +8,8 @@ flatpak_builder_SOURCES = \
builder/builder-manifest.h \
builder/builder-options.c \
builder/builder-options.h \
+ builder/builder-extension.c \
+ builder/builder-extension.h \
builder/builder-module.c \
builder/builder-module.h \
builder/builder-post-process.c \
diff --git a/builder/builder-extension.c b/builder/builder-extension.c
new file mode 100644
index 00000000..208f3f5f
--- /dev/null
+++ b/builder/builder-extension.c
@@ -0,0 +1,425 @@
+/* builder-extension.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 .
+ *
+ * Authors:
+ * Alexander Larsson
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include "libglnx/libglnx.h"
+
+#include "flatpak-utils.h"
+#include "flatpak-run.h"
+#include "builder-utils.h"
+#include "builder-extension.h"
+
+struct BuilderExtension
+{
+ GObject parent;
+
+ char *name;
+ char *directory;
+ gboolean bundle;
+ gboolean autodelete;
+ gboolean no_autodownload;
+ gboolean subdirectories;
+ char *add_ld_path;
+ char *download_if;
+ char *enable_if;
+ char *merge_dirs;
+ char *subdirectory_suffix;
+ char *version;
+ char *versions;
+};
+
+typedef struct
+{
+ GObjectClass parent_class;
+} BuilderExtensionClass;
+
+G_DEFINE_TYPE (BuilderExtension, builder_extension, G_TYPE_OBJECT);
+
+enum {
+ PROP_0,
+ PROP_DIRECTORY,
+ PROP_BUNDLE,
+ PROP_AUTODELETE,
+ PROP_ADD_LD_PATH,
+ PROP_DOWNLOAD_IF,
+ PROP_ENABLE_IF,
+ PROP_MERGE_DIRS,
+ PROP_NO_AUTODOWNLOAD,
+ PROP_SUBDIRECTORIES,
+ PROP_SUBDIRECTORY_SUFFIX,
+ PROP_VERSION,
+ PROP_VERSIONS,
+ LAST_PROP
+};
+
+static void
+builder_extension_finalize (GObject *object)
+{
+ BuilderExtension *self = (BuilderExtension *) object;
+
+ g_free (self->name);
+ g_free (self->directory);
+ g_free (self->add_ld_path);
+ g_free (self->download_if);
+ g_free (self->enable_if);
+ g_free (self->merge_dirs);
+ g_free (self->subdirectory_suffix);
+ g_free (self->version);
+ g_free (self->versions);
+
+ G_OBJECT_CLASS (builder_extension_parent_class)->finalize (object);
+}
+
+static void
+builder_extension_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ BuilderExtension *self = BUILDER_EXTENSION (object);
+
+ switch (prop_id)
+ {
+ case PROP_DIRECTORY:
+ g_value_set_string (value, self->directory);
+ break;
+
+ case PROP_BUNDLE:
+ g_value_set_boolean (value, self->bundle);
+ break;
+
+ case PROP_AUTODELETE:
+ g_value_set_boolean (value, self->autodelete);
+ break;
+
+ case PROP_NO_AUTODOWNLOAD:
+ g_value_set_boolean (value, self->autodelete);
+ break;
+
+ case PROP_SUBDIRECTORIES:
+ g_value_set_boolean (value, self->autodelete);
+ break;
+
+ case PROP_ADD_LD_PATH:
+ g_value_set_string (value, self->add_ld_path);
+ break;
+
+ case PROP_DOWNLOAD_IF:
+ g_value_set_string (value, self->download_if);
+ break;
+
+ case PROP_ENABLE_IF:
+ g_value_set_string (value, self->enable_if);
+ break;
+
+ case PROP_MERGE_DIRS:
+ g_value_set_string (value, self->merge_dirs);
+ break;
+
+ case PROP_SUBDIRECTORY_SUFFIX:
+ g_value_set_string (value, self->subdirectory_suffix);
+ break;
+
+ case PROP_VERSION:
+ g_value_set_string (value, self->version);
+ break;
+
+ case PROP_VERSIONS:
+ g_value_set_string (value, self->versions);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+builder_extension_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ BuilderExtension *self = BUILDER_EXTENSION (object);
+
+ switch (prop_id)
+ {
+ case PROP_DIRECTORY:
+ g_clear_pointer (&self->directory, g_free);
+ self->directory = g_value_dup_string (value);
+ break;
+
+ case PROP_BUNDLE:
+ self->bundle = g_value_get_boolean (value);
+ break;
+
+ case PROP_AUTODELETE:
+ self->autodelete = g_value_get_boolean (value);
+ break;
+
+ case PROP_NO_AUTODOWNLOAD:
+ self->no_autodownload = g_value_get_boolean (value);
+ break;
+
+ case PROP_SUBDIRECTORIES:
+ self->subdirectories = g_value_get_boolean (value);
+ break;
+
+ case PROP_ADD_LD_PATH:
+ g_clear_pointer (&self->add_ld_path, g_free);
+ self->add_ld_path = g_value_dup_string (value);
+ break;
+
+ case PROP_DOWNLOAD_IF:
+ g_clear_pointer (&self->download_if, g_free);
+ self->download_if = g_value_dup_string (value);
+ break;
+
+ case PROP_ENABLE_IF:
+ g_clear_pointer (&self->enable_if, g_free);
+ self->enable_if = g_value_dup_string (value);
+ break;
+
+ case PROP_MERGE_DIRS:
+ g_clear_pointer (&self->merge_dirs, g_free);
+ self->merge_dirs = g_value_dup_string (value);
+ break;
+
+ case PROP_SUBDIRECTORY_SUFFIX:
+ g_clear_pointer (&self->subdirectory_suffix, g_free);
+ self->subdirectory_suffix = g_value_dup_string (value);
+ break;
+
+ case PROP_VERSION:
+ g_clear_pointer (&self->version, g_free);
+ self->version = g_value_dup_string (value);
+ break;
+
+ case PROP_VERSIONS:
+ g_clear_pointer (&self->versions, g_free);
+ self->versions = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+builder_extension_class_init (BuilderExtensionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = builder_extension_finalize;
+ object_class->get_property = builder_extension_get_property;
+ object_class->set_property = builder_extension_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_DIRECTORY,
+ g_param_spec_string ("directory",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_BUNDLE,
+ g_param_spec_boolean ("bundle",
+ "",
+ "",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_AUTODELETE,
+ g_param_spec_boolean ("autodelete",
+ "",
+ "",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_NO_AUTODOWNLOAD,
+ g_param_spec_boolean ("no-autodownload",
+ "",
+ "",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SUBDIRECTORIES,
+ g_param_spec_boolean ("subdirectories",
+ "",
+ "",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ADD_LD_PATH,
+ g_param_spec_string ("add-ld-path",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_DOWNLOAD_IF,
+ g_param_spec_string ("download-if",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ENABLE_IF,
+ g_param_spec_string ("enable-if",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_MERGE_DIRS,
+ g_param_spec_string ("merge-dirs",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SUBDIRECTORY_SUFFIX,
+ g_param_spec_string ("subdirectory-suffix",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_VERSION,
+ g_param_spec_string ("version",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_VERSIONS,
+ g_param_spec_string ("versions",
+ "",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+}
+
+static void
+builder_extension_init (BuilderExtension *self)
+{
+}
+
+void
+builder_extension_set_name (BuilderExtension *self,
+ const char *name)
+{
+ g_free (self->name);
+ self->name = g_strdup (name);
+}
+
+const char *
+builder_extension_get_name (BuilderExtension *self)
+{
+ return self->name;
+}
+
+
+gboolean
+builder_extension_is_bundled (BuilderExtension *self)
+{
+ return self->bundle;
+}
+
+const char *
+builder_extension_get_directory (BuilderExtension *self)
+{
+ return self->directory;
+}
+
+static void
+add_arg (BuilderExtension *self,
+ GPtrArray *args,
+ const char *key,
+ const char *value)
+{
+ if (value == NULL)
+ return;
+ g_ptr_array_add (args,
+ g_strdup_printf ("--extension=%s=%s=%s", self->name, key, value));
+}
+
+static void
+add_argb (BuilderExtension *self,
+ GPtrArray *args,
+ const char *key,
+ gboolean val)
+{
+ if (val)
+ add_arg (self, args, key, "true");
+}
+
+void
+builder_extension_add_finish_args (BuilderExtension *self,
+ GPtrArray *args)
+{
+ if (self->directory == NULL)
+ {
+ g_warning ("No directory specified for extension '%s'", self->name);
+ return;
+ }
+
+ add_arg (self, args, FLATPAK_METADATA_KEY_DIRECTORY, self->directory);
+ add_argb (self, args, FLATPAK_METADATA_KEY_AUTODELETE, self->autodelete);
+ add_argb (self, args, FLATPAK_METADATA_KEY_NO_AUTODOWNLOAD, self->no_autodownload);
+ add_argb (self, args, FLATPAK_METADATA_KEY_SUBDIRECTORIES, self->subdirectories);
+ add_arg (self, args, FLATPAK_METADATA_KEY_ADD_LD_PATH, self->add_ld_path);
+ add_arg (self, args, FLATPAK_METADATA_KEY_DOWNLOAD_IF, self->download_if);
+ add_arg (self, args, FLATPAK_METADATA_KEY_ENABLE_IF, self->enable_if);
+ add_arg (self, args, FLATPAK_METADATA_KEY_MERGE_DIRS, self->merge_dirs);
+ add_arg (self, args, FLATPAK_METADATA_KEY_SUBDIRECTORY_SUFFIX, self->subdirectory_suffix);
+ add_arg (self, args, FLATPAK_METADATA_KEY_VERSION, self->version);
+ add_arg (self, args, FLATPAK_METADATA_KEY_VERSIONS, self->versions);
+}
+
+void
+builder_extension_checksum (BuilderExtension *self,
+ BuilderCache *cache,
+ BuilderContext *context)
+{
+ builder_cache_checksum_str (cache, BUILDER_EXTENSION_CHECKSUM_VERSION);
+ builder_cache_checksum_str (cache, self->name);
+ builder_cache_checksum_str (cache, self->directory);
+ builder_cache_checksum_boolean (cache, self->bundle);
+ builder_cache_checksum_boolean (cache, self->autodelete);
+ builder_cache_checksum_boolean (cache, self->no_autodownload);
+ builder_cache_checksum_boolean (cache, self->subdirectories);
+ builder_cache_checksum_str (cache, self->add_ld_path);
+ builder_cache_checksum_str (cache, self->download_if);
+ builder_cache_checksum_str (cache, self->enable_if);
+ builder_cache_checksum_str (cache, self->merge_dirs);
+ builder_cache_checksum_str (cache, self->subdirectory_suffix);
+ builder_cache_checksum_str (cache, self->version);
+ builder_cache_checksum_str (cache, self->versions);
+}
diff --git a/builder/builder-extension.h b/builder/builder-extension.h
new file mode 100644
index 00000000..9c318ed3
--- /dev/null
+++ b/builder/builder-extension.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2017 Red Hat, Inc
+ *
+ * This program 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library. If not, see .
+ *
+ * Authors:
+ * Alexander Larsson
+ */
+
+#ifndef __BUILDER_EXTENSION_H__
+#define __BUILDER_EXTENSION_H__
+
+#include
+
+#include "builder-context.h"
+#include "builder-cache.h"
+
+G_BEGIN_DECLS
+
+typedef struct BuilderExtension BuilderExtension;
+
+#define BUILDER_TYPE_EXTENSION (builder_extension_get_type ())
+#define BUILDER_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUILDER_TYPE_EXTENSION, BuilderExtension))
+#define BUILDER_IS_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUILDER_TYPE_EXTENSION))
+
+/* Bump this if format changes in incompatible ways to force rebuild */
+#define BUILDER_EXTENSION_CHECKSUM_VERSION "1"
+
+GType builder_extension_get_type (void);
+
+void builder_extension_set_name (BuilderExtension *self,
+ const char *name);
+const char * builder_extension_get_name (BuilderExtension *self);
+
+gboolean builder_extension_is_bundled (BuilderExtension *self);
+const char * builder_extension_get_directory (BuilderExtension *self);
+
+void builder_extension_add_finish_args (BuilderExtension *self,
+ GPtrArray *args);
+void builder_extension_checksum (BuilderExtension *self,
+ BuilderCache *cache,
+ BuilderContext *context);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderExtension, g_object_unref)
+
+G_END_DECLS
+
+#endif /* __BUILDER_EXTENSION_H__ */
diff --git a/builder/builder-main.c b/builder/builder-main.c
index 3e650511..2377c737 100644
--- a/builder/builder-main.c
+++ b/builder/builder-main.c
@@ -170,6 +170,7 @@ do_export (BuilderContext *build_context,
gboolean runtime,
const gchar *location,
const gchar *directory,
+ char **exclude_dirs,
const gchar *branch,
const gchar *collection_id,
...)
@@ -212,6 +213,12 @@ do_export (BuilderContext *build_context,
g_ptr_array_add (args, g_strdup ((gchar *) arg));
va_end (ap);
+ if (exclude_dirs)
+ {
+ for (i = 0; exclude_dirs[i] != NULL; i++)
+ g_ptr_array_add (args, g_strdup_printf ("--exclude=/%s/*", exclude_dirs[i]));
+ }
+
/* Mandatory positional arguments. */
g_ptr_array_add (args, g_strdup (location));
g_ptr_array_add (args, g_strdup (directory));
@@ -740,12 +747,14 @@ main (int argc,
{
g_autoptr(GFile) debuginfo_metadata = NULL;
g_autoptr(GFile) sourcesinfo_metadata = NULL;
+ g_auto(GStrv) exclude_dirs = builder_manifest_get_exclude_dirs (manifest);
+ GList *l;
g_print ("Exporting %s to repo\n", builder_manifest_get_id (manifest));
if (!do_export (build_context, &error,
FALSE,
- opt_repo, app_dir_path, builder_manifest_get_branch (manifest),
+ opt_repo, app_dir_path, exclude_dirs, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
"--exclude=/lib/debug/*",
"--include=/lib/debug/app",
@@ -778,7 +787,7 @@ main (int argc,
files_arg = g_strconcat (builder_context_get_build_runtime (build_context) ? "--files=usr" : "--files=files",
"/share/runtime/locale/", NULL);
if (!do_export (build_context, &error, TRUE,
- opt_repo, app_dir_path, builder_manifest_get_branch (manifest),
+ opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
metadata_arg,
files_arg,
@@ -797,7 +806,7 @@ main (int argc,
g_print ("Exporting %s to repo\n", debug_id);
if (!do_export (build_context, &error, TRUE,
- opt_repo, app_dir_path, builder_manifest_get_branch (manifest),
+ opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
"--metadata=metadata.debuginfo",
builder_context_get_build_runtime (build_context) ? "--files=usr/lib/debug" : "--files=files/lib/debug",
@@ -808,6 +817,35 @@ main (int argc,
}
}
+ for (l = builder_manifest_get_add_extensions (manifest); l != NULL; l = l->next)
+ {
+ BuilderExtension *e = l->data;
+ const char *extension_id = NULL;
+ g_autofree char *metadata_arg = NULL;
+ g_autofree char *files_arg = NULL;
+
+ if (!builder_extension_is_bundled (e))
+ continue;
+
+ extension_id = builder_extension_get_name (e);
+ g_print ("Exporting %s to repo\n", extension_id);
+
+ metadata_arg = g_strdup_printf ("--metadata=metadata.%s", extension_id);
+ files_arg = g_strdup_printf ("--files=%s/%s",
+ builder_context_get_build_runtime (build_context) ? "usr" : "files",
+ builder_extension_get_directory (e));
+
+ if (!do_export (build_context, &error, TRUE,
+ opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
+ builder_manifest_get_collection_id (manifest),
+ metadata_arg, files_arg,
+ NULL))
+ {
+ g_printerr ("Export failed: %s\n", error->message);
+ return 1;
+ }
+ }
+
/* Export sources extensions */
sourcesinfo_metadata = g_file_get_child (app_dir, "metadata.sources");
if (g_file_query_exists (sourcesinfo_metadata, NULL))
@@ -816,7 +854,7 @@ main (int argc,
g_print ("Exporting %s to repo\n", sources_id);
if (!do_export (build_context, &error, TRUE,
- opt_repo, app_dir_path, builder_manifest_get_branch (manifest),
+ opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
"--metadata=metadata.sources",
"--files=sources",
@@ -835,7 +873,7 @@ main (int argc,
g_print ("Exporting %s to repo\n", platform_id);
if (!do_export (build_context, &error, TRUE,
- opt_repo, app_dir_path, builder_manifest_get_branch (manifest),
+ opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
"--metadata=metadata.platform",
"--files=platform",
@@ -868,7 +906,7 @@ main (int argc,
metadata_arg = g_strdup_printf ("--metadata=%s", name);
files_arg = g_strconcat ("--files=platform/share/runtime/locale/", NULL);
if (!do_export (build_context, &error, TRUE,
- opt_repo, app_dir_path, builder_manifest_get_branch (manifest),
+ opt_repo, app_dir_path, NULL, builder_manifest_get_branch (manifest),
builder_manifest_get_collection_id (manifest),
metadata_arg,
files_arg,
diff --git a/builder/builder-manifest.c b/builder/builder-manifest.c
index a7354699..aa7c7d09 100644
--- a/builder/builder-manifest.c
+++ b/builder/builder-manifest.c
@@ -31,6 +31,7 @@
#include "builder-utils.h"
#include "flatpak-utils.h"
#include "builder-post-process.h"
+#include "builder-extension.h"
#include "libglnx/libglnx.h"
@@ -95,6 +96,7 @@ struct BuilderManifest
BuilderOptions *build_options;
GList *modules;
GList *expanded_modules;
+ GList *add_extensions;
};
typedef struct
@@ -149,6 +151,7 @@ enum {
PROP_DESKTOP_FILE_NAME_PREFIX,
PROP_DESKTOP_FILE_NAME_SUFFIX,
PROP_COLLECTION_ID,
+ PROP_ADD_EXTENSIONS,
LAST_PROP
};
@@ -174,6 +177,7 @@ builder_manifest_finalize (GObject *object)
g_free (self->command);
g_clear_object (&self->build_options);
g_list_free_full (self->modules, g_object_unref);
+ g_list_free_full (self->add_extensions, g_object_unref);
g_list_free (self->expanded_modules);
g_strfreev (self->cleanup);
g_strfreev (self->cleanup_commands);
@@ -322,6 +326,10 @@ builder_manifest_get_property (GObject *object,
g_value_set_pointer (value, self->modules);
break;
+ case PROP_ADD_EXTENSIONS:
+ g_value_set_pointer (value, self->add_extensions);
+ break;
+
case PROP_CLEANUP:
g_value_set_boxed (value, self->cleanup);
break;
@@ -518,6 +526,12 @@ builder_manifest_set_property (GObject *object,
self->modules = g_value_get_pointer (value);
break;
+ case PROP_ADD_EXTENSIONS:
+ g_list_free_full (self->add_extensions, g_object_unref);
+ /* NOTE: This takes ownership of the list! */
+ self->add_extensions = g_value_get_pointer (value);
+ break;
+
case PROP_CLEANUP:
tmp = self->cleanup;
self->cleanup = g_strdupv (g_value_get_boxed (value));
@@ -772,6 +786,12 @@ builder_manifest_class_init (BuilderManifestClass *klass)
"",
"",
G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ADD_EXTENSIONS,
+ g_param_spec_pointer ("add-extensions",
+ "",
+ "",
+ G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_CLEANUP,
g_param_spec_boxed ("cleanup",
@@ -956,6 +976,31 @@ builder_manifest_serialize_property (JsonSerializable *serializable,
json_array_unref (array);
}
+ return retval;
+ }
+ else if (strcmp (property_name, "add-extensions") == 0)
+ {
+ BuilderManifest *self = BUILDER_MANIFEST (serializable);
+ JsonNode *retval = NULL;
+
+ if (self->add_extensions)
+ {
+ JsonObject *object;
+ GList *l;
+
+ object = json_object_new ();
+
+ for (l = self->add_extensions; l != NULL; l = l->next)
+ {
+ BuilderExtension *e = l->data;
+ JsonNode *child = json_gobject_serialize (G_OBJECT (e));
+ json_object_set_member (object, (char *) builder_extension_get_name (e), child);
+ }
+
+ retval = json_node_init_object (json_node_alloc (), object);
+ json_object_unref (object);
+ }
+
return retval;
}
else
@@ -967,6 +1012,14 @@ builder_manifest_serialize_property (JsonSerializable *serializable,
}
}
+static gint
+sort_extension (gconstpointer a,
+ gconstpointer b)
+{
+ return strcmp (builder_extension_get_name (BUILDER_EXTENSION (a)),
+ builder_extension_get_name (BUILDER_EXTENSION (b)));
+}
+
static gboolean
builder_manifest_deserialize_property (JsonSerializable *serializable,
const gchar *property_name,
@@ -1044,6 +1097,48 @@ builder_manifest_deserialize_property (JsonSerializable *serializable,
return TRUE;
}
+ return FALSE;
+ }
+ else if (strcmp (property_name, "add-extensions") == 0)
+ {
+ if (JSON_NODE_TYPE (property_node) == JSON_NODE_NULL)
+ {
+ g_value_set_pointer (value, NULL);
+ return TRUE;
+ }
+ else if (JSON_NODE_TYPE (property_node) == JSON_NODE_OBJECT)
+ {
+ JsonObject *object = json_node_get_object (property_node);
+ g_autoptr(GHashTable) hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+ g_autoptr(GList) members = NULL;
+ GList *extensions;
+ GList *l;
+
+ members = json_object_get_members (object);
+ for (l = members; l != NULL; l = l->next)
+ {
+ const char *member_name = l->data;
+ JsonNode *val;
+ GObject *extension;
+
+ val = json_object_get_member (object, member_name);
+ extension = json_gobject_deserialize (BUILDER_TYPE_EXTENSION, val);
+ if (extension == NULL)
+ return FALSE;
+
+ builder_extension_set_name (BUILDER_EXTENSION (extension), member_name);
+ g_hash_table_insert (hash, (char *)builder_extension_get_name (BUILDER_EXTENSION (extension)), extension);
+ }
+
+ extensions = g_hash_table_get_values (hash);
+ g_hash_table_steal_all (hash);
+
+ extensions = g_list_sort (extensions, sort_extension);
+ g_value_set_pointer (value, extensions);
+
+ return TRUE;
+ }
+
return FALSE;
}
else
@@ -1122,6 +1217,12 @@ builder_manifest_get_modules (BuilderManifest *self)
return self->modules;
}
+GList *
+builder_manifest_get_add_extensions (BuilderManifest *self)
+{
+ return self->add_extensions;
+}
+
static const char *
builder_manifest_get_runtime_version (BuilderManifest *self)
{
@@ -1459,11 +1560,19 @@ builder_manifest_checksum_for_finish (BuilderManifest *self,
BuilderCache *cache,
BuilderContext *context)
{
+ GList *l;
+
builder_cache_checksum_str (cache, BUILDER_MANIFEST_CHECKSUM_FINISH_VERSION);
builder_cache_checksum_strv (cache, self->finish_args);
builder_cache_checksum_str (cache, self->command);
builder_cache_checksum_compat_strv (cache, self->inherit_extensions);
+ for (l = self->add_extensions; l != NULL; l = l->next)
+ {
+ BuilderExtension *e = l->data;
+ builder_extension_checksum (e, cache, context);
+ }
+
if (self->metadata)
{
GFile *base_dir = builder_context_get_base_dir (context);
@@ -2209,6 +2318,7 @@ builder_manifest_finish (BuilderManifest *self,
g_autoptr(GPtrArray) args = NULL;
g_autoptr(GSubprocess) subp = NULL;
int i;
+ GList *l;
JsonNode *node;
JsonGenerator *generator;
@@ -2375,6 +2485,9 @@ builder_manifest_finish (BuilderManifest *self,
g_ptr_array_add (args, g_strdup (self->finish_args[i]));
}
+ for (l = self->add_extensions; l != NULL; l = l->next)
+ builder_extension_add_finish_args (l->data, args);
+
g_ptr_array_add (args, g_file_get_path (app_dir));
g_ptr_array_add (args, NULL);
@@ -2519,6 +2632,30 @@ builder_manifest_finish (BuilderManifest *self,
return FALSE;
}
+
+ for (l = self->add_extensions; l != NULL; l = l->next)
+ {
+ BuilderExtension *e = l->data;
+ g_autofree char *extension_metadata_name = NULL;
+ g_autoptr(GFile) metadata_extension_file = NULL;
+ g_autofree char *metadata_contents = NULL;
+
+ if (!builder_extension_is_bundled (e))
+ continue;
+
+ extension_metadata_name = g_strdup_printf ("metadata.%s", builder_extension_get_name (e));
+ metadata_extension_file = g_file_get_child (app_dir, extension_metadata_name);
+ metadata_contents = g_strdup_printf ("[Runtime]\n"
+ "name=%s\n"
+ "\n"
+ "[ExtensionOf]\n"
+ "ref=%s\n",
+ builder_extension_get_name (e), ref);
+ if (!g_file_set_contents (flatpak_file_get_path_cached (metadata_extension_file),
+ metadata_contents, strlen (metadata_contents), error))
+ return FALSE;
+ }
+
if (!builder_context_disable_rofiles (context, error))
return FALSE;
@@ -3173,3 +3310,23 @@ builder_manifest_run (BuilderManifest *self,
/* Not reached */
return TRUE;
}
+
+char **
+builder_manifest_get_exclude_dirs (BuilderManifest *self)
+{
+ g_autoptr(GPtrArray) dirs = NULL;
+ GList *l;
+
+ dirs = g_ptr_array_new ();
+
+ for (l = self->add_extensions; l != NULL; l = l->next)
+ {
+ BuilderExtension *e = l->data;
+
+ if (builder_extension_is_bundled (e))
+ g_ptr_array_add (dirs, g_strdup (builder_extension_get_directory (e)));
+ }
+ g_ptr_array_add (dirs, NULL);
+
+ return (char **)g_ptr_array_free (g_steal_pointer (&dirs), FALSE);
+}
diff --git a/builder/builder-manifest.h b/builder/builder-manifest.h
index e95075cd..04acad85 100644
--- a/builder/builder-manifest.h
+++ b/builder/builder-manifest.h
@@ -27,6 +27,7 @@
#include "builder-options.h"
#include "builder-module.h"
#include "builder-cache.h"
+#include "builder-extension.h"
G_BEGIN_DECLS
@@ -56,6 +57,7 @@ const char * builder_manifest_get_id_platform (BuilderManifest *self);
char * builder_manifest_get_locale_id_platform (BuilderManifest *self);
BuilderOptions *builder_manifest_get_build_options (BuilderManifest *self);
GList * builder_manifest_get_modules (BuilderManifest *self);
+GList * builder_manifest_get_add_extensions (BuilderManifest *self);
const char * builder_manifest_get_branch (BuilderManifest *self);
void builder_manifest_set_default_branch (BuilderManifest *self,
const char *default_branch);
@@ -63,6 +65,9 @@ const char * builder_manifest_get_collection_id (BuilderManifest *self);
void builder_manifest_set_default_collection_id (BuilderManifest *self,
const char *default_collection_id);
+
+char ** builder_manifest_get_exclude_dirs (BuilderManifest *self);
+
gboolean builder_manifest_start (BuilderManifest *self,
gboolean allow_missing_runtimes,
BuilderContext *context,
diff --git a/doc/flatpak-manifest.xml b/doc/flatpak-manifest.xml
index 2006cae1..8c189fb4 100644
--- a/doc/flatpak-manifest.xml
+++ b/doc/flatpak-manifest.xml
@@ -169,6 +169,10 @@
String members in the array are interpreted as the name of a separate json file that contains a module.
See below for details.
+
+ (objects)
+ This is a dictionary of extension objects. The key is the name of the extension. See below for details.
+
(array of strings)
An array of file patterns that should be removed at the end.
@@ -276,6 +280,36 @@
+
+ Extension
+
+ Extension define extension points in the app/runtime that can be implemented by extensions, supplying extra files
+ which are available during runtime..
+
+
+ These are the properties that are accepted:
+
+
+
+ (string)
+ The directory where the extension is mounted.
+
+
+ (boolean)
+ If this is true, then the data
+ created in the extension directory is omitted from
+ the result, and instead packaged in a separate
+ extension..
+
+
+
+ Additionally the standard flatpak extension properies
+ are supported, and put directly into the metadata file:
+ autodelete, no-autodownload, subdirectories,
+ add-ld-path, download-if, enable-if, merge-dirs,
+ subdirectory-suffix, version, versions.
+
+
Module