[gnome-builder/wip/large-project] git: cleanup git vcs implementation



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]