[gnome-builder/wip/chergert/git-oop: 5/5] wip on git callbacks



commit c323a71afa94ee272846b8e93688f962e3ad2024
Author: Christian Hergert <chergert redhat com>
Date:   Wed Mar 20 12:51:43 2019 -0700

    wip on git callbacks

 src/plugins/git/gbp-git-client.c           | 162 ++++++++++++++++++++++++-
 src/plugins/git/gbp-git-client.h           |   7 +-
 src/plugins/git/gbp-git-remote-callbacks.c | 185 ++---------------------------
 src/plugins/git/gbp-git-remote-callbacks.h |   7 +-
 src/plugins/git/gbp-git-vcs-cloner.c       |   2 +-
 src/plugins/git/gnome-builder-git.c        |   7 +-
 src/plugins/git/meson.build                |   3 +-
 7 files changed, 178 insertions(+), 195 deletions(-)
---
diff --git a/src/plugins/git/gbp-git-client.c b/src/plugins/git/gbp-git-client.c
index 018ffc481..7a15c0b88 100644
--- a/src/plugins/git/gbp-git-client.c
+++ b/src/plugins/git/gbp-git-client.c
@@ -22,6 +22,8 @@
 
 #include "config.h"
 
+#include <glib/gi18n.h>
+
 #include <gio/gunixinputstream.h>
 #include <gio/gunixoutputstream.h>
 #include <glib-unix.h>
@@ -38,6 +40,7 @@ struct _GbpGitClient
   JsonrpcClient            *rpc_client;
   GFile                    *root_uri;
   gint                      state;
+  GHashTable               *notif_by_token;
 };
 
 enum {
@@ -77,6 +80,62 @@ call_free (gpointer data)
   g_slice_free (Call, c);
 }
 
