[gnome-builder] git: port git plugin API to use gnome-builder-git daemon
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] git: port git plugin API to use gnome-builder-git daemon
- Date: Wed, 10 Apr 2019 07:37:26 +0000 (UTC)
commit 77363f3829aa746521670b11d0314e5885aa28d5
Author: Christian Hergert <chergert redhat com>
Date: Wed Apr 10 00:31:14 2019 -0700
git: port git plugin API to use gnome-builder-git daemon
This ports the various plugin API for Builder's git integration to use
the new gnome-builder-git daemon. The daemon is spawned and uses the
DBus marshalling format (without a DBus daemon) over STDIN/STDOUT pipes
to the subprocess.
The daemon itself manages most of the state now and allows for some
more threading from DBus proxies in the Builder code-base.
src/plugins/git/gbp-git-buffer-addin.c | 47 +-
src/plugins/git/gbp-git-buffer-change-monitor.c | 1036 ++++++-----------------
src/plugins/git/gbp-git-buffer-change-monitor.h | 24 +-
src/plugins/git/gbp-git-dependency-updater.c | 86 +-
src/plugins/git/gbp-git-vcs-cloner.c | 160 ++--
src/plugins/git/gbp-git-vcs-cloner.h | 2 +-
src/plugins/git/gbp-git-vcs-config.c | 194 ++---
src/plugins/git/gbp-git-vcs-config.h | 6 +-
src/plugins/git/gbp-git-vcs-initializer.c | 117 ++-
src/plugins/git/gbp-git-vcs-initializer.h | 2 +-
src/plugins/git/gbp-git-vcs.c | 954 ++++++++-------------
src/plugins/git/gbp-git-vcs.h | 16 +-
src/plugins/git/gbp-git-workbench-addin.c | 369 +++-----
src/plugins/git/gbp-git-workbench-addin.h | 2 +-
src/plugins/git/git-plugin.c | 76 +-
src/plugins/git/git.plugin | 2 +-
src/plugins/git/meson.build | 9 +-
17 files changed, 1055 insertions(+), 2047 deletions(-)
---
diff --git a/src/plugins/git/gbp-git-buffer-addin.c b/src/plugins/git/gbp-git-buffer-addin.c
index 274366e88..441256226 100644
--- a/src/plugins/git/gbp-git-buffer-addin.c
+++ b/src/plugins/git/gbp-git-buffer-addin.c
@@ -22,7 +22,6 @@
#include "config.h"
-#include <libgit2-glib/ggit.h>
#include <libide-vcs.h>
#include "gbp-git-buffer-addin.h"
@@ -31,8 +30,8 @@
struct _GbpGitBufferAddin
{
- GObject parent_instance;
- GbpGitBufferChangeMonitor *monitor;
+ GObject parent_instance;
+ IdeBufferChangeMonitor *monitor;
};
static void
@@ -41,9 +40,9 @@ gbp_git_buffer_addin_file_laoded (IdeBufferAddin *addin,
GFile *file)
{
GbpGitBufferAddin *self = (GbpGitBufferAddin *)addin;
- g_autoptr(GbpGitBufferChangeMonitor) monitor = NULL;
+ g_autoptr(IdeBufferChangeMonitor) monitor = NULL;
g_autoptr(IdeContext) context = NULL;
- GgitRepository *repository;
+ IpcGitRepository *repository;
IdeObjectBox *box;
IdeVcs *vcs;
@@ -51,38 +50,19 @@ gbp_git_buffer_addin_file_laoded (IdeBufferAddin *addin,
g_assert (IDE_IS_BUFFER (buffer));
g_assert (G_IS_FILE (file));
- context = ide_buffer_ref_context (buffer);
- vcs = ide_context_peek_child_typed (context, IDE_TYPE_VCS);
- if (!GBP_IS_GIT_VCS (vcs))
+ if (!(context = ide_buffer_ref_context (buffer)) ||
+ !(vcs = ide_context_peek_child_typed (context, IDE_TYPE_VCS)) ||
+ !GBP_IS_GIT_VCS (vcs) ||
+ !(repository = gbp_git_vcs_get_repository (GBP_GIT_VCS (vcs))) ||
+ !(monitor = gbp_git_buffer_change_monitor_new (buffer, repository, file, NULL, NULL)))
return;
- if (!(repository = gbp_git_vcs_get_repository (GBP_GIT_VCS (vcs))))
- return;
-
- self->monitor = g_object_new (GBP_TYPE_GIT_BUFFER_CHANGE_MONITOR,
- "buffer", buffer,
- "repository", repository,
- NULL);
+ ide_clear_and_destroy_object (&self->monitor);
+ self->monitor = g_steal_pointer (&monitor);
box = ide_object_box_from_object (G_OBJECT (buffer));
ide_object_append (IDE_OBJECT (box), IDE_OBJECT (self->monitor));
-
- ide_buffer_set_change_monitor (buffer, IDE_BUFFER_CHANGE_MONITOR (self->monitor));
-}
-
-static void
-gbp_git_buffer_addin_file_saved (IdeBufferAddin *addin,
- IdeBuffer *buffer,
- GFile *file)
-{
- GbpGitBufferAddin *self = (GbpGitBufferAddin *)addin;
-
- g_assert (GBP_IS_GIT_BUFFER_ADDIN (self));
- g_assert (IDE_IS_BUFFER (buffer));
- g_assert (G_IS_FILE (file));
-
- if (self->monitor != NULL)
- ide_buffer_change_monitor_reload (IDE_BUFFER_CHANGE_MONITOR (self->monitor));
+ ide_buffer_set_change_monitor (buffer, self->monitor);
}
static void
@@ -137,7 +117,7 @@ gbp_git_buffer_addin_settle_async (IdeBufferAddin *addin,
if (self->monitor == NULL)
ide_task_return_boolean (task, TRUE);
else
- gbp_git_buffer_change_monitor_wait_async (self->monitor,
+ gbp_git_buffer_change_monitor_wait_async (GBP_GIT_BUFFER_CHANGE_MONITOR (self->monitor),
cancellable,
gbp_git_buffer_addin_settle_cb,
g_steal_pointer (&task));
@@ -155,7 +135,6 @@ static void
buffer_addin_iface_init (IdeBufferAddinInterface *iface)
{
iface->file_loaded = gbp_git_buffer_addin_file_laoded;
- iface->file_saved = gbp_git_buffer_addin_file_saved;
iface->unload = gbp_git_buffer_addin_unload;
iface->settle_async = gbp_git_buffer_addin_settle_async;
iface->settle_finish = gbp_git_buffer_addin_settle_finish;
diff --git a/src/plugins/git/gbp-git-buffer-change-monitor.c b/src/plugins/git/gbp-git-buffer-change-monitor.c
index 72f3ce13f..5a92f7f6a 100644
--- a/src/plugins/git/gbp-git-buffer-change-monitor.c
+++ b/src/plugins/git/gbp-git-buffer-change-monitor.c
@@ -1,6 +1,6 @@
/* gbp-git-buffer-change-monitor.c
*
- * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ * Copyright 2015-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
@@ -18,508 +18,195 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
-/* Some code from this file is loosely based around the git-diff
- * plugin from Atom. Namely, API usage for iterating through hunks
- * containing changes. It's license is provided below.
- */
-
-/*
- * Copyright (c) 2014 GitHub Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
#define G_LOG_DOMAIN "gbp-git-buffer-change-monitor"
-#include <dazzle.h>
-#include <glib/gi18n.h>
-#include <libgit2-glib/ggit.h>
-#include <stdlib.h>
-
-#include "gbp-git-buffer-change-monitor.h"
-#include "gbp-git-vcs.h"
+#include "config.h"
-#include "line-cache.h"
+#include <dazzle.h>
+#include <string.h>
-#define DELAY_CHANGED_SEC 1
+#include "daemon/ipc-git-change-monitor.h"
+#include "daemon/line-cache.h"
-/**
- * SECTION:gbp-git-buffer-change-monitor
- *
- * This module provides line change monitoring when used in conjunction with an
- * GbpGitVcs. The changes are generated by comparing the buffer contents to
- * the version found inside of the git repository.
- *
- * To enable us to avoid blocking the main loop, the actual diff is performed
- * in a background thread. To avoid threading issues with the rest of LibGBP,
- * this module creates a copy of the loaded repository. A single thread will be
- * dispatched for the context and all reload tasks will be performed from that
- * thread.
- *
- * Upon completion of the diff, the results will be passed back to the primary
- * thread and the state updated for use by line change renderer in the source
- * view.
- *
- * Since: 3.32
- */
+#include "gbp-git-buffer-change-monitor.h"
struct _GbpGitBufferChangeMonitor
{
- IdeBufferChangeMonitor parent_instance;
-
- DzlSignalGroup *signal_group;
-
- GgitRepository *repository;
- GArray *lines;
-
- GgitBlob *cached_blob;
+ IdeBufferChangeMonitor parent;
+ IpcGitChangeMonitor *proxy;
+ DzlSignalGroup *buffer_signals;
LineCache *cache;
-
- GQueue wait_tasks;
-
- guint changed_timeout;
-
- guint state_dirty : 1;
- guint in_calculation : 1;
+ guint last_change_count;
+ guint queued_source;
guint delete_range_requires_recalculation : 1;
- guint is_child_of_workdir : 1;
- guint in_failed_state : 1;
};
-typedef struct
-{
- GgitRepository *repository;
- LineCache *cache;
- GFile *file;
- GBytes *content;
- GgitBlob *blob;
- IdeObject *lock_object;
- guint is_child_of_workdir : 1;
-} DiffTask;
-
-typedef struct
-{
- gint old_start;
- gint old_lines;
- gint new_start;
- gint new_lines;
-} Range;
+enum { SLOW, FAST };
+static const guint g_delay[] = { 750, 50 };
G_DEFINE_TYPE (GbpGitBufferChangeMonitor, gbp_git_buffer_change_monitor, IDE_TYPE_BUFFER_CHANGE_MONITOR)
-DZL_DEFINE_COUNTER (instances, "GbpGitBufferChangeMonitor", "Instances", "The number of git buffer change
monitor instances.");
-
-enum {
- PROP_0,
- PROP_REPOSITORY,
- LAST_PROP
-};
-
-static GParamSpec *properties [LAST_PROP];
-static GAsyncQueue *work_queue;
-static GThread *work_thread;
-
-static void
-diff_task_free (gpointer data)
-{
- DiffTask *diff = data;
-
- if (diff)
- {
- g_clear_object (&diff->file);
- g_clear_object (&diff->blob);
- g_clear_object (&diff->repository);
- g_clear_object (&diff->lock_object);
- g_clear_pointer (&diff->cache, line_cache_free);
- g_clear_pointer (&diff->content, g_bytes_unref);
- g_slice_free (DiffTask, diff);
- }
-}
-
-static void
-complete_wait_tasks (GbpGitBufferChangeMonitor *self,
- GParamSpec *pspec,
- IdeTask *calculate_task)
-{
- gpointer taskptr;
-
- g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (IDE_IS_TASK (calculate_task));
-
- while ((taskptr = g_queue_pop_head (&self->wait_tasks)))
- {
- g_autoptr(IdeTask) task = taskptr;
-
- ide_task_return_boolean (task, TRUE);
- }
-}
-
-static LineCache *
-gbp_git_buffer_change_monitor_calculate_finish (GbpGitBufferChangeMonitor *self,
- GAsyncResult *result,
- GError **error)
+static gboolean
+queued_update_source_cb (GbpGitBufferChangeMonitor *self)
{
- IdeTask *task = (IdeTask *)result;
- DiffTask *diff;
-
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (IDE_IS_TASK (result));
- if (ide_object_set_error_if_destroyed (IDE_OBJECT (self), error))
- return NULL;
-
- diff = ide_task_get_task_data (task);
-
- if (diff != NULL)
- {
- g_assert (GGIT_IS_REPOSITORY (diff->repository));
- g_assert (G_IS_FILE (diff->file));
- g_assert (diff->content != NULL);
- g_assert (GBP_IS_GIT_VCS (diff->lock_object));
-
- /* Keep the blob around for future use */
- if (diff->blob != self->cached_blob)
- g_set_object (&self->cached_blob, diff->blob);
+ self->queued_source = 0;
- /* If the file is a child of the working directory, we need to know */
- self->is_child_of_workdir = diff->is_child_of_workdir;
- }
+ gbp_git_buffer_change_monitor_wait_async (self, NULL, NULL, NULL);
- return ide_task_propagate_pointer (task, error);
+ return G_SOURCE_REMOVE;
}
static void
-gbp_git_buffer_change_monitor_calculate_async (GbpGitBufferChangeMonitor *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+gbp_git_buffer_change_monitor_queue_update (GbpGitBufferChangeMonitor *self,
+ gboolean fast)
{
- g_autoptr(IdeTask) task = NULL;
- g_autoptr(IdeContext) context = NULL;
- GbpGitVcs *vcs;
- IdeBuffer *buffer;
- DiffTask *diff;
- GFile *file;
+ guint delay;
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- g_assert (self->repository != NULL);
-
- self->state_dirty = FALSE;
-
- task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_source_tag (task, gbp_git_buffer_change_monitor_calculate_async);
-
- g_signal_connect_object (task,
- "notify::completed",
- G_CALLBACK (complete_wait_tasks),
- self,
- G_CONNECT_SWAPPED);
-
- buffer = ide_buffer_change_monitor_get_buffer (IDE_BUFFER_CHANGE_MONITOR (self));
- g_assert (IDE_IS_BUFFER (buffer));
-
- file = ide_buffer_get_file (buffer);
- g_assert (G_IS_FILE (file));
- context = ide_object_ref_context (IDE_OBJECT (self));
- vcs = ide_context_peek_child_typed (context, GBP_TYPE_GIT_VCS);
+ fast = !!fast;
- if (!GBP_IS_GIT_VCS (vcs))
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- "Cannot provide changes, not connected to GbpGitVcs.");
- return;
- }
-
- diff = g_slice_new0 (DiffTask);
- diff->file = g_object_ref (file);
- diff->repository = g_object_ref (self->repository);
- diff->cache = line_cache_new ();
- diff->content = ide_buffer_dup_content (buffer);
- diff->blob = self->cached_blob ? g_object_ref (self->cached_blob) : NULL;
- diff->lock_object = g_object_ref (IDE_OBJECT (vcs));
+ /* Re-use existing source if this is slow */
+ if (fast == SLOW && self->queued_source)
+ return;
- ide_task_set_task_data (task, diff, diff_task_free);
+ delay = g_delay[fast];
- self->in_calculation = TRUE;
+ g_clear_handle_id (&self->queued_source, g_source_remove);
- g_async_queue_push (work_queue, g_steal_pointer (&task));
+ self->queued_source =
+ gdk_threads_add_timeout_full (G_PRIORITY_HIGH,
+ delay,
+ (GSourceFunc) queued_update_source_cb,
+ g_object_ref (self),
+ g_object_unref);
}
static void
-foreach_cb (gpointer data,
- gpointer user_data)
-{
- const LineEntry *entry = data;
- struct {
- IdeBufferChangeMonitorForeachFunc func;
- gpointer user_data;
- } *state = user_data;
- IdeBufferLineChange change = 0;
-
- if (entry->mark & LINE_MARK_ADDED)
- change |= IDE_BUFFER_LINE_CHANGE_ADDED;
-
- if (entry->mark & LINE_MARK_REMOVED)
- change |= IDE_BUFFER_LINE_CHANGE_DELETED;
-
- if (entry->mark & LINE_MARK_PREVIOUS_REMOVED)
- change |= IDE_BUFFER_LINE_CHANGE_PREVIOUS_DELETED;
-
- if (entry->mark & LINE_MARK_CHANGED)
- change |= IDE_BUFFER_LINE_CHANGE_CHANGED;
-
- state->func (entry->line, change, state->user_data);
-}
-
-static void
-gbp_git_buffer_change_monitor_foreach_change (IdeBufferChangeMonitor *monitor,
- guint begin_line,
- guint end_line,
- IdeBufferChangeMonitorForeachFunc callback,
- gpointer user_data)
+gbp_git_buffer_change_monitor_destroy (IdeObject *object)
{
- GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
- struct {
- IdeBufferChangeMonitorForeachFunc func;
- gpointer user_data;
- } state = { callback, user_data };
-
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (callback != NULL);
-
- if (end_line == G_MAXUINT)
- end_line--;
+ GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)object;
- if (self->cache == NULL)
+ if (self->buffer_signals)
{
- /* If within working directory, synthesize line addition. */
- if (self->is_child_of_workdir)
- {
- for (guint i = begin_line; i < end_line; i++)
- callback (i, IDE_BUFFER_LINE_CHANGE_ADDED, user_data);
- }
-
- return;
+ dzl_signal_group_set_target (self->buffer_signals, NULL);
+ g_clear_object (&self->buffer_signals);
}
- line_cache_foreach_in_range (self->cache, begin_line, end_line, foreach_cb, &state);
-}
-
-static IdeBufferLineChange
-gbp_git_buffer_change_monitor_get_change (IdeBufferChangeMonitor *monitor,
- guint line)
-{
- GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
- guint mark;
-
- /* Don't imply changes we don't know are real, in the case that
- * we failed to communicate with git properly about the blob diff.
- */
- if (self->in_failed_state)
- return IDE_BUFFER_LINE_CHANGE_NONE;
-
- if (self->cache == NULL)
+ if (self->proxy != NULL)
{
- /* If within working directory, synthesize line addition. */
- if (self->is_child_of_workdir)
- return IDE_BUFFER_LINE_CHANGE_ADDED;
- return IDE_BUFFER_LINE_CHANGE_NONE;
+ ipc_git_change_monitor_call_close (self->proxy, NULL, NULL, NULL);
+ g_clear_object (&self->proxy);
}
- mark = line_cache_get_mark (self->cache, line + 1);
-
- if (mark & LINE_MARK_ADDED)
- return IDE_BUFFER_LINE_CHANGE_ADDED;
- else if (mark & LINE_MARK_REMOVED)
- return IDE_BUFFER_LINE_CHANGE_DELETED;
- else if (mark & LINE_MARK_CHANGED)
- return IDE_BUFFER_LINE_CHANGE_CHANGED;
- else
- return IDE_BUFFER_LINE_CHANGE_NONE;
-}
-
-void
-gbp_git_buffer_change_monitor_set_repository (GbpGitBufferChangeMonitor *self,
- GgitRepository *repository)
-{
- gboolean do_reload;
-
- g_return_if_fail (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_return_if_fail (GGIT_IS_REPOSITORY (repository));
-
- do_reload = self->repository != NULL && repository != NULL;
-
- if (g_set_object (&self->repository, repository))
- {
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_REPOSITORY]);
+ g_clear_pointer (&self->cache, line_cache_free);
+ g_clear_handle_id (&self->queued_source, g_source_remove);
- if (do_reload)
- ide_buffer_change_monitor_reload (IDE_BUFFER_CHANGE_MONITOR (self));
- }
+ IDE_OBJECT_CLASS (gbp_git_buffer_change_monitor_parent_class)->destroy (object);
}
static void
-gbp_git_buffer_change_monitor__calculate_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data_unused)
+gbp_git_buffer_change_monitor_load (IdeBufferChangeMonitor *monitor,
+ IdeBuffer *buffer)
{
- GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)object;
- LineCache *cache;
- g_autoptr(GError) error = NULL;
+ GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (user_data_unused == NULL);
-
- self->in_calculation = FALSE;
-
- cache = gbp_git_buffer_change_monitor_calculate_finish (self, result, &error);
-
- if (cache == NULL)
- {
- if (!self->in_failed_state && !g_error_matches (error, GGIT_ERROR, GGIT_ERROR_NOTFOUND))
- {
- ide_object_warning (self,
- /* translators: %s is replaced with the error string from git */
- _("There was a failure while calculating line changes from git. The exact
error was: %s"),
- error->message);
- self->in_failed_state = TRUE;
- }
- }
- else
- {
- g_clear_pointer (&self->cache, line_cache_free);
- self->cache = g_steal_pointer (&cache);
- self->in_failed_state = FALSE;
- }
-
- ide_buffer_change_monitor_emit_changed (IDE_BUFFER_CHANGE_MONITOR (self));
+ g_assert (IDE_IS_BUFFER (buffer));
- /* Recalculate if the buffer has changed since last request. */
- if (self->state_dirty)
- gbp_git_buffer_change_monitor_calculate_async (self,
- NULL,
- gbp_git_buffer_change_monitor__calculate_cb,
- NULL);
+ dzl_signal_group_set_target (self->buffer_signals, buffer);
+ gbp_git_buffer_change_monitor_queue_update (self, FAST);
}
static void
-gbp_git_buffer_change_monitor_recalculate (GbpGitBufferChangeMonitor *self)
+gbp_git_buffer_change_monitor_reload (IdeBufferChangeMonitor *monitor)
{
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
+ GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
- self->state_dirty = TRUE;
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- if (!self->in_calculation)
- gbp_git_buffer_change_monitor_calculate_async (self,
- NULL,
- gbp_git_buffer_change_monitor__calculate_cb,
- NULL);
+ gbp_git_buffer_change_monitor_queue_update (self, FAST);
}
static void
-gbp_git_buffer_change_monitor__buffer_delete_range_after_cb (GbpGitBufferChangeMonitor *self,
- GtkTextIter *begin,
- GtkTextIter *end,
- IdeBuffer *buffer)
+buffer_delete_range_after_cb (GbpGitBufferChangeMonitor *self,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ IdeBuffer *buffer)
{
- IDE_ENTRY;
-
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (begin);
- g_assert (end);
+ g_assert (begin != NULL);
+ g_assert (end != NULL);
g_assert (IDE_IS_BUFFER (buffer));
if (self->delete_range_requires_recalculation)
{
self->delete_range_requires_recalculation = FALSE;
- gbp_git_buffer_change_monitor_recalculate (self);
+ gbp_git_buffer_change_monitor_queue_update (self, FAST);
}
-
- IDE_EXIT;
}
static void
-gbp_git_buffer_change_monitor__buffer_delete_range_cb (GbpGitBufferChangeMonitor *self,
- GtkTextIter *begin,
- GtkTextIter *end,
- IdeBuffer *buffer)
+buffer_delete_range_cb (GbpGitBufferChangeMonitor *self,
+ GtkTextIter *begin,
+ GtkTextIter *end,
+ IdeBuffer *buffer)
{
- IdeBufferLineChange change;
-
- IDE_ENTRY;
+ guint begin_line;
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
g_assert (begin != NULL);
g_assert (end != NULL);
g_assert (IDE_IS_BUFFER (buffer));
+ begin_line = gtk_text_iter_get_line (begin);
+
/*
* We need to recalculate the diff when text is deleted if:
*
* 1) The range includes a newline.
* 2) The current line change is set to NONE.
*
- * Technically we need to do it on every change to be more correct, but that wastes a lot of
- * power. So instead, we'll be a bit lazy about it here and pick up the other changes on a much
- * more conservative timeout, generated by gbp_git_buffer_change_monitor__buffer_changed_cb().
+ * Technically we need to do it on every change to be more correct, but that
+ * wastes a lot of power. So instead, we'll be a bit lazy about it here and
+ * pick up the other changes on a much more conservative timeout, generated
+ * by gbp_git_buffer_change_monitor__buffer_changed_cb().
*/
- if (gtk_text_iter_get_line (begin) != gtk_text_iter_get_line (end))
+ if (begin_line != gtk_text_iter_get_line (end))
IDE_GOTO (recalculate);
- change = gbp_git_buffer_change_monitor_get_change (IDE_BUFFER_CHANGE_MONITOR (self),
- gtk_text_iter_get_line (begin));
- if (change == IDE_BUFFER_LINE_CHANGE_NONE)
+ if (self->cache == NULL || !line_cache_get_mark (self->cache, begin_line))
IDE_GOTO (recalculate);
- IDE_EXIT;
+ return;
recalculate:
/*
* We need to wait for the delete to occur, so mark it as necessary and let
- * gbp_git_buffer_change_monitor__buffer_delete_range_after_cb perform the operation.
+ * gbp_git_buffer_change_monitor__buffer_delete_range_after_cb perform the
+ * operation.
*/
self->delete_range_requires_recalculation = TRUE;
-
- IDE_EXIT;
}
static void
-gbp_git_buffer_change_monitor__buffer_insert_text_after_cb (GbpGitBufferChangeMonitor *self,
- GtkTextIter *location,
- gchar *text,
- gint len,
- IdeBuffer *buffer)
+buffer_insert_text_after_cb (GbpGitBufferChangeMonitor *self,
+ GtkTextIter *location,
+ gchar *text,
+ gint len,
+ IdeBuffer *buffer)
{
- IdeBufferLineChange change;
-
- IDE_ENTRY;
+ guint line;
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (location);
- g_assert (text);
+ g_assert (location != NULL);
+ g_assert (text != NULL);
g_assert (IDE_IS_BUFFER (buffer));
/*
@@ -528,426 +215,241 @@ gbp_git_buffer_change_monitor__buffer_insert_text_after_cb (GbpGitBufferChangeMo
* 1) A newline is included in the text.
* 2) The line currently has flags of NONE.
*
- * Technically we need to do it on every change to be more correct, but that wastes a lot of
- * power. So instead, we'll be a bit lazy about it here and pick up the other changes on a much
- * more conservative timeout, generated by gbp_git_buffer_change_monitor__buffer_changed_cb().
+ * Technically we need to do it on every change to be more correct, but that
+ * wastes a lot of power. So instead, we'll be a bit lazy about it here and
+ * pick up the other changes on a much more conservative timeout
*/
- if (NULL != memmem (text, len, "\n", 1))
- IDE_GOTO (recalculate);
-
- change = gbp_git_buffer_change_monitor_get_change (IDE_BUFFER_CHANGE_MONITOR (self),
- gtk_text_iter_get_line (location));
- if (change == IDE_BUFFER_LINE_CHANGE_NONE)
- IDE_GOTO (recalculate);
+ line = gtk_text_iter_get_line (location);
- IDE_EXIT;
-
-recalculate:
- gbp_git_buffer_change_monitor_recalculate (self);
-
- IDE_EXIT;
+ if (self->cache == NULL ||
+ NULL != memmem (text, len, "\n", 1) ||
+ !line_cache_get_mark (self->cache, line))
+ gbp_git_buffer_change_monitor_queue_update (self, FAST);
}
-static gboolean
-gbp_git_buffer_change_monitor__changed_timeout_cb (gpointer user_data)
+static void
+buffer_changed_after_cb (GbpGitBufferChangeMonitor *self,
+ IdeBuffer *buffer)
{
- GbpGitBufferChangeMonitor *self = user_data;
-
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
-
- self->changed_timeout = 0;
- gbp_git_buffer_change_monitor_recalculate (self);
+ g_assert (IDE_IS_BUFFER_CHANGE_MONITOR (self));
+ g_assert (IDE_IS_BUFFER (buffer));
- return G_SOURCE_REMOVE;
+ gbp_git_buffer_change_monitor_queue_update (self, SLOW);
}
static void
-gbp_git_buffer_change_monitor__buffer_changed_after_cb (GbpGitBufferChangeMonitor *self,
- IdeBuffer *buffer)
+foreach_cb (gpointer data,
+ gpointer user_data)
{
- g_assert (IDE_IS_BUFFER_CHANGE_MONITOR (self));
- g_assert (IDE_IS_BUFFER (buffer));
+ const LineEntry *entry = data;
+ struct {
+ IdeBufferChangeMonitorForeachFunc func;
+ gpointer user_data;
+ } *state = user_data;
+ IdeBufferLineChange change = 0;
- self->state_dirty = TRUE;
+ if (entry->mark & LINE_MARK_ADDED)
+ change |= IDE_BUFFER_LINE_CHANGE_ADDED;
- if (self->in_calculation)
- return;
+ if (entry->mark & LINE_MARK_REMOVED)
+ change |= IDE_BUFFER_LINE_CHANGE_DELETED;
+
+ if (entry->mark & LINE_MARK_PREVIOUS_REMOVED)
+ change |= IDE_BUFFER_LINE_CHANGE_PREVIOUS_DELETED;
+
+ if (entry->mark & LINE_MARK_CHANGED)
+ change |= IDE_BUFFER_LINE_CHANGE_CHANGED;
- dzl_clear_source (&self->changed_timeout);
- self->changed_timeout = g_timeout_add_seconds (DELAY_CHANGED_SEC,
- gbp_git_buffer_change_monitor__changed_timeout_cb,
- self);
+ state->func (entry->line, change, state->user_data);
}
static void
-gbp_git_buffer_change_monitor_reload (IdeBufferChangeMonitor *monitor)
+gbp_git_buffer_change_monitor_foreach_change (IdeBufferChangeMonitor *monitor,
+ guint begin_line,
+ guint end_line,
+ IdeBufferChangeMonitorForeachFunc callback,
+ gpointer user_data)
{
GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
-
- IDE_ENTRY;
+ struct {
+ IdeBufferChangeMonitorForeachFunc func;
+ gpointer user_data;
+ } state = { callback, user_data };
g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
+ g_assert (callback != NULL);
- g_clear_object (&self->cached_blob);
- gbp_git_buffer_change_monitor_recalculate (self);
+ if (end_line == G_MAXUINT)
+ end_line--;
- IDE_EXIT;
+ if (self->cache == NULL)
+ {
+ for (guint i = begin_line; i < end_line; i++)
+ callback (i, IDE_BUFFER_LINE_CHANGE_ADDED, user_data);
+ return;
+ }
+
+ line_cache_foreach_in_range (self->cache, begin_line, end_line, foreach_cb, &state);
}
-static void
-gbp_git_buffer_change_monitor_load (IdeBufferChangeMonitor *monitor,
- IdeBuffer *buffer)
+static IdeBufferLineChange
+gbp_git_buffer_change_monitor_get_change (IdeBufferChangeMonitor *monitor,
+ guint line)
{
GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)monitor;
+ guint mark;
- IDE_ENTRY;
+ g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_return_if_fail (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_return_if_fail (IDE_IS_BUFFER (buffer));
+ if (self->cache == NULL)
+ return IDE_BUFFER_LINE_CHANGE_ADDED;
- dzl_signal_group_set_target (self->signal_group, buffer);
+ mark = line_cache_get_mark (self->cache, line + 1);
- IDE_EXIT;
+ if (mark & LINE_MARK_ADDED)
+ return IDE_BUFFER_LINE_CHANGE_ADDED;
+ else if (mark & LINE_MARK_REMOVED)
+ return IDE_BUFFER_LINE_CHANGE_DELETED;
+ else if (mark & LINE_MARK_CHANGED)
+ return IDE_BUFFER_LINE_CHANGE_CHANGED;
+ else
+ return IDE_BUFFER_LINE_CHANGE_NONE;
}
-static gint
-diff_hunk_cb (GgitDiffDelta *delta,
- GgitDiffHunk *hunk,
- gpointer user_data)
+static void
+gbp_git_buffer_change_monitor_class_init (GbpGitBufferChangeMonitorClass *klass)
{
- GArray *ranges = user_data;
- Range range;
+ IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
+ IdeBufferChangeMonitorClass *monitor_class = IDE_BUFFER_CHANGE_MONITOR_CLASS (klass);
- g_assert (delta != NULL);
- g_assert (hunk != NULL);
- g_assert (ranges != NULL);
+ monitor_class->load = gbp_git_buffer_change_monitor_load;
+ monitor_class->reload = gbp_git_buffer_change_monitor_reload;
+ monitor_class->get_change = gbp_git_buffer_change_monitor_get_change;
+ monitor_class->foreach_change = gbp_git_buffer_change_monitor_foreach_change;
- range.old_start = ggit_diff_hunk_get_old_start (hunk);
- range.old_lines = ggit_diff_hunk_get_old_lines (hunk);
- range.new_start = ggit_diff_hunk_get_new_start (hunk);
- range.new_lines = ggit_diff_hunk_get_new_lines (hunk);
+ i_object_class->destroy = gbp_git_buffer_change_monitor_destroy;
+}
- g_array_append_val (ranges, range);
+static void
+gbp_git_buffer_change_monitor_init (GbpGitBufferChangeMonitor *self)
+{
+ self->buffer_signals = dzl_signal_group_new (IDE_TYPE_BUFFER);
- return 0;
+ dzl_signal_group_connect_object (self->buffer_signals,
+ "insert-text",
+ G_CALLBACK (buffer_insert_text_after_cb),
+ self,
+ G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+ dzl_signal_group_connect_object (self->buffer_signals,
+ "delete-range",
+ G_CALLBACK (buffer_delete_range_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ dzl_signal_group_connect_object (self->buffer_signals,
+ "delete-range",
+ G_CALLBACK (buffer_delete_range_after_cb),
+ self,
+ G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+ dzl_signal_group_connect_object (self->buffer_signals,
+ "changed",
+ G_CALLBACK (buffer_changed_after_cb),
+ self,
+ G_CONNECT_SWAPPED | G_CONNECT_AFTER);
}
-static gboolean
-gbp_git_buffer_change_monitor_calculate_threaded (GbpGitBufferChangeMonitor *self,
- DiffTask *diff,
- GError **error)
+IdeBufferChangeMonitor *
+gbp_git_buffer_change_monitor_new (IdeBuffer *buffer,
+ IpcGitRepository *repository,
+ GFile *file,
+ GCancellable *cancellable,
+ GError **error)
{
- g_autofree gchar *relative_path = NULL;
- g_autoptr(GgitDiffOptions) options = NULL;
+ GbpGitBufferChangeMonitor *ret;
+ g_autoptr(IpcGitChangeMonitor) proxy = NULL;
+ g_autoptr(IdeContext) context = NULL;
g_autoptr(GFile) workdir = NULL;
- g_autoptr(GArray) ranges = NULL;
- LineCache *cache;
- const guint8 *data;
- gsize data_len = 0;
+ g_autofree gchar *relative_path = NULL;
+ g_autofree gchar *obj_path = NULL;
+ GDBusConnection *connection;
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
- g_assert (diff != NULL);
- g_assert (G_IS_FILE (diff->file));
- g_assert (diff->cache != NULL);
- g_assert (GGIT_IS_REPOSITORY (diff->repository));
- g_assert (diff->content != NULL);
- g_assert (!diff->blob || GGIT_IS_BLOB (diff->blob));
- g_assert (error != NULL);
- g_assert (*error == NULL);
-
- workdir = ggit_repository_get_workdir (diff->repository);
-
- if (!workdir)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_FILENAME,
- _("Repository does not have a working directory."));
- return FALSE;
- }
+ g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+ g_return_val_if_fail (IDE_IS_BUFFER (buffer), NULL);
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
- relative_path = g_file_get_relative_path (workdir, diff->file);
+ context = ide_buffer_ref_context (buffer);
+ workdir = ide_context_ref_workdir (context);
- if (!relative_path)
+ if (!g_file_has_prefix (file, workdir))
{
g_set_error (error,
G_IO_ERROR,
- G_IO_ERROR_INVALID_FILENAME,
- _("File is not under control of git working directory."));
- return FALSE;
- }
-
- diff->is_child_of_workdir = TRUE;
-
- /*
- * Find the blob if necessary. This will be cached by the main thread for
- * us on the way out of the async operation.
- */
- if (diff->blob == NULL)
- {
- GgitOId *entry_oid = NULL;
- GgitOId *oid = NULL;
- GgitObject *blob = NULL;
- GgitObject *commit = NULL;
- GgitRef *head = NULL;
- GgitTree *tree = NULL;
- GgitTreeEntry *entry = NULL;
-
- head = ggit_repository_get_head (diff->repository, error);
- if (!head)
- goto cleanup;
-
- oid = ggit_ref_get_target (head);
- if (!oid)
- goto cleanup;
-
- commit = ggit_repository_lookup (diff->repository, oid, GGIT_TYPE_COMMIT, error);
- if (!commit)
- goto cleanup;
-
- tree = ggit_commit_get_tree (GGIT_COMMIT (commit));
- if (!tree)
- goto cleanup;
-
- entry = ggit_tree_get_by_path (tree, relative_path, error);
- if (!entry)
- goto cleanup;
-
- entry_oid = ggit_tree_entry_get_id (entry);
- if (!entry_oid)
- goto cleanup;
-
- blob = ggit_repository_lookup (diff->repository, entry_oid, GGIT_TYPE_BLOB, error);
- if (!blob)
- goto cleanup;
-
- diff->blob = g_object_ref (GGIT_BLOB (blob));
-
- cleanup:
- g_clear_object (&blob);
- g_clear_pointer (&entry_oid, ggit_oid_free);
- g_clear_pointer (&entry, ggit_tree_entry_unref);
- g_clear_object (&tree);
- g_clear_object (&commit);
- g_clear_pointer (&oid, ggit_oid_free);
- g_clear_object (&head);
- }
-
- if (diff->blob == NULL)
- {
- if (*error == NULL)
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_NOT_FOUND,
- _("The requested file does not exist within the git index."));
- return FALSE;
+ G_IO_ERROR_NOT_SUPPORTED,
+ "Cannot monitor files outside the working directory");
+ return NULL;
}
- data = g_bytes_get_data (diff->content, &data_len);
+ relative_path = g_file_get_relative_path (workdir, file);
- ranges = g_array_new (FALSE, FALSE, sizeof (Range));
- options = ggit_diff_options_new ();
-
- ggit_diff_options_set_n_context_lines (options, 0);
-
- ggit_diff_blob_to_buffer (diff->blob,
- relative_path,
- data,
- data_len,
- relative_path,
- options,
- NULL, /* File Callback */
- NULL, /* Binary Callback */
- diff_hunk_cb, /* Hunk Callback */
- NULL,
- ranges,
- error);
-
- cache = diff->cache;
-
- for (guint i = 0; i < ranges->len; i++)
- {
- const Range *range = &g_array_index (ranges, Range, i);
- gint start_line = range->new_start - 1;
- gint end_line = range->new_start + range->new_lines - 1;
-
- if (range->old_lines == 0 && range->new_lines > 0)
- {
- line_cache_mark_range (cache, start_line, end_line, LINE_MARK_ADDED);
- }
- else if (range->new_lines == 0 && range->old_lines > 0)
- {
- if (start_line < 0)
- line_cache_mark_range (cache, 0, 0, LINE_MARK_PREVIOUS_REMOVED);
- else
- line_cache_mark_range (cache, start_line + 1, start_line + 1, LINE_MARK_REMOVED);
- }
- else
- {
- line_cache_mark_range (cache, start_line, end_line, LINE_MARK_CHANGED);
- }
- }
-
- return *error == NULL;
-}
-
-static gpointer
-gbp_git_buffer_change_monitor_worker (gpointer data)
-{
- GAsyncQueue *queue = data;
- gpointer taskptr;
+ if (!ipc_git_repository_call_create_change_monitor_sync (repository,
+ relative_path,
+ &obj_path,
+ cancellable,
+ error))
+ return NULL;
- g_assert (queue != NULL);
+ connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (repository));
- /*
- * This is a single thread worker that dispatches the particular
- * change to the given change monitor. We require a single thread
- * so that we can mantain the invariant that only a single thread
- * can access a GgitRepository at a time (and change monitors all
- * share the same GgitRepository amongst themselves).
- */
+ if (!(proxy = ipc_git_change_monitor_proxy_new_sync (connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ obj_path,
+ cancellable,
+ error)))
+ return NULL;
- while ((taskptr = g_async_queue_pop (queue)))
- {
- GbpGitBufferChangeMonitor *self;
- g_autoptr(GError) error = NULL;
- g_autoptr(IdeTask) task = taskptr;
- DiffTask *diff;
- gboolean ret;
-
- self = ide_task_get_source_object (task);
- g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
-
- diff = ide_task_get_task_data (task);
- g_assert (diff != NULL);
-
- /* Acquire the lock for the parent to ensure we have access to repository */
- ide_object_lock (diff->lock_object);
- ret = gbp_git_buffer_change_monitor_calculate_threaded (self, diff, &error);
- ide_object_unlock (diff->lock_object);
-
- if (!ret)
- ide_task_return_error (task, g_steal_pointer (&error));
- else
- ide_task_return_pointer (task,
- g_steal_pointer (&diff->cache),
- line_cache_free);
- }
+ ret = g_object_new (GBP_TYPE_GIT_BUFFER_CHANGE_MONITOR,
+ "buffer", buffer,
+ NULL);
+ ret->proxy = g_steal_pointer (&proxy);
- return NULL;
+ return IDE_BUFFER_CHANGE_MONITOR (g_steal_pointer (&ret));
}
static void
-gbp_git_buffer_change_monitor_destroy (IdeObject *object)
+gbp_git_buffer_change_monitor_wait_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GbpGitBufferChangeMonitor *self = (GbpGitBufferChangeMonitor *)object;
+ IpcGitChangeMonitor *proxy = (IpcGitChangeMonitor *)object;
+ g_autoptr(GVariant) changes = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ GbpGitBufferChangeMonitor *self;
- dzl_clear_source (&self->changed_timeout);
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IPC_IS_GIT_CHANGE_MONITOR (proxy));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
- if (self->signal_group)
+ if (!ipc_git_change_monitor_call_list_changes_finish (proxy, &changes, result, &error))
{
- dzl_signal_group_set_target (self->signal_group, NULL);
- g_clear_object (&self->signal_group);
+ ide_task_return_error (task, g_steal_pointer (&error));
+ return;
}
- g_clear_object (&self->cached_blob);
- g_clear_object (&self->repository);
- g_clear_pointer (&self->cache, line_cache_free);
+ self = ide_task_get_source_object (task);
- IDE_OBJECT_CLASS (gbp_git_buffer_change_monitor_parent_class)->destroy (object);
-}
-
-static void
-gbp_git_buffer_change_monitor_finalize (GObject *object)
-{
- G_OBJECT_CLASS (gbp_git_buffer_change_monitor_parent_class)->finalize (object);
-
- DZL_COUNTER_DEC (instances);
-}
-
-static void
-gbp_git_buffer_change_monitor_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GbpGitBufferChangeMonitor *self = GBP_GIT_BUFFER_CHANGE_MONITOR (object);
-
- switch (prop_id)
+ if (changes != NULL)
{
- case PROP_REPOSITORY:
- gbp_git_buffer_change_monitor_set_repository (self, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ g_clear_pointer (&self->cache, line_cache_free);
+ self->cache = line_cache_new_from_variant (changes);
}
-}
-
-static void
-gbp_git_buffer_change_monitor_class_init (GbpGitBufferChangeMonitorClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
- IdeBufferChangeMonitorClass *parent_class = IDE_BUFFER_CHANGE_MONITOR_CLASS (klass);
- object_class->finalize = gbp_git_buffer_change_monitor_finalize;
- object_class->set_property = gbp_git_buffer_change_monitor_set_property;
-
- i_object_class->destroy = gbp_git_buffer_change_monitor_destroy;
-
- parent_class->load = gbp_git_buffer_change_monitor_load;
- parent_class->get_change = gbp_git_buffer_change_monitor_get_change;
- parent_class->reload = gbp_git_buffer_change_monitor_reload;
- parent_class->foreach_change = gbp_git_buffer_change_monitor_foreach_change;
-
- properties [PROP_REPOSITORY] =
- g_param_spec_object ("repository",
- "Repository",
- "The repository to use for calculating diffs.",
- GGIT_TYPE_REPOSITORY,
- (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, LAST_PROP, properties);
-
- /* Note: We use a single worker thread so that we can maintain the
- * invariant that only a single thread is touching the GgitRepository
- * at a time. (Also, you can only type in one editor at a time, so
- * on worker thread for interactive blob changes is fine.
- */
- work_queue = g_async_queue_new ();
- work_thread = g_thread_new ("GbpGitBufferChangeMonitorWorker",
- gbp_git_buffer_change_monitor_worker,
- work_queue);
-}
-
-static void
-gbp_git_buffer_change_monitor_init (GbpGitBufferChangeMonitor *self)
-{
- DZL_COUNTER_INC (instances);
+ ide_buffer_change_monitor_emit_changed (IDE_BUFFER_CHANGE_MONITOR (self));
- self->signal_group = dzl_signal_group_new (IDE_TYPE_BUFFER);
- dzl_signal_group_connect_object (self->signal_group,
- "insert-text",
- G_CALLBACK (gbp_git_buffer_change_monitor__buffer_insert_text_after_cb),
- self,
- G_CONNECT_SWAPPED | G_CONNECT_AFTER);
- dzl_signal_group_connect_object (self->signal_group,
- "delete-range",
- G_CALLBACK (gbp_git_buffer_change_monitor__buffer_delete_range_cb),
- self,
- G_CONNECT_SWAPPED);
- dzl_signal_group_connect_object (self->signal_group,
- "delete-range",
- G_CALLBACK (gbp_git_buffer_change_monitor__buffer_delete_range_after_cb),
- self,
- G_CONNECT_SWAPPED | G_CONNECT_AFTER);
- dzl_signal_group_connect_object (self->signal_group,
- "changed",
- G_CALLBACK (gbp_git_buffer_change_monitor__buffer_changed_after_cb),
- self,
- G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+ ide_task_return_boolean (task, TRUE);
}
void
@@ -957,6 +459,8 @@ gbp_git_buffer_change_monitor_wait_async (GbpGitBufferChangeMonitor *self,
gpointer user_data)
{
g_autoptr(IdeTask) task = NULL;
+ IdeBuffer *buffer;
+ guint change_count;
g_return_if_fail (IDE_IS_MAIN_THREAD ());
g_return_if_fail (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
@@ -965,16 +469,29 @@ gbp_git_buffer_change_monitor_wait_async (GbpGitBufferChangeMonitor *self,
task = ide_task_new (self, cancellable, callback, user_data);
ide_task_set_source_tag (task, gbp_git_buffer_change_monitor_wait_async);
- if (!self->state_dirty && !self->in_calculation)
+ if (ide_task_return_error_if_cancelled (task))
+ return;
+
+ buffer = ide_buffer_change_monitor_get_buffer (IDE_BUFFER_CHANGE_MONITOR (self));
+ change_count = ide_buffer_get_change_count (buffer);
+
+ /* Update the peer of buffer contents immediately in-case it does
+ * not yet have teh newest version.
+ */
+ if (change_count != self->last_change_count)
{
- ide_task_return_boolean (task, TRUE);
- return;
- }
+ g_autoptr(GBytes) bytes = ide_buffer_dup_content (buffer);
- g_queue_push_tail (&self->wait_tasks, g_steal_pointer (&task));
+ self->last_change_count = change_count;
+ ipc_git_change_monitor_call_update_content (self->proxy,
+ (const gchar *)g_bytes_get_data (bytes, NULL),
+ NULL, NULL, NULL);
+ }
- if (!self->in_calculation)
- gbp_git_buffer_change_monitor_recalculate (self);
+ ipc_git_change_monitor_call_list_changes (self->proxy,
+ cancellable,
+ gbp_git_buffer_change_monitor_wait_cb,
+ g_steal_pointer (&task));
}
gboolean
@@ -984,7 +501,6 @@ gbp_git_buffer_change_monitor_wait_finish (GbpGitBufferChangeMonitor *self,
{
g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
g_return_val_if_fail (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (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-buffer-change-monitor.h b/src/plugins/git/gbp-git-buffer-change-monitor.h
index c5e620d7d..2d0e6b921 100644
--- a/src/plugins/git/gbp-git-buffer-change-monitor.h
+++ b/src/plugins/git/gbp-git-buffer-change-monitor.h
@@ -20,23 +20,27 @@
#pragma once
-#include <libgit2-glib/ggit.h>
#include <libide-code.h>
+#include "daemon/ipc-git-repository.h"
+
G_BEGIN_DECLS
#define GBP_TYPE_GIT_BUFFER_CHANGE_MONITOR (gbp_git_buffer_change_monitor_get_type())
G_DECLARE_FINAL_TYPE (GbpGitBufferChangeMonitor, gbp_git_buffer_change_monitor, GBP,
GIT_BUFFER_CHANGE_MONITOR, IdeBufferChangeMonitor)
-void gbp_git_buffer_change_monitor_set_repository (GbpGitBufferChangeMonitor *self,
- GgitRepository *repository);
-void gbp_git_buffer_change_monitor_wait_async (GbpGitBufferChangeMonitor *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean gbp_git_buffer_change_monitor_wait_finish (GbpGitBufferChangeMonitor *self,
- GAsyncResult *result,
- GError **error);
+IdeBufferChangeMonitor *gbp_git_buffer_change_monitor_new (IdeBuffer *buffer,
+ IpcGitRepository *repository,
+ GFile *file,
+ GCancellable *cancellable,
+ GError **error);
+void gbp_git_buffer_change_monitor_wait_async (GbpGitBufferChangeMonitor *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gbp_git_buffer_change_monitor_wait_finish (GbpGitBufferChangeMonitor *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/src/plugins/git/gbp-git-dependency-updater.c b/src/plugins/git/gbp-git-dependency-updater.c
index 6c75bd34d..3d5ac00dc 100644
--- a/src/plugins/git/gbp-git-dependency-updater.c
+++ b/src/plugins/git/gbp-git-dependency-updater.c
@@ -22,44 +22,35 @@
#include "config.h"
+#include <glib/gi18n.h>
+
+#include "daemon/ipc-git-repository.h"
+
#include "gbp-git-dependency-updater.h"
-#include "gbp-git-submodule-stage.h"
+#include "gbp-git-progress.h"
+#include "gbp-git-vcs.h"
struct _GbpGitDependencyUpdater
{
IdeObject parent_instance;
};
-static void
-find_submodule_stage_cb (gpointer data,
- gpointer user_data)
-{
- GbpGitSubmoduleStage **stage = user_data;
-
- g_assert (IDE_IS_PIPELINE_STAGE (data));
- g_assert (stage != NULL);
- g_assert (*stage == NULL || IDE_IS_PIPELINE_STAGE (*stage));
-
- if (GBP_IS_GIT_SUBMODULE_STAGE (data))
- *stage = GBP_GIT_SUBMODULE_STAGE (data);
-}
-
static void
gbp_git_dependency_updater_update_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
- IdeBuildManager *manager = (IdeBuildManager *)object;
+ IpcGitRepository *repository = (IpcGitRepository *)object;
g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
IDE_ENTRY;
- g_assert (IDE_IS_BUILD_MANAGER (manager));
+ g_assert (IPC_IS_GIT_REPOSITORY (repository));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
- if (!ide_build_manager_rebuild_finish (manager, result, &error))
+ if (!ipc_git_repository_call_update_submodules_finish (repository, result, &error))
ide_task_return_error (task, g_steal_pointer (&error));
else
ide_task_return_boolean (task, TRUE);
@@ -73,10 +64,13 @@ gbp_git_dependency_updater_update_async (IdeDependencyUpdater *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ g_autoptr(IpcGitProgress) progress = NULL;
g_autoptr(IdeTask) task = NULL;
- GbpGitSubmoduleStage *stage = NULL;
- IdePipeline *pipeline;
- IdeBuildManager *manager;
+ g_autoptr(IdeVcs) vcs = NULL;
+ g_autoptr(IdeNotification) notif = NULL;
+ g_autoptr(GError) error = NULL;
+ IpcGitRepository *repository;
+ GDBusConnection *connection;
IdeContext *context;
IDE_ENTRY;
@@ -86,50 +80,42 @@ gbp_git_dependency_updater_update_async (IdeDependencyUpdater *self,
task = ide_task_new (self, cancellable, callback, user_data);
ide_task_set_source_tag (task, gbp_git_dependency_updater_update_async);
- ide_task_set_priority (task, G_PRIORITY_LOW);
context = ide_object_get_context (IDE_OBJECT (self));
- manager = ide_build_manager_from_context (context);
- pipeline = ide_build_manager_get_pipeline (manager);
+ vcs = ide_object_get_child_typed (IDE_OBJECT (context), IDE_TYPE_VCS);
- g_assert (!pipeline || IDE_IS_PIPELINE (pipeline));
-
- if (pipeline == NULL)
+ if (!GBP_IS_GIT_VCS (vcs))
{
ide_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_FAILED,
- "Cannot update git submodules until build pipeline is initialized");
+ "Git version control is not in use");
IDE_EXIT;
}
- /* Find the submodule stage and tell it to download updates one time */
- ide_pipeline_foreach_stage (pipeline, find_submodule_stage_cb, &stage);
+ repository = gbp_git_vcs_get_repository (GBP_GIT_VCS (vcs));
+ connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (repository));
+
+ notif = g_object_new (IDE_TYPE_NOTIFICATION,
+ "title", _("Updating Git Submodules"),
+ NULL);
- if (stage == NULL)
+ if (!(progress = gbp_git_progress_new (connection, notif, cancellable, &error)))
{
- /* Synthesize success if there is no submodule stage */
- ide_task_return_boolean (task, TRUE);
+ ide_task_return_error (task, g_steal_pointer (&error));
IDE_EXIT;
}
- gbp_git_submodule_stage_force_update (stage);
-
- /* Ensure downloads and everything past it is invalidated */
- ide_pipeline_invalidate_phase (pipeline, IDE_PIPELINE_PHASE_DOWNLOADS);
-
- /* Start building all the way up to the project configure so that
- * the user knows if the updates broke their configuration or anything.
- *
- * TODO: This should probably be done by the calling API so that we don't
- * race with other updaters.
- */
- ide_build_manager_rebuild_async (manager,
- IDE_PIPELINE_PHASE_CONFIGURE,
- NULL,
- NULL,
- gbp_git_dependency_updater_update_cb,
- g_steal_pointer (&task));
+ ide_task_set_task_data (task, g_object_ref (progress), g_object_unref);
+ gbp_git_progress_set_withdraw (GBP_GIT_PROGRESS (progress), TRUE);
+ ide_notification_attach (notif, IDE_OBJECT (context));
+
+ ipc_git_repository_call_update_submodules (repository,
+ TRUE,
+ g_dbus_interface_skeleton_get_object_path
(G_DBUS_INTERFACE_SKELETON (progress)),
+ cancellable,
+ gbp_git_dependency_updater_update_cb,
+ g_steal_pointer (&task));
IDE_EXIT;
}
diff --git a/src/plugins/git/gbp-git-vcs-cloner.c b/src/plugins/git/gbp-git-vcs-cloner.c
index 0a03b7b4c..91454a4a9 100644
--- a/src/plugins/git/gbp-git-vcs-cloner.c
+++ b/src/plugins/git/gbp-git-vcs-cloner.c
@@ -22,34 +22,34 @@
#include "config.h"
-#include <dazzle.h>
#include <glib/gi18n.h>
#include <libide-threading.h>
-#include "gbp-git-remote-callbacks.h"
+#include "daemon/ipc-git-service.h"
+
+#include "gbp-git-client.h"
+#include "gbp-git-progress.h"
#include "gbp-git-vcs-cloner.h"
struct _GbpGitVcsCloner
{
- GObject parent_instance;
+ IdeObject parent_instance;
};
typedef struct
{
+ IpcGitProgress *progress;
IdeNotification *notif;
IdeVcsUri *uri;
gchar *branch;
GFile *location;
GFile *project_file;
- gchar *author_name;
- gchar *author_email;
} CloneRequest;
static void vcs_cloner_iface_init (IdeVcsClonerInterface *iface);
-G_DEFINE_TYPE_WITH_CODE (GbpGitVcsCloner, gbp_git_vcs_cloner, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS_CLONER,
- vcs_cloner_iface_init))
+G_DEFINE_TYPE_WITH_CODE (GbpGitVcsCloner, gbp_git_vcs_cloner, IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS_CLONER, vcs_cloner_iface_init))
static void
clone_request_free (gpointer data)
@@ -63,6 +63,7 @@ clone_request_free (gpointer data)
g_clear_object (&req->notif);
g_clear_object (&req->location);
g_clear_object (&req->project_file);
+ g_clear_object (&req->progress);
g_slice_free (CloneRequest, req);
}
}
@@ -152,81 +153,30 @@ gbp_git_vcs_cloner_validate_uri (IdeVcsCloner *cloner,
}
static void
-gbp_git_vcs_cloner_worker (IdeTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+gbp_git_vcs_cloner_clone_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_autoptr(GgitConfig) config = NULL;
- g_autoptr(GFile) config_file = NULL;
+ IpcGitService *service = (IpcGitService *)object;
+ g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
- g_autofree gchar *uristr = NULL;
- GgitRepository *repository;
- GgitCloneOptions *clone_options;
- GgitFetchOptions *fetch_options;
- GgitRemoteCallbacks *callbacks;
- CloneRequest *req = task_data;
+ g_autofree gchar *git_location = NULL;
+ g_assert (IPC_IS_GIT_SERVICE (service));
+ g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
- g_assert (GBP_IS_GIT_VCS_CLONER (source_object));
- g_assert (req != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- callbacks = gbp_git_remote_callbacks_new (req->notif);
-
- g_signal_connect_object (cancellable,
- "cancelled",
- G_CALLBACK (gbp_git_remote_callbacks_cancel),
- callbacks,
- G_CONNECT_SWAPPED);
-
- fetch_options = ggit_fetch_options_new ();
- ggit_fetch_options_set_remote_callbacks (fetch_options, callbacks);
-
- clone_options = ggit_clone_options_new ();
- ggit_clone_options_set_is_bare (clone_options, FALSE);
- ggit_clone_options_set_checkout_branch (clone_options, req->branch);
- ggit_clone_options_set_fetch_options (clone_options, fetch_options);
- g_clear_pointer (&fetch_options, ggit_fetch_options_free);
-
- uristr = ide_vcs_uri_to_string (req->uri);
-
- repository = ggit_repository_clone (uristr, req->location, clone_options, &error);
-
- g_clear_object (&callbacks);
- g_clear_object (&clone_options);
- if (repository == NULL)
- {
- ide_task_return_error (task, g_steal_pointer (&error));
- return;
- }
-
- if (ide_task_return_error_if_cancelled (task))
- return;
-
- config_file = g_file_get_child (req->location, ".git/config");
-
- if ((config = ggit_config_new_from_file (config_file, &error)))
- {
- if (req->author_name)
- ggit_config_set_string (config, "user.name", req->author_name, &error);
- if (req->author_email)
- ggit_config_set_string (config, "user.email", req->author_email, &error);
- }
-
- req->project_file = ggit_repository_get_workdir (repository);
-
- ide_task_return_boolean (task, TRUE);
-
- g_clear_object (&repository);
+ if (!ipc_git_service_call_clone_finish (service, &git_location, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_boolean (task, TRUE);
}
static void
gbp_git_vcs_cloner_clone_async (IdeVcsCloner *cloner,
const gchar *uri,
const gchar *destination,
- GVariantDict *options,
+ GVariant *options,
IdeNotification *notif,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -235,11 +185,17 @@ gbp_git_vcs_cloner_clone_async (IdeVcsCloner *cloner,
GbpGitVcsCloner *self = (GbpGitVcsCloner *)cloner;
g_autoptr(IdeNotification) notif_local = NULL;
g_autoptr(IdeVcsUri) vcs_uri = NULL;
+ g_autoptr(IpcGitService) service = NULL;
g_autoptr(IdeTask) task = NULL;
g_autoptr(GFile) location = NULL;
+ g_autoptr(GError) error = NULL;
g_autofree gchar *uristr = NULL;
+ GDBusConnection *connection;
+ GbpGitClient *client = NULL;
CloneRequest *req;
+ GVariantDict dict;
const gchar *branch;
+ IdeContext *context;
g_assert (GBP_IS_GIT_VCS_CLONER (cloner));
g_assert (uri != NULL);
@@ -247,34 +203,32 @@ gbp_git_vcs_cloner_clone_async (IdeVcsCloner *cloner,
g_assert (!notif || IDE_IS_NOTIFICATION (notif));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ /* Get our client to communicate with the daemon */
+ context = ide_object_get_context (IDE_OBJECT (self));
+ client = gbp_git_client_from_context (context);
+
task = ide_task_new (self, cancellable, callback, user_data);
ide_task_set_source_tag (task, gbp_git_vcs_cloner_clone_async);
+ /* Ensure we always have a notification to work with */
if (notif == NULL)
{
notif_local = ide_notification_new ();
notif = notif_local;
}
- if (!g_variant_dict_lookup (options, "branch", "&s", &branch))
- branch = "master";
+ ide_notification_set_title (notif, _("Cloning repository"));
- /*
- * ggit_repository_clone() will block and we don't have a good way to
- * cancel it. So we need to return immediately (even though the clone
- * will continue in the background for now).
- *
- * FIXME: Find Ggit API to cancel clone. We might need access to the
- * GgitRemote so we can ggit_remote_disconnect().
- */
- ide_task_set_return_on_cancel (task, TRUE);
+ /* Extract branch, leave other options to pass-through */
+ g_variant_dict_init (&dict, options);
+ if (!g_variant_dict_lookup (&dict, "branch", "&s", &branch))
+ branch = "master";
+ g_variant_dict_remove (&dict, "branch");
+ /* Make sure we have a real URI to connect to */
uristr = g_strstrip (g_strdup (uri));
location = g_file_new_for_path (destination);
-
- vcs_uri = ide_vcs_uri_new (uristr);
-
- if (vcs_uri == NULL)
+ if (!(vcs_uri = ide_vcs_uri_new (uristr)))
{
ide_task_return_new_error (task,
G_IO_ERROR,
@@ -283,21 +237,39 @@ gbp_git_vcs_cloner_clone_async (IdeVcsCloner *cloner,
return;
}
+ /* Always set a username if the transport is SSH */
if (g_strcmp0 ("ssh", ide_vcs_uri_get_scheme (vcs_uri)) == 0)
{
if (ide_vcs_uri_get_user (vcs_uri) == NULL)
- ide_vcs_uri_set_user (vcs_uri, g_get_user_name ());
+ {
+ ide_vcs_uri_set_user (vcs_uri, g_get_user_name ());
+ g_free (uristr);
+ uristr = ide_vcs_uri_to_string (vcs_uri);
+ }
}
- g_assert (IDE_IS_NOTIFICATION (notif));
-
+ /* Create state for the task */
req = clone_request_new (vcs_uri, branch, location, notif);
+ ide_task_set_task_data (task, req, clone_request_free);
- g_variant_dict_lookup (options, "author-name", "s", &req->author_name);
- g_variant_dict_lookup (options, "author-email", "s", &req->author_email);
+ if (!(service = gbp_git_client_get_service (client, cancellable, &error)) ||
+ !(connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (service))) ||
+ !(req->progress = gbp_git_progress_new (connection, notif, cancellable, &error)))
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ g_variant_dict_clear (&dict);
+ return;
+ }
- ide_task_set_task_data (task, req, clone_request_free);
- ide_task_run_in_thread (task, gbp_git_vcs_cloner_worker);
+ ipc_git_service_call_clone (service,
+ uristr,
+ g_file_peek_path (req->location),
+ req->branch ?: "master",
+ g_variant_dict_end (&dict),
+ g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON
(req->progress)),
+ cancellable,
+ gbp_git_vcs_cloner_clone_cb,
+ g_steal_pointer (&task));
}
static gboolean
diff --git a/src/plugins/git/gbp-git-vcs-cloner.h b/src/plugins/git/gbp-git-vcs-cloner.h
index d634242e9..2acc2dc49 100644
--- a/src/plugins/git/gbp-git-vcs-cloner.h
+++ b/src/plugins/git/gbp-git-vcs-cloner.h
@@ -26,6 +26,6 @@ G_BEGIN_DECLS
#define GBP_TYPE_GIT_VCS_CLONER (gbp_git_vcs_cloner_get_type())
-G_DECLARE_FINAL_TYPE (GbpGitVcsCloner, gbp_git_vcs_cloner, GBP, GIT_VCS_CLONER, GObject)
+G_DECLARE_FINAL_TYPE (GbpGitVcsCloner, gbp_git_vcs_cloner, GBP, GIT_VCS_CLONER, IdeObject)
G_END_DECLS
diff --git a/src/plugins/git/gbp-git-vcs-config.c b/src/plugins/git/gbp-git-vcs-config.c
index cf8a20153..9d67d2999 100644
--- a/src/plugins/git/gbp-git-vcs-config.c
+++ b/src/plugins/git/gbp-git-vcs-config.c
@@ -1,6 +1,7 @@
/* gbp-git-vcs-config.c
*
* Copyright 2016 Akshaya Kakkilaya <akshaya kakkilaya gmail com>
+ * 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
@@ -22,147 +23,128 @@
#include "config.h"
-#include <libgit2-glib/ggit.h>
+#include <libide-threading.h>
#include <libide-vcs.h>
+#include "daemon/ipc-git-config.h"
+
+#include "gbp-git-client.h"
#include "gbp-git-vcs-config.h"
struct _GbpGitVcsConfig
{
- GObject parent_instance;
-
- GgitConfig *config;
+ IdeObject parent_instance;
+ guint is_global : 1;
};
static void vcs_config_init (IdeVcsConfigInterface *iface);
-G_DEFINE_TYPE_EXTENDED (GbpGitVcsConfig, gbp_git_vcs_config, G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS_CONFIG, vcs_config_init))
-
-GbpGitVcsConfig *
-gbp_git_vcs_config_new (void)
-{
- return g_object_new (GBP_TYPE_GIT_VCS_CONFIG, NULL);
-}
-
-static void
-gbp_git_vcs_config_get_string (GgitConfig *config,
- const gchar *key,
- GValue *value,
- GError **error)
-{
- const gchar *str;
-
- g_assert (GGIT_IS_CONFIG (config));
- g_assert (key != NULL);
+G_DEFINE_TYPE_WITH_CODE (GbpGitVcsConfig, gbp_git_vcs_config, IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS_CONFIG, vcs_config_init))
- str = ggit_config_get_string (config, key, error);
-
- g_value_set_string (value, str);
-}
-
-static void
-gbp_git_vcs_config_set_string (GgitConfig *config,
- const gchar *key,
- const GValue *value,
- GError **error)
+static const gchar *
+get_key (IdeVcsConfigType type)
{
- const gchar *str;
-
- g_assert (GGIT_IS_CONFIG (config));
- g_assert (key != NULL);
-
- str = g_value_get_string (value);
-
- if (str != NULL)
- ggit_config_set_string (config, key, str, error);
-}
-
-static void
-gbp_git_vcs_config_get_config (IdeVcsConfig *self,
- IdeVcsConfigType type,
- GValue *value)
-{
- g_autoptr(GgitConfig) config = NULL;
- GgitConfig *orig_config;
-
- g_return_if_fail (GBP_IS_GIT_VCS_CONFIG (self));
-
- orig_config = GBP_GIT_VCS_CONFIG (self)->config;
- config = ggit_config_snapshot (orig_config, NULL);
-
- if(config == NULL)
- return;
-
switch (type)
{
case IDE_VCS_CONFIG_FULL_NAME:
- gbp_git_vcs_config_get_string (config, "user.name", value, NULL);
- break;
-
+ return "user.name";
case IDE_VCS_CONFIG_EMAIL:
- gbp_git_vcs_config_get_string (config, "user.email", value, NULL);
- break;
-
+ return "user.email";
default:
- break;
+ return NULL;
}
}
-static void
-gbp_git_vcs_config_set_config (IdeVcsConfig *self,
- IdeVcsConfigType type,
- const GValue *value)
+static IpcGitConfig *
+get_config (GbpGitVcsConfig *self,
+ GCancellable *cancellable,
+ GError **error)
{
- GgitConfig *config;
+ g_autofree gchar *obj_path = NULL;
+ g_autoptr(IpcGitService) service = NULL;
+ GDBusConnection *connection;
+ GbpGitClient *client;
+ IdeContext *context;
- g_return_if_fail (GBP_IS_GIT_VCS_CONFIG (self));
+ g_assert (GBP_IS_GIT_VCS_CONFIG (self));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- config = GBP_GIT_VCS_CONFIG (self)->config;
+ context = ide_object_get_context (IDE_OBJECT (self));
+ client = gbp_git_client_from_context (context);
- switch (type)
+ if (!self->is_global)
{
- case IDE_VCS_CONFIG_FULL_NAME:
- gbp_git_vcs_config_set_string (config, "user.name", value, NULL);
- break;
+ /* TODO: get config from repository */
+ }
- case IDE_VCS_CONFIG_EMAIL:
- gbp_git_vcs_config_set_string (config, "user.email", value, NULL);
- break;
+ if (!(service = gbp_git_client_get_service (client, cancellable, error)))
+ return NULL;
+
+ if (!ipc_git_service_call_load_config_sync (service, &obj_path, cancellable, error))
+ return NULL;
+
+ connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (service));
+
+ return ipc_git_config_proxy_new_sync (connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ obj_path,
+ cancellable,
+ error);
- default:
- break;
- }
}
static void
-gbp_git_vcs_config_constructed (GObject *object)
+gbp_git_vcs_config_get_config (IdeVcsConfig *config,
+ IdeVcsConfigType type,
+ GValue *value)
{
- GbpGitVcsConfig *self = GBP_GIT_VCS_CONFIG (object);
+ GbpGitVcsConfig *self = (GbpGitVcsConfig *)config;
+ g_autoptr(IpcGitConfig) proxy = NULL;
- g_autoptr(GFile) global_file = NULL;
+ g_assert (GBP_IS_GIT_VCS_CONFIG (self));
+ g_assert (value != NULL);
- if (!(global_file = ggit_config_find_global ()))
+ if ((proxy = get_config (self, NULL, NULL)))
{
- g_autofree gchar *path = NULL;
-
- path = g_build_filename (g_get_home_dir (), ".gitconfig", NULL);
- global_file = g_file_new_for_path (path);
- }
+ g_autofree gchar *str = NULL;
- self->config = ggit_config_new_from_file (global_file, NULL);
+ ipc_git_config_call_read_key_sync (proxy, get_key (type), &str, NULL, NULL);
+ ipc_git_config_call_close (proxy, NULL, NULL, NULL);
- G_OBJECT_CLASS (gbp_git_vcs_config_parent_class)->constructed (object);
+ g_value_set_string (value, str);
+ }
}
static void
-gbp_git_vcs_config_finalize (GObject *object)
+gbp_git_vcs_config_set_config (IdeVcsConfig *config,
+ IdeVcsConfigType type,
+ const GValue *value)
{
- GbpGitVcsConfig *self = GBP_GIT_VCS_CONFIG (object);
+ GbpGitVcsConfig *self = (GbpGitVcsConfig *)config;
+ g_autoptr(IpcGitConfig) proxy = NULL;
- g_object_unref (self->config);
+ g_assert (GBP_IS_GIT_VCS_CONFIG (self));
+ g_assert (value != NULL);
- G_OBJECT_CLASS (gbp_git_vcs_config_parent_class)->finalize (object);
+ if ((proxy = get_config (self, NULL, NULL)))
+ {
+ g_auto(GValue) str = G_VALUE_INIT;
+
+ if (!G_VALUE_HOLDS_STRING (value))
+ {
+ g_value_init (&str, G_TYPE_STRING);
+ g_value_transform (value, &str);
+ value = &str;
+ }
+
+ ipc_git_config_call_write_key_sync (proxy,
+ get_key (type),
+ g_value_get_string (value),
+ NULL, NULL);
+ ipc_git_config_call_close (proxy, NULL, NULL, NULL);
+ }
}
static void
@@ -175,13 +157,19 @@ vcs_config_init (IdeVcsConfigInterface *iface)
static void
gbp_git_vcs_config_class_init (GbpGitVcsConfigClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->constructed = gbp_git_vcs_config_constructed;
- object_class->finalize = gbp_git_vcs_config_finalize;
}
static void
gbp_git_vcs_config_init (GbpGitVcsConfig *self)
{
+ self->is_global = TRUE;
+}
+
+void
+gbp_git_vcs_config_set_global (GbpGitVcsConfig *self,
+ gboolean is_global)
+{
+ g_return_if_fail (GBP_IS_GIT_VCS_CONFIG (self));
+
+ self->is_global = !!is_global;
}
diff --git a/src/plugins/git/gbp-git-vcs-config.h b/src/plugins/git/gbp-git-vcs-config.h
index acc416d03..65a1d3721 100644
--- a/src/plugins/git/gbp-git-vcs-config.h
+++ b/src/plugins/git/gbp-git-vcs-config.h
@@ -1,6 +1,7 @@
/* gbp-git-vcs-config.h
*
* Copyright 2016 Akshaya Kakkilaya <akshaya kakkilaya gmail com>
+ * Copyright 2016-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
@@ -26,8 +27,9 @@ G_BEGIN_DECLS
#define GBP_TYPE_GIT_VCS_CONFIG (gbp_git_vcs_config_get_type())
-G_DECLARE_FINAL_TYPE (GbpGitVcsConfig, gbp_git_vcs_config, GBP, GIT_VCS_CONFIG, GObject)
+G_DECLARE_FINAL_TYPE (GbpGitVcsConfig, gbp_git_vcs_config, GBP, GIT_VCS_CONFIG, IdeObject)
-GbpGitVcsConfig *gbp_git_vcs_config_new (void);
+void gbp_git_vcs_config_set_global (GbpGitVcsConfig *self,
+ gboolean is_global);
G_END_DECLS
diff --git a/src/plugins/git/gbp-git-vcs-initializer.c b/src/plugins/git/gbp-git-vcs-initializer.c
index d05b3690d..faa4f6595 100644
--- a/src/plugins/git/gbp-git-vcs-initializer.c
+++ b/src/plugins/git/gbp-git-vcs-initializer.c
@@ -20,53 +20,70 @@
#define G_LOG_DOMAIN "gbp-git-vcs-initializer"
-#include "config.h"
-
-#include <libgit2-glib/ggit.h>
-#include <libide-threading.h>
-
+#include "gbp-git-client.h"
#include "gbp-git-vcs-initializer.h"
struct _GbpGitVcsInitializer
{
- GObject parent_instance;
+ IdeObject parent_instance;
};
-static void vcs_initializer_init (IdeVcsInitializerInterface *iface);
-
-G_DEFINE_TYPE_EXTENDED (GbpGitVcsInitializer, gbp_git_vcs_initializer, G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS_INITIALIZER, vcs_initializer_init))
-
-static void
-gbp_git_vcs_initializer_class_init (GbpGitVcsInitializerClass *klass)
+static gchar *
+gbp_git_vcs_initializer_get_title (IdeVcsInitializer *self)
{
+ return g_strdup ("Git");
}
static void
-gbp_git_vcs_initializer_init (GbpGitVcsInitializer *self)
+create_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ IpcGitService *service = (IpcGitService *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *git_location = NULL;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IPC_IS_GIT_SERVICE (service));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!ipc_git_service_call_create_finish (service, &git_location, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_boolean (task, TRUE);
}
static void
-gbp_git_vcs_initializer_initialize_worker (IdeTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+get_service_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_autoptr(GgitRepository) repository = NULL;
+ GbpGitClient *client = (GbpGitClient *)object;
+ g_autoptr(IpcGitService) service = NULL;
+ g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
- GFile *file = task_data;
+ GCancellable *cancellable;
+ GFile *file;
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_GIT_CLIENT (client));
+ g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
- g_assert (GBP_IS_GIT_VCS_INITIALIZER (source_object));
- g_assert (G_IS_FILE (file));
- repository = ggit_repository_init_repository (file, FALSE, &error);
+ cancellable = ide_task_get_cancellable (task);
+ file = ide_task_get_task_data (task);
- if (repository == NULL)
+ if (!(service = gbp_git_client_get_service_finish (client, result, &error)))
ide_task_return_error (task, g_steal_pointer (&error));
else
- ide_task_return_boolean (task, TRUE);
+ ipc_git_service_call_create (service,
+ g_file_peek_path (file),
+ FALSE,
+ cancellable,
+ create_cb,
+ g_steal_pointer (&task));
}
static void
@@ -76,16 +93,26 @@ gbp_git_vcs_initializer_initialize_async (IdeVcsInitializer *initializer,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GbpGitVcsInitializer *self = (GbpGitVcsInitializer *)initializer;
g_autoptr(IdeTask) task = NULL;
+ GbpGitClient *client;
+ IdeContext *context;
- g_return_if_fail (GBP_IS_GIT_VCS_INITIALIZER (self));
- g_return_if_fail (G_IS_FILE (file));
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_GIT_VCS_INITIALIZER (initializer));
+ g_assert (G_IS_FILE (file));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_task_data (task, g_object_ref (file), g_object_unref);
- ide_task_run_in_thread (task, gbp_git_vcs_initializer_initialize_worker);
+ task = ide_task_new (initializer, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_git_vcs_initializer_initialize_async);
+ ide_task_set_task_data (task, g_file_dup (file), g_object_unref);
+
+ context = ide_object_get_context (IDE_OBJECT (initializer));
+ client = gbp_git_client_from_context (context);
+
+ gbp_git_client_get_service_async (client,
+ cancellable,
+ get_service_cb,
+ g_steal_pointer (&task));
}
static gboolean
@@ -93,22 +120,30 @@ gbp_git_vcs_initializer_initialize_finish (IdeVcsInitializer *initializer,
GAsyncResult *result,
GError **error)
{
- g_return_val_if_fail (GBP_IS_GIT_VCS_INITIALIZER (initializer), FALSE);
- g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_GIT_VCS_INITIALIZER (initializer));
+ g_assert (IDE_IS_TASK (result));
return ide_task_propagate_boolean (IDE_TASK (result), error);
}
-static gchar *
-gbp_git_vcs_initializer_get_title (IdeVcsInitializer *initilizer)
-{
- return g_strdup ("Git");
-}
-
static void
-vcs_initializer_init (IdeVcsInitializerInterface *iface)
+vcs_initializer_iface_init (IdeVcsInitializerInterface *iface)
{
iface->get_title = gbp_git_vcs_initializer_get_title;
iface->initialize_async = gbp_git_vcs_initializer_initialize_async;
iface->initialize_finish = gbp_git_vcs_initializer_initialize_finish;
}
+
+G_DEFINE_TYPE_WITH_CODE (GbpGitVcsInitializer, gbp_git_vcs_initializer, IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS_INITIALIZER, vcs_initializer_iface_init))
+
+static void
+gbp_git_vcs_initializer_class_init (GbpGitVcsInitializerClass *klass)
+{
+}
+
+static void
+gbp_git_vcs_initializer_init (GbpGitVcsInitializer *self)
+{
+}
diff --git a/src/plugins/git/gbp-git-vcs-initializer.h b/src/plugins/git/gbp-git-vcs-initializer.h
index 16493bf88..cdaaab4db 100644
--- a/src/plugins/git/gbp-git-vcs-initializer.h
+++ b/src/plugins/git/gbp-git-vcs-initializer.h
@@ -26,6 +26,6 @@ G_BEGIN_DECLS
#define GBP_TYPE_GIT_VCS_INITIALIZER (gbp_git_vcs_initializer_get_type())
-G_DECLARE_FINAL_TYPE (GbpGitVcsInitializer, gbp_git_vcs_initializer, GBP, GIT_VCS_INITIALIZER, GObject)
+G_DECLARE_FINAL_TYPE (GbpGitVcsInitializer, gbp_git_vcs_initializer, GBP, GIT_VCS_INITIALIZER, IdeObject)
G_END_DECLS
diff --git a/src/plugins/git/gbp-git-vcs.c b/src/plugins/git/gbp-git-vcs.c
index b70e0f683..b74641e59 100644
--- a/src/plugins/git/gbp-git-vcs.c
+++ b/src/plugins/git/gbp-git-vcs.c
@@ -1,6 +1,6 @@
/* gbp-git-vcs.c
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2014-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
@@ -22,7 +22,7 @@
#include "config.h"
-#include <stdlib.h>
+#include "daemon/ipc-git-types.h"
#include "gbp-git-branch.h"
#include "gbp-git-tag.h"
@@ -31,476 +31,181 @@
struct _GbpGitVcs
{
- IdeObject parent_instance;
- GgitRepository *repository;
- GFile *location;
- GFile *workdir;
- gchar *branch;
+ IdeObject parent;
+
+ /* read-only, thread-safe access */
+ IpcGitRepository *repository;
+ GFile *workdir;
};
enum {
PROP_0,
PROP_BRANCH_NAME,
- PROP_LOCATION,
- PROP_REPOSITORY,
PROP_WORKDIR,
N_PROPS
};
-static void vcs_iface_init (IdeVcsInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (GbpGitVcs, gbp_git_vcs, IDE_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS, vcs_iface_init))
-
-static GParamSpec *properties [N_PROPS];
-
-static void
-gbp_git_vcs_finalize (GObject *object)
-{
- GbpGitVcs *self = (GbpGitVcs *)object;
-
- g_clear_object (&self->repository);
- g_clear_object (&self->location);
- g_clear_object (&self->workdir);
- g_clear_pointer (&self->branch, g_free);
-
- G_OBJECT_CLASS (gbp_git_vcs_parent_class)->finalize (object);
-}
-
-static void
-gbp_git_vcs_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GbpGitVcs *self = GBP_GIT_VCS (object);
-
- switch (prop_id)
- {
- case PROP_BRANCH_NAME:
- g_value_set_string (value, self->branch);
- break;
-
- case PROP_LOCATION:
- g_value_set_object (value, self->location);
- break;
-
- case PROP_REPOSITORY:
- g_value_set_object (value, self->repository);
- break;
-
- case PROP_WORKDIR:
- g_value_set_object (value, self->workdir);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gbp_git_vcs_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GbpGitVcs *self = GBP_GIT_VCS (object);
-
- switch (prop_id)
- {
- case PROP_BRANCH_NAME:
- self->branch = g_value_dup_string (value);
- break;
-
- case PROP_LOCATION:
- self->location = g_value_dup_object (value);
- break;
-
- case PROP_REPOSITORY:
- self->repository = g_value_dup_object (value);
- break;
-
- case PROP_WORKDIR:
- self->workdir = g_value_dup_object (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gbp_git_vcs_class_init (GbpGitVcsClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = gbp_git_vcs_finalize;
- object_class->get_property = gbp_git_vcs_get_property;
- object_class->set_property = gbp_git_vcs_set_property;
-
- properties [PROP_BRANCH_NAME] =
- g_param_spec_string ("branch-name",
- "Branch Name",
- "The name of the branch",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_LOCATION] =
- g_param_spec_object ("location",
- "Location",
- "The location for the repository",
- G_TYPE_FILE,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_REPOSITORY] =
- g_param_spec_object ("repository",
- "Repository",
- "The underlying repository object",
- GGIT_TYPE_REPOSITORY,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_WORKDIR] =
- g_param_spec_object ("workdir",
- "Workdir",
- "Working directory of the repository",
- G_TYPE_FILE,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-gbp_git_vcs_init (GbpGitVcs *self)
-{
-}
-
-GFile *
-gbp_git_vcs_get_location (GbpGitVcs *self)
-{
- g_return_val_if_fail (GBP_IS_GIT_VCS (self), NULL);
- return self->location;
-}
-
-GgitRepository *
-gbp_git_vcs_get_repository (GbpGitVcs *self)
-{
- g_return_val_if_fail (GBP_IS_GIT_VCS (self), NULL);
- return self->repository;
-}
-
static GFile *
gbp_git_vcs_get_workdir (IdeVcs *vcs)
{
return GBP_GIT_VCS (vcs)->workdir;
}
-static gchar *
-gbp_git_vcs_get_branch_name (IdeVcs *vcs)
-{
- gchar *ret;
-
- g_return_val_if_fail (GBP_IS_GIT_VCS (vcs), NULL);
-
- ide_object_lock (IDE_OBJECT (vcs));
- ret = g_strdup (GBP_GIT_VCS (vcs)->branch);
- ide_object_unlock (IDE_OBJECT (vcs));
-
- return g_steal_pointer (&ret);
-}
-
-static IdeVcsConfig *
-gbp_git_vcs_get_config (IdeVcs *vcs)
-{
- return g_object_new (GBP_TYPE_GIT_VCS_CONFIG, NULL);
-}
static gboolean
gbp_git_vcs_is_ignored (IdeVcs *vcs,
GFile *file,
GError **error)
{
- g_autofree gchar *name = NULL;
GbpGitVcs *self = (GbpGitVcs *)vcs;
- gboolean ret = FALSE;
+ g_autofree gchar *relative_path = NULL;
+ gboolean is_ignored = FALSE;
g_assert (GBP_IS_GIT_VCS (self));
g_assert (G_IS_FILE (file));
- /* Note: this function is required to be thread-safe so that workers
- * can check if files are ignored from a thread without
- * round-tripping to the main thread.
- */
-
- /* self->workdir is not changed after creation, so safe
- * to access it from a thread.
- */
- name = g_file_get_relative_path (self->workdir, file);
- if (g_strcmp0 (name, ".git") == 0)
- return TRUE;
+ if (g_file_equal (self->workdir, file))
+ return FALSE;
/*
- * If we have a valid name to work with, we want to query the
- * repository. But this could be called from a thread, so ensure
- * we are the only thread accessing self->repository right now.
+ * This may be called from threads.
+ *
+ * However, we do not change our GbpGitVcs.repository field after the
+ * creation of the GbpGitVcs. Also, the GDBusProxy (IpcGitRepository)
+ * is thread-safe in terms of calling operations on the remote object
+ * from multiple threads.
+ *
+ * Also, GbpGitVcs.workdir is not changed after creation, so we can
+ * use that to for determining the relative path.
*/
- if (name != NULL)
- {
- ide_object_lock (IDE_OBJECT (self));
- ret = ggit_repository_path_is_ignored (self->repository, name, error);
- ide_object_unlock (IDE_OBJECT (self));
- }
- return ret;
-}
+ if (!g_file_has_prefix (file, self->workdir))
+ return TRUE;
-typedef struct
-{
- GFile *repository_location;
- GFile *directory_or_file;
- GFile *workdir;
- GListStore *store;
- guint recursive : 1;
-} ListStatus;
+ relative_path = g_file_get_relative_path (self->workdir, file);
-static void
-list_status_free (gpointer data)
-{
- ListStatus *ls = data;
+ if (!ipc_git_repository_call_path_is_ignored_sync (self->repository,
+ relative_path,
+ &is_ignored,
+ NULL,
+ error))
+ return FALSE;
- g_clear_object (&ls->repository_location);
- g_clear_object (&ls->directory_or_file);
- g_clear_object (&ls->workdir);
- g_clear_object (&ls->store);
- g_slice_free (ListStatus, ls);
+ return is_ignored;
}
-static gint
-gbp_git_vcs_list_status_cb (const gchar *path,
- GgitStatusFlags flags,
- gpointer user_data)
+static IdeVcsConfig *
+gbp_git_vcs_get_config (IdeVcs *vcs)
{
- ListStatus *state = user_data;
- g_autoptr(GFile) file = NULL;
- g_autoptr(IdeVcsFileInfo) info = NULL;
- IdeVcsFileStatus status = 0;
-
- g_assert (path != NULL);
- g_assert (state != NULL);
- g_assert (G_IS_LIST_STORE (state->store));
- g_assert (G_IS_FILE (state->workdir));
+ IdeVcsConfig *config;
- file = g_file_get_child (state->workdir, path);
-
- switch (flags)
- {
- case GGIT_STATUS_INDEX_DELETED:
- case GGIT_STATUS_WORKING_TREE_DELETED:
- status = IDE_VCS_FILE_STATUS_DELETED;
- break;
-
- case GGIT_STATUS_INDEX_RENAMED:
- status = IDE_VCS_FILE_STATUS_RENAMED;
- break;
-
- case GGIT_STATUS_INDEX_NEW:
- case GGIT_STATUS_WORKING_TREE_NEW:
- status = IDE_VCS_FILE_STATUS_ADDED;
- break;
-
- case GGIT_STATUS_INDEX_MODIFIED:
- case GGIT_STATUS_INDEX_TYPECHANGE:
- case GGIT_STATUS_WORKING_TREE_MODIFIED:
- case GGIT_STATUS_WORKING_TREE_TYPECHANGE:
- status = IDE_VCS_FILE_STATUS_CHANGED;
- break;
-
- case GGIT_STATUS_IGNORED:
- status = IDE_VCS_FILE_STATUS_IGNORED;
- break;
-
- case GGIT_STATUS_CURRENT:
- status = IDE_VCS_FILE_STATUS_UNCHANGED;
- break;
-
- default:
- status = IDE_VCS_FILE_STATUS_UNTRACKED;
- break;
- }
+ g_assert (GBP_IS_GIT_VCS (vcs));
- info = g_object_new (IDE_TYPE_VCS_FILE_INFO,
- "file", file,
- "status", status,
- NULL);
+ config = g_object_new (GBP_TYPE_GIT_VCS_CONFIG,
+ "parent", vcs,
+ NULL);
+ gbp_git_vcs_config_set_global (GBP_GIT_VCS_CONFIG (config), FALSE);
- g_list_store_append (state->store, info);
+ return g_steal_pointer (&config);
+}
- return 0;
+static gchar *
+gbp_git_vcs_get_branch_name (IdeVcs *vcs)
+{
+ return ipc_git_repository_dup_branch (GBP_GIT_VCS (vcs)->repository);
}
static void
-gbp_git_vcs_list_status_worker (IdeTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+gbp_git_vcs_switch_branch_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- ListStatus *state = task_data;
- g_autoptr(GListStore) store = NULL;
- g_autoptr(GFile) workdir = NULL;
- g_autoptr(GgitRepository) repository = NULL;
- g_autoptr(GgitStatusOptions) options = NULL;
+ IpcGitRepository *repository = (IpcGitRepository *)object;
+ g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
- g_autofree gchar *relative = NULL;
- gchar *strv[] = { NULL, NULL };
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IPC_IS_GIT_REPOSITORY (repository));
+ g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
- g_assert (GBP_IS_GIT_VCS (source_object));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- g_assert (state != NULL);
- g_assert (G_IS_FILE (state->repository_location));
- if (!(repository = ggit_repository_open (state->repository_location, &error)))
- {
- ide_task_return_error (task, g_steal_pointer (&error));
- return;
- }
-
- if (!(workdir = ggit_repository_get_workdir (repository)))
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "Failed to locate working directory");
- return;
- }
-
- g_set_object (&state->workdir, workdir);
-
- if (state->directory_or_file != NULL)
- relative = g_file_get_relative_path (workdir, state->directory_or_file);
-
- strv[0] = relative;
- options = ggit_status_options_new (GGIT_STATUS_OPTION_DEFAULT,
- GGIT_STATUS_SHOW_INDEX_AND_WORKDIR,
- (const gchar **)strv);
-
- store = g_list_store_new (IDE_TYPE_VCS_FILE_INFO);
- g_set_object (&state->store, store);
-
- if (!ggit_repository_file_status_foreach (repository,
- options,
- gbp_git_vcs_list_status_cb,
- state,
- &error))
+ if (!ipc_git_repository_call_switch_branch_finish (repository, result, &error))
ide_task_return_error (task, g_steal_pointer (&error));
else
- ide_task_return_pointer (task, g_steal_pointer (&store), g_object_unref);
+ ide_task_return_boolean (task, TRUE);
}
static void
-gbp_git_vcs_list_status_async (IdeVcs *vcs,
- GFile *directory_or_file,
- gboolean include_descendants,
- gint io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+gbp_git_vcs_switch_branch_async (IdeVcs *vcs,
+ IdeVcsBranch *branch,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GbpGitVcs *self = (GbpGitVcs *)vcs;
g_autoptr(IdeTask) task = NULL;
- ListStatus *state;
+ g_autofree gchar *branch_name = NULL;
- IDE_ENTRY;
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_GIT_VCS (self));
+ g_assert (GBP_IS_GIT_BRANCH (branch));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- g_return_if_fail (GBP_IS_GIT_VCS (self));
- g_return_if_fail (!directory_or_file || G_IS_FILE (directory_or_file));
- 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_vcs_switch_branch_async);
- ide_object_lock (IDE_OBJECT (self));
- state = g_slice_new0 (ListStatus);
- state->directory_or_file = g_object_ref (directory_or_file);
- state->repository_location = ggit_repository_get_location (self->repository);
- state->recursive = !!include_descendants;
- ide_object_unlock (IDE_OBJECT (self));
+ branch_name = ide_vcs_branch_get_name (branch);
- task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_source_tag (task, gbp_git_vcs_list_status_async);
- ide_task_set_priority (task, io_priority);
- ide_task_set_return_on_cancel (task, TRUE);
- ide_task_set_task_data (task, state, list_status_free);
-
- if (state->repository_location == NULL)
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No repository loaded");
- else
- ide_task_run_in_thread (task, gbp_git_vcs_list_status_worker);
+ ipc_git_repository_call_switch_branch (self->repository,
+ branch_name,
+ cancellable,
+ gbp_git_vcs_switch_branch_cb,
+ g_steal_pointer (&task));
+}
- IDE_EXIT;
+static gboolean
+gbp_git_vcs_switch_branch_finish (IdeVcs *vcs,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_GIT_VCS (vcs));
+ g_assert (IDE_IS_TASK (result));
+
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
}
-static GListModel *
-gbp_git_vcs_list_status_finish (IdeVcs *vcs,
- GAsyncResult *result,
- GError **error)
+static GPtrArray *
+create_branches (gchar **refs)
{
- g_return_val_if_fail (GBP_IS_GIT_VCS (vcs), NULL);
- g_return_val_if_fail (IDE_IS_TASK (result), NULL);
+ GPtrArray *ret = g_ptr_array_new_with_free_func (g_object_unref);
+
+ if (refs != NULL)
+ {
+ for (guint i = 0; refs[i]; i++)
+ g_ptr_array_add (ret, gbp_git_branch_new (refs[i]));
+ }
- return ide_task_propagate_pointer (IDE_TASK (result), error);
+ return g_steal_pointer (&ret);
}
static void
-gbp_git_vcs_list_branches_worker (IdeTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+gbp_git_vcs_list_branches_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GbpGitVcs *self = source_object;
- g_autoptr(GPtrArray) branches = NULL;
+ IpcGitRepository *repository = (IpcGitRepository *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ g_auto(GStrv) refs = NULL;
+ g_assert (IPC_IS_GIT_REPOSITORY (repository));
+ g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
- g_assert (GBP_IS_GIT_VCS (self));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- branches = g_ptr_array_new_with_free_func (g_object_unref);
-
- ide_object_lock (IDE_OBJECT (self));
- if (self->repository != NULL)
- {
- g_autoptr(GgitBranchEnumerator) enumerator = NULL;
- g_autoptr(GError) error = NULL;
-
- if (!(enumerator = ggit_repository_enumerate_branches (self->repository,
- GGIT_BRANCH_LOCAL,
- &error)))
- {
- ide_task_return_error (task, g_steal_pointer (&error));
- goto unlock;
- }
-
- while (ggit_branch_enumerator_next (enumerator))
- {
- g_autoptr(GgitRef) ref = ggit_branch_enumerator_get (enumerator);
- const gchar *name = ggit_ref_get_name (ref);
-
- g_ptr_array_add (branches, gbp_git_branch_new (name));
- }
-
- ide_task_return_pointer (task,
- g_steal_pointer (&branches),
- g_ptr_array_unref);
- }
+ if (!ipc_git_repository_call_list_refs_by_kind_finish (repository, &refs, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
else
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No repository to access");
- }
-
-unlock:
- ide_object_unlock (IDE_OBJECT (self));
+ ide_task_return_pointer (task, create_branches (refs), g_ptr_array_unref);
}
static void
@@ -512,27 +217,18 @@ gbp_git_vcs_list_branches_async (IdeVcs *vcs,
GbpGitVcs *self = (GbpGitVcs *)vcs;
g_autoptr(IdeTask) task = NULL;
- IDE_ENTRY;
-
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (GBP_IS_GIT_VCS (self));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_source_tag (task, gbp_git_vcs_list_status_async);
- ide_task_set_return_on_cancel (task, TRUE);
-
- ide_object_lock (IDE_OBJECT (self));
- if (self->repository == NULL)
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No repository loaded");
- else
- ide_task_run_in_thread (task, gbp_git_vcs_list_branches_worker);
- ide_object_unlock (IDE_OBJECT (self));
+ ide_task_set_source_tag (task, gbp_git_vcs_list_branches_async);
- IDE_EXIT;
+ ipc_git_repository_call_list_refs_by_kind (self->repository,
+ IPC_GIT_REF_BRANCH,
+ cancellable,
+ gbp_git_vcs_list_branches_cb,
+ g_steal_pointer (&task));
}
static GPtrArray *
@@ -540,67 +236,49 @@ gbp_git_vcs_list_branches_finish (IdeVcs *vcs,
GAsyncResult *result,
GError **error)
{
- g_return_val_if_fail (GBP_IS_GIT_VCS (vcs), NULL);
- g_return_val_if_fail (IDE_IS_TASK (result), NULL);
+ GPtrArray *ret;
- return ide_task_propagate_pointer (IDE_TASK (result), error);
-}
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_GIT_VCS (vcs));
+ g_assert (IDE_IS_TASK (result));
-static gint
-compare_tags (gconstpointer a,
- gconstpointer b)
-{
- return g_utf8_collate (*(const gchar **)a, *(const gchar **)b);
+ ret = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+ return IDE_PTR_ARRAY_STEAL_FULL (&ret);
}
-static void
-gbp_git_vcs_list_tags_worker (IdeTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+static GPtrArray *
+create_tags (gchar **refs)
{
- GbpGitVcs *self = source_object;
- g_autoptr(GPtrArray) tags = NULL;
-
- g_assert (IDE_IS_TASK (task));
- g_assert (GBP_IS_GIT_VCS (self));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ GPtrArray *ret = g_ptr_array_new_with_free_func (g_object_unref);
- tags = g_ptr_array_new_with_free_func (g_object_unref);
-
- ide_object_lock (IDE_OBJECT (self));
-
- if (self->repository != NULL)
+ if (refs != NULL)
{
- g_autoptr(GgitBranchEnumerator) enumerator = NULL;
- g_auto(GStrv) names = NULL;
- g_autoptr(GError) error = NULL;
+ for (guint i = 0; refs[i]; i++)
+ g_ptr_array_add (ret, gbp_git_tag_new (refs[i]));
+ }
- if (!(names = ggit_repository_list_tags (self->repository, &error)))
- {
- ide_task_return_error (task, g_steal_pointer (&error));
- goto unlock;
- }
+ return g_steal_pointer (&ret);
+}
- qsort (names, g_strv_length (names), sizeof (gchar *), compare_tags);
+static void
+gbp_git_vcs_list_tags_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IpcGitRepository *repository = (IpcGitRepository *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ g_auto(GStrv) refs = NULL;
- for (guint i = 0; names[i] != NULL; i++)
- g_ptr_array_add (tags, gbp_git_tag_new (names[i]));
+ g_assert (IPC_IS_GIT_REPOSITORY (repository));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
- ide_task_return_pointer (task,
- g_steal_pointer (&tags),
- g_ptr_array_unref);
- }
+ if (!ipc_git_repository_call_list_refs_by_kind_finish (repository, &refs, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
else
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No repository to access");
- }
-
-unlock:
- ide_object_unlock (IDE_OBJECT (self));
+ ide_task_return_pointer (task, create_tags (refs), g_ptr_array_unref);
}
static void
@@ -612,27 +290,18 @@ gbp_git_vcs_list_tags_async (IdeVcs *vcs,
GbpGitVcs *self = (GbpGitVcs *)vcs;
g_autoptr(IdeTask) task = NULL;
- IDE_ENTRY;
-
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (GBP_IS_GIT_VCS (self));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_source_tag (task, gbp_git_vcs_list_status_async);
- ide_task_set_return_on_cancel (task, TRUE);
-
- ide_object_lock (IDE_OBJECT (self));
- if (self->repository == NULL)
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No repository loaded");
- else
- ide_task_run_in_thread (task, gbp_git_vcs_list_tags_worker);
- ide_object_unlock (IDE_OBJECT (self));
+ ide_task_set_source_tag (task, gbp_git_vcs_list_tags_async);
- IDE_EXIT;
+ ipc_git_repository_call_list_refs_by_kind (self->repository,
+ IPC_GIT_REF_TAG,
+ cancellable,
+ gbp_git_vcs_list_tags_cb,
+ g_steal_pointer (&task));
}
static GPtrArray *
@@ -640,215 +309,256 @@ gbp_git_vcs_list_tags_finish (IdeVcs *vcs,
GAsyncResult *result,
GError **error)
{
- g_return_val_if_fail (GBP_IS_GIT_VCS (vcs), NULL);
- g_return_val_if_fail (IDE_IS_TASK (result), NULL);
+ GPtrArray *ret;
- return ide_task_propagate_pointer (IDE_TASK (result), error);
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_GIT_VCS (vcs));
+ g_assert (IDE_IS_TASK (result));
+
+ ret = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+ return IDE_PTR_ARRAY_STEAL_FULL (&ret);
}
-static void
-gbp_git_vcs_switch_branch_worker (IdeTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+static GListModel *
+create_status_model (GbpGitVcs *self,
+ GVariant *files)
{
- g_autoptr(GgitCheckoutOptions) checkout_options = NULL;
- g_autoptr(GgitObject) obj = NULL;
- g_autoptr(GgitRef) ref = NULL;
- g_autoptr(GError) error = NULL;
- GbpGitVcs *self = source_object;
- const gchar *id = task_data;
+ g_autoptr(GListStore) store = NULL;
+ GVariantIter iter;
+ const gchar *path = NULL;
+ guint flags = 0;
- g_assert (IDE_IS_TASK (task));
g_assert (GBP_IS_GIT_VCS (self));
- g_assert (id != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_assert (files != NULL);
- ide_object_lock (IDE_OBJECT (self));
+ store = g_list_store_new (IDE_TYPE_VCS_FILE_INFO);
- if (self->repository == NULL)
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No repository to switch");
- goto unlock;
- }
+ g_variant_iter_init (&iter, files);
- if (!(ref = ggit_repository_lookup_reference (self->repository, id, &error)) ||
- !(obj = ggit_ref_lookup (ref, &error)))
+ while (g_variant_iter_next (&iter, "(&su)", &path, &flags))
{
- ide_task_return_error (task, g_steal_pointer (&error));
- goto unlock;
+ g_autoptr(GFile) file = g_file_get_child (self->workdir, path);
+
+ g_list_store_append (store,
+ g_object_new (IDE_TYPE_VCS_FILE_INFO,
+ "file", file,
+ "status", flags,
+ NULL));
}
- checkout_options = ggit_checkout_options_new ();
- ggit_checkout_options_set_strategy (checkout_options, GGIT_CHECKOUT_SAFE);
+ return G_LIST_MODEL (g_steal_pointer (&store));
+}
- /* Update the tree contents */
- if (!ggit_repository_checkout_tree (self->repository,
- obj,
- checkout_options,
- &error))
- {
- ide_task_return_error (task, g_steal_pointer (&error));
- goto unlock;
- }
+static void
+gbp_git_vcs_list_status_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IpcGitRepository *repository = (IpcGitRepository *)object;
+ g_autoptr(GVariant) files = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ GbpGitVcs *self;
- /* Now update head to point at the branch */
- if (!ggit_repository_set_head (self->repository, id, &error))
- {
- ide_task_return_error (task, g_steal_pointer (&error));
- goto unlock;
- }
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IPC_IS_GIT_REPOSITORY (repository));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
- ide_task_return_boolean (task, TRUE);
+ self = ide_task_get_source_object (task);
-unlock:
- ide_object_unlock (IDE_OBJECT (self));
+ if (!ipc_git_repository_call_list_status_finish (repository, &files, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_object (task, create_status_model (self, files));
}
static void
-gbp_git_vcs_switch_branch_async (IdeVcs *vcs,
- IdeVcsBranch *branch,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+gbp_git_vcs_list_status_async (IdeVcs *vcs,
+ GFile *directory_or_file,
+ gboolean include_descendants,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ GbpGitVcs *self = (GbpGitVcs *)vcs;
g_autoptr(IdeTask) task = NULL;
+ g_autofree gchar *relative_path = NULL;
g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_GIT_VCS (vcs));
- g_assert (GBP_IS_GIT_BRANCH (branch));
+ g_assert (GBP_IS_GIT_VCS (self));
+ g_assert (G_IS_FILE (directory_or_file));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- task = ide_task_new (vcs, cancellable, callback, user_data);
- ide_task_set_source_tag (task, gbp_git_vcs_switch_branch_async);
- ide_task_set_task_data (task,
- g_strdup (ide_vcs_branch_get_name (branch)),
- g_free);
- ide_task_run_in_thread (task, gbp_git_vcs_switch_branch_worker);
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_git_vcs_list_status_async);
+
+ if (!g_file_has_prefix (directory_or_file, self->workdir) &&
+ !g_file_equal (directory_or_file, self->workdir))
+ {
+ ide_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "Directory is not within repository");
+ return;
+ }
+
+ relative_path = g_file_get_relative_path (self->workdir, directory_or_file);
+
+ ipc_git_repository_call_list_status (self->repository,
+ relative_path ?: "",
+ cancellable,
+ gbp_git_vcs_list_status_cb,
+ g_steal_pointer (&task));
}
-static gboolean
-gbp_git_vcs_switch_branch_finish (IdeVcs *vcs,
- GAsyncResult *result,
- GError **error)
+static GListModel *
+gbp_git_vcs_list_status_finish (IdeVcs *vcs,
+ GAsyncResult *result,
+ GError **error)
{
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (GBP_IS_GIT_VCS (vcs));
g_assert (IDE_IS_TASK (result));
- ide_vcs_emit_changed (vcs);
-
- return ide_task_propagate_boolean (IDE_TASK (result), error);
+ return ide_task_propagate_object (IDE_TASK (result), error);
}
static void
vcs_iface_init (IdeVcsInterface *iface)
{
iface->get_workdir = gbp_git_vcs_get_workdir;
- iface->get_branch_name = gbp_git_vcs_get_branch_name;
- iface->get_config = gbp_git_vcs_get_config;
iface->is_ignored = gbp_git_vcs_is_ignored;
- iface->list_status_async = gbp_git_vcs_list_status_async;
- iface->list_status_finish = gbp_git_vcs_list_status_finish;
+ iface->get_config = gbp_git_vcs_get_config;
+ iface->get_branch_name = gbp_git_vcs_get_branch_name;
+ iface->switch_branch_async = gbp_git_vcs_switch_branch_async;
+ iface->switch_branch_finish = gbp_git_vcs_switch_branch_finish;
iface->list_branches_async = gbp_git_vcs_list_branches_async;
iface->list_branches_finish = gbp_git_vcs_list_branches_finish;
iface->list_tags_async = gbp_git_vcs_list_tags_async;
iface->list_tags_finish = gbp_git_vcs_list_tags_finish;
- iface->switch_branch_async = gbp_git_vcs_switch_branch_async;
- iface->switch_branch_finish = gbp_git_vcs_switch_branch_finish;
+ iface->list_status_async = gbp_git_vcs_list_status_async;
+ iface->list_status_finish = gbp_git_vcs_list_status_finish;
}
+G_DEFINE_TYPE_WITH_CODE (GbpGitVcs, gbp_git_vcs, IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_VCS, vcs_iface_init))
+
+static GParamSpec *properties [N_PROPS];
+
static void
-gbp_git_vcs_reload_worker (IdeTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+gbp_git_vcs_finalize (GObject *object)
{
- g_autoptr(GgitRepository) repository = NULL;
- g_autoptr(GError) error = NULL;
- GFile *location = task_data;
+ GbpGitVcs *self = (GbpGitVcs *)object;
- IDE_ENTRY;
+ g_clear_object (&self->repository);
- g_assert (!IDE_IS_MAIN_THREAD ());
- g_assert (IDE_IS_TASK (task));
- g_assert (GBP_IS_GIT_VCS (source_object));
- g_assert (G_IS_FILE (location));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ G_OBJECT_CLASS (gbp_git_vcs_parent_class)->finalize (object);
+}
- if (!(repository = ggit_repository_open (location, &error)))
- ide_task_return_error (task, g_steal_pointer (&error));
- else
- ide_task_return_pointer (task, g_steal_pointer (&repository), g_object_unref);
+static void
+gbp_git_vcs_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbpGitVcs *self = GBP_GIT_VCS (object);
+
+ switch (prop_id)
+ {
+ case PROP_BRANCH_NAME:
+ g_value_take_string (value, gbp_git_vcs_get_branch_name (IDE_VCS (self)));
+ break;
- IDE_EXIT;
+ case PROP_WORKDIR:
+ g_value_take_object (value, g_file_dup (self->workdir));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
}
-void
-gbp_git_vcs_reload_async (GbpGitVcs *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static void
+gbp_git_vcs_class_init (GbpGitVcsClass *klass)
{
- g_autoptr(IdeTask) task = NULL;
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
- IDE_ENTRY;
+ object_class->finalize = gbp_git_vcs_finalize;
+ object_class->get_property = gbp_git_vcs_get_property;
- g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_GIT_VCS (self));
+ properties [PROP_BRANCH_NAME] =
+ g_param_spec_string ("branch-name",
+ "Branch Name",
+ "The name of the current branch",
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_priority (task, G_PRIORITY_LOW);
- ide_task_set_source_tag (task, gbp_git_vcs_reload_async);
- ide_task_set_task_data (task, g_object_ref (self->location), g_object_unref);
- ide_task_run_in_thread (task, gbp_git_vcs_reload_worker);
+ properties [PROP_WORKDIR] =
+ g_param_spec_object ("workdir",
+ "Workdir",
+ "The workdir of the vcs",
+ G_TYPE_FILE,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- IDE_EXIT;
+ g_object_class_install_properties (object_class, N_PROPS, properties);
}
-gboolean
-gbp_git_vcs_reload_finish (GbpGitVcs *self,
- GAsyncResult *result,
- GError **error)
+static void
+gbp_git_vcs_init (GbpGitVcs *self)
{
- g_autoptr(GgitRepository) repository = NULL;
- g_autoptr(GgitRef) ref = NULL;
+}
- g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
- g_return_val_if_fail (GBP_IS_GIT_VCS (self), FALSE);
- g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+static void
+gbp_git_vcs_notify_branch_cb (GbpGitVcs *self,
+ GParamSpec *pspec,
+ IpcGitRepository *repository)
+{
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BRANCH_NAME]);
+}
- ide_object_lock (IDE_OBJECT (self));
+static void
+gbp_git_vcs_changed_cb (GbpGitVcs *self,
+ IpcGitRepository *repository)
+{
+ ide_vcs_emit_changed (IDE_VCS (self));
+}
- if (!(repository = ide_task_propagate_pointer (IDE_TASK (result), error)))
- goto failure;
+GbpGitVcs *
+gbp_git_vcs_new (IpcGitRepository *repository)
+{
+ const gchar *workdir;
+ GbpGitVcs *ret;
- if ((ref = ggit_repository_get_head (repository, NULL)))
- {
- const gchar *name = ggit_ref_get_shorthand (ref);
-
- if (name != NULL)
- {
- if (!ide_str_equal0 (name, self->branch))
- {
- g_free (self->branch);
- self->branch = g_strdup (name);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BRANCH_NAME]);
- }
- }
- }
+ g_return_val_if_fail (IPC_IS_GIT_REPOSITORY (repository), NULL);
- if (g_set_object (&self->repository, repository))
- {
- ide_vcs_emit_changed (IDE_VCS (self));
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_REPOSITORY]);
- }
+ workdir = ipc_git_repository_get_workdir (repository);
+
+ ret = g_object_new (GBP_TYPE_GIT_VCS, NULL);
+ ret->repository = g_object_ref (repository);
+ ret->workdir = g_file_new_for_path (workdir);
+
+ g_signal_connect_object (repository,
+ "notify::branch",
+ G_CALLBACK (gbp_git_vcs_notify_branch_cb),
+ ret,
+ G_CONNECT_SWAPPED);
+
+ g_signal_connect_object (repository,
+ "changed",
+ G_CALLBACK (gbp_git_vcs_changed_cb),
+ ret,
+ G_CONNECT_SWAPPED);
+
+ return g_steal_pointer (&ret);
+}
-failure:
- ide_object_unlock (IDE_OBJECT (self));
+IpcGitRepository *
+gbp_git_vcs_get_repository (GbpGitVcs *self)
+{
+ g_return_val_if_fail (GBP_IS_GIT_VCS (self), NULL);
- return repository != NULL;
+ return self->repository;
}
diff --git a/src/plugins/git/gbp-git-vcs.h b/src/plugins/git/gbp-git-vcs.h
index cb337921a..0d395dbf6 100644
--- a/src/plugins/git/gbp-git-vcs.h
+++ b/src/plugins/git/gbp-git-vcs.h
@@ -1,6 +1,6 @@
/* gbp-git-vcs.h
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2014-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
@@ -20,23 +20,17 @@
#pragma once
-#include <libgit2-glib/ggit.h>
#include <libide-vcs.h>
+#include "daemon/ipc-git-repository.h"
+
G_BEGIN_DECLS
#define GBP_TYPE_GIT_VCS (gbp_git_vcs_get_type())
G_DECLARE_FINAL_TYPE (GbpGitVcs, gbp_git_vcs, GBP, GIT_VCS, IdeObject)
-GFile *gbp_git_vcs_get_location (GbpGitVcs *self);
-GgitRepository *gbp_git_vcs_get_repository (GbpGitVcs *self);
-void gbp_git_vcs_reload_async (GbpGitVcs *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean gbp_git_vcs_reload_finish (GbpGitVcs *self,
- GAsyncResult *result,
- GError **error);
+GbpGitVcs *gbp_git_vcs_new (IpcGitRepository *repository);
+IpcGitRepository *gbp_git_vcs_get_repository (GbpGitVcs *self);
G_END_DECLS
diff --git a/src/plugins/git/gbp-git-workbench-addin.c b/src/plugins/git/gbp-git-workbench-addin.c
index e3831d98e..669250456 100644
--- a/src/plugins/git/gbp-git-workbench-addin.c
+++ b/src/plugins/git/gbp-git-workbench-addin.c
@@ -1,6 +1,6 @@
/* gbp-git-workbench-addin.c
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * 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
@@ -22,243 +22,164 @@
#include "config.h"
-#include <libgit2-glib/ggit.h>
-#include <libide-editor.h>
-#include <libide-io.h>
-#include <libide-threading.h>
+#include <libide-vcs.h>
-#include "gbp-git-buffer-change-monitor.h"
-#include "gbp-git-index-monitor.h"
-#include "gbp-git-vcs.h"
+#include "daemon/ipc-git-service.h"
+
+#include "gbp-git-client.h"
#include "gbp-git-workbench-addin.h"
+#include "gbp-git-vcs.h"
struct _GbpGitWorkbenchAddin
{
- GObject parent_instance;
- IdeWorkbench *workbench;
- GbpGitIndexMonitor *monitor;
- guint has_loaded : 1;
+ GObject parent_instance;
+ IdeWorkbench *workbench;
};
static void
-gbp_git_workbench_addin_load_project_worker (IdeTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+gbp_git_workbench_addin_load_project_new_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- g_autoptr(GgitRepository) repository = NULL;
- g_autoptr(GbpGitVcs) vcs = NULL;
- g_autoptr(GFile) location = NULL;
- g_autoptr(GFile) workdir = NULL;
+ GbpGitWorkbenchAddin *self;
+ g_autoptr(IpcGitRepository) repository = NULL;
+ g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
- g_autofree gchar *worktree_branch = NULL;
- GFile *directory = task_data;
+ g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
- g_assert (GBP_IS_GIT_WORKBENCH_ADDIN (source_object));
- g_assert (G_IS_FILE (directory));
-
- /* Short-circuit if we don't .git */
- if (!(location = ggit_repository_discover_full (directory, TRUE, NULL, &error)))
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- "Failed to locate git repository location");
- return;
- }
-
- g_debug ("Located .git at %s", g_file_peek_path (location));
-
- /* If @location is a regular file, we might have a git-worktree link */
- if (g_file_query_file_type (location, 0, NULL) == G_FILE_TYPE_REGULAR)
- {
- g_autofree gchar *contents = NULL;
- gsize len;
-
- if (g_file_load_contents (location, NULL, &contents, &len, NULL, NULL))
- {
- IdeLineReader reader;
- gchar *line;
- gsize line_len;
-
- ide_line_reader_init (&reader, contents, len);
-
- while ((line = ide_line_reader_next (&reader, &line_len)))
- {
- line[line_len] = 0;
-
- if (g_str_has_prefix (line, "gitdir: "))
- {
- g_autoptr(GFile) location_parent = g_file_get_parent (location);
- const gchar *path = line + strlen ("gitdir: ");
- const gchar *branch;
-
- g_clear_object (&location);
-
- if (g_path_is_absolute (path))
- location = g_file_new_for_path (path);
- else
- location = g_file_resolve_relative_path (location_parent, path);
-
- /*
- * Worktrees only have a single branch, and it is the name
- * of the suffix of .git/worktrees/<name>
- */
- if ((branch = strrchr (line, G_DIR_SEPARATOR)))
- worktree_branch = g_strdup (branch + 1);
-
- break;
- }
- }
- }
- }
- if (!(repository = ggit_repository_open (location, &error)))
+ if (!(repository = ipc_git_repository_proxy_new_finish (result, &error)))
{
ide_task_return_error (task, g_steal_pointer (&error));
return;
}
- workdir = ggit_repository_get_workdir (repository);
+ self = ide_task_get_source_object (task);
- g_assert (G_IS_FILE (location));
- g_assert (G_IS_FILE (workdir));
- g_assert (GGIT_IS_REPOSITORY (repository));
-
- if (worktree_branch == NULL)
+ if (self->workbench != NULL)
{
- g_autoptr(GgitRef) ref = NULL;
-
- if ((ref = ggit_repository_get_head (repository, NULL)))
- worktree_branch = g_strdup (ggit_ref_get_shorthand (ref));
+ g_autoptr(GbpGitVcs) vcs = gbp_git_vcs_new (repository);
- if (worktree_branch == NULL)
- worktree_branch = g_strdup ("master");
+ ide_workbench_set_vcs (self->workbench, IDE_VCS (vcs));
}
- vcs = g_object_new (GBP_TYPE_GIT_VCS,
- "branch-name", worktree_branch,
- "location", location,
- "repository", repository,
- "workdir", workdir,
- NULL);
-
- ide_task_return_pointer (task, g_steal_pointer (&vcs), g_object_unref);
+ ide_task_return_boolean (task, TRUE);
}
static void
-gbp_git_workbench_addin_load_project_async (IdeWorkbenchAddin *addin,
- IdeProjectInfo *project_info,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+gbp_git_workbench_addin_load_project_open_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GbpGitWorkbenchAddin *self = (GbpGitWorkbenchAddin *)addin;
- g_autoptr(IdeTask) task = NULL;
- GFile *directory;
-
- g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_GIT_WORKBENCH_ADDIN (self));
- g_assert (IDE_IS_PROJECT_INFO (project_info));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- self->has_loaded = TRUE;
-
- task = ide_task_new (self, cancellable, callback, user_data);
- ide_task_set_source_tag (task, gbp_git_workbench_addin_load_project_async);
+ IpcGitService *service = (IpcGitService *)object;
+ g_autofree gchar *obj_path = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ GDBusConnection *connection;
- if (!(directory = ide_project_info_get_directory (project_info)))
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- "Missing directory from project info");
- return;
- }
+ g_assert (IPC_IS_GIT_SERVICE (service));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
- /* Try to discover the git repository from a worker thread. If we find
- * it, we'll set the VCS on the workbench for various components to use.
- */
- ide_task_set_task_data (task, g_object_ref (directory), g_object_unref);
- ide_task_run_in_thread (task, gbp_git_workbench_addin_load_project_worker);
+ connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (service));
+
+ if (!ipc_git_service_call_open_finish (service, &obj_path, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ipc_git_repository_proxy_new (connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ obj_path,
+ ide_task_get_cancellable (task),
+ gbp_git_workbench_addin_load_project_new_cb,
+ g_object_ref (task));
}
static void
-gbp_git_workbench_addin_foreach_buffer_cb (IdeBuffer *buffer,
- gpointer user_data)
+gbp_git_workbench_addin_load_project_discover_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GgitRepository *repository = user_data;
- IdeBufferChangeMonitor *monitor;
-
- g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (IDE_IS_BUFFER (buffer));
- g_assert (GGIT_IS_REPOSITORY (repository));
+ IpcGitService *service = (IpcGitService *)object;
+ g_autofree gchar *git_location = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
- monitor = ide_buffer_get_change_monitor (buffer);
+ g_assert (IPC_IS_GIT_SERVICE (service));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
- if (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (monitor))
- gbp_git_buffer_change_monitor_set_repository (GBP_GIT_BUFFER_CHANGE_MONITOR (monitor),
- repository);
+ if (!ipc_git_service_call_discover_finish (service, &git_location, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ipc_git_service_call_open (service,
+ git_location,
+ ide_task_get_cancellable (task),
+ gbp_git_workbench_addin_load_project_open_cb,
+ g_object_ref (task));
}
static void
-gbp_git_workbench_addin_reload_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+gbp_git_workbench_addin_load_project_service_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GbpGitVcs *vcs = (GbpGitVcs *)object;
- g_autoptr(GbpGitWorkbenchAddin) self = user_data;
+ GbpGitClient *client = (GbpGitClient *)object;
+ g_autoptr(IpcGitService) service = NULL;
+ g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
- IdeBufferManager *buffer_manager;
- GgitRepository *repository;
- IdeContext *context;
+ IdeProjectInfo *project_info;
+ GFile *directory;
- g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_GIT_VCS (vcs));
+ g_assert (GBP_IS_GIT_CLIENT (client));
g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (GBP_IS_GIT_WORKBENCH_ADDIN (self));
-
- if (!gbp_git_vcs_reload_finish (vcs, result, &error))
- return;
+ g_assert (IDE_IS_TASK (task));
- if (self->workbench == NULL)
- return;
+ if (!(service = gbp_git_client_get_service_finish (client, result, &error)))
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
- repository = gbp_git_vcs_get_repository (vcs);
- context = ide_workbench_get_context (self->workbench);
- buffer_manager = ide_buffer_manager_from_context (context);
+ project_info = ide_task_get_task_data (task);
+ directory = ide_project_info_get_directory (project_info);
- ide_buffer_manager_foreach (buffer_manager,
- gbp_git_workbench_addin_foreach_buffer_cb,
- repository);
+ ipc_git_service_call_discover (service,
+ g_file_peek_path (directory),
+ ide_task_get_cancellable (task),
+ gbp_git_workbench_addin_load_project_discover_cb,
+ g_object_ref (task));
}
static void
-gbp_git_workbench_addin_monitor_changed_cb (GbpGitWorkbenchAddin *self,
- GbpGitIndexMonitor *monitor)
+gbp_git_workbench_addin_load_project_async (IdeWorkbenchAddin *addin,
+ IdeProjectInfo *project_info,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ GbpGitWorkbenchAddin *self = (GbpGitWorkbenchAddin *)addin;
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(GError) error = NULL;
+ GbpGitClient *client;
IdeContext *context;
- IdeVcs *vcs;
-
- IDE_ENTRY;
- g_assert (IDE_IS_MAIN_THREAD ());
g_assert (GBP_IS_GIT_WORKBENCH_ADDIN (self));
- g_assert (GBP_IS_GIT_INDEX_MONITOR (monitor));
-
- context = ide_workbench_get_context (self->workbench);
- vcs = ide_vcs_from_context (context);
+ g_assert (IDE_IS_PROJECT_INFO (project_info));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- if (!GBP_IS_GIT_VCS (vcs))
- IDE_EXIT;
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_git_workbench_addin_load_project_async);
+ ide_task_set_task_data (task, g_object_ref (project_info), g_object_unref);
- gbp_git_vcs_reload_async (GBP_GIT_VCS (vcs),
- NULL,
- gbp_git_workbench_addin_reload_cb,
- g_object_ref (self));
+ context = ide_workbench_get_context (self->workbench);
+ client = gbp_git_client_from_context (context);
- IDE_EXIT;
+ gbp_git_client_get_service_async (client,
+ cancellable,
+ gbp_git_workbench_addin_load_project_service_cb,
+ g_steal_pointer (&task));
}
static gboolean
@@ -266,98 +187,34 @@ gbp_git_workbench_addin_load_project_finish (IdeWorkbenchAddin *addin,
GAsyncResult *result,
GError **error)
{
- GbpGitWorkbenchAddin *self = (GbpGitWorkbenchAddin *)addin;
- g_autoptr(GbpGitVcs) vcs = NULL;
-
- g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_GIT_WORKBENCH_ADDIN (self));
+ g_assert (GBP_IS_GIT_WORKBENCH_ADDIN (addin));
g_assert (IDE_IS_TASK (result));
- if ((vcs = ide_task_propagate_pointer (IDE_TASK (result), error)))
- {
- if (IDE_IS_WORKBENCH (self->workbench))
- {
- /* Set the vcs for the workbench */
- ide_workbench_set_vcs (self->workbench, IDE_VCS (vcs));
-
- if (self->monitor == NULL)
- {
- GFile *location = gbp_git_vcs_get_location (vcs);
-
- self->monitor = gbp_git_index_monitor_new (location);
-
- g_signal_connect_object (self->monitor,
- "changed",
- G_CALLBACK (gbp_git_workbench_addin_monitor_changed_cb),
- self,
- G_CONNECT_SWAPPED);
- }
- }
- }
-
- return vcs != NULL;
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
}
static void
gbp_git_workbench_addin_load (IdeWorkbenchAddin *addin,
IdeWorkbench *workbench)
-{
- GBP_GIT_WORKBENCH_ADDIN (addin)->workbench = workbench;
-}
-
-static void
-gbp_git_workbench_addin_unload (IdeWorkbenchAddin *addin,
- IdeWorkbench *workbench)
{
GbpGitWorkbenchAddin *self = (GbpGitWorkbenchAddin *)addin;
- g_assert (IDE_IS_MAIN_THREAD ());
g_assert (GBP_IS_GIT_WORKBENCH_ADDIN (self));
g_assert (IDE_IS_WORKBENCH (workbench));
- g_clear_object (&self->monitor);
-
- self->workbench = NULL;
-}
-
-static void
-load_git_for_editor_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- gbp_git_workbench_addin_load_project_finish (IDE_WORKBENCH_ADDIN (object), result, NULL);
+ self->workbench = workbench;
}
static void
-gbp_git_workbench_addin_workspace_added (IdeWorkbenchAddin *addin,
- IdeWorkspace *workspace)
+gbp_git_workbench_addin_unload (IdeWorkbenchAddin *addin,
+ IdeWorkbench *workbench)
{
GbpGitWorkbenchAddin *self = (GbpGitWorkbenchAddin *)addin;
g_assert (GBP_IS_GIT_WORKBENCH_ADDIN (self));
- g_assert (IDE_IS_WORKSPACE (workspace));
+ g_assert (IDE_IS_WORKBENCH (workbench));
- if (!self->has_loaded)
- {
- /* If we see a new IdeEditorWorkspace without having loaded a project,
- * that means that we are in a non-project scenario (dedicated editor
- * window). We can try our best to load a git repository based on
- * the files that are loaded.
- */
- if (IDE_IS_EDITOR_WORKSPACE (workspace))
- {
- IdeContext *context = ide_workbench_get_context (self->workbench);
- g_autoptr(GFile) workdir = ide_context_ref_workdir (context);
- g_autoptr(IdeTask) task = NULL;
-
- self->has_loaded = TRUE;
-
- task = ide_task_new (self, NULL, load_git_for_editor_cb, NULL);
- ide_task_set_source_tag (task, gbp_git_workbench_addin_workspace_added);
- ide_task_set_task_data (task, g_object_ref (workdir), g_object_unref);
- ide_task_run_in_thread (task, gbp_git_workbench_addin_load_project_worker);
- }
- }
+ self->workbench = NULL;
}
static void
@@ -367,12 +224,10 @@ workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface)
iface->unload = gbp_git_workbench_addin_unload;
iface->load_project_async = gbp_git_workbench_addin_load_project_async;
iface->load_project_finish = gbp_git_workbench_addin_load_project_finish;
- iface->workspace_added = gbp_git_workbench_addin_workspace_added;
}
G_DEFINE_TYPE_WITH_CODE (GbpGitWorkbenchAddin, gbp_git_workbench_addin, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKBENCH_ADDIN,
- workbench_addin_iface_init))
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKBENCH_ADDIN, workbench_addin_iface_init))
static void
gbp_git_workbench_addin_class_init (GbpGitWorkbenchAddinClass *klass)
diff --git a/src/plugins/git/gbp-git-workbench-addin.h b/src/plugins/git/gbp-git-workbench-addin.h
index 218b02004..9b7dba9bd 100644
--- a/src/plugins/git/gbp-git-workbench-addin.h
+++ b/src/plugins/git/gbp-git-workbench-addin.h
@@ -1,6 +1,6 @@
/* gbp-git-workbench-addin.h
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * 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
diff --git a/src/plugins/git/git-plugin.c b/src/plugins/git/git-plugin.c
index 85ae8d074..c77425f12 100644
--- a/src/plugins/git/git-plugin.c
+++ b/src/plugins/git/git-plugin.c
@@ -23,7 +23,6 @@
#include "config.h"
#include <libpeas/peas.h>
-#include <libgit2-glib/ggit.h>
#include <libide-editor.h>
#include <libide-foundry.h>
#include <libide-vcs.h>
@@ -31,66 +30,35 @@
#include "gbp-git-buffer-addin.h"
#include "gbp-git-dependency-updater.h"
#include "gbp-git-pipeline-addin.h"
-#include "gbp-git-remote-callbacks.h"
#include "gbp-git-vcs-cloner.h"
#include "gbp-git-vcs-config.h"
#include "gbp-git-vcs-initializer.h"
#include "gbp-git-workbench-addin.h"
-static gboolean
-register_ggit (void)
-{
- GgitFeatureFlags ggit_flags;
-
- ggit_init ();
-
- ggit_flags = ggit_get_features ();
-
- if ((ggit_flags & GGIT_FEATURE_THREADS) == 0)
- {
- g_printerr ("Builder requires libgit2-glib with threading support.");
- return FALSE;
- }
-
- if ((ggit_flags & GGIT_FEATURE_SSH) == 0)
- {
- g_printerr ("Builder requires libgit2-glib with SSH support.");
- return FALSE;
- }
-
- return TRUE;
-}
-
-
_IDE_EXTERN void
_gbp_git_register_types (PeasObjectModule *module)
{
- if (register_ggit ())
- {
- ide_g_file_add_ignored_pattern (".git");
-
- peas_object_module_register_extension_type (module,
- IDE_TYPE_BUFFER_ADDIN,
- GBP_TYPE_GIT_BUFFER_ADDIN);
- peas_object_module_register_extension_type (module,
- IDE_TYPE_PIPELINE_ADDIN,
- GBP_TYPE_GIT_PIPELINE_ADDIN);
- peas_object_module_register_extension_type (module,
- IDE_TYPE_DEPENDENCY_UPDATER,
- GBP_TYPE_GIT_DEPENDENCY_UPDATER);
- peas_object_module_register_extension_type (module,
- IDE_TYPE_VCS_CONFIG,
- GBP_TYPE_GIT_VCS_CONFIG);
- peas_object_module_register_extension_type (module,
- IDE_TYPE_VCS_CLONER,
- GBP_TYPE_GIT_VCS_CLONER);
- peas_object_module_register_extension_type (module,
- IDE_TYPE_VCS_INITIALIZER,
- GBP_TYPE_GIT_VCS_INITIALIZER);
- peas_object_module_register_extension_type (module,
- IDE_TYPE_WORKBENCH_ADDIN,
- GBP_TYPE_GIT_WORKBENCH_ADDIN);
+ ide_g_file_add_ignored_pattern (".git");
- g_type_ensure (GBP_TYPE_GIT_REMOTE_CALLBACKS);
- }
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_BUFFER_ADDIN,
+ GBP_TYPE_GIT_BUFFER_ADDIN);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_DEPENDENCY_UPDATER,
+ GBP_TYPE_GIT_DEPENDENCY_UPDATER);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_PIPELINE_ADDIN,
+ GBP_TYPE_GIT_PIPELINE_ADDIN);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_VCS_CLONER,
+ GBP_TYPE_GIT_VCS_CLONER);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_VCS_CONFIG,
+ GBP_TYPE_GIT_VCS_CONFIG);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_VCS_INITIALIZER,
+ GBP_TYPE_GIT_VCS_INITIALIZER);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_WORKBENCH_ADDIN,
+ GBP_TYPE_GIT_WORKBENCH_ADDIN);
}
diff --git a/src/plugins/git/git.plugin b/src/plugins/git/git.plugin
index e190366cc..8592d5293 100644
--- a/src/plugins/git/git.plugin
+++ b/src/plugins/git/git.plugin
@@ -1,7 +1,7 @@
[Plugin]
Authors=Christian Hergert <christian hergert me>
Builtin=true
-Copyright=Copyright © 2015-2018 Christian Hergert
+Copyright=Copyright © 2015-2019 Christian Hergert
Description=Support for the Git version control system
Embedded=_gbp_git_register_types
Module=git
diff --git a/src/plugins/git/meson.build b/src/plugins/git/meson.build
index 6bf39781f..d08ba06c5 100644
--- a/src/plugins/git/meson.build
+++ b/src/plugins/git/meson.build
@@ -3,23 +3,22 @@ if get_option('plugin_git')
subdir('daemon')
plugins_sources += files([
- 'git-plugin.c',
+ 'daemon/line-cache.c',
'gbp-git-branch.c',
'gbp-git-buffer-addin.c',
'gbp-git-buffer-change-monitor.c',
'gbp-git-client.c',
'gbp-git-dependency-updater.c',
- 'gbp-git-index-monitor.c',
'gbp-git-pipeline-addin.c',
- 'gbp-git-remote-callbacks.c',
+ 'gbp-git-progress.c',
'gbp-git-submodule-stage.c',
'gbp-git-tag.c',
- 'gbp-git-vcs.c',
'gbp-git-vcs-cloner.c',
'gbp-git-vcs-config.c',
'gbp-git-vcs-initializer.c',
+ 'gbp-git-vcs.c',
'gbp-git-workbench-addin.c',
- 'line-cache.c',
+ 'git-plugin.c',
])
plugins_sources += [
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]