[gnome-builder] flatpak: Discover flatpak manifests and add them as runtimes
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] flatpak: Discover flatpak manifests and add them as runtimes
- Date: Tue, 15 Nov 2016 07:26:32 +0000 (UTC)
commit 457fc3d8f08a4a8e1a60c2f6bf9842fc38ca6694
Author: Matthew Leeds <mleeds redhat com>
Date: Mon Nov 14 23:26:00 2016 -0800
flatpak: Discover flatpak manifests and add them as runtimes
When a repo includes a flatpak manifest, GNOME Builder should know
how to use it with flatpak-builder to build the project's dependencies
so the build will be more likely to work. This commit teaches
GbpFlatpakRuntimeProvider how to identify manifests (by file name and
doing a sanity check on the contents) and add them to the list of
runtimes.
https://bugzilla.gnome.org/show_bug.cgi?id=773764
plugins/flatpak/configure.ac | 3 +-
plugins/flatpak/gbp-flatpak-runtime-provider.c | 243 ++++++++++++++++++++++++
plugins/flatpak/gbp-flatpak-runtime.c | 66 +++++++-
3 files changed, 310 insertions(+), 2 deletions(-)
---
diff --git a/plugins/flatpak/configure.ac b/plugins/flatpak/configure.ac
index 8b2ccf6..d820b50 100644
--- a/plugins/flatpak/configure.ac
+++ b/plugins/flatpak/configure.ac
@@ -9,7 +9,8 @@ AC_ARG_ENABLE([flatpak-plugin],
AS_IF([test "$enable_flatpak_plugin" != no],[
PKG_CHECK_MODULES(FLATPAK,
- [flatpak >= flatpak_required_version],
+ [flatpak >= flatpak_required_version
+ json-glib-1.0 >= json_glib_required_version],
[have_flatpak=yes],
[have_flatpak=no])
diff --git a/plugins/flatpak/gbp-flatpak-runtime-provider.c b/plugins/flatpak/gbp-flatpak-runtime-provider.c
index 82652f1..1cb9193 100644
--- a/plugins/flatpak/gbp-flatpak-runtime-provider.c
+++ b/plugins/flatpak/gbp-flatpak-runtime-provider.c
@@ -20,6 +20,7 @@
#include <string.h>
#include <flatpak.h>
+#include <json-glib/json-glib.h>
#include "util/ide-posix.h"
@@ -36,6 +37,16 @@ struct _GbpFlatpakRuntimeProvider
GPtrArray *runtimes;
};
+typedef struct
+{
+ gchar *platform;
+ gchar *branch;
+ gchar *sdk;
+ gchar *app_id;
+ gchar *primary_module;
+ GFile *file;
+} FlatpakManifest;
+
static void runtime_provider_iface_init (IdeRuntimeProviderInterface *);
G_DEFINE_TYPE_EXTENDED (GbpFlatpakRuntimeProvider, gbp_flatpak_runtime_provider, G_TYPE_OBJECT, 0,
@@ -71,6 +82,20 @@ contains_id (GPtrArray *ar,
return FALSE;
}
+static void
+flatpak_manifest_free (void *data)
+{
+ FlatpakManifest *manifest = data;
+
+ g_free (manifest->branch);
+ g_free (manifest->sdk);
+ g_free (manifest->platform);
+ g_free (manifest->app_id);
+ g_free (manifest->primary_module);
+ g_clear_object (&manifest->file);
+ g_slice_free (FlatpakManifest, manifest);
+}
+
static gboolean
gbp_flatpak_runtime_provider_load_refs (GbpFlatpakRuntimeProvider *self,
FlatpakInstallation *installation,
@@ -180,6 +205,215 @@ gbp_flatpak_runtime_provider_load_refs (GbpFlatpakRuntimeProvider *self,
return TRUE;
}
+static gchar *
+guess_primary_module (JsonObject *manifest_object,
+ GFile *directory)
+{
+ JsonArray *modules = NULL;
+ gchar *dir_name;
+ guint num_modules;
+
+ g_assert (manifest_object != NULL);
+ g_assert (G_IS_FILE (directory));
+
+ dir_name = g_file_get_basename (directory);
+ g_assert (!ide_str_empty0 (dir_name));
+ modules = json_object_get_array_member (manifest_object, "modules");
+ g_assert (modules != NULL);
+
+ num_modules = json_array_get_length (modules);
+ for (guint i = 0; i < num_modules; i++)
+ {
+ JsonNode *module;
+ module = json_array_get_element (modules, i);
+ if (JSON_NODE_HOLDS_OBJECT (module))
+ {
+ const gchar *module_name;
+ module_name = json_object_get_string_member (json_node_get_object (module), "name");
+ if (num_modules == 1 || g_strcmp0 (module_name, dir_name) == 0)
+ return g_strdup (module_name);
+ }
+ }
+
+ g_warning ("Unable to determine the primary module in the flatpak manifest");
+ return NULL;
+}
+
+static GPtrArray *
+gbp_flatpak_runtime_provider_find_flatpak_manifests (GbpFlatpakRuntimeProvider *self,
+ GCancellable *cancellable,
+ GFile *directory,
+ GError **error)
+{
+ g_autoptr(GFileEnumerator) enumerator = NULL;
+ GFileInfo *file_info = NULL;
+ GPtrArray *ar;
+
+ g_assert (GBP_IS_FLATPAK_RUNTIME_PROVIDER (self));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_assert (G_IS_FILE (directory));
+
+ ar = g_ptr_array_new ();
+ g_ptr_array_set_free_func (ar, flatpak_manifest_free);
+
+ enumerator = g_file_enumerate_children (directory,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable,
+ error);
+ if (!enumerator)
+ return NULL;
+
+ while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, NULL)))
+ {
+ GFileType file_type;
+ g_autofree gchar *name = NULL;
+ g_autofree gchar *path = NULL;
+ g_autoptr(GRegex) filename_regex = NULL;
+ g_autoptr(GMatchInfo) match_info = NULL;
+ g_autoptr(JsonParser) parser = NULL;
+ JsonNode *root_node = NULL;
+ JsonNode *app_id_node = NULL;
+ JsonNode *id_node = NULL;
+ JsonNode *runtime_node = NULL;
+ JsonNode *runtime_version_node = NULL;
+ JsonNode *sdk_node = NULL;
+ JsonNode *modules_node = NULL;
+ JsonObject *root_object = NULL;
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(GFile) file = NULL;
+ FlatpakManifest *manifest;
+
+ file_type = g_file_info_get_file_type (file_info);
+ name = g_strdup (g_file_info_get_name (file_info));
+ g_clear_object (&file_info);
+
+ if (name == NULL || file_type == G_FILE_TYPE_DIRECTORY)
+ continue;
+
+ file = g_file_get_child (directory, name);
+
+ /* This regex is based on https://wiki.gnome.org/HowDoI/ChooseApplicationID */
+ filename_regex = g_regex_new ("^[[:alnum:]-_]+\\.[[:alnum:]-_]+(\\.[[:alnum:]-_]+)*\\.json$",
+ 0, 0, NULL);
+
+ g_regex_match (filename_regex, name, 0, &match_info);
+ if (!g_match_info_matches (match_info))
+ continue;
+
+ /* Check if the contents look like a flatpak manifest */
+ path = g_file_get_path (file);
+ parser = json_parser_new ();
+ json_parser_load_from_file (parser, path, &local_error);
+ if (local_error != NULL)
+ continue;
+
+ root_node = json_parser_get_root (parser);
+ if (!JSON_NODE_HOLDS_OBJECT (root_node))
+ continue;
+
+ root_object = json_node_get_object (root_node);
+ app_id_node = json_object_get_member (root_object, "app-id");
+ id_node = json_object_get_member (root_object, "id");
+ runtime_node = json_object_get_member (root_object, "runtime");
+ runtime_version_node = json_object_get_member (root_object, "runtime-version");
+ sdk_node = json_object_get_member (root_object, "sdk");
+ modules_node = json_object_get_member (root_object, "modules");
+
+ if ((!JSON_NODE_HOLDS_VALUE (app_id_node) && !JSON_NODE_HOLDS_VALUE (id_node)) ||
+ !JSON_NODE_HOLDS_VALUE (runtime_node) ||
+ !JSON_NODE_HOLDS_VALUE (sdk_node) ||
+ !JSON_NODE_HOLDS_ARRAY (modules_node))
+ continue;
+
+ IDE_TRACE_MSG ("Discovered flatpak manifest at %s", path);
+
+ manifest = g_slice_new0 (FlatpakManifest);
+ manifest->file = g_steal_pointer (&file);
+ manifest->platform = json_node_dup_string (runtime_node);
+ if (!JSON_NODE_HOLDS_VALUE (runtime_version_node) || ide_str_empty0 (json_node_get_string
(runtime_version_node)))
+ manifest->branch = g_strdup ("master");
+ else
+ manifest->branch = json_node_dup_string (runtime_version_node);
+ manifest->sdk = json_node_dup_string (sdk_node);
+ if (JSON_NODE_HOLDS_VALUE (app_id_node))
+ manifest->app_id = json_node_dup_string (app_id_node);
+ else
+ manifest->app_id = json_node_dup_string (id_node);
+ manifest->primary_module = guess_primary_module (root_object, directory);
+
+ g_ptr_array_add (ar, manifest);
+ }
+
+ return ar;
+}
+
+static gboolean
+gbp_flatpak_runtime_provider_load_manifests (GbpFlatpakRuntimeProvider *self,
+ GPtrArray *runtimes,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(GPtrArray) ar = NULL;
+ g_autoptr(GFileInfo) file_info = NULL;
+ IdeContext *context;
+ GFile *project_file;
+ g_autoptr(GFile) project_dir = NULL;
+
+ g_assert (GBP_IS_FLATPAK_RUNTIME_PROVIDER (self));
+
+ context = ide_object_get_context (IDE_OBJECT (self->manager));
+ project_file = ide_context_get_project_file (context);
+
+ g_assert (G_IS_FILE (project_file));
+
+ file_info = g_file_query_info (project_file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable,
+ error);
+
+ if (file_info == NULL)
+ return FALSE;
+
+ if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
+ project_dir = g_object_ref (project_file);
+ else
+ project_dir = g_file_get_parent (project_file);
+
+ ar = gbp_flatpak_runtime_provider_find_flatpak_manifests (self, cancellable, project_dir, error);
+
+ if (ar == NULL)
+ return FALSE;
+
+ IDE_TRACE_MSG ("Found %u flatpak manifests", ar->len);
+
+ for (guint i = 0; i < ar->len; i++)
+ {
+ FlatpakManifest *manifest = g_ptr_array_index (ar, i);
+ gchar *id;
+
+ id = g_file_get_basename (manifest->file);
+ if (contains_id (runtimes, id))
+ continue;
+
+ g_ptr_array_add (runtimes,
+ g_object_new (GBP_TYPE_FLATPAK_RUNTIME,
+ "branch", manifest->branch,
+ "sdk", manifest->sdk,
+ "platform", manifest->platform,
+ "manifest", manifest->file,
+ "primary-module", manifest->primary_module,
+ "app-id", manifest->app_id,
+ "context", context,
+ "id", id,
+ "display-name", id,
+ NULL));
+ }
+
+ return TRUE;
+}
+
static void
gbp_flatpak_runtime_provider_load_worker (GTask *task,
gpointer source_object,
@@ -200,6 +434,7 @@ gbp_flatpak_runtime_provider_load_worker (GTask *task,
ret = g_ptr_array_new_with_free_func (g_object_unref);
+ /* Load system flatpak runtimes */
if (NULL == (self->system_installation = flatpak_installation_new_system (cancellable, &error)) ||
!gbp_flatpak_runtime_provider_load_refs (self, self->system_installation, ret, cancellable, &error))
{
@@ -207,6 +442,7 @@ gbp_flatpak_runtime_provider_load_worker (GTask *task,
g_clear_error (&error);
}
+ /* Load user flatpak runtimes */
path = g_build_filename (g_get_home_dir (), ".local", "share", "flatpak", NULL);
file = g_file_new_for_path (path);
@@ -217,6 +453,13 @@ gbp_flatpak_runtime_provider_load_worker (GTask *task,
g_clear_error (&error);
}
+ /* Load flatpak manifests in the repo */
+ if (!gbp_flatpak_runtime_provider_load_manifests (self, ret, cancellable, &error))
+ {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
g_task_return_pointer (task, g_steal_pointer (&ret), (GDestroyNotify)g_ptr_array_unref);
IDE_EXIT;
diff --git a/plugins/flatpak/gbp-flatpak-runtime.c b/plugins/flatpak/gbp-flatpak-runtime.c
index 39a9393..75dc51e 100644
--- a/plugins/flatpak/gbp-flatpak-runtime.c
+++ b/plugins/flatpak/gbp-flatpak-runtime.c
@@ -28,6 +28,9 @@ struct _GbpFlatpakRuntime
gchar *sdk;
gchar *platform;
gchar *branch;
+ gchar *primary_module;
+ gchar *app_id;
+ GFile *manifest;
};
G_DEFINE_TYPE (GbpFlatpakRuntime, gbp_flatpak_runtime, IDE_TYPE_RUNTIME)
@@ -37,6 +40,9 @@ enum {
PROP_BRANCH,
PROP_PLATFORM,
PROP_SDK,
+ PROP_PRIMARY_MODULE,
+ PROP_APP_ID,
+ PROP_MANIFEST,
LAST_PROP
};
@@ -219,9 +225,13 @@ static void
gbp_flatpak_runtime_prepare_configuration (IdeRuntime *runtime,
IdeConfiguration *configuration)
{
- g_assert (IDE_IS_RUNTIME (runtime));
+ GbpFlatpakRuntime* self = (GbpFlatpakRuntime *)runtime;
+
+ g_assert (GBP_IS_FLATPAK_RUNTIME (self));
g_assert (IDE_IS_CONFIGURATION (configuration));
+ if (!ide_str_empty0 (self->app_id))
+ ide_configuration_set_app_id (configuration, self->app_id);
ide_configuration_set_prefix (configuration, "/app");
}
@@ -247,6 +257,18 @@ gbp_flatpak_runtime_get_property (GObject *object,
g_value_set_string (value, self->sdk);
break;
+ case PROP_PRIMARY_MODULE:
+ g_value_set_string (value, self->primary_module);
+ break;
+
+ case PROP_APP_ID:
+ g_value_set_string (value, self->app_id);
+ break;
+
+ case PROP_MANIFEST:
+ g_value_set_object (value, self->manifest);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@@ -274,6 +296,18 @@ gbp_flatpak_runtime_set_property (GObject *object,
self->sdk = g_value_dup_string (value);
break;
+ case PROP_PRIMARY_MODULE:
+ self->primary_module = g_value_dup_string (value);
+ break;
+
+ case PROP_APP_ID:
+ self->app_id = g_value_dup_string (value);
+ break;
+
+ case PROP_MANIFEST:
+ self->manifest = g_value_dup_object (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@@ -287,6 +321,9 @@ gbp_flatpak_runtime_finalize (GObject *object)
g_clear_pointer (&self->sdk, g_free);
g_clear_pointer (&self->platform, g_free);
g_clear_pointer (&self->branch, g_free);
+ g_clear_pointer (&self->primary_module, g_free);
+ g_clear_pointer (&self->app_id, g_free);
+ g_clear_object (&self->manifest);
G_OBJECT_CLASS (gbp_flatpak_runtime_parent_class)->finalize (object);
}
@@ -334,6 +371,33 @@ gbp_flatpak_runtime_class_init (GbpFlatpakRuntimeClass *klass)
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
+ properties [PROP_PRIMARY_MODULE] =
+ g_param_spec_string ("primary-module",
+ "Primary module",
+ "Primary module",
+ NULL,
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_APP_ID] =
+ g_param_spec_string ("app-id",
+ "App ID",
+ "App ID",
+ NULL,
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_MANIFEST] =
+ g_param_spec_object ("manifest",
+ "Manifest",
+ "Manifest file for use with flatpak-builder",
+ G_TYPE_FILE,
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]