[gnome-builder/wip/chergert/code-index-revamp: 12/16] code-index: add accessory builder/executor objects
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/code-index-revamp: 12/16] code-index: add accessory builder/executor objects
- Date: Sat, 2 Feb 2019 04:37:37 +0000 (UTC)
commit cc6e19c532d06b9d62898b0be4ed783d42525ed2
Author: Christian Hergert <chergert redhat com>
Date: Fri Feb 1 20:32:44 2019 -0800
code-index: add accessory builder/executor objects
These can be used to simplify our indexing work a bit, going forward.
src/plugins/code-index/gbp-code-index-builder.c | 582 +++++++++++++++++++++++
src/plugins/code-index/gbp-code-index-builder.h | 46 ++
src/plugins/code-index/gbp-code-index-executor.c | 288 +++++++++++
src/plugins/code-index/gbp-code-index-executor.h | 43 ++
src/plugins/code-index/gbp-code-index-plan.c | 2 +-
src/plugins/code-index/gbp-code-index-plan.h | 2 +-
src/plugins/code-index/meson.build | 2 +
7 files changed, 963 insertions(+), 2 deletions(-)
---
diff --git a/src/plugins/code-index/gbp-code-index-builder.c b/src/plugins/code-index/gbp-code-index-builder.c
new file mode 100644
index 000000000..fe79fe764
--- /dev/null
+++ b/src/plugins/code-index/gbp-code-index-builder.c
@@ -0,0 +1,582 @@
+/* gbp-code-index-builder.c
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-code-index-builder"
+
+#include "config.h"
+
+#include <dazzle.h>
+#include <libide-code.h>
+#include <libide-io.h>
+#include <libide-foundry.h>
+#include <libpeas/peas.h>
+
+#include "gbp-code-index-builder.h"
+#include "gbp-code-index-plan.h"
+
+struct _GbpCodeIndexBuilder
+{
+ IdeObject parent_instance;
+ GFile *source_dir;
+ GFile *index_dir;
+ GPtrArray *items;
+ IdePersistentMapBuilder *map;
+ DzlFuzzyIndexBuilder *fuzzy;
+ guint next_file_id;
+ guint has_run : 1;
+};
+
+typedef struct
+{
+ guint n_active;
+ guint completed;
+} Run;
+
+G_DEFINE_TYPE (GbpCodeIndexBuilder, gbp_code_index_builder, IDE_TYPE_OBJECT)
+
+static void
+run_free (Run *state)
+{
+ g_slice_free (Run, state);
+}
+
+static void
+gbp_code_index_builder_finalize (GObject *object)
+{
+ GbpCodeIndexBuilder *self = (GbpCodeIndexBuilder *)object;
+
+ g_clear_object (&self->index_dir);
+ g_clear_object (&self->source_dir);
+ g_clear_pointer (&self->items, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (gbp_code_index_builder_parent_class)->finalize (object);
+}
+
+static void
+gbp_code_index_builder_class_init (GbpCodeIndexBuilderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gbp_code_index_builder_finalize;
+}
+
+static void
+gbp_code_index_builder_init (GbpCodeIndexBuilder *self)
+{
+ self->items = g_ptr_array_new_with_free_func ((GDestroyNotify)gbp_code_index_plan_item_free);
+ self->map = ide_persistent_map_builder_new ();
+ self->fuzzy = dzl_fuzzy_index_builder_new ();
+}
+
+static void
+gbp_code_index_builder_submit (GbpCodeIndexBuilder *self,
+ GFile *file,
+ GPtrArray *entries)
+{
+ g_autofree gchar *filename = NULL;
+ gchar num[16];
+ guint file_id;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (G_IS_FILE (file));
+ g_assert (entries != NULL);
+
+ file_id = self->next_file_id;
+ self->next_file_id++;
+
+ /*
+ * Storing file_name:id and id:file_name into index, file_name:id will be
+ * used to check whether a file is there in index or not.
+ *
+ * This can get called multiple times, but it's fine because we're just
+ * updating a GVariantDict until the file has been processed.
+ */
+ g_snprintf (num, sizeof (num), "%u", file_id);
+ filename = g_file_get_path (file);
+ dzl_fuzzy_index_builder_set_metadata_uint32 (self->fuzzy, filename, file_id);
+ dzl_fuzzy_index_builder_set_metadata_string (self->fuzzy, num, filename);
+
+ IDE_TRACE_MSG ("Adding %u entries for %s", entries->len, filename);
+
+ for (guint i = 0; i < entries->len; i++)
+ {
+ IdeCodeIndexEntry *entry = g_ptr_array_index (entries, i);
+ const gchar *key;
+ const gchar *name;
+ IdeSymbolKind kind;
+ IdeSymbolFlags flags;
+ guint begin_line;
+ guint begin_line_offset;
+
+ key = ide_code_index_entry_get_key (entry);
+ name = ide_code_index_entry_get_name (entry);
+ kind = ide_code_index_entry_get_kind (entry);
+ flags = ide_code_index_entry_get_flags (entry);
+
+ ide_code_index_entry_get_range (entry,
+ &begin_line,
+ &begin_line_offset,
+ NULL,
+ NULL);
+
+ /* In our index lines and offsets are 1-based */
+
+ if (key != NULL)
+ ide_persistent_map_builder_insert (self->map,
+ key,
+ g_variant_new ("(uuuu)",
+ file_id,
+ begin_line,
+ begin_line_offset,
+ flags),
+ !!(flags & IDE_SYMBOL_FLAGS_IS_DEFINITION));
+
+ if (name != NULL)
+ dzl_fuzzy_index_builder_insert (self->fuzzy,
+ name,
+ g_variant_new ("(uuuuu)",
+ file_id,
+ begin_line,
+ begin_line_offset,
+ flags,
+ kind),
+ 0);
+ }
+}
+
+GbpCodeIndexBuilder *
+gbp_code_index_builder_new (GFile *source_dir,
+ GFile *index_dir)
+{
+ GbpCodeIndexBuilder *self;
+
+ g_return_val_if_fail (G_IS_FILE (source_dir), NULL);
+ g_return_val_if_fail (G_IS_FILE (index_dir), NULL);
+
+ self = g_object_new (GBP_TYPE_CODE_INDEX_BUILDER, NULL);
+ self->source_dir = g_object_ref (source_dir);
+ self->index_dir = g_object_ref (index_dir);
+
+ return g_steal_pointer (&self);
+}
+
+void
+gbp_code_index_builder_add_item (GbpCodeIndexBuilder *self,
+ const GbpCodeIndexPlanItem *item)
+{
+ g_return_if_fail (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_return_if_fail (self->has_run == FALSE);
+ g_return_if_fail (item != NULL);
+
+ g_ptr_array_add (self->items, gbp_code_index_plan_item_copy (item));
+}
+
+static void
+code_index_entries_collect_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeCodeIndexEntries *entries = (IdeCodeIndexEntries *)object;
+ GbpCodeIndexBuilder *self;
+ g_autoptr(GPtrArray) items = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ GFile *file;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IDE_IS_CODE_INDEX_ENTRIES (entries));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ self = ide_task_get_source_object (task);
+ file = ide_task_get_task_data (task);
+
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (G_IS_FILE (file));
+
+ if (!(items = ide_code_index_entries_collect_finish (entries, result, &error)))
+ items = g_ptr_array_new_full (0, g_object_unref);
+
+ gbp_code_index_builder_submit (self, file, items);
+ ide_task_return_boolean (task, TRUE);
+}
+
+static void
+code_indexer_index_file_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeCodeIndexer *indexer = (IdeCodeIndexer *)object;
+ g_autoptr(IdeCodeIndexEntries) entries = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IDE_IS_CODE_INDEXER (indexer));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!(entries = ide_code_indexer_index_file_finish (indexer, result, &error)))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_code_index_entries_collect_async (entries,
+ ide_task_get_cancellable (task),
+ code_index_entries_collect_cb,
+ g_object_ref (task));
+}
+
+static void
+gbp_code_index_builder_index_file_async (GbpCodeIndexBuilder *self,
+ GFile *file,
+ IdeCodeIndexer *indexer,
+ const gchar * const *build_flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = NULL;
+
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (G_IS_FILE (file));
+ g_assert (IDE_IS_CODE_INDEXER (indexer));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_code_index_builder_index_file_async);
+ ide_task_set_task_data (task, g_object_ref (file), g_object_unref);
+
+ ide_code_indexer_index_file_async (indexer,
+ file,
+ build_flags,
+ cancellable,
+ code_indexer_index_file_cb,
+ g_steal_pointer (&task));
+}
+
+static gboolean
+gbp_code_index_builder_index_file_finish (GbpCodeIndexBuilder *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (IDE_IS_TASK (result));
+
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
+
+static void
+gbp_code_index_builder_index_file_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpCodeIndexBuilder *self = (GbpCodeIndexBuilder *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ Run *state;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ gbp_code_index_builder_index_file_finish (self, result, &error);
+
+ state = ide_task_get_task_data (task);
+ state->n_active--;
+ state->completed++;
+
+ if (state->n_active == 0)
+ ide_task_return_boolean (task, TRUE);
+}
+
+static void
+gbp_code_index_builder_aggregate_async (GbpCodeIndexBuilder *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(GHashTable) indexers = NULL;
+ PeasEngine *engine;
+ Run *state;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_code_index_builder_aggregate_async);
+
+ if (self->items->len == 0)
+ {
+ ide_task_return_boolean (task, TRUE);
+ IDE_EXIT;
+ }
+
+ state = g_slice_new0 (Run);
+ state->n_active = 1;
+ ide_task_set_task_data (task, state, run_free);
+
+ engine = peas_engine_get_default ();
+ indexers = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+
+ /* We just queue up all of our indexer work up-front, and let the various
+ * backends manage their own queue-depth. That way, we don't waste time
+ * coordinating back and forth for async-but-serial processing.
+ */
+
+ for (guint i = 0; i < self->items->len; i++)
+ {
+ const GbpCodeIndexPlanItem *item = g_ptr_array_index (self->items, i);
+ const gchar *name = g_file_info_get_name (item->file_info);
+ g_autoptr(GFile) child = NULL;
+ IdeCodeIndexer *indexer;
+
+ if (name == NULL)
+ continue;
+
+ if (!(indexer = g_hash_table_lookup (indexers, item->indexer_module_name)))
+ {
+ PeasPluginInfo *plugin_info;
+
+ if (!(plugin_info = peas_engine_get_plugin_info (engine, item->indexer_module_name)))
+ continue;
+
+ indexer = (IdeCodeIndexer *)
+ peas_engine_create_extension (engine, plugin_info, IDE_TYPE_CODE_INDEXER,
+ "parent", self,
+ NULL);
+
+ if (indexer == NULL)
+ continue;
+
+ g_hash_table_insert (indexers, (gchar *)item->indexer_module_name, indexer);
+ }
+
+ state->n_active++;
+
+ child = g_file_get_child (self->source_dir, name);
+
+ gbp_code_index_builder_index_file_async (self,
+ child,
+ indexer,
+ (const gchar * const *)item->build_flags,
+ cancellable,
+ gbp_code_index_builder_index_file_cb,
+ g_object_ref (task));
+ }
+
+ state->n_active--;
+
+ g_ptr_array_remove_range (self->items, 0, self->items->len);
+
+ if (state->n_active == 0)
+ ide_task_return_boolean (task, TRUE);
+
+ IDE_EXIT;
+}
+
+static gboolean
+gbp_code_index_builder_aggregate_finish (GbpCodeIndexBuilder *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
+ g_return_val_if_fail (GBP_IS_CODE_INDEX_BUILDER (self), FALSE);
+ g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
+
+static void
+gbp_code_index_builder_persist_write_fuzzy_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ DzlFuzzyIndexBuilder *fuzzy = (DzlFuzzyIndexBuilder *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (DZL_IS_FUZZY_INDEX_BUILDER (fuzzy));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!dzl_fuzzy_index_builder_write_finish (fuzzy, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_boolean (task, TRUE);
+}
+
+static void
+gbp_code_index_builder_persist_write_map_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdePersistentMapBuilder *map = (IdePersistentMapBuilder *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GFile) file = NULL;
+ GbpCodeIndexBuilder *self;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IDE_IS_PERSISTENT_MAP_BUILDER (map));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!ide_persistent_map_builder_write_finish (map, result, &error))
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ self = ide_task_get_source_object (task);
+ file = g_file_get_child (self->index_dir, "SymbolNames");
+
+ dzl_fuzzy_index_builder_set_metadata_uint32 (self->fuzzy, "n_files", self->next_file_id);
+
+ dzl_fuzzy_index_builder_write_async (self->fuzzy,
+ file,
+ G_PRIORITY_DEFAULT,
+ ide_task_get_cancellable (task),
+ gbp_code_index_builder_persist_write_fuzzy_cb,
+ g_object_ref (task));
+}
+
+static void
+gbp_code_index_builder_persist_async (GbpCodeIndexBuilder *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(GFile) file = NULL;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_code_index_builder_persist_async);
+
+ file = g_file_get_child (self->index_dir, "SymbolKeys");
+
+ ide_persistent_map_builder_write_async (self->map,
+ file,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ gbp_code_index_builder_persist_write_map_cb,
+ g_steal_pointer (&task));
+}
+
+static gboolean
+gbp_code_index_builder_persist_finish (GbpCodeIndexBuilder *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (IDE_IS_TASK (result));
+
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
+
+static void
+gbp_code_index_builder_persist_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpCodeIndexBuilder *self = (GbpCodeIndexBuilder *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!gbp_code_index_builder_persist_finish (self, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_boolean (task, TRUE);
+}
+
+static void
+gbp_code_index_builder_aggregate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpCodeIndexBuilder *self = (GbpCodeIndexBuilder *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!gbp_code_index_builder_aggregate_finish (self, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ gbp_code_index_builder_persist_async (self,
+ ide_task_get_cancellable (task),
+ gbp_code_index_builder_persist_cb,
+ g_object_ref (task));
+}
+
+void
+gbp_code_index_builder_run_async (GbpCodeIndexBuilder *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = NULL;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (GBP_IS_CODE_INDEX_BUILDER (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (self->has_run == FALSE);
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_code_index_builder_run_async);
+
+ self->has_run = TRUE;
+
+ gbp_code_index_builder_aggregate_async (self,
+ cancellable,
+ gbp_code_index_builder_aggregate_cb,
+ g_steal_pointer (&task));
+}
+
+gboolean
+gbp_code_index_builder_run_finish (GbpCodeIndexBuilder *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
+ g_return_val_if_fail (GBP_IS_CODE_INDEX_BUILDER (self), FALSE);
+ g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
diff --git a/src/plugins/code-index/gbp-code-index-builder.h b/src/plugins/code-index/gbp-code-index-builder.h
new file mode 100644
index 000000000..023c86472
--- /dev/null
+++ b/src/plugins/code-index/gbp-code-index-builder.h
@@ -0,0 +1,46 @@
+/* gbp-code-index-builder.h
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+#include "gbp-code-index-plan.h"
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CODE_INDEX_BUILDER (gbp_code_index_builder_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCodeIndexBuilder, gbp_code_index_builder, GBP, CODE_INDEX_BUILDER, IdeObject)
+
+GbpCodeIndexBuilder *gbp_code_index_builder_new (GFile *source_dir,
+ GFile *index_dir);
+void gbp_code_index_builder_add_item (GbpCodeIndexBuilder *self,
+ const GbpCodeIndexPlanItem *item);
+void gbp_code_index_builder_run_async (GbpCodeIndexBuilder *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gbp_code_index_builder_run_finish (GbpCodeIndexBuilder *self,
+ GAsyncResult *result,
+ GError **error);
+
+
+G_END_DECLS
diff --git a/src/plugins/code-index/gbp-code-index-executor.c
b/src/plugins/code-index/gbp-code-index-executor.c
new file mode 100644
index 000000000..79b735b1b
--- /dev/null
+++ b/src/plugins/code-index/gbp-code-index-executor.c
@@ -0,0 +1,288 @@
+/* gbp-code-index-executor.c
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-code-index-executor"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <libide-code.h>
+#include <libide-foundry.h>
+#include <libide-threading.h>
+#include <libpeas/peas.h>
+
+#include "gbp-code-index-builder.h"
+#include "gbp-code-index-executor.h"
+
+struct _GbpCodeIndexExecutor
+{
+ IdeObject parent_instance;
+ GbpCodeIndexPlan *plan;
+};
+
+typedef struct
+{
+ GbpCodeIndexPlan *plan;
+ IdeNotification *notif;
+ GFile *cachedir;
+ GFile *workdir;
+ GPtrArray *builders;
+ guint pos;
+ guint64 num_ops;
+ guint64 num_completed;
+} Execute;
+
+G_DEFINE_TYPE (GbpCodeIndexExecutor, gbp_code_index_executor, IDE_TYPE_OBJECT)
+
+static void
+execute_free (Execute *exec)
+{
+ g_clear_object (&exec->plan);
+ g_clear_object (&exec->notif);
+ g_clear_object (&exec->cachedir);
+ g_clear_object (&exec->workdir);
+ g_clear_pointer (&exec->builders, g_ptr_array_unref);
+ g_slice_free (Execute, exec);
+}
+
+GbpCodeIndexExecutor *
+gbp_code_index_executor_new (GbpCodeIndexPlan *plan)
+{
+ GbpCodeIndexExecutor *self;
+
+ g_return_val_if_fail (GBP_IS_CODE_INDEX_PLAN (plan), NULL);
+
+ self = g_object_new (GBP_TYPE_CODE_INDEX_EXECUTOR, NULL);
+ self->plan = g_object_ref (plan);
+
+ return g_steal_pointer (&self);
+}
+
+static void
+gbp_code_index_executor_finalize (GObject *object)
+{
+ GbpCodeIndexExecutor *self = (GbpCodeIndexExecutor *)object;
+
+ g_clear_object (&self->plan);
+
+ G_OBJECT_CLASS (gbp_code_index_executor_parent_class)->finalize (object);
+}
+
+static void
+gbp_code_index_executor_class_init (GbpCodeIndexExecutorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gbp_code_index_executor_finalize;
+}
+
+static void
+gbp_code_index_executor_init (GbpCodeIndexExecutor *self)
+{
+}
+
+static gboolean
+execute_count_ops_cb (GFile *directory,
+ GPtrArray *plan_items,
+ GbpCodeIndexReason reason,
+ gpointer user_data)
+{
+ guint64 *count = user_data;
+ (*count)++;
+ return FALSE;
+}
+
+static guint64
+execute_count_ops (GbpCodeIndexPlan *plan)
+{
+ guint64 count = 0;
+ gbp_code_index_plan_foreach (plan, execute_count_ops_cb, &count);
+ return count;
+}
+
+static gboolean
+gbp_code_index_executor_collect_cb (GFile *directory,
+ GPtrArray *plan_items,
+ GbpCodeIndexReason reason,
+ gpointer user_data)
+{
+ g_autoptr(GbpCodeIndexBuilder) builder = NULL;
+ g_autoptr(GFile) index_dir = NULL;
+ g_autofree gchar *relative = NULL;
+ IdeTask *task = user_data;
+ GbpCodeIndexExecutor *self;
+ Execute *state;
+
+ g_assert (G_IS_FILE (directory));
+ g_assert (plan_items != NULL);
+ g_assert (IDE_IS_TASK (task));
+
+ self = ide_task_get_source_object (task);
+ state = ide_task_get_task_data (task);
+
+ relative = g_file_get_relative_path (state->workdir, directory);
+
+ if (relative == NULL)
+ index_dir = g_object_ref (state->cachedir);
+ else
+ index_dir = g_file_get_child (state->cachedir, relative);
+
+ if (reason == GBP_CODE_INDEX_REASON_REMOVE_INDEX)
+ {
+ g_autoptr(GFile) names = g_file_get_child (index_dir, "SymbolNames");
+ g_autoptr(GFile) keys = g_file_get_child (index_dir, "SymbolKeys");
+
+ g_file_delete_async (names, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
+ g_file_delete_async (keys, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
+
+ state->num_completed++;
+
+ ide_notification_set_progress (state->notif,
+ (gdouble)state->num_completed / (gdouble)state->num_ops);
+
+ return FALSE;
+ }
+
+ builder = gbp_code_index_builder_new (directory, index_dir);
+ ide_object_append (IDE_OBJECT (self), IDE_OBJECT (builder));
+
+ for (guint i = 0; i < plan_items->len; i++)
+ gbp_code_index_builder_add_item (builder, g_ptr_array_index (plan_items, i));
+
+ g_ptr_array_add (state->builders, g_steal_pointer (&builder));
+
+ return FALSE;
+}
+
+static void
+gbp_code_index_executor_run_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpCodeIndexBuilder *builder = (GbpCodeIndexBuilder *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ Execute *state;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_CODE_INDEX_BUILDER (builder));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ gbp_code_index_builder_run_finish (builder, result, &error);
+
+ state = ide_task_get_task_data (task);
+
+ state->pos++;
+ state->num_completed++;
+
+ ide_notification_set_progress (state->notif,
+ (gdouble)state->num_completed / (gdouble)state->num_ops);
+
+ if (state->pos >= state->builders->len)
+ {
+ ide_task_return_boolean (task, TRUE);
+ return;
+ }
+
+ gbp_code_index_builder_run_async (g_ptr_array_index (state->builders, state->pos),
+ ide_task_get_cancellable (task),
+ gbp_code_index_executor_run_cb,
+ g_object_ref (task));
+}
+
+void
+gbp_code_index_executor_execute_async (GbpCodeIndexExecutor *self,
+ IdeNotification *notif,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(IdeContext) context = NULL;
+ Execute *state;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (GBP_IS_CODE_INDEX_EXECUTOR (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_code_index_executor_execute_async);
+
+ if (!(context = ide_object_ref_context (IDE_OBJECT (self))))
+ {
+ ide_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Not connected to object tree");
+ IDE_EXIT;
+ }
+
+ state = g_slice_new0 (Execute);
+ state->plan = g_object_ref (self->plan);
+ state->notif = notif ? g_object_ref (notif) : ide_notification_new ();
+ state->num_ops = execute_count_ops (self->plan);
+ state->builders = g_ptr_array_new_with_free_func ((GDestroyNotify)ide_object_unref_and_destroy);
+ state->cachedir = ide_context_cache_file (context, "code-index", NULL);
+ state->workdir = ide_context_ref_workdir (context);
+ state->pos = 0;
+ ide_task_set_task_data (task, state, execute_free);
+
+ ide_notification_set_has_progress (state->notif, TRUE);
+ ide_notification_set_progress (state->notif, 0.0);
+ ide_notification_set_progress_is_imprecise (state->notif, FALSE);
+
+ gbp_code_index_plan_foreach (self->plan,
+ gbp_code_index_executor_collect_cb,
+ task);
+
+ if (state->builders->len == 0)
+ {
+ ide_task_return_boolean (task, TRUE);
+ IDE_EXIT;
+ }
+
+ gbp_code_index_builder_run_async (g_ptr_array_index (state->builders, 0),
+ cancellable,
+ gbp_code_index_executor_run_cb,
+ g_steal_pointer (&task));
+
+ IDE_EXIT;
+}
+
+gboolean
+gbp_code_index_executor_execute_finish (GbpCodeIndexExecutor *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ gboolean ret;
+
+ IDE_ENTRY;
+
+ g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
+ g_return_val_if_fail (GBP_IS_CODE_INDEX_EXECUTOR (self), FALSE);
+ g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+ ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+ IDE_RETURN (ret);
+}
diff --git a/src/plugins/code-index/gbp-code-index-executor.h
b/src/plugins/code-index/gbp-code-index-executor.h
new file mode 100644
index 000000000..676d7b925
--- /dev/null
+++ b/src/plugins/code-index/gbp-code-index-executor.h
@@ -0,0 +1,43 @@
+/* gbp-code-index-executor.h
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+#include "gbp-code-index-plan.h"
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CODE_INDEX_EXECUTOR (gbp_code_index_executor_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCodeIndexExecutor, gbp_code_index_executor, GBP, CODE_INDEX_EXECUTOR, IdeObject)
+
+GbpCodeIndexExecutor *gbp_code_index_executor_new (GbpCodeIndexPlan *plan);
+void gbp_code_index_executor_execute_async (GbpCodeIndexExecutor *self,
+ IdeNotification *notif,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gbp_code_index_executor_execute_finish (GbpCodeIndexExecutor *self,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
diff --git a/src/plugins/code-index/gbp-code-index-plan.c b/src/plugins/code-index/gbp-code-index-plan.c
index 4193fa217..582a4bfd0 100644
--- a/src/plugins/code-index/gbp-code-index-plan.c
+++ b/src/plugins/code-index/gbp-code-index-plan.c
@@ -773,7 +773,7 @@ gbp_code_index_plan_load_flags_finish (GbpCodeIndexPlan *self,
}
GbpCodeIndexPlanItem *
-gbp_code_index_plan_copy (const GbpCodeIndexPlanItem *item)
+gbp_code_index_plan_item_copy (const GbpCodeIndexPlanItem *item)
{
GbpCodeIndexPlanItem *ret;
diff --git a/src/plugins/code-index/gbp-code-index-plan.h b/src/plugins/code-index/gbp-code-index-plan.h
index be5753d34..e90337cba 100644
--- a/src/plugins/code-index/gbp-code-index-plan.h
+++ b/src/plugins/code-index/gbp-code-index-plan.h
@@ -84,7 +84,7 @@ gboolean gbp_code_index_plan_load_flags_finish (GbpCodeIndexPlan
void gbp_code_index_plan_foreach (GbpCodeIndexPlan *self,
GbpCodeIndexPlanForeach foreach_func,
gpointer foreach_data);
-GbpCodeIndexPlanItem *gbp_code_index_plan_copy (const GbpCodeIndexPlanItem *item);
+GbpCodeIndexPlanItem *gbp_code_index_plan_item_copy (const GbpCodeIndexPlanItem *item);
void gbp_code_index_plan_item_free (GbpCodeIndexPlanItem *item);
G_END_DECLS
diff --git a/src/plugins/code-index/meson.build b/src/plugins/code-index/meson.build
index dc6ae2b40..c9d886823 100644
--- a/src/plugins/code-index/meson.build
+++ b/src/plugins/code-index/meson.build
@@ -3,6 +3,8 @@ if get_option('plugin_code_index')
plugins_sources += files([
'code-index-plugin.c',
'gbp-code-index-application-addin.c',
+ 'gbp-code-index-builder.c',
+ 'gbp-code-index-executor.c',
'gbp-code-index-plan.c',
'gbp-code-index-workbench-addin.c',
'ide-code-index-builder.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]