+static void
+gbp_git_client_notification_cb (GbpGitClient  *self,
+                                const gchar   *command,
+                                GVariant      *reply,
+                                JsonrpcClient *client)
+{
+  const gchar *token = NULL;
+  IdeNotification *notif;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_GIT_CLIENT (client));
+  g_assert (command != NULL);
+  g_assert (JSONRPC_IS_CLIENT (client));
+
+  if (reply == NULL)
+    return;
+
+  if (g_str_equal (command, "$/progress") &&
+      JSONRPC_MESSAGE_PARSE (reply, "token", JSONRPC_MESSAGE_GET_STRING (&token)) &&
+      (notif = g_hash_table_lookup (self->notif_by_token, token)))
+    {
+      gdouble progress;
+      const gchar *message;
+
+      if (!JSONRPC_MESSAGE_PARSE (reply, "progress", JSONRPC_MESSAGE_GET_DOUBLE (&progress)))
+        progress = 0.0;
+
+      if (!JSONRPC_MESSAGE_PARSE (reply, "message", JSONRPC_MESSAGE_GET_STRING (&message)))
+        message = NULL;
+
+      if (message != NULL)
+        ide_notification_set_body (notif, message);
+
+      if (progress > 0.0)
+        ide_notification_set_progress (notif, CLAMP (progress, 0.0, 1.0));
+    }
+}
+
+static gchar *
+gbp_git_client_track_progress (GbpGitClient    *self,
+                               IdeNotification *notif)
+{
+  g_autofree gchar *token = NULL;
+
+  g_assert (GBP_IS_GIT_CLIENT (self));
+  g_assert (IDE_IS_NOTIFICATION (notif));
+
+  if (self->notif_by_token == NULL)
+    self->notif_by_token = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+  token = g_uuid_string_random ();
+  g_hash_table_insert (self->notif_by_token, g_strdup (token), g_object_ref (notif));
+
+  return g_steal_pointer (&token);
+}
+
 static void
 gbp_git_client_subprocess_exited (GbpGitClient            *self,
                                   IdeSubprocess           *subprocess,
@@ -136,6 +195,12 @@ gbp_git_client_subprocess_spawned (GbpGitClient            *self,
   self->rpc_client = jsonrpc_client_new (stream);
   jsonrpc_client_set_use_gvariant (self->rpc_client, TRUE);
 
+  g_signal_connect_object (self->rpc_client,
+                           "notification",
+                           G_CALLBACK (gbp_git_client_notification_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
   queued = g_steal_pointer (&self->get_client.head);
 
   self->get_client.head = NULL;
@@ -160,10 +225,7 @@ gbp_git_client_subprocess_spawned (GbpGitClient            *self,
     "capabilities", "{", "}"
   );
 
-  jsonrpc_client_call_async (self->rpc_client,
-                             "initialize",
-                             params,
-                             NULL, NULL, NULL);
+  jsonrpc_client_call_async (self->rpc_client, "initialize", params, NULL, NULL, NULL);
 
   IDE_EXIT;
 }
@@ -319,6 +381,7 @@ gbp_git_client_finalize (GObject *object)
   g_clear_object (&self->rpc_client);
   g_clear_object (&self->root_uri);
   g_clear_object (&self->supervisor);
+  g_clear_pointer (&self->notif_by_token, g_hash_table_unref);
 
   g_assert (self->get_client.head == NULL);
   g_assert (self->get_client.tail == NULL);
@@ -588,3 +651,94 @@ gbp_git_client_is_ignored_finish (GbpGitClient  *self,
 
   return FALSE;
 }
+
+static void
+gbp_git_client_clone_url_cb (GObject      *object,
+                             GAsyncResult *result,
+                             gpointer      user_data)
+{
+  GbpGitClient *self = (GbpGitClient *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GVariant) reply = NULL;
+  g_autoptr(GError) error = NULL;
+  const gchar *token = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_GIT_CLIENT (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  if (!gbp_git_client_call_finish (self, result, &reply, &error))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_task_return_boolean (task, TRUE);
+
+  if ((token = ide_task_get_task_data (task)) && self->notif_by_token)
+    g_hash_table_remove (self->notif_by_token, token);
+}
+
+void
+gbp_git_client_clone_url_async (GbpGitClient        *self,
+                                const gchar         *url,
+                                GFile               *destination,
+                                const gchar         *branch,
+                                IdeNotification     *notif,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+  g_autoptr(GVariant) command = NULL;
+  g_autofree gchar *token = NULL;
+  g_autofree gchar *dest_uri = NULL;
+
+  g_return_if_fail (GBP_IS_GIT_CLIENT (self));
+  g_return_if_fail (url != NULL);
+  g_return_if_fail (G_IS_FILE (destination));
+  g_return_if_fail (!notif || IDE_IS_NOTIFICATION (notif));
+  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_git_client_clone_url_async);
+
+  if (notif != NULL)
+    {
+      token = gbp_git_client_track_progress (self, notif);
+      ide_notification_set_title (notif, _("Cloning Repository"));
+      ide_notification_set_icon_name (notif, "builder-vcs-git-symbolic");
+      ide_notification_set_progress (notif, 0.0);
+    }
+
+  if (branch == NULL)
+    branch = "master";
+
+  dest_uri = g_file_get_uri (destination);
+
+  command = JSONRPC_MESSAGE_NEW (
+    "token", JSONRPC_MESSAGE_PUT_STRING (token),
+    "url", JSONRPC_MESSAGE_PUT_STRING (url),
+    "destination", JSONRPC_MESSAGE_PUT_STRING (dest_uri),
+    "branch", JSONRPC_MESSAGE_PUT_STRING (branch)
+  );
+
+  if (token != NULL)
+    ide_task_set_task_data (task, g_strdup (token), g_free);
+
+  gbp_git_client_call_async (self,
+                             "git/cloneUrl",
+                             command,
+                             cancellable,
+                             gbp_git_client_clone_url_cb,
+                             g_steal_pointer (&task));
+}
+
+gboolean
+gbp_git_client_clone_url_finish (GbpGitClient  *self,
+                                 GAsyncResult  *result,
+                                 GError       **error)
+{
+  g_return_val_if_fail (GBP_IS_GIT_CLIENT (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/git/gbp-git-client.h b/src/plugins/git/gbp-git-client.h
index cb9cd2c53..299a2be64 100644
--- a/src/plugins/git/gbp-git-client.h
+++ b/src/plugins/git/gbp-git-client.h
@@ -82,10 +82,9 @@ gboolean      gbp_git_client_switch_branch_finish     (GbpGitClient           *s
                                                        GError                **error);
 void          gbp_git_client_clone_url_async          (GbpGitClient           *self,
                                                        const gchar            *url,
-                                                       GFile                   *destination,
-                                                       GFileProgressCallback   progress,
-                                                       gpointer                progress_data,
-                                                       GDestroyNotify          progress_notify,
+                                                       GFile                  *destination,
+                                                       const gchar            *branch,
+                                                       IdeNotification        *notif,
                                                        GCancellable           *cancellable,
                                                        GAsyncReadyCallback     callback,
                                                        gpointer                user_data);
diff --git a/src/plugins/git/gbp-git-remote-callbacks.c b/src/plugins/git/gbp-git-remote-callbacks.c
index 4bdb9b3e7..ea15e1f96 100644
--- a/src/plugins/git/gbp-git-remote-callbacks.c
+++ b/src/plugins/git/gbp-git-remote-callbacks.c
@@ -20,143 +20,25 @@
 
 #define G_LOG_DOMAIN "gbp-git-remote-callbacks"
 
-#include <dazzle.h>
 #include <glib/gi18n.h>
 
 #include "gbp-git-remote-callbacks.h"
 
-#define ANIMATION_DURATION_MSEC 250
-
 struct _GbpGitRemoteCallbacks
 {
-  GgitRemoteCallbacks    parent_instance;
-
-  GMutex                 mutex;
-  GString               *body;
-  gdouble                progress;
-  guint                  status_source;
-
-  /* bitflags of what we've tried */
-  GgitCredtype           tried;
-
-  guint                  cancelled : 1;
+  GgitRemoteCallbacks parent_instance;
+  GgitCredtype        tried;
+  guint               cancelled : 1;
 };
 
 G_DEFINE_TYPE (GbpGitRemoteCallbacks, gbp_git_remote_callbacks, GGIT_TYPE_REMOTE_CALLBACKS)
 
-enum {
-  STATUS,
-  N_SIGNALS
-};
-
-static guint signals [N_SIGNALS];
-
 GgitRemoteCallbacks *
 gbp_git_remote_callbacks_new (void)
 {
   return g_object_new (GBP_TYPE_GIT_REMOTE_CALLBACKS, NULL);
 }
 
-static gboolean
-gbp_git_remote_callbacks_do_emit_status (GbpGitRemoteCallbacks *self)
-{
-  g_autofree gchar *message = NULL;
-  gdouble progress = 0.0;
-
-  g_assert (GBP_IS_GIT_REMOTE_CALLBACKS (self));
-
-  g_mutex_lock (&self->mutex);
-
-  self->status_source = 0;
-
-  progress = self->progress;
-
-  if (self->body->len > 1)
-    {
-      const gchar *endptr;
-
-      endptr = &self->body->str[self->body->len - 1];
-
-      if (*endptr == '\n')
-        endptr--;
-
-      while (endptr >= self->body->str)
-        {
-          if (*endptr == '\n' || *endptr == '\r')
-            {
-              message = g_strdup (endptr + 1);
-              break;
-            }
-
-          endptr--;
-        }
-    }
-
-  g_mutex_unlock (&self->mutex);
-
-  g_signal_emit (self, signals [STATUS], 0, message, progress);
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-gbp_git_remote_callbacks_emit_status (GbpGitRemoteCallbacks *self)
-{
-  g_assert (GBP_IS_GIT_REMOTE_CALLBACKS (self));
-
-  g_mutex_lock (&self->mutex);
-  if (self->status_source == 0)
-    self->status_source = g_idle_add_full (G_PRIORITY_HIGH,
-                                           (GSourceFunc)gbp_git_remote_callbacks_do_emit_status,
-                                           g_object_ref (self),
-                                           g_object_unref);
-  g_mutex_unlock (&self->mutex);
-}
-
-static void
-gbp_git_remote_callbacks_real_progress (GgitRemoteCallbacks *callbacks,
-                                        const gchar         *message)
-{
-  GbpGitRemoteCallbacks *self = (GbpGitRemoteCallbacks *)callbacks;
-
-  g_assert (GBP_IS_GIT_REMOTE_CALLBACKS (self));
-
-  g_mutex_lock (&self->mutex);
-  if (self->body == NULL)
-    self->body = g_string_new (message);
-  else
-    g_string_append (self->body, message);
-  g_mutex_unlock (&self->mutex);
-
-  gbp_git_remote_callbacks_emit_status (self);
-}
-
-static void
-gbp_git_remote_callbacks_real_transfer_progress (GgitRemoteCallbacks  *callbacks,
-                                                 GgitTransferProgress *stats)
-{
-  GbpGitRemoteCallbacks *self = (GbpGitRemoteCallbacks *)callbacks;
-  guint total;
-  guint received;
-
-  g_assert (GBP_IS_GIT_REMOTE_CALLBACKS (self));
-  g_assert (stats != NULL);
-
-  if (self->cancelled)
-    return;
-
-  total = ggit_transfer_progress_get_total_objects (stats);
-  received = ggit_transfer_progress_get_received_objects (stats);
-  if (total == 0)
-    return;
-
-  g_mutex_lock (&self->mutex);
-  self->progress = (gdouble)received / (gdouble)total;
-  g_mutex_unlock (&self->mutex);
-
-  gbp_git_remote_callbacks_emit_status (self);
-}
-
 static GgitCred *
 gbp_git_remote_callbacks_real_credentials (GgitRemoteCallbacks  *callbacks,
                                            const gchar          *url,
@@ -167,12 +49,10 @@ gbp_git_remote_callbacks_real_credentials (GgitRemoteCallbacks  *callbacks,
   GbpGitRemoteCallbacks *self = (GbpGitRemoteCallbacks *)callbacks;
   GgitCred *ret = NULL;
 
-  IDE_ENTRY;
-
   g_assert (GBP_IS_GIT_REMOTE_CALLBACKS (self));
   g_assert (url != NULL);
 
-  IDE_TRACE_MSG ("username=%s url=%s", username_from_url ?: "", url);
+  g_debug ("username=%s url=%s", username_from_url ?: "", url);
 
   if (self->cancelled)
     {
@@ -180,7 +60,7 @@ gbp_git_remote_callbacks_real_credentials (GgitRemoteCallbacks  *callbacks,
                    G_IO_ERROR,
                    G_IO_ERROR_CANCELLED,
                    "The operation has been canceled");
-      IDE_RETURN (NULL);
+      return NULL;
     }
 
   allowed_types &= ~self->tried;
@@ -194,7 +74,7 @@ gbp_git_remote_callbacks_real_credentials (GgitRemoteCallbacks  *callbacks,
       self->tried |= GGIT_CREDTYPE_SSH_KEY;
 
       if (ret != NULL)
-        IDE_RETURN (ret);
+        return g_steal_pointer (&ret);
     }
 
   if ((allowed_types & GGIT_CREDTYPE_SSH_INTERACTIVE) != 0)
@@ -206,75 +86,28 @@ gbp_git_remote_callbacks_real_credentials (GgitRemoteCallbacks  *callbacks,
       self->tried |= GGIT_CREDTYPE_SSH_INTERACTIVE;
 
       if (ret != NULL)
-        IDE_RETURN (ret);
+        return g_steal_pointer (&ret);
     }
 
   g_set_error (error,
                G_IO_ERROR,
                G_IO_ERROR_NOT_SUPPORTED,
-               _("Builder failed to provide appropriate credentials when cloning repository."));
-
-  IDE_RETURN (NULL);
-}
-
-static void
-gbp_git_remote_callbacks_finalize (GObject *object)
-{
-  GbpGitRemoteCallbacks *self = (GbpGitRemoteCallbacks *)object;
+               _("Builder failed to provide appropriate credentials when cloning the repository."));
 
-  g_clear_object (&self->progress);
-
-  if (self->body != NULL)
-    {
-      g_string_free (self->body, TRUE);
-      self->body = NULL;
-    }
-
-  g_clear_handle_id (&self->status_source, g_source_remove);
-
-  g_mutex_clear (&self->mutex);
-
-  G_OBJECT_CLASS (gbp_git_remote_callbacks_parent_class)->finalize (object);
+  return NULL;
 }
 
 static void
 gbp_git_remote_callbacks_class_init (GbpGitRemoteCallbacksClass *klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GgitRemoteCallbacksClass *callbacks_class = GGIT_REMOTE_CALLBACKS_CLASS (klass);
 
-  object_class->finalize = gbp_git_remote_callbacks_finalize;
-
-  callbacks_class->transfer_progress = gbp_git_remote_callbacks_real_transfer_progress;
-  callbacks_class->progress = gbp_git_remote_callbacks_real_progress;
   callbacks_class->credentials = gbp_git_remote_callbacks_real_credentials;
-
-  /**
-   * GbpGitRemoteCallbacks::status:
-   * @self: a GbpGitRemoteCallbacks
-   * @message: the status message string
-   * @progress: the progress for the operation
-   *
-   * This signal is emitted when the progress or the status message changes
-   * for the operation.
-   *
-   * Since: 3.34
-   */
-  signals [STATUS] =
-    g_signal_new ("status",
-                  G_TYPE_FROM_CLASS (klass),
-                  G_SIGNAL_RUN_LAST,
-                  0, NULL, NULL, NULL,
-                  G_TYPE_NONE,
-                  2,
-                  G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
-                  G_TYPE_DOUBLE);
 }
 
 static void
 gbp_git_remote_callbacks_init (GbpGitRemoteCallbacks *self)
 {
-  g_mutex_init (&self->mutex);
 }
 
 /**
diff --git a/src/plugins/git/gbp-git-remote-callbacks.h b/src/plugins/git/gbp-git-remote-callbacks.h
index 7ddfbb51c..7af902519 100644
--- a/src/plugins/git/gbp-git-remote-callbacks.h
+++ b/src/plugins/git/gbp-git-remote-callbacks.h
@@ -21,7 +21,6 @@
 #pragma once
 
 #include <libgit2-glib/ggit.h>
-#include <libide-core.h>
 
 G_BEGIN_DECLS
 
@@ -29,9 +28,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GbpGitRemoteCallbacks, gbp_git_remote_callbacks, GBP, GIT_REMOTE_CALLBACKS, 
GgitRemoteCallbacks)
 
-GgitRemoteCallbacks *gbp_git_remote_callbacks_new          (void);
-gdouble              gbp_git_remote_callbacks_get_fraction (GbpGitRemoteCallbacks *self);
-IdeNotification     *gbp_git_remote_callbacks_get_progress (GbpGitRemoteCallbacks *self);
-void                 gbp_git_remote_callbacks_cancel       (GbpGitRemoteCallbacks *self);
+GgitRemoteCallbacks *gbp_git_remote_callbacks_new    (void);
+void                 gbp_git_remote_callbacks_cancel (GbpGitRemoteCallbacks *self);
 
 G_END_DECLS
diff --git a/src/plugins/git/gbp-git-vcs-cloner.c b/src/plugins/git/gbp-git-vcs-cloner.c
index 0a03b7b4c..4bcdc6a6f 100644
--- a/src/plugins/git/gbp-git-vcs-cloner.c
+++ b/src/plugins/git/gbp-git-vcs-cloner.c
@@ -172,7 +172,7 @@ gbp_git_vcs_cloner_worker (IdeTask      *task,
   g_assert (req != NULL);
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  callbacks = gbp_git_remote_callbacks_new (req->notif);
+  callbacks = gbp_git_remote_callbacks_new ();
 
   g_signal_connect_object (cancellable,
                            "cancelled",
diff --git a/src/plugins/git/gnome-builder-git.c b/src/plugins/git/gnome-builder-git.c
index 88a4fe735..76686d426 100644
--- a/src/plugins/git/gnome-builder-git.c
+++ b/src/plugins/git/gnome-builder-git.c
@@ -626,9 +626,8 @@ handle_clone_url (JsonrpcServer *server,
     "token", JSONRPC_MESSAGE_GET_STRING (&token)
   );
 
-  JSONRPC_MESSAGE_PARSE (params,
-    "branch", JSONRPC_MESSAGE_GET_STRING (&branch)
-  );
+  if (!JSONRPC_MESSAGE_PARSE (params, "branch", JSONRPC_MESSAGE_GET_STRING (&branch)))
+    branch = "master";
 
   if (!r || !(destination = g_file_new_for_uri (dest_uri)))
     {
@@ -659,7 +658,7 @@ handle_clone_url (JsonrpcServer *server,
 
   options = ggit_clone_options_new ();
   ggit_clone_options_set_is_bare (options, FALSE);
-  ggit_clone_options_set_checkout_branch (options, branch ? branch : "master");
+  ggit_clone_options_set_checkout_branch (options, branch);
   ggit_clone_options_set_fetch_options (options, fetch_options);
 
   gbp_git_clone_url_async (git,
diff --git a/src/plugins/git/meson.build b/src/plugins/git/meson.build
index a89cde277..6fcf0358d 100644
--- a/src/plugins/git/meson.build
+++ b/src/plugins/git/meson.build
@@ -21,8 +21,9 @@ plugins_sources += files([
 ])
 
 gnome_builder_git_sources = [
-  'gnome-builder-git.c',
   'gbp-git.c',
+  'gbp-git-remote-callbacks.c',
+  'gnome-builder-git.c',
 ]
 
 plugin_git_resources = gnome.compile_resources(


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]