[gnome-builder/wip/large-project] git: cleanup git vcs implementation
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/large-project] git: cleanup git vcs implementation
- Date: Mon, 15 Jun 2015 04:36:38 +0000 (UTC)
commit 6a27bb16df8d3f65db207f4ff53c8fbb94011094
Author: Christian Hergert <christian hergert me>
Date: Sun Jun 14 21:36:07 2015 -0700
git: cleanup git vcs implementation
We can do a lot of this synchronously now (in a thread) and no longer
need to load any tree information.
libide/git/ide-git-vcs.c | 433 +++-------------------------------------------
1 files changed, 27 insertions(+), 406 deletions(-)
---
diff --git a/libide/git/ide-git-vcs.c b/libide/git/ide-git-vcs.c
index b9448b6..f6e098a 100644
--- a/libide/git/ide-git-vcs.c
+++ b/libide/git/ide-git-vcs.c
@@ -39,6 +39,7 @@ struct _IdeGitVcs
GgitRepository *repository;
GgitRepository *change_monitor_repository;
+
GFile *working_directory;
GFileMonitor *monitor;
@@ -118,271 +119,33 @@ ide_git_vcs_get_buffer_change_monitor (IdeVcs *vcs,
NULL);
}
-static void
-ide_git_vcs_load_repository_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+static GgitRepository *
+ide_git_vcs_load (IdeGitVcs *self,
+ GError **error)
{
- GFile *project_file = task_data;
g_autoptr(GFile) location = NULL;
GgitRepository *repository = NULL;
- GError *error = NULL;
-
- g_assert (G_IS_TASK (task));
- g_assert (G_IS_FILE (project_file));
-
- location = ggit_repository_discover (project_file, &error);
-
- if (!location)
- {
- g_task_return_error (task, error);
- return;
- }
-
- repository = ggit_repository_open (location, &error);
-
- if (!repository)
- {
- g_task_return_error (task, error);
- return;
- }
-
- g_task_return_pointer (task, repository, g_object_unref);
-}
-
-static void
-ide_git_vcs_load_repository_async (IdeGitVcs *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_autoptr(GTask) task = NULL;
IdeContext *context;
GFile *project_file;
g_assert (IDE_IS_GIT_VCS (self));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
context = ide_object_get_context (IDE_OBJECT (self));
project_file = ide_context_get_project_file (context);
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_task_data (task, g_object_ref (project_file), g_object_unref);
- g_task_run_in_thread (task, ide_git_vcs_load_repository_worker);
-}
-
-static GgitRepository *
-ide_git_vcs_load_repository_finish (IdeGitVcs *self,
- GAsyncResult *result,
- GError **error)
-{
- GTask *task = (GTask *)result;
- GgitRepository *ret;
-
- g_assert (IDE_IS_GIT_VCS (self));
-
- ret = g_task_propagate_pointer (task, error);
-
- if (ret)
- {
- GFile *working_directory;
-
- working_directory = ggit_repository_get_workdir (ret);
- g_set_object (&self->working_directory, working_directory);
- }
-
- return ret;
-}
-
-static void
-ide_git_vcs_reload_index_add_path (IdeGitVcs *self,
- GHashTable *cache,
- const gchar *path,
- const gchar *workdir,
- gboolean is_directory)
-{
- IdeProjectItem *parent;
- IdeProjectItem *item;
- IdeContext *context;
- GFileInfo *file_info = NULL;
- GFile *file = NULL;
- g_autofree gchar *fullpath = NULL;
- gchar *dir;
- gchar *name;
-
- g_return_if_fail (IDE_IS_GIT_VCS (self));
- g_return_if_fail (cache);
- g_return_if_fail (path);
-
- context = ide_object_get_context (IDE_OBJECT (self));
-
- dir = g_path_get_dirname (path);
- name = g_path_get_basename (path);
-
- parent = g_hash_table_lookup (cache, dir);
-
- if (!parent)
- {
- ide_git_vcs_reload_index_add_path (self, cache, dir, workdir, TRUE);
- parent = g_hash_table_lookup (cache, dir);
- }
-
- g_assert (IDE_IS_PROJECT_ITEM (parent));
-
- file_info = g_file_info_new ();
- g_file_info_set_name (file_info, name);
- g_file_info_set_display_name (file_info, name);
-
- /*
- * TODO: We can probably extract some additional information from the
- * index such as symbolic link, etc.
- */
- if (is_directory)
- g_file_info_set_file_type (file_info, G_FILE_TYPE_DIRECTORY);
-
- fullpath = g_build_filename (workdir, path, NULL);
- file = g_file_new_for_path (fullpath);
-
- item = g_object_new (IDE_TYPE_PROJECT_FILE,
- "context", context,
- "file", file,
- "file-info", file_info,
- "parent", parent,
- "path", path,
- NULL);
- ide_project_item_append (parent, item);
+ if (!(location = ggit_repository_discover (project_file, error)))
+ return NULL;
- g_hash_table_insert (cache, g_strdup (path), g_object_ref (item));
-
- g_clear_object (&file);
- g_clear_object (&file_info);
- g_clear_object (&item);
- g_clear_pointer (&dir, g_free);
- g_clear_pointer (&name, g_free);
-}
-
-static void
-ide_git_vcs_build_tree_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- IdeGitVcs *self = source_object;
- GgitIndexEntries *entries = NULL;
- GgitRepository *repository = task_data;
- IdeProjectItem *root;
- IdeProjectItem *files = NULL;
- IdeContext *context;
- IdeProject *project;
- GgitIndex *index = NULL;
- GHashTable *cache = NULL;
- g_autofree gchar *workdir = NULL;
- g_autoptr(GFile) workdir_file = NULL;
- GError *error = NULL;
- guint count;
- guint i;
-
- g_assert (G_IS_TASK (task));
- g_assert (IDE_IS_GIT_VCS (self));
- g_assert (GGIT_IS_REPOSITORY (repository));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ if (!(repository = ggit_repository_open (location, error)))
+ return NULL;
- index = ggit_repository_get_index (repository, &error);
- if (!index)
- goto cleanup;
+ /* Only set once, on load. Not thread-safe otherwise. */
+ if (self->working_directory == NULL)
+ self->working_directory = ggit_repository_get_workdir (repository);
- entries = ggit_index_get_entries (index);
- if (!entries)
- goto cleanup;
-
- count = ggit_index_entries_size (entries);
- cache = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_object_unref);
-
- context = ide_object_get_context (IDE_OBJECT (self));
- project = ide_context_get_project (context);
-
- ide_project_reader_lock (project);
- root = ide_project_get_root (project);
- files = g_object_new (IDE_TYPE_PROJECT_FILES,
- "context", context,
- "parent", root,
- NULL);
- ide_project_reader_unlock (project);
-
- g_hash_table_insert (cache, g_strdup ("."), g_object_ref (files));
-
- workdir_file = ggit_repository_get_workdir (repository);
- workdir = g_file_get_path (workdir_file);
-
- for (i = 0; i < count; i++)
- {
- GgitIndexEntry *entry;
- const gchar *path;
-
- entry = ggit_index_entries_get_by_index (entries, i);
- path = ggit_index_entry_get_path (entry);
- ide_git_vcs_reload_index_add_path (self, cache, path, workdir, FALSE);
- ggit_index_entry_unref (entry);
- }
-
-cleanup:
- if (error)
- g_task_return_error (task, error);
- else
- g_task_return_pointer (task, g_object_ref (files), g_object_unref);
-
- g_clear_pointer (&cache, g_hash_table_unref);
- g_clear_pointer (&entries, ggit_index_entries_unref);
- g_clear_object (&files);
- g_clear_object (&index);
-}
-
-static void
-ide_git_vcs_build_tree_async (IdeGitVcs *self,
- GgitRepository *repository,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_autoptr(GTask) task = NULL;
-
- g_assert (IDE_IS_GIT_VCS (self));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_task_data (task, g_object_ref (repository), g_object_unref);
- g_task_run_in_thread (task, ide_git_vcs_build_tree_worker);
+ return repository;
}
-static IdeProjectFiles *
-ide_git_vcs_build_tree_finish (IdeGitVcs *self,
- GAsyncResult *result,
- GError **error)
-{
- GTask *task = (GTask *)result;
-
- g_return_val_if_fail (IDE_IS_GIT_VCS (self), NULL);
-
- return g_task_propagate_pointer (task, error);
-}
-
-static void
-ide_git_vcs__reload_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeGitVcs *self = (IdeGitVcs *)object;
- g_autoptr(GError) error = NULL;
-
- g_assert (IDE_IS_GIT_VCS (self));
-
- if (!ide_git_vcs_reload_finish (self, result, &error))
- g_message ("%s", error->message);
-}
-
-
static gboolean
ide_git_vcs__changed_timeout_cb (gpointer user_data)
{
@@ -393,7 +156,7 @@ ide_git_vcs__changed_timeout_cb (gpointer user_data)
g_assert (IDE_IS_GIT_VCS (self));
self->changed_timeout = 0;
- ide_git_vcs_reload_async (self, NULL, ide_git_vcs__reload_cb, NULL);
+ ide_git_vcs_reload_async (self, NULL, NULL, NULL);
IDE_RETURN (G_SOURCE_REMOVE);
}
@@ -456,31 +219,30 @@ ide_git_vcs_load_monitor (IdeGitVcs *self,
}
static void
-ide_git_vcs_reload__load_repository_cb3 (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+ide_git_vcs_reload_worker (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
{
- IdeGitVcs *self = (IdeGitVcs *)object;
- g_autoptr(GTask) task = user_data;
- GgitRepository *repository;
+ IdeGitVcs *self = source_object;
+ g_autoptr(GgitRepository) repository1 = NULL;
+ g_autoptr(GgitRepository) repository2 = NULL;
GError *error = NULL;
+ g_assert (G_IS_TASK (task));
g_assert (IDE_IS_GIT_VCS (self));
- g_assert (G_IS_ASYNC_RESULT (result));
-
- repository = ide_git_vcs_load_repository_finish (self, result, &error);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- if (!repository)
+ if (!(repository1 = ide_git_vcs_load (self, &error)) ||
+ !(repository2 = ide_git_vcs_load (self, &error)))
{
g_task_return_error (task, error);
return;
}
- g_set_object (&self->change_monitor_repository, repository);
+ g_set_object (&self->repository, repository1);
+ g_set_object (&self->change_monitor_repository, repository2);
- /*
- * Now finally, load the change monitor so that we can detect future changes.
- */
if (!ide_git_vcs_load_monitor (self, &error))
{
g_task_return_error (task, error);
@@ -491,131 +253,6 @@ ide_git_vcs_reload__load_repository_cb3 (GObject *object,
}
static void
-ide_git_vcs_reload__build_tree_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeGitVcs *self = (IdeGitVcs *)object;
- g_autoptr(GTask) task = user_data;
- g_autoptr(IdeProjectFiles) files = NULL;
- GError *error = NULL;
-
- g_assert (IDE_IS_GIT_VCS (self));
- g_assert (G_IS_TASK (task));
-
- files = ide_git_vcs_build_tree_finish (self, result, &error);
-
- if (!files)
- {
- g_task_return_error (task, error);
- return;
- }
-
- /*
- * XXX:
- *
- * This is a hack to only load the project files the first time. We need to do this for real
- * in the project tree to make appropriate events for tree changes.
- */
- if (!self->loaded_files)
- {
-#if 0
- IdeContext *context;
- IdeProject *project;
- IdeProjectItem *root;
-
- context = ide_object_get_context (IDE_OBJECT (self));
- project = ide_context_get_project (context);
-
- if (FALSE)
- {
- ide_project_writer_lock (project);
- root = ide_project_get_root (project);
- /* TODO: Replace existing item!!! */
- ide_project_item_append (root, IDE_PROJECT_ITEM (files));
- ide_project_writer_unlock (project);
- }
-#endif
- self->loaded_files = TRUE;
- }
-
- /*
- * Load the repository a third time for use by the threaded change monitors generating diffs.
- * I know it seems like a lot of loading, but it is a lot better than the N_FILES repositories
- * we had open previously.
- */
- ide_git_vcs_load_repository_async (self,
- g_task_get_cancellable (task),
- ide_git_vcs_reload__load_repository_cb3,
- g_object_ref (task));
-}
-
-static void
-ide_git_vcs_reload__load_repository_cb2 (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeGitVcs *self = (IdeGitVcs *)object;
- g_autoptr(GTask) task = user_data;
- GgitRepository *repository;
- GError *error = NULL;
-
- g_assert (IDE_IS_GIT_VCS (self));
- g_assert (G_IS_ASYNC_RESULT (result));
-
- repository = ide_git_vcs_load_repository_finish (self, result, &error);
-
- if (!repository)
- {
- g_task_return_error (task, error);
- return;
- }
-
- /*
- * Now go load the files for the project tree.
- */
- ide_git_vcs_build_tree_async (self,
- repository,
- g_task_get_cancellable (task),
- ide_git_vcs_reload__build_tree_cb,
- g_object_ref (task));
-
- g_clear_object (&repository);
-}
-
-static void
-ide_git_vcs_reload__load_repository_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeGitVcs *self = (IdeGitVcs *)object;
- g_autoptr(GTask) task = user_data;
- GgitRepository *repository;
- GError *error = NULL;
-
- g_assert (IDE_IS_GIT_VCS (self));
- g_assert (G_IS_ASYNC_RESULT (result));
-
- repository = ide_git_vcs_load_repository_finish (self, result, &error);
-
- if (!repository)
- {
- g_task_return_error (task, error);
- return;
- }
-
- g_set_object (&self->repository, repository);
-
- /*
- * Now load the repository again for use by the threaded index builder.
- */
- ide_git_vcs_load_repository_async (self,
- g_task_get_cancellable (task),
- ide_git_vcs_reload__load_repository_cb2,
- g_object_ref (task));
-}
-
-static void
ide_git_vcs_reload_async (IdeGitVcs *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -629,23 +266,7 @@ ide_git_vcs_reload_async (IdeGitVcs *self,
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
-
- if (self->reloading)
- {
- /*
- * Ignore if we are already reloading. We should probably set a bit here and attept to
- * reload again after the current process completes.
- */
- g_task_return_boolean (task, TRUE);
- IDE_EXIT;
- }
-
- self->reloading = TRUE;
-
- ide_git_vcs_load_repository_async (self,
- NULL,
- ide_git_vcs_reload__load_repository_cb,
- g_object_ref (task));
+ g_task_run_in_thread (task, ide_git_vcs_reload_worker);
IDE_EXIT;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]