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