[gnome-builder/wip/mwleeds/ide-config-provider] flatpak: writeback manifests to disk
- From: Matthew Leeds <mwleeds src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/mwleeds/ide-config-provider] flatpak: writeback manifests to disk
- Date: Wed, 18 Jan 2017 08:28:56 +0000 (UTC)
commit 11d9ebf2304fd7ecb092b45833a85d68352e226a
Author: Matthew Leeds <mleeds redhat com>
Date: Wed Jan 18 02:28:10 2017 -0600
flatpak: writeback manifests to disk
.../flatpak/gbp-flatpak-configuration-provider.c | 345 +++++++++++++++++++-
.../flatpak/gbp-flatpak-configuration-provider.h | 8 +
2 files changed, 352 insertions(+), 1 deletions(-)
---
diff --git a/plugins/flatpak/gbp-flatpak-configuration-provider.c
b/plugins/flatpak/gbp-flatpak-configuration-provider.c
index c8b3a36..e6dcda2 100644
--- a/plugins/flatpak/gbp-flatpak-configuration-provider.c
+++ b/plugins/flatpak/gbp-flatpak-configuration-provider.c
@@ -30,12 +30,17 @@
#include "gbp-flatpak-configuration-provider.h"
#include "gbp-flatpak-configuration.h"
+#define WRITEBACK_TIMEOUT_SECS 2
+
struct _GbpFlatpakConfigurationProvider
{
GObject parent_instance;
IdeConfigurationManager *manager;
GCancellable *cancellable;
GPtrArray *configurations;
+
+ gulong writeback_handler;
+ guint change_count;
};
typedef struct
@@ -58,6 +63,336 @@ G_DEFINE_TYPE_EXTENDED (GbpFlatpakConfigurationProvider, gbp_flatpak_configurati
static void gbp_flatpak_configuration_provider_load (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager);
static void gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager);
+static void
+gbp_flatpak_configuration_provider_save_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = user_data;
+ GError *error = NULL;
+ GFile *file = (GFile *)object;
+
+ g_assert (G_IS_FILE (file));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ if (!g_file_replace_contents_finish (file, result, NULL, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+}
+
+void
+gbp_flatpak_configuration_provider_save_async (GbpFlatpakConfigurationProvider *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ if (self->change_count == 0)
+ {
+ g_task_return_boolean (task, TRUE);
+ return;
+ }
+
+ self->change_count = 0;
+
+ if (self->configurations != NULL)
+ {
+ for (guint i = 0; i < self->configurations->len; i++)
+ {
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(GFileInputStream) file_stream = NULL;
+ g_autoptr(GDataInputStream) data_stream = NULL;
+ g_autoptr(GRegex) runtime_regex = NULL;
+ g_autoptr(GRegex) config_opts_regex = NULL;
+ g_autoptr(GRegex) primary_module_regex = NULL;
+ g_autoptr(GPtrArray) new_lines = NULL;
+ g_auto(GStrv) new_config_opts = NULL;
+ g_auto(GStrv) new_runtime_parts = NULL;
+ g_autofree gchar *primary_module_regex_str = NULL;
+ g_autofree gchar *primary_module_right_curly_brace = NULL;
+ g_autofree gchar *right_curly_brace_line = NULL;
+ g_autofree gchar *primary_module_indent = NULL;
+ g_autofree gchar *config_opt_indent = NULL;
+ gchar *json_string = NULL;
+ GBytes *bytes = NULL;
+ const gchar *primary_module;
+ const gchar *new_runtime_id;
+ gchar *new_config_opts_string;
+ gchar *new_runtime_name;
+ gchar *array_prefix;
+ guint opts_per_line;
+ GFile *manifest;
+ gboolean in_config_opts_array;
+ gboolean in_primary_module;
+ gboolean config_opts_replaced;
+
+ GbpFlatpakConfiguration *configuration = (GbpFlatpakConfiguration *)g_ptr_array_index
(self->configurations, i);
+
+ manifest = gbp_flatpak_configuration_get_manifest (configuration);
+ if (manifest == NULL)
+ continue;
+
+ primary_module = gbp_flatpak_configuration_get_primary_module (configuration);
+ if (primary_module == NULL)
+ {
+ g_warning ("Flatpak manifest configuration has no primary module set");
+ continue;
+ }
+
+ file_stream = g_file_read (manifest, NULL, &local_error);
+ if (file_stream == NULL)
+ {
+ g_warning ("An error occurred while opening manifest file: %s", local_error->message);
+ continue;
+ }
+
+ data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
+
+ runtime_regex = g_regex_new ("^\\s*\"runtime\"\\s*:\\s*\"(?<id>.+)\",$", 0, 0, NULL);
+ config_opts_regex = g_regex_new ("^(\\s*\"config-opts\"\\s*:\\s*\\[).+$", 0, 0, NULL);
+ primary_module_regex_str = g_strdup_printf ("^(\\s*)\"name\"\\s*:\\s*\"%s\",$", primary_module);
+ primary_module_regex = g_regex_new (primary_module_regex_str, 0, 0, NULL);
+
+ new_runtime_id = ide_configuration_get_runtime_id (IDE_CONFIGURATION (configuration));
+ if (g_str_has_prefix (new_runtime_id, "flatpak:"))
+ {
+ new_runtime_parts = g_strsplit (new_runtime_id + 8, "/", 3);
+ if (new_runtime_parts[0] != NULL)
+ new_runtime_name = new_runtime_parts[0];
+ }
+
+ new_config_opts_string = g_strdup (ide_configuration_get_config_opts (IDE_CONFIGURATION
(configuration)));
+ if (!ide_str_empty0 (new_config_opts_string))
+ {
+ new_config_opts = g_strsplit (g_strstrip (new_config_opts_string), " ", 0);
+ }
+
+ new_lines = g_ptr_array_new_with_free_func (g_free);
+ in_config_opts_array = FALSE;
+ in_primary_module = FALSE;
+ config_opts_replaced = 0;
+ for (;;)
+ {
+ gchar *line;
+
+ line = g_data_input_stream_read_line_utf8 (data_stream, NULL, NULL, &local_error);
+ if (local_error != NULL || line == NULL)
+ break;
+
+ if (!in_primary_module)
+ {
+ g_autoptr(GMatchInfo) match_info = NULL;
+ g_regex_match (primary_module_regex, line, 0, &match_info);
+ if (g_match_info_matches (match_info))
+ {
+ gchar *previous_line;
+
+ in_primary_module = TRUE;
+ previous_line = (gchar *)g_ptr_array_index (new_lines, new_lines->len - 1);
+ primary_module_right_curly_brace = g_strjoinv ("}", g_strsplit (previous_line, "{",
0));
+ primary_module_indent = g_match_info_fetch (match_info, 1);
+ }
+ }
+
+ /* Replace the runtime with the user-chosen one */
+ if (!ide_str_empty0 (new_runtime_name))
+ {
+ g_autoptr(GMatchInfo) match_info = NULL;
+ g_regex_match (runtime_regex, line, 0, &match_info);
+ if (g_match_info_matches (match_info))
+ {
+ gchar *old_runtime_ptr;
+ gchar *new_line;
+ old_runtime_ptr = g_strstr_len (line, -1, g_match_info_fetch_named (match_info, "id"));
+ *old_runtime_ptr = '\0';
+ new_line = g_strdup_printf ("%s%s\",", line, new_runtime_name);
+ g_free (line);
+ line = new_line;
+ }
+ }
+
+ if (in_primary_module)
+ {
+ g_autoptr(GMatchInfo) match_info = NULL;
+
+ /* Check if we're at the end of the module and haven't seen a config-opts property */
+ if (g_str_has_prefix (line, primary_module_right_curly_brace))
+ {
+ in_primary_module = FALSE;
+ if (!config_opts_replaced && new_config_opts != NULL)
+ {
+ gchar *previous_line;
+
+ previous_line = (gchar *)g_ptr_array_remove_index (new_lines, new_lines->len - 1);
+ g_ptr_array_add (new_lines, g_strdup_printf ("%s,", previous_line));
+ right_curly_brace_line = line;
+ line = g_strdup_printf ("%s\"config-opts\": []", primary_module_indent);
+ }
+ }
+
+ /* Update the list of configure options, or omit it entirely */
+ g_regex_match (config_opts_regex, line, 0, &match_info);
+ if (g_match_info_matches (match_info) || in_config_opts_array)
+ {
+ gchar *right_bracket;
+
+ right_bracket = g_strstr_len (line, -1, "]");
+ if (g_match_info_matches (match_info))
+ {
+ array_prefix = g_match_info_fetch (match_info, 1);
+ if (right_bracket != NULL)
+ {
+ /*
+ * Ensure that all options will be on one line,
+ * even if there are more than before
+ */
+ opts_per_line = g_strv_length (new_config_opts);
+ }
+ else
+ {
+ in_config_opts_array = TRUE;
+ opts_per_line = (g_strv_length (g_strsplit (line, "\"", 0)) - 3) / 2;
+ continue;
+ }
+ }
+ if (right_bracket == NULL)
+ {
+ in_config_opts_array = TRUE;
+ config_opt_indent = g_strsplit (line, "\"", 0)[0];
+ continue;
+ }
+
+ /* At this point it's either a single line or we're on the last line */
+ in_config_opts_array = FALSE;
+ config_opts_replaced = TRUE;
+ if (new_config_opts == NULL)
+ {
+ line = g_strdup_printf ("%s],", array_prefix);
+ }
+ else
+ {
+ gchar *array_suffix;
+ array_suffix = *(right_bracket - 1) == ' ' ? " ]" : "]";
+ if (config_opt_indent == NULL)
+ config_opt_indent = g_strsplit (line, "\"", 0)[0];
+ for (guint j = 0; g_strv_length (new_config_opts) > j; j += opts_per_line)
+ {
+ g_autoptr(GPtrArray) config_opts_subset = NULL;
+ gchar *prefix;
+ gchar *suffix;
+
+ prefix = (j == 0) ? array_prefix : config_opt_indent;
+ suffix = (g_strv_length (new_config_opts) <= j + opts_per_line) ? array_suffix
: "";
+ config_opts_subset = g_ptr_array_new ();
+ for (guint k = 0; k < opts_per_line && new_config_opts[j+k]; ++k)
+ g_ptr_array_add (config_opts_subset, new_config_opts[j+k]);
+ g_ptr_array_add (config_opts_subset, NULL);
+
+ line = g_strdup_printf ("%s\"%s\"%s,", prefix,
+ g_strjoinv ("\", \"", (gchar
**)config_opts_subset->pdata),
+ suffix);
+ g_ptr_array_add (new_lines, line);
+ }
+ continue;
+ }
+ }
+ }
+
+ //TODO deal with other things the user might have changed
+
+ g_ptr_array_add (new_lines, line);
+ if (right_curly_brace_line != NULL)
+ {
+ g_ptr_array_add (new_lines, right_curly_brace_line);
+ right_curly_brace_line = NULL;
+ }
+ }
+
+ /* Ensure there's a newline at the end of the file */
+ g_ptr_array_add (new_lines, g_strdup (""));
+ g_ptr_array_add (new_lines, NULL);
+ json_string = g_strjoinv ("\n", (gchar **)new_lines->pdata);
+ bytes = g_bytes_new_take (json_string, strlen (json_string));
+
+ g_file_replace_contents_bytes_async (manifest,
+ bytes,
+ NULL,
+ FALSE,
+ G_FILE_CREATE_NONE,
+ cancellable,
+ gbp_flatpak_configuration_provider_save_cb,
+ g_object_ref (task));
+ }
+ }
+
+ //TODO write all the manifests not just one
+
+ IDE_EXIT;
+}
+
+gboolean
+gbp_flatpak_configuration_provider_save_finish (GbpFlatpakConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static gboolean
+gbp_flatpak_configuration_provider_do_writeback (gpointer data)
+{
+ GbpFlatpakConfigurationProvider *self = data;
+
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+
+ self->writeback_handler = 0;
+
+ gbp_flatpak_configuration_provider_save_async (self, NULL, NULL, NULL);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+gbp_flatpak_configuration_provider_queue_writeback (GbpFlatpakConfigurationProvider *self)
+{
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+
+ IDE_ENTRY;
+
+ if (self->writeback_handler != 0)
+ g_source_remove (self->writeback_handler);
+
+ self->writeback_handler = g_timeout_add_seconds (WRITEBACK_TIMEOUT_SECS,
+ gbp_flatpak_configuration_provider_do_writeback,
+ self);
+
+ IDE_EXIT;
+}
+
+static void
+gbp_flatpak_configuration_provider_changed (GbpFlatpakConfigurationProvider *self,
+ IdeConfiguration *configuration)
+{
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (IDE_IS_CONFIGURATION (configuration));
+
+ self->change_count++;
+
+ gbp_flatpak_configuration_provider_queue_writeback (self);
+}
+
static gboolean
contains_id (GPtrArray *ar,
const gchar *id)
@@ -450,6 +785,12 @@ gbp_flatpak_configuration_provider_load_manifests (GbpFlatpakConfigurationProvid
if (manifest->config_opts != NULL)
ide_configuration_set_config_opts (IDE_CONFIGURATION (configuration), manifest->config_opts);
+ g_signal_connect_object (configuration,
+ "changed",
+ G_CALLBACK (gbp_flatpak_configuration_provider_changed),
+ self,
+ G_CONNECT_SWAPPED);
+
g_ptr_array_add (configurations, configuration);
}
@@ -555,9 +896,11 @@ gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider,
g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
+ ide_clear_source (&self->writeback_handler);
+
if (self->configurations != NULL)
{
- for (guint i= 0; i < self->configurations->len; i++)
+ for (guint i = 0; i < self->configurations->len; i++)
{
IdeConfiguration *configuration = g_ptr_array_index (self->configurations, i);
diff --git a/plugins/flatpak/gbp-flatpak-configuration-provider.h
b/plugins/flatpak/gbp-flatpak-configuration-provider.h
index 7a262b7..dfc7905 100644
--- a/plugins/flatpak/gbp-flatpak-configuration-provider.h
+++ b/plugins/flatpak/gbp-flatpak-configuration-provider.h
@@ -27,6 +27,14 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GbpFlatpakConfigurationProvider, gbp_flatpak_configuration_provider, GBP,
FLATPAK_CONFIGURATION_PROVIDER, GObject)
+void gbp_flatpak_configuration_provider_save_async (GbpFlatpakConfigurationProvider *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gbp_flatpak_configuration_provider_save_finish (GbpFlatpakConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#endif /* GBP_FLATPAK_CONFIGURATION_PROVIDER_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]