[gnome-builder] config: monitor manifests for changes
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] config: monitor manifests for changes
- Date: Wed, 31 Jan 2018 10:29:47 +0000 (UTC)
commit 23f9747b1a20b01c144b66fa4ede985cf4f8191f
Author: Christian Hergert <chergert redhat com>
Date: Wed Jan 31 01:51:06 2018 -0800
config: monitor manifests for changes
If a flatpak manifest is changed outside of Builder, this
ensures that we update it. It tries to avoid reacting to changes
caused by saving the manifest back to disk.
.../flatpak/gbp-flatpak-configuration-provider.c | 174 ++++++++++++++++++++-
src/plugins/flatpak/gbp-flatpak-manifest.c | 90 ++++++++++-
2 files changed, 256 insertions(+), 8 deletions(-)
---
diff --git a/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
b/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
index e09f2600a..af93bedeb 100644
--- a/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
+++ b/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
@@ -33,7 +33,9 @@ struct _GbpFlatpakConfigurationProvider
GPtrArray *configs;
};
-static void gbp_flatpak_configuration_provider_save_tick (GTask *task);
+static void manifest_save_tick (GTask *task);
+static void manifest_needs_reload (GbpFlatpakConfigurationProvider *self,
+ GbpFlatpakManifest *manifest);
static void
gbp_flatpak_configuration_provider_save_cb (GObject *object,
@@ -51,11 +53,11 @@ gbp_flatpak_configuration_provider_save_cb (GObject *object,
if (!gbp_flatpak_manifest_save_finish (manifest, result, &error))
g_warning ("Failed to save manifest: %s", error->message);
- gbp_flatpak_configuration_provider_save_tick (task);
+ manifest_save_tick (task);
}
static void
-gbp_flatpak_configuration_provider_save_tick (GTask *task)
+manifest_save_tick (GTask *task)
{
g_autoptr(GbpFlatpakManifest) manifest = NULL;
GbpFlatpakConfigurationProvider *self;
@@ -125,7 +127,7 @@ gbp_flatpak_configuration_provider_save_async (IdeConfigurationProvider *provide
g_task_set_task_data (task, g_steal_pointer (&ar), (GDestroyNotify)g_ptr_array_unref);
- gbp_flatpak_configuration_provider_save_tick (task);
+ manifest_save_tick (task);
IDE_EXIT;
}
@@ -141,6 +143,155 @@ gbp_flatpak_configuration_provider_save_finish (IdeConfigurationProvider *provi
return g_task_propagate_boolean (G_TASK (result), error);
}
+static void
+load_manifest_worker (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GbpFlatpakConfigurationProvider *self = source_object;
+ g_autoptr(GbpFlatpakManifest) manifest = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *name = NULL;
+ IdeContext *context;
+ GFile *file = task_data;
+
+ g_assert (G_IS_TASK (task));
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (G_IS_FILE (file));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ context = ide_object_get_context (IDE_OBJECT (self));
+ name = g_file_get_basename (file);
+ manifest = gbp_flatpak_manifest_new (context, file, name);
+
+ if (!g_initable_init (G_INITABLE (manifest), cancellable, &error))
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ g_signal_connect_object (manifest,
+ "needs-reload",
+ G_CALLBACK (manifest_needs_reload),
+ self,
+ G_CONNECT_SWAPPED);
+
+ g_task_return_pointer (task, g_steal_pointer (&manifest), g_object_unref);
+}
+
+static void
+load_manifest_async (GbpFlatpakConfigurationProvider *self,
+ GFile *file,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (G_IS_FILE (file));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, load_manifest_async);
+ g_task_set_priority (task, G_PRIORITY_LOW);
+ g_task_set_task_data (task, g_object_ref (file), g_object_unref);
+ g_task_run_in_thread (task, load_manifest_worker);
+}
+
+static GbpFlatpakManifest *
+load_manifest_finish (GbpFlatpakConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (G_IS_TASK (result));
+ g_assert (g_task_is_valid (G_TASK (result), self));
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+reload_manifest_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)object;
+ g_autoptr(GbpFlatpakManifest) old_manifest = user_data;
+ g_autoptr(GbpFlatpakManifest) new_manifest = NULL;
+ g_autoptr(GError) error = NULL;
+ IdeConfigurationManager *manager;
+ IdeConfiguration *current;
+ IdeContext *context;
+ gboolean is_active;
+
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (GBP_IS_FLATPAK_MANIFEST (old_manifest));
+
+ new_manifest = load_manifest_finish (self, result, &error);
+
+ if (new_manifest == NULL)
+ {
+ g_warning ("Failed to reload manifest: %s", error->message);
+
+ /* Watch for future changes */
+ g_signal_connect_object (old_manifest,
+ "needs-reload",
+ G_CALLBACK (manifest_needs_reload),
+ self,
+ G_CONNECT_SWAPPED);
+ return;
+ }
+
+ g_ptr_array_remove (self->configs, old_manifest);
+ g_ptr_array_add (self->configs, g_object_ref (new_manifest));
+
+ context = ide_object_get_context (IDE_OBJECT (self));
+ manager = ide_context_get_configuration_manager (context);
+ current = ide_configuration_manager_get_current (manager);
+
+ is_active = current == IDE_CONFIGURATION (old_manifest);
+
+ ide_configuration_provider_emit_added (IDE_CONFIGURATION_PROVIDER (self),
+ IDE_CONFIGURATION (new_manifest));
+
+ if (is_active)
+ ide_configuration_manager_set_current (manager,
+ IDE_CONFIGURATION (new_manifest));
+
+ ide_configuration_provider_emit_removed (IDE_CONFIGURATION_PROVIDER (self),
+ IDE_CONFIGURATION (old_manifest));
+}
+
+static void
+manifest_needs_reload (GbpFlatpakConfigurationProvider *self,
+ GbpFlatpakManifest *manifest)
+{
+ g_autoptr(GTask) task = NULL;
+ GFile *file;
+
+ IDE_ENTRY;
+
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (GBP_IS_FLATPAK_MANIFEST (manifest));
+
+ g_signal_handlers_disconnect_by_func (manifest,
+ G_CALLBACK (manifest_needs_reload),
+ self);
+
+ file = gbp_flatpak_manifest_get_file (manifest);
+
+ load_manifest_async (self,
+ file,
+ NULL,
+ reload_manifest_cb,
+ g_object_ref (manifest));
+
+ IDE_EXIT;
+}
+
static void
gbp_flatpak_configuration_provider_load_worker (GTask *task,
gpointer source_object,
@@ -179,6 +330,12 @@ gbp_flatpak_configuration_provider_load_worker (GTask *task,
continue;
}
+ g_signal_connect_object (manifest,
+ "needs-reload",
+ G_CALLBACK (manifest_needs_reload),
+ self,
+ G_CONNECT_SWAPPED);
+
g_ptr_array_add (manifests, g_steal_pointer (&manifest));
}
@@ -342,13 +499,16 @@ gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider)
g_autoptr(IdeConfiguration) config = NULL;
config = g_object_ref (g_ptr_array_index (self->configs, i - 1));
- g_ptr_array_remove_index (self->configs, i);
+ g_signal_handlers_disconnect_by_func (config,
+ G_CALLBACK (manifest_needs_reload),
+ self);
+ g_ptr_array_remove_index (self->configs, i - 1);
ide_configuration_provider_emit_removed (provider, config);
}
- }
- g_clear_pointer (&self->configs, g_ptr_array_unref);
+ g_clear_pointer (&self->configs, g_ptr_array_unref);
+ }
IDE_EXIT;
}
diff --git a/src/plugins/flatpak/gbp-flatpak-manifest.c b/src/plugins/flatpak/gbp-flatpak-manifest.c
index 3512a2e18..4e702d11e 100644
--- a/src/plugins/flatpak/gbp-flatpak-manifest.c
+++ b/src/plugins/flatpak/gbp-flatpak-manifest.c
@@ -30,6 +30,7 @@ struct _GbpFlatpakManifest
IdeConfiguration parent_instance;
GFile *file;
+ GFileMonitor *file_monitor;
JsonNode *root;
@@ -65,7 +66,13 @@ enum {
N_PROPS
};
+enum {
+ NEEDS_RELOAD,
+ N_SIGNALS
+};
+
static GParamSpec *properties [N_PROPS];
+static guint signals [N_SIGNALS];
static GRegex *app_id_regex;
static gboolean
@@ -462,12 +469,81 @@ gbp_flatpak_manifest_supports_runtime (IdeConfiguration *config,
return GBP_IS_FLATPAK_RUNTIME (runtime);
}
+static void
+gbp_flatpak_manifest_file_changed (GbpFlatpakManifest *self,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ GFileMonitor *file_monitor)
+{
+ g_assert (GBP_IS_FLATPAK_MANIFEST (self));
+ g_assert (G_IS_FILE_MONITOR (file_monitor));
+
+ if (event == G_FILE_MONITOR_EVENT_CHANGED || event == G_FILE_MONITOR_EVENT_CREATED)
+ g_signal_emit (self, signals [NEEDS_RELOAD], 0);
+}
+
+static void
+gbp_flatpak_manifest_block_monitor (GbpFlatpakManifest *self)
+{
+ g_assert (GBP_IS_FLATPAK_MANIFEST (self));
+
+ g_signal_handlers_block_matched (self->file_monitor,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ g_signal_lookup ("changed", G_TYPE_FILE_MONITOR),
+ 0,
+ NULL,
+ gbp_flatpak_manifest_file_changed,
+ self);
+}
+
+static void
+gbp_flatpak_manifest_unblock_monitor (GbpFlatpakManifest *self)
+{
+ g_assert (GBP_IS_FLATPAK_MANIFEST (self));
+
+ g_signal_handlers_unblock_matched (self->file_monitor,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ g_signal_lookup ("changed", G_TYPE_FILE_MONITOR),
+ 0,
+ NULL,
+ gbp_flatpak_manifest_file_changed,
+ self);
+}
+
+static void
+gbp_flatpak_manifest_set_file (GbpFlatpakManifest *self,
+ GFile *file)
+{
+ g_assert (GBP_IS_FLATPAK_MANIFEST (self));
+ g_assert (self->file == NULL);
+ g_assert (self->file_monitor == NULL);
+ g_assert (!file || G_IS_FILE (file));
+
+ if (file == NULL)
+ {
+ g_critical ("GbpFlatpakManifest:file is required upon construction");
+ return;
+ }
+
+ g_set_object (&self->file, file);
+
+ self->file_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
+
+ g_signal_connect_object (self->file_monitor,
+ "changed",
+ G_CALLBACK (gbp_flatpak_manifest_file_changed),
+ self,
+ G_CONNECT_SWAPPED);
+}
+
static void
gbp_flatpak_manifest_finalize (GObject *object)
{
GbpFlatpakManifest *self = (GbpFlatpakManifest *)object;
g_clear_object (&self->file);
+ g_clear_object (&self->file_monitor);
g_clear_pointer (&self->root, json_node_unref);
@@ -517,7 +593,7 @@ gbp_flatpak_manifest_set_property (GObject *object,
switch (prop_id)
{
case PROP_FILE:
- self->file = g_value_dup_object (value);
+ gbp_flatpak_manifest_set_file (self, g_value_get_object (value));
break;
default:
@@ -546,6 +622,14 @@ gbp_flatpak_manifest_class_init (GbpFlatpakManifestClass *klass)
g_object_class_install_properties (object_class, N_PROPS, properties);
+ signals [NEEDS_RELOAD] =
+ g_signal_new ("needs-reload",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
/* This regex is based on https://wiki.gnome.org/HowDoI/ChooseApplicationID */
app_id_regex = g_regex_new ("^[[:alnum:]-_]+\\.[[:alnum:]-_]+(\\.[[:alnum:]-_]+)*$",
G_REGEX_OPTIMIZE, 0, NULL);
@@ -784,6 +868,8 @@ gbp_flatpak_manifest_save_cb (GObject *object,
ide_configuration_set_dirty (IDE_CONFIGURATION (self), FALSE);
g_task_return_boolean (task, TRUE);
+ gbp_flatpak_manifest_unblock_monitor (self);
+
IDE_EXIT;
}
@@ -847,6 +933,8 @@ gbp_flatpak_manifest_save_async (GbpFlatpakManifest *self,
data[len] = '\n';
bytes = g_bytes_new_take (g_steal_pointer (&data), len + 1);
+ gbp_flatpak_manifest_block_monitor (self);
+
/*
* Now that we have a buffer containing the UTF-8 encoded formatted
* JSON, we can asynchronously write that content to disk without hvaing
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